X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/blobdiff_plain/55ed379c6ca93abb3d43c514e038ccedf9fd84c8..8656dc507aee9c5dcb3a6ad876565f5fcac425ae:/lock.c diff --git a/lock.c b/lock.c index 445e43d..437ad10 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.6 2004/04/08 01:36:13 mdw Exp $ * * Simplified POSIX locking interface * @@ -27,23 +27,10 @@ * MA 02111-1307, USA. */ -/*----- Revision history --------------------------------------------------* - * - * $Log: lock.c,v $ - * 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. - * - * Revision 1.1 1999/05/15 10:33:53 mdw - * Add simplified locking code. - * - */ - /*----- Header files ------------------------------------------------------*/ #include +#include #include #include #include @@ -60,9 +47,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 +62,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 +82,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 +111,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); + + /* --- 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 --- */ - alarm(LOCK_TIMEOUT); - if ((e = fcntl(fd, F_SETLKW, &fk)) != 0) { - if (errno == EINTR) - errno = EAGAIN; + 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); }