Sunday, October 12, 2014

Unix Prog: alarm and pause functions(2)

Use alarm to check system call time out

A common use for alarm is to check whether a specific system all times out.
Following example illustrate this:

readtimeout.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
 #include<signal.h>  
   
 #define MAXLINE 100  
   
 void sig_alrm(int signo)  
 {  
  printf("sig_alrm interrupted!\n");  
 }  
   
 int main(int argc, char* argv[])  
 {  
  int n;  
  char line[MAXLINE];  
   
  if(signal(SIGALRM, sig_alrm) == SIG_ERR) {  
   printf("signal error!\n");  
   exit(1);  
  }  
  alarm(5);  
  if((n = read(STDIN_FILENO, line, MAXLINE)) < 0) {  
   printf("read error!\n");  
   exit(2);  
  }  
  alarm(0);  
   
  write(STDOUT_FILENO, line, n);  
  exit(0);  
 }  

shell:
The program setup the sig_alrm handler for signal SIGALRM, and then make it trigger SIGALRM after 5 seconds. Then it start reading information from the standard input. User just input "Hel", and stop for more than 5 seconds, SIGALRM occurs, interrupt the "read". But in current system, read could be restarted even if it is interrupted, at this time, user input the remaining words: "lo world!", the program output the "Hello world!".
 ubuntu@ip-172-31-23-227:~$ ./readtimeout.out  
 Helsig_alrm interrupted!  
 lo world!  
 Hello world!  

Potential Problems:
1) alarm(5) and read system calls make one race condition. It is possible that after executing the alarm(5), and scheduler delays the execution of read, and SIGALRM occurs before the read system call.
2) For system supporting the auto restart of read system call, the alarm doesn't work here, since our intention is to terminate the "read" system call if it spends too much time.

Following program solve this problem.

readtimeout.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
 #include<signal.h>  
 #include<setjmp.h>  
   
 #define MAXLINE 100  
   
 jmp_buf env_alrm;  
   
 void sig_alrm(int signo)  
 {  
  printf("sig_alrm interrupted!\n");  
  longjmp(env_alrm, 1);  
 }  
   
 int main(int argc, char* argv[])  
 {  
  int n;  
  char line[MAXLINE];  
   
  if(signal(SIGALRM, sig_alrm) == SIG_ERR) {  
   printf("signal error!\n");  
   exit(1);  
  }  
   
  if(setjmp(env_alrm) == 0) {  
   alarm(5);  
   if((n = read(STDIN_FILENO, line, MAXLINE)) < 0) {  
    printf("read error!\n");  
    exit(2);  
   }  
   alarm(0);  
  }  
   
  write(STDOUT_FILENO, line, n);  
  exit(0);  
 }  

shell:
The program setup the sig_alrm handler for SIGALRM, and then starts alarm and read. During this period, user just input "Hello" but doesn't finish the input. After 5 seconds, alarm expires, SIGALRM occurs, in sig_alrm handler, it use longjmp to come back to setjmp with return value 1, and then system exits, while also outputting the "Hello" input by user.
 ubuntu@ip-172-31-23-227:~$ ./readtimeout.out  
 Hellosig_alrm interrupted!  
 ubuntu@ip-172-31-23-227:~$ Hello  

Note: the program still has the problem of interrupting other signal handlers.

No comments:

Post a Comment