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
Post a Comment