c - Parent and child sync by signals trouble -


so, task sync parent , 2 children in way: 1 child sends sigusr2 signal parent , blocks waiting parent msg. sync implemented global flags, parent waits of flag_ch become 1 (it happens when child sends sigusr2) , sends signal sigusr1 child, , child resumes (cause global flag_p becomes 1)

the trouble parent receives signals 1 child, , blocks waiting second child signals, don't appear . idea?..

#include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <signal.h> #include <sys/signalfd.h> #define lpc 10 pid_t ch[2];  sig_atomic_t flag_ch[2] = {0, 0}; sig_atomic_t flag_p = 0;  int get_ind(pid_t ch_pid) {     int i;     (i = 0; < 2; ++i) {         if (ch_pid == ch[i])             return i;     }     return -1; }  void usr_handler(int signo, siginfo_t* si, void* unused) {     int ch_index;     switch(signo) {         case sigusr2:             ch_index = get_ind(si->si_pid);             if (ch_index >= 0)                 flag_ch[ch_index] = 1;             else                 fprintf(stderr, "signal handled not child pid %d\n", si->si_pid);             break;         case sigusr1:             flag_p = 1;             break;     } }  void set_usr_handler(void) {     struct sigaction sa;     sa.sa_sigaction = usr_handler;     sa.sa_flags = sa_siginfo;     sa.sa_restorer = null;      sigemptyset(&sa.sa_mask);      if (0 != sigaction(sigusr1, &sa, null))         abort_prg("signal [sigusr1] error");      if (0 != sigaction(sigusr2, &sa, null))         abort_prg("signal [sigusr2] error"); }   void child_proc(void) {     int i;     (i = 0; < lpc; ++i) {         if (0 != kill(getppid(), sigusr2))             exit(1);         while (0 == flag_p) { };             flag_p = 0;     } }  int wait_child(void) {     while (0 == flag_ch[0] && 0 == flag_ch[1]) { };     if (1 == flag_ch[0]) {         flag_ch[0] = 0;         return ch[0];     }     flag_ch[1] = 0;     return ch[1]; }  void parent_proc(void) {     int i;     pid_t ch_pid;     (i = 0; < lpc * 2; ++i) {         ch_pid = wait_child();         printf("parent: received pid [%d]\n", ch_pid);         if (0 != kill(ch_pid, sigusr1))             exit(1);     } }  int main(int argc, char* argv[]) {     set_usr_handler();     int i;     (i = 0; < 2; ++i) {         pid_t child = fork();         if (0 > child)             exit(1);         if (0 == child) {             child_proc();             return 0;         }         ch[i] = child;     }        parent_proc();     return 0; } 

my guess it's missing volatile in few global variable declarations. example, flag_p not being volatile means loop

while (flag_p == 0) { } 

can run forever: gcc compiles load global variable once register, , loop until register non-zero (which never occurs).

a conservative approximation should make volatile mutable variables read or written in signal handler.

edit: source of problem can think of signals not cumulative: either parent process has no sigusr2 pending, or has one. if both children send parent process @ same time, 1 might delivered, far know.

edit: think "better" solution (more flexible , more portable) along lines of: not use signals @ all, use pipes. make 1 pipe between parent , each of children, , children send character 'x' on pipes when done. parent waits select(); or if wants wait until both children ready, can read 'x' character 1 pipe , other, blocking in both cases (the order doesn't matter).


Comments

Popular posts from this blog

Why does Ruby on Rails generate add a blank line to the end of a file? -

keyboard - Smiles and long press feature in Android -

node.js - Bad Request - node js ajax post -