Architecture Sending Signals - Chad Salinas ::: Data Scientist
Life and times of Chad Salinas
Chad Salinas, golf caddy, data scientist, chad rPubs, recovering chess addict, daddy caddy
954
post-template-default,single,single-post,postid-954,single-format-standard,qode-listing-1.0.1,qode-social-login-1.0,qode-news-1.0,qode-quick-links-1.0,qode-restaurant-1.0,ajax_fade,page_not_loaded,,qode-title-hidden,qode_grid_1300,qode-theme-ver-12.0.1,qode-theme-bridge,bridge,wpb-js-composer js-comp-ver-5.4.2,vc_responsive

Architecture Sending Signals

How to send a signal to another process

Attribution:  I thank Jerry Cain at Stanford for inspiring the following content

static void reapChild(int unused) {
    while(true) {
       pid_t pid = waitpid(-1, NULL, WNOHANG);  // don’t wait for all children to return
       if(pid <= 0) break:      // return 0 means their are still children that haven’t finished
                                         // return -1 means all children have finished
     // return of a positive int would mean we got a legitimate pid from a child that finished
     // so, we remove the child process from the queue of jobs
    printf( “Job %d removed from job list \n”, pid);
}
int main() {
    signal(SIGCHLD, reapChild);
    for(int i = 0; i < 3; i++) {
        pid_t pid = fork();
        if(pid == 0) {
            char*argv[] = {“date”, NULL};
            execvp(argv[0], argv);
        }
        sleep(1);
        printf(“Job %d added to job list\n”, pid);
    }
return 0;
}
Problem:  Above code prints “Job …removed…”  before “Job …added…”.
Background:  Think of the printf that adds a job to a job list as a placeholder for some more substantial code.  We need to register an interest in hearing about SIGCHILD, but we need to defer acting on the SIGCHLD alert until we are at a place in the code that accomplishes our goal, namely once we have added the job to the job list.
Solution:  Use signal blocking to TEMPORARILY suspend acting on the SIGCHLD.
int main() {
    signal(SIGCHLD, reapChild);
    // prepare a data structure to catalog all of the signals we are paying attention to
    // but we want to suspend our obligation to react to until its convenient for us.
    sigset_t mask;  // gives a 32 bit bit vector o for no signal, 1 for that signal is on
    sigemptyset(&mask);
    sigaddset(&mask, SIGCHLD);
    for(int i = 0; i < 3; i++) {
        // still send the SIGCHLD, but suspend having to react to it
        sigprocmask(SIG_BLOCK, &mask, NULL);
         pid_t pid = fork();
         if(pid == 0) {
            // don’t block signals behind the child’s back
           // this entire solution scaffolding was for the parent to make progress to a certain                 // point in the code, so lift the block for the child
           sigprocmask(SIG_UNBLOCK, &mask, NULL);
             char*argv[] = {“date”, NULL};
             execvp(argv[0], argv);
        }
        sleep(1);
        printf(“Job %d added to job list\n”, pid);
        // back to normal mode where main will call reapChild to react to pending SIGCHLD
        sigprocmask(SIG_UNBLOCK, &mask, NULL);
    }
return 0;
}

End of example

How to programmatically send a signal to a process to another process.
void kill(pid_t pid, int sig) ;
kill is bad name.  It was originally intended to kill the receiving process but was later multi-purposed to just send signals to processes in the family.  Now to kill a process use:
kill(pid, 9) where kill is just sending to the process and its the 9 flag that is killing the process.  The receiving process cannot install a handler to deal with the -9 flag.

Any programming problem can be solved by adding a level of indirection.

– David J. Wheeler
No Comments

Sorry, the comment form is closed at this time.