X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/blobdiff_plain/898dd094b1f9e1742d432e90b88d09092a5d09f3..c8e2638452354ac3f67c0a47c759ed00703f0128:/lock.c diff --git a/lock.c b/lock.c index 9dfabab..335c3ac 100644 --- a/lock.c +++ b/lock.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: lock.c,v 1.2 1999/05/26 20:53:40 mdw Exp $ + * $Id: lock.c,v 1.5 1999/06/19 20:35:45 mdw Exp $ * * Simplified POSIX locking interface * @@ -30,6 +30,15 @@ /*----- Revision history --------------------------------------------------* * * $Log: lock.c,v $ + * Revision 1.5 1999/06/19 20:35:45 mdw + * Whoops. I'd left the type of the jump buffer as `sigjmp_buf'. + * + * 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. + * * Revision 1.2 1999/05/26 20:53:40 mdw * Fixes for stupid bugs. * @@ -41,6 +50,7 @@ /*----- Header files ------------------------------------------------------*/ #include +#include #include #include #include @@ -57,9 +67,13 @@ #define LOCK_TIMEOUT 10 /* Maximum time in seconds to wait */ +/*----- Static variables --------------------------------------------------*/ + +static jmp_buf jmp; /* Jump here to interrup @fcntl@ */ + /*----- Main code ---------------------------------------------------------*/ -/* --- @lock_alarm@ --- * +/* --- @sigalrm@ --- * * * Arguments: @int sig@ = signal number * @@ -68,7 +82,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@ --- * * @@ -88,8 +102,10 @@ static void lock_alarm(int sig) { ; } int lock_file(int fd, unsigned how) { struct flock fk; - void (*alrm)(int); + struct sigaction sa, osa; + sigset_t ss, oss; int e; + int al, d, left; /* --- Fill in the easy bits --- */ @@ -104,7 +120,7 @@ int lock_file(int fd, unsigned how) return (fcntl(fd, F_SETLK, &fk)); } - /* --- Set an alarm handler --- */ + /* --- Decide how to do the locking --- */ if (how == LOCK_EXCL) fk.l_type = F_WRLCK; @@ -115,14 +131,64 @@ int lock_file(int fd, unsigned how) return (-1); } - alrm = signal(SIGALRM, lock_alarm); - alarm(LOCK_TIMEOUT); - if ((e = fcntl(fd, F_SETLKW, &fk)) != 0) { - if (errno == EINTR) - errno = EAGAIN; + /* --- 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 = sigalrm; + sa.sa_flags = 0; +#ifdef SA_INTERRUPT + sa.sa_flags |= SA_INTERRUPT; +#endif + sigemptyset(&sa.sa_mask); + if (sigaction(SIGALRM, &sa, &osa)) + return (-1); + + /* --- 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); + + /* --- 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; } - alarm(0); - signal(SIGALRM, alrm); + + /* --- Do it --- */ + + e = fcntl(fd, F_SETLKW, &fk); + + /* --- Tidy up the mess I left --- */ + + left = alarm(0); + if (al) + alarm(al - d + left); +done: + sigaction(SIGALRM, &osa, 0); return (e); }