X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/blobdiff_plain/898dd094b1f9e1742d432e90b88d09092a5d09f3..d4efbcd93c940ad522fcf8c601ec1829d2e0b10d:/lock.c diff --git a/lock.c b/lock.c index 9dfabab..19392a8 100644 --- a/lock.c +++ b/lock.c @@ -1,13 +1,13 @@ /* -*-c-*- * - * $Id: lock.c,v 1.2 1999/05/26 20:53:40 mdw Exp $ + * $Id: lock.c,v 1.6 2004/04/08 01:36:13 mdw Exp $ * * Simplified POSIX locking interface * * (c) 1997 Straylight/Edgeware */ -/*----- Licensing notice --------------------------------------------------* +/*----- Licensing notice --------------------------------------------------* * * This file is part of the mLib utilities library. * @@ -15,32 +15,22 @@ * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - * + * * mLib is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. - * + * * You should have received a copy of the GNU Library General Public * License along with mLib; if not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. */ -/*----- Revision history --------------------------------------------------* - * - * $Log: lock.c,v $ - * 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 @@ -57,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 * @@ -68,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@ --- * * @@ -88,8 +82,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 +100,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 +111,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); }