chiark / gitweb /
More sophisticated and excessive signal and alarm handling.
authormdw <mdw>
Sat, 19 Jun 1999 20:33:16 +0000 (20:33 +0000)
committermdw <mdw>
Sat, 19 Jun 1999 20:33:16 +0000 (20:33 +0000)
lock.c

diff --git a/lock.c b/lock.c
index 445e43de71c4bec5d4dd2d9d57773aa793f382f0..ad223eee8ac6249488972e88d132e6e4b160d632 100644 (file)
--- a/lock.c
+++ b/lock.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: lock.c,v 1.3 1999/06/06 01:23:00 mdw Exp $
+ * $Id: lock.c,v 1.4 1999/06/19 20:33:16 mdw Exp $
  *
  * Simplified POSIX locking interface
  *
@@ -30,6 +30,9 @@
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: lock.c,v $
+ * Revision 1.4  1999/06/19 20:33:16  mdw
+ * More sophisticated and excessive signal and alarm handling.
+ *
  * Revision 1.3  1999/06/06 01:23:00  mdw
  * Fix signal handling.
  *
@@ -44,6 +47,7 @@
 /*----- Header files ------------------------------------------------------*/
 
 #include <errno.h>
+#include <setjmp.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 
 #define LOCK_TIMEOUT 10                        /* Maximum time in seconds to wait */
 
+/*----- Static variables --------------------------------------------------*/
+
+static sigjmp_buf jmp;                 /* Jump here to interrup @fcntl@ */
+
 /*----- Main code ---------------------------------------------------------*/
 
-/* --- @lock_alarm@ --- *
+/* --- @sigalrm@ --- *
  *
  * Arguments:  @int sig@ = signal number
  *
@@ -71,7 +79,7 @@
  * Use:                Makes sure that a @SIGALRM@ signal interrupts system calls.
  */
 
-static void lock_alarm(int sig) { ; }
+static void sigalrm(int sig) { longjmp(jmp, 1); }
 
 /* --- @lock_file@ --- *
  *
@@ -91,8 +99,10 @@ static void lock_alarm(int sig) { ; }
 int lock_file(int fd, unsigned how)
 {
   struct flock fk;
-  struct sigaction sa, oldsa;
+  struct sigaction sa, osa;
+  sigset_t ss, oss; 
   int e;
+  int al, d, left;
 
   /* --- Fill in the easy bits --- */
 
@@ -118,26 +128,64 @@ int lock_file(int fd, unsigned how)
     return (-1);
   }
 
-  /* --- Set up the alarm --- */
+  /* --- Block @SIGALRM@ for a while --- *
+   *
+   * I don't want stray alarms going off while I'm busy here.
+   */
+
+  sigemptyset(&ss);
+  sigaddset(&ss, SIGALRM);
+  if (sigprocmask(SIG_BLOCK, &ss, &oss))
+    return (-1);
+
+  /* --- Set up the signal handler --- */
 
-  sa.sa_handler = lock_alarm;
+  sa.sa_handler = sigalrm;
   sa.sa_flags = 0;
+#ifdef SA_INTERRUPT
+  sa.sa_flags |= SA_INTERRUPT;
+#endif
   sigemptyset(&sa.sa_mask);
-  if (sigaction(SIGALRM, &sa, &oldsa))
+  if (sigaction(SIGALRM, &sa, &osa))
     return (-1);
 
-  /* --- Do it --- */
+  /* --- Set up the alarm, remembering when it's meant to go off --- */
+
+  al = alarm(0);
+  if (al && al < LOCK_TIMEOUT)
+    d = al;
+  else
+    d = LOCK_TIMEOUT;
+  alarm(d);
 
-  alarm(LOCK_TIMEOUT);
-  if ((e = fcntl(fd, F_SETLKW, &fk)) != 0) {
-    if (errno == EINTR)
-      errno = EAGAIN;
+  /* --- Set up the return context for the signal handler --- */
+
+  if (setjmp(jmp)) {
+    sigprocmask(SIG_SETMASK, &oss, 0);
+    errno = EINTR;
+    e = -1;
+    goto done;
+  }
+
+  /* --- Unblock the signal and we're ready --- */
+
+  if (sigprocmask(SIG_SETMASK, &oss, 0)) {
+    alarm(al);
+    e = -1;
+    goto done;
   }
 
-  /* --- Remove the alarm handling --- */
+  /* --- Do it --- */
+
+  e = fcntl(fd, F_SETLKW, &fk);
+
+  /* --- Tidy up the mess I left --- */
 
-  alarm(0);
-  sigaction(SIGALRM, &oldsa, 0);
+  left = alarm(0);
+  if (al)
+    alarm(al - d + left);
+done:
+  sigaction(SIGALRM, &osa, 0);
   return (e);
 }