Signal Handling - Chad Salinas ::: Data Scientist
Use Slidify to create motion charts to share with the world on rPubs Chad Salinas or GitHub.
Slidify, rPubs Chad Salinas, Motion Charts, Hans Rosling
945
post-template-default,single,single-post,postid-945,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
a

Signal Handling

Signal handling, like most things, is difficult when you don’t understand it, then it is easy once you do understand!

How does the os or kernal communicate to processes that something interesting happened?

Problem:
Ex.  Dereference an address that is outside of our code’s jurisdiction results in a segmentation fault.
“Segmentation fault (core dumped)”
The address we tried to access doesn’t belong to any stack or heap segment.
Solution:
We can install a function to be run when a signal category is raised by the os.
static void handleSIGSEGV(int unused) {
    printf( “You dereferenced a NULL pointer.\n”);
    exit(0);
}
int main(int argc, char* argv[]) { …
    signal(SIGSEGV, handleSIGSEGV);
    *(int *) NULL = 0;
    printf(“We better never get here\n.”);
    return 0;
}
Some other signals include:
  • SIGILL
  • SIGFPE
  • SIGTSTP
  • SIGINT
  • SIGPIPE
  • SIGCHLD
SIGCHLD is the signal category sent by the OS to the parent process EVERY TIME a child process finishes.  Default behavior is for the parent process to ignore the signal, but parent process does have the option to install a handler to deal with this signal.
//  Dad sleeps and waits for 5 children finished example
static const size_t kNumChildren = 5;
static size_t numDone = 0;
static void reapChild(int unused) {
    waitpid(-1, NULL, 0);
    numDone++;
}
int main(…) {
    signal(SIGCHLD, reapChild);
    for(size_t kid = 1; kid <= kNumChildren, kid++) {
        pid_t pid = fork();
        if(pid == 0) {   // in a child
            sleep(3*kid);
            printf(“Kid # %zu done playing.\n”, kid);
            return 0;
        }
    }
   // in the parent process
    while(numDone < kNumChildren) {
        printf(“Kids missing.\n”);
        sleep(5);
        printf(“Dad wakes up and counts kids.\n”);
     }
     return 0;
}
Code looks good, but it is contrived to yield a fortunate spacing between when child processes finish and dad wakes up.  If we modify all child processes to sleep the same amount of time exposes a problem.  Now, all children could return while dad is sleeping. Dad would wake up and think only one child returned.  Signal handler does not maintain a count of outstanding signals that need to be handled. Instead signal handler maintains a boolean of whether their exists one or more signals to be handled.
Solution:
Change reapChild function to reap each child until there are no more.
static void reapChild(int unused) {
    while(true) {
        pid_t pid = waitpid(-1, NULL, 0);
        if(pid == -1) break;
        numDone++;
    }
}
Problem: What if we go back and change children to play for various different times?  Dad will wake up the 1st time and find that their are children still playing and go back to sleep.  But, he will be trapped inside the reapChild() waiting for the -1 return.  But -1 won’t be returned until all of the  children have finished playing.
Solution:
// modify kids to sleep a varying amount of time
sleep (3*kid)
// modify waitpid to not keep dad waiting in the SIGCHLD handler
pid_t pid = waitpid(-1, NULL, WNOHANG);
WNOHANG doesn’t hang up the dad when NO children have finished playing.
Dad wants to know if any children have finished and he gets the child’s pid.
If no child is finished, pid is 0, then dad is not hung up.
If all children are finished, pid would be -1

Chad Salinas working on Plotly

Chad Salinas working on analytics project.

Chad Salinas late nighter

Let the dataset change your mindset

– Hans Rosling
No Comments

Sorry, the comment form is closed at this time.