chiark / gitweb /
Support for resource pools, based on the Apache model.
[mLib] / lock.c
... / ...
CommitLineData
1/* -*-c-*-
2 *
3 * $Id: lock.c,v 1.5 1999/06/19 20:35:45 mdw Exp $
4 *
5 * Simplified POSIX locking interface
6 *
7 * (c) 1997 Straylight/Edgeware
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of the mLib utilities library.
13 *
14 * mLib is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * mLib is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public
25 * License along with mLib; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27 * MA 02111-1307, USA.
28 */
29
30/*----- Revision history --------------------------------------------------*
31 *
32 * $Log: lock.c,v $
33 * Revision 1.5 1999/06/19 20:35:45 mdw
34 * Whoops. I'd left the type of the jump buffer as `sigjmp_buf'.
35 *
36 * Revision 1.4 1999/06/19 20:33:16 mdw
37 * More sophisticated and excessive signal and alarm handling.
38 *
39 * Revision 1.3 1999/06/06 01:23:00 mdw
40 * Fix signal handling.
41 *
42 * Revision 1.2 1999/05/26 20:53:40 mdw
43 * Fixes for stupid bugs.
44 *
45 * Revision 1.1 1999/05/15 10:33:53 mdw
46 * Add simplified locking code.
47 *
48 */
49
50/*----- Header files ------------------------------------------------------*/
51
52#include <errno.h>
53#include <setjmp.h>
54#include <signal.h>
55#include <stdio.h>
56#include <stdlib.h>
57#include <string.h>
58#include <time.h>
59
60#include <sys/types.h>
61#include <unistd.h>
62#include <fcntl.h>
63
64#include "lock.h"
65
66/*----- Tunable constants -------------------------------------------------*/
67
68#define LOCK_TIMEOUT 10 /* Maximum time in seconds to wait */
69
70/*----- Static variables --------------------------------------------------*/
71
72static jmp_buf jmp; /* Jump here to interrup @fcntl@ */
73
74/*----- Main code ---------------------------------------------------------*/
75
76/* --- @sigalrm@ --- *
77 *
78 * Arguments: @int sig@ = signal number
79 *
80 * Returns: ---
81 *
82 * Use: Makes sure that a @SIGALRM@ signal interrupts system calls.
83 */
84
85static void sigalrm(int sig) { longjmp(jmp, 1); }
86
87/* --- @lock_file@ --- *
88 *
89 * Arguments: @int fd@ = file descriptor to lock
90 * @unsigned how@ = type of lock required
91 *
92 * Returns: 0 if OK, -1 if it failed.
93 *
94 * Use: Acquires a lock on the given file. The value @how@
95 * specifies the type of lock to acquire: @LOCK_EXCL@ gets
96 * an exclusive (write) lock; @LOCK_NONEXCL@ gets a non-
97 * exclusive (read) lock and @LOCK_UNLOCK@ releases any locks.
98 * Acquiring a lock gets timed out after a while with an
99 * error.
100 */
101
102int lock_file(int fd, unsigned how)
103{
104 struct flock fk;
105 struct sigaction sa, osa;
106 sigset_t ss, oss;
107 int e;
108 int al, d, left;
109
110 /* --- Fill in the easy bits --- */
111
112 fk.l_whence = SEEK_SET;
113 fk.l_start = 0;
114 fk.l_len = 0;
115
116 /* --- Unlocking is really easy --- */
117
118 if (how == LOCK_UNLOCK) {
119 fk.l_type = F_UNLCK;
120 return (fcntl(fd, F_SETLK, &fk));
121 }
122
123 /* --- Decide how to do the locking --- */
124
125 if (how == LOCK_EXCL)
126 fk.l_type = F_WRLCK;
127 else if (how == LOCK_NONEXCL)
128 fk.l_type = F_RDLCK;
129 else {
130 errno = EINVAL;
131 return (-1);
132 }
133
134 /* --- Block @SIGALRM@ for a while --- *
135 *
136 * I don't want stray alarms going off while I'm busy here.
137 */
138
139 sigemptyset(&ss);
140 sigaddset(&ss, SIGALRM);
141 if (sigprocmask(SIG_BLOCK, &ss, &oss))
142 return (-1);
143
144 /* --- Set up the signal handler --- */
145
146 sa.sa_handler = sigalrm;
147 sa.sa_flags = 0;
148#ifdef SA_INTERRUPT
149 sa.sa_flags |= SA_INTERRUPT;
150#endif
151 sigemptyset(&sa.sa_mask);
152 if (sigaction(SIGALRM, &sa, &osa))
153 return (-1);
154
155 /* --- Set up the alarm, remembering when it's meant to go off --- */
156
157 al = alarm(0);
158 if (al && al < LOCK_TIMEOUT)
159 d = al;
160 else
161 d = LOCK_TIMEOUT;
162 alarm(d);
163
164 /* --- Set up the return context for the signal handler --- */
165
166 if (setjmp(jmp)) {
167 sigprocmask(SIG_SETMASK, &oss, 0);
168 errno = EINTR;
169 e = -1;
170 goto done;
171 }
172
173 /* --- Unblock the signal and we're ready --- */
174
175 if (sigprocmask(SIG_SETMASK, &oss, 0)) {
176 alarm(al);
177 e = -1;
178 goto done;
179 }
180
181 /* --- Do it --- */
182
183 e = fcntl(fd, F_SETLKW, &fk);
184
185 /* --- Tidy up the mess I left --- */
186
187 left = alarm(0);
188 if (al)
189 alarm(al - d + left);
190done:
191 sigaction(SIGALRM, &osa, 0);
192 return (e);
193}
194
195/*----- That's all, fokls -------------------------------------------------*/