Browse Source

sleep: check "SIGCHLD is SIG_IGN'ed" first. Saves two syscalls in common case

    text	   data	    bss	    dec	    hex	filename
-    197	      0	      0	    197	     c5	libc/unistd/sleep.o
+    168	      0	      0	    168	     a8	libc/unistd/sleep.o

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
Denys Vlasenko 14 years ago
parent
commit
62fb840ea0
1 changed files with 18 additions and 22 deletions
  1. 18 22
      libc/unistd/sleep.c

+ 18 - 22
libc/unistd/sleep.c

@@ -50,6 +50,7 @@ unsigned int sleep (unsigned int seconds)
 {
 {
     struct timespec ts = { .tv_sec = (long int) seconds, .tv_nsec = 0 };
     struct timespec ts = { .tv_sec = (long int) seconds, .tv_nsec = 0 };
     sigset_t set;
     sigset_t set;
+    struct sigaction oact;
     unsigned int result;
     unsigned int result;
 
 
     /* This is not necessary but some buggy programs depend on this.  */
     /* This is not necessary but some buggy programs depend on this.  */
@@ -62,33 +63,28 @@ unsigned int sleep (unsigned int seconds)
 
 
     /* Linux will wake up the system call, nanosleep, when SIGCHLD
     /* Linux will wake up the system call, nanosleep, when SIGCHLD
        arrives even if SIGCHLD is ignored.  We have to deal with it
        arrives even if SIGCHLD is ignored.  We have to deal with it
-       in libc.  We block SIGCHLD first.  */
+       in libc.  */
+
     __sigemptyset (&set);
     __sigemptyset (&set);
     __sigaddset (&set, SIGCHLD);
     __sigaddset (&set, SIGCHLD);
-    sigprocmask (SIG_BLOCK, &set, &set); /* never fails */
 
 
-    /* If SIGCHLD was already blocked, no need to check SIG_IGN. Else...  */
+    /* Is SIGCHLD set to SIG_IGN? */
+    sigaction (SIGCHLD, NULL, &oact); /* never fails */
+    if (oact.sa_handler == SIG_IGN) {
+	/* Yes.  Block SIGCHLD, save old mask.  */
+	sigprocmask (SIG_BLOCK, &set, &set); /* never fails */
+    }
+
+    /* Run nanosleep, with SIGCHLD blocked if SIGCHLD is SIG_IGNed.  */
+    result = nanosleep (&ts, &ts);
+
     if (!__sigismember (&set, SIGCHLD)) {
     if (!__sigismember (&set, SIGCHLD)) {
-	struct sigaction oact;
+	/* We did block SIGCHLD, and old mask had no SIGCHLD bit.
-
+	   IOW: we need to unblock SIGCHLD now. Do it.  */
-	/* Is SIGCHLD set to SIG_IGN? */
+	/* this sigprocmask call never fails, thus never updates errno,
-	sigaction (SIGCHLD, NULL, &oact); /* never fails */
+	   and therefore we don't need to save/restore it.  */
-	if (oact.sa_handler == SIG_IGN) {
+	sigprocmask (SIG_SETMASK, &set, NULL); /* never fails */
-	    /* Yes, run nanosleep with SIGCHLD blocked.  */
-	    result = nanosleep (&ts, &ts);
-
-	    /* Unblock SIGCHLD by restoring signal mask.  */
-	    /* this sigprocmask call never fails, thus never updates errno,
-	       and therefore we don't need to save/restore it.  */
-	    sigprocmask (SIG_SETMASK, &set, NULL);
-	} else {
-	    /* No workaround needed, unblock SIGCHLD by restoring signal mask.  */
-	    sigprocmask (SIG_SETMASK, &set, NULL);
-	    result = nanosleep (&ts, &ts);
-	}
     }
     }
-    else
-	result = nanosleep (&ts, &ts);
 
 
     if (result != 0)
     if (result != 0)
 	/* Round remaining time.  */
 	/* Round remaining time.  */