1

I want to map a pid_t returned by wait or waitpid to a struct of pipe file descriptors.

In the example below I do that with linear search. Is there better way to do that without a linear search or even a hash table? Using a function provided by UNIX or by approaching the problem a different way?

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <sys/wait.h>

#define READ_END    0
#define WRITE_END   1

typedef struct {
    pid_t pid;
    int fd_stdout[2];
    int fd_stdin[2];
    int fd_stderr[2];

    char *temp;
} Proc;

Proc fork_exec(char *file);

int main(int argc, char **argv) {

    char *files[] = {
        "A", "B", "C", "D",
        "E", "F", "G", "H",
        "I", "J", "K"
        // ...
    };

    const int num_files = sizeof(files) / sizeof(char *);

    const int process_count = 4;
    Proc procs[process_count];
    int file_index = 0;
    for (int i = 0; i < process_count && i < num_files; i++, file_index++) {
        procs[i] = fork_exec(files[i]);
    }

    for (; file_index < num_files; file_index++) {
        int status = 0;
        pid_t pid = waitpid(-1, &status, 0);

        /* !!! \/ How do I avoid this? \/ !!! */
        int index = -1;
        for (int i = 0; i < process_count; i++) {
            if (procs[i].pid == pid) {
                index = i;
                break;
            }
        }
        /* !!! ^ How do I avoid this? ^ !!! */

        assert(index != -1);

        printf("Done with %s\n", procs[index].temp);

        procs[index] = fork_exec(files[file_index]);
    }

    for (int j = 0; j < 4; j++) {
        int status = 0;
        pid_t pid = waitpid(-1, &status, 0);

        /* !!! \/ How do I avoid this? \/ !!! */
        int index = -1;
        for (int i = 0; i < process_count; i++) {
            if (procs[i].pid == pid) {
                index = i;
                break;
            }
        }
        /* !!! ^ How do I avoid this? ^ !!! */

        assert(index != -1);

        printf("Done with %s\n", procs[index].temp);
    }
}


Proc fork_exec(char *file) {
    Proc p = { 0 };
    assert(pipe(p.fd_stdin)  != -1);
    assert(pipe(p.fd_stdout) != -1);
    assert(pipe(p.fd_stderr) != -1);

    pid_t pid = fork();
    assert(pid != -1);

    if (pid == 0) {
        close(p.fd_stdin[WRITE_END]);
        close(p.fd_stdout[READ_END]);
        close(p.fd_stderr[READ_END]);

        dup2(p.fd_stdin[READ_END], STDIN_FILENO);
        dup2(p.fd_stdout[WRITE_END], STDOUT_FILENO);
        dup2(p.fd_stderr[WRITE_END], STDERR_FILENO);

        close(p.fd_stdin[READ_END]);
        close(p.fd_stdout[WRITE_END]);
        close(p.fd_stderr[WRITE_END]);

        execl("sha256sum", "sha256sum", file);
    }

    close(p.fd_stdin[READ_END]);
    close(p.fd_stdout[WRITE_END]);
    close(p.fd_stderr[WRITE_END]);

    p.pid = pid;
    p.temp = file;

    return p;
}

walnut
  • 21,629
  • 4
  • 23
  • 59
Klokat
  • 53
  • 2
  • Use C++ containers, like `std::unordered_map` or `std::map`, to map a `pid_t` to a `Proc`? – Sam Varshavchik Dec 12 '19 at 02:08
  • @SamVarshavchik I'm trying to avoid using C++ features for now since I want to be able to compile with a C compiler as well.Perhaps I shouldn't have tagged this as a C++ question. Sorry about that. – Klokat Dec 12 '19 at 02:16
  • @Klokat I removed the C++ tag (you can also [edit] tags yourself). You should not aim to compile source files with both a C and C++ compilers. The languages are too different. For cross-language usage usually only the header files are designed to work with both and the source files are compiled as the language they were written for. – walnut Dec 12 '19 at 02:22
  • For an array of size `4` (or any small number) linear search is going to be the most efficient algorithm anyway. Do you intend the numbers to be significantly larger? – walnut Dec 12 '19 at 02:27
  • @walnut I suppose no more than 16 or so. I was really hoping for a more elegant solution. – Klokat Dec 12 '19 at 02:36
  • @Klokat I suppose you can move it into a function and `return` instead of using the `index` variable and `break`. That seems more elegant to me. There are also POSIX functions implementing linear search, binary search, hash table and search tree algorithms (`lsearch`, `bsearch`, `hsearch`, `tsearch` and friends), but I am not used to using them, so I don't think I'll write an answer. Sort and binary search are also part of the C standard (`qsort`, `bsearch`) – walnut Dec 12 '19 at 02:44
  • With just a couple dozen elements, linear search should be fine. You'll spend more time programming a more efficient alternative than you'll save in processing. You don't really need to be concerned about this until you get in the thousands of elements. – Barmar Dec 12 '19 at 03:38

0 Answers0