X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/blobdiff_plain/55ed379c6ca93abb3d43c514e038ccedf9fd84c8..c8e2638452354ac3f67c0a47c759ed00703f0128:/lock.c diff --git a/lock.c b/lock.c index 445e43d..335c3ac 100644 --- 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.5 1999/06/19 20:35:45 mdw Exp $ * * Simplified POSIX locking interface * @@ -30,6 +30,12 @@ /*----- 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. * @@ -44,6 +50,7 @@ /*----- Header files ------------------------------------------------------*/ #include +#include #include #include #include @@ -60,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 * @@ -71,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@ --- * * @@ -91,8 +102,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 +131,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. + */ - sa.sa_handler = lock_alarm; + 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, &oldsa)) + if (sigaction(SIGALRM, &sa, &osa)) return (-1); - /* --- Do it --- */ + /* --- Set up the alarm, remembering when it's meant to go off --- */ - alarm(LOCK_TIMEOUT); - if ((e = fcntl(fd, F_SETLKW, &fk)) != 0) { - if (errno == EINTR) - errno = EAGAIN; + 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; } - /* --- 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); }