0

The program consists of 2 parts (i was asked to use pipe): A. manager - that creates processes that will help him calculate how many instances of a particular char are in the file. B. Count - Calculates how many instances there are in the file and returns the pipe to the manager. Moreover, In each program I changed the behavior of SIGPIPE, and changed the behavior I desired.

in the manager.c:

for(i = 0; i < len_sym; i++){
        ...
        if (pipe(pipe_fds + (2 * i)) == -1) {
            perror("ERROR : Failed creating pipe");
            exit(EXIT_FAILURE);
        }
        if ((curr_child = fork()) == 0){ //son
            dup2(pipe_fds[2*i + 1], STDOUT_FILENO);
            close(pipe_fds[2*i + 1]);
            close(pipe_fds[2*i + 0]);
            execvp(child_args[0], child_args);
        }
        else { //parent
            if (curr_child == -1){
                exit(EXIT_FAILURE);
            }
            close(pipe_fds[2*i + 1]); // close writerfd
            child_pids[i] = curr_child;
            printf("%d son created with pid %d\n", i + 1, child_pids[i]);
            // if (i == 1) {
            //     kill(curr_child, SIGPIPE);
            // }
        }
    }

    for(i = 0; i < len_sym; i++){
        curr_child = waitpid(child_pids[i], &exit_code, 0);
        printf("exit code %d\n", exit_code);
        printf("child pid %d\n", curr_child);

        if (curr_child == -1 || 256 == exit_code) {
            exit(EXIT_FAILURE);
        }

        if (WIFEXITED(exit_code)) {
            int bytes_read;
            while ((bytes_read = read(pipe_fds[i*2 + 0], buff, BUFF_SIZE)) > 0) {
                buff[bytes_read] = '\0';
                printf("%s", buff);
            }
            if (bytes_read == -1) {
                perror("ERROR : Failed reading from fifo");
                close(pipe_fds[i*2 + 0]);
                exit(EXIT_FAILURE);
            }
            close(pipe_fds[i*2 + 0]);
            child_pids[i] = 0;
        }
    }

handling SIGPIPE in manager.c


void my_signal_handler(int signum) {
    switch (signum) {
        case SIGPIPE:
            printf("SIGPIPE for Manager process %d. Leaving\n", getpid());
            for (int i = 0; i < len_sym; i++) {
                if ((child_pids != NULL) && child_pids[i]) {
                    kill(child_pids[i], SIGTERM);
                }
            }
            exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}

void register_signal_handlin() {
    struct sigaction new_action;
    memset(&new_action, 0, sizeof(new_action));
    new_action.sa_handler = my_signal_handler;
    if (0 != sigaction(SIGPIPE, &new_action, NULL)) {
        exit(EXIT_FAILURE);
    }
}

in the count.c:

for (j = 0; j < file_length; j++){
        if (*temp++ == c){
            counter++;
        }
    }
    sleep(10);
    if (argc > 4){
        sprintf(buff, "Process %d finishes. Symbol %c. Instances %d.\n", getpid(), c, counter);
        int buff_len = strlen(buff);
        int bytes_written;
        while ((bytes_written = write(writerfd, p, buff_len)) > 0) {
            p += bytes_written;
            buff_len -= bytes_written;
        }
        if (bytes_written == -1) {
            perror("PROCESS ERROR : Failed writing to fifo");
            close(writerfd);
            return EXIT_FAILURE;
        }
        close(writerfd);
    }

handling SIGPIPE in count.c

void my_signal_handler(int signum) {
    switch (signum) {
        case SIGPIPE:
            printf("SIGPIPE for process %d. Symbol %c. Counter %d.\n", getpid(), c, counter); 
            exit(EXIT_FAILURE);
        case SIGTERM:
            exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}


void register_signal_handling() {
    struct sigaction new_action;
    memset(&new_action, 0, sizeof(new_action));
    new_action.sa_handler = my_signal_handler;

    if (0 != sigaction(SIGPIPE, &new_action, NULL)) {
        exit(EXIT_FAILURE);
    }
    if (0 != sigaction(SIGTERM, &new_action, NULL)) {
        exit(EXIT_FAILURE);
    }
}

So in fact I run the manger program, and at the same time opens a new terminal, and from it sends kill -13 to a particular process.

the problems:

  1. In the manager I get an exit code of 256. Why?

  2. The WIFSIGNALED flag does not turn on, although I have sent a signal to the process.

  3. The return from the waitpid function is not -1, but the process number I sent kill -13 from the second terminal.

  4. I tried to send kill to one of the children from the manager and for some reason he activates the signal handler of the manager rather than the child's signal handler.

I am in the process of learning OS, so I will be happy for any help.

  • The status code set by `waitpid()` is **not** the waited for processes exit value. Read the man page for details, but you get the exit code with `WEXITSTATUS()` *only if* `WIFEXITED()` is true. – Shawn Apr 16 '19 at 08:55
  • And if that count.c is for the child process, when it gets signal 13 (SIGPIPE), it exits normally so `WIFSIGNALED()` would naturally be false for it. – Shawn Apr 16 '19 at 09:02
  • Also, you can't use `printf()` in a signal handler (or `exit()` for that matter). See http://www.man7.org/linux/man-pages/man7/signal-safety.7.html – Shawn Apr 16 '19 at 09:07
  • why when the child process gets signal 13 (SIGPIPE), it exits normally? – Avri Fridenson Apr 16 '19 at 09:47
  • That's what you wrote it to do. – Shawn Apr 16 '19 at 10:09
  • True, that's what happened. I try to understand the logic. why did this happen? I mean, I sent a signal, so why the program exits normally and WIFSIGNALED is false? What is the logic? – Avri Fridenson Apr 16 '19 at 10:21

0 Answers0