Impact of Signals on Unix/Linux System Calls

Discussion in 'C' started by poornaMoksha, Oct 8, 2011.

  1. poornaMoksha

    poornaMoksha New Member

    Joined:
    Jan 29, 2011
    Messages:
    150
    Likes Received:
    33
    Trophy Points:
    0
    Occupation:
    Software developer
    Location:
    India
    Suppose a system call was blocked due to some reason (like waiting for a read of some data on terminal) and during this time a signal occurs. Do you know what happens in this scenario?

    In this article we will discuss the impact of signals on system calls.

    System calls are different from normal function calls as a system call takes the flow control all the way to kernel. System calls are divided into two categories :
    • Slow system calls
    • Rest of the system calls
    Now, what are Slow system calls ?

    Slow system calls are those that can block for ever. These calls usually wait for a condition to occur and these calls can wait for infinite time if the condition does not occur. For example :
    1. The 'pause()' function call, which by default puts the calling process into sleep until and unless a signal is caught by this process.
    2. The 'read()' function calls to pipes(for example) which can block for ever until some data is present.
    3. The 'write()' function calls to pipes(for example) which can block for ever until the pipe is ready to accept the data.
    4. Some 'ioctl()' functions.
    The alternative definitions of the slow system calls could be :

    "The system calls that can take time to execute if/when operating on a slow device (like pipe, terminal)"

    If (lets say) read() function has received and transfered some data to application and is waiting to receive the rest of the data in order to give application the complete data it requested. Suppose, at this very moment a signal occurred. Now, in todays POSIX compliant systems a read() call would not fail rather it would return partial success with the partial amount of data it could read for the application. Same goes for a system function call like 'write()' which would return partial success with writing partial data that it could.

    But, what does this behavior mean? Does the application need to handle the partial success cases? Does that mean some more checks in the code like :

    Code:
    again:
      if ((n = read(fd, buffer, BUFFERSIZE)) < 0) {
          if (errno == EINTR)
              goto again; /* Seems like an interrupted system call, go back and try to execute once again */
          /* handle other errors */
                   }
    
    Thankfully, the answer to the above questions is NO. In modern day POSIX compliant systems, the interrupted system calls are restarted automatically by default. This takes away the overhead from an application programmer to test each time whether the a call to read() or write() was a complete success or a partial success.

    An Interesting Example



    Now, we understand the process that a system call is interrupted when a signal occurs. Lets demonstrate it through an example.

    Code:
    #include<stdio.h>
    #include<signal.h>
    #include<unistd.h>
    
    int flag;
    
    void sig_handler(int signo)
    {
       flag = 1;
       if (signo == SIGUSR1)
           printf("received SIGUSR1\n");
       else if (signo == SIGUSR2)
           printf("received SIGUSR2\n");
       else
           printf("ERR : received signal %d\n", signo);
    }
    
    int main(void)
    {
        if (signal(SIGUSR1, sig_handler) == SIG_ERR)
            printf("\ncan't catch SIGUSR1\n");
        if (signal(SIGUSR2, sig_handler) == SIG_ERR)
            printf("\ncan't catch SIGUSR2\n");
    
        /* Lets assume a logic consumes some processor time here*/
    
        /* now comes this while loop*/
        while(flag == 0)  // Simulate a dummy wait
            pause(); // Make this process to sleep until a signal occurs   (A slow system call :-) )
    
        return 0;
    }
    • In the above piece of code, we have created a signal handler 'sig_handler()'.
    • We have used a flag 'flag' which is initialized as '0'.
    • In the main() function, the process is made to sleep by pause() system call.
    • The process is awakened only when a signal is received(property exhibited by pause() function).
    • Whenever a signal USR1 or USR2 occurs, the signal handler 'sig_handler()' gets called.
    • In the signal handler the flag 'flag' is set to one.
    • Since the process is awakened through a signal, the while loop executes once again
    • Since 'flag' is now '1', so pause() is not called and main() returns.
    So, this was a demo code that relates the practical aspect of the concept told throughout this article.

    But you might be thinking, what was so interesting in that?

    Now, lets suppose that whomsoever wrote this code, wrote it with a precondition that when this code will run, once a signal USR1 will occur and this program will terminate after that. Note that the programmer knows that signal would occur only once and his/her program would catch it and return gracefully.

    If you have a closer look at the logic, you will observe a small flaw in the program. The flaw can be exploited in the time window between when the while loop is called for the very first time and the pause() function is yet to be executed. Suppose, during this time gap, the long awaited :) signal occurs. Ohh, did you guess what happens in this case? I'll tell you. In this case, before calling the pause() function, signal handler is called. Now, since the signal never occurs again, so the pause() system call never returns and hence the program is blocked for ever until its killed or system is taken down.

    So, we see that programming with signals also required extreme care as we do not want our process to hang due to some loophole that the programmer left.

    Conclusion



    To conclude, the signals hold the capability of interrupting system calls that are working with slow devices like terminals. pipes etc. The application does not need to take care of this as POSIX compliant OSs allow the rescheduling of these system calls (internally) after the signal is handled.

    Stay tuned for more
     
    pradeep likes this.
  2. kumkum01

    kumkum01 New Member

    Joined:
    Apr 13, 2011
    Messages:
    10
    Likes Received:
    0
    Trophy Points:
    0
    Nice thread....Thanks for share useful information in this site...I really like this........:snobby::snobby:
     
  3. shabbir

    shabbir Administrator Staff Member

    Joined:
    Jul 12, 2004
    Messages:
    15,375
    Likes Received:
    388
    Trophy Points:
    83
    But this is not a thread but an article.
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice