chiark / gitweb /
Hack if there is no @_SC_OPEN_MAX@ or @OPEN_MAX@.
[mLib] / lock.c
CommitLineData
edb89af3 1/* -*-c-*-
2 *
8e94a44e 3 * $Id: lock.c,v 1.5 1999/06/19 20:35:45 mdw Exp $
edb89af3 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 $
8e94a44e 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 *
988b0fdb 36 * Revision 1.4 1999/06/19 20:33:16 mdw
37 * More sophisticated and excessive signal and alarm handling.
38 *
55ed379c 39 * Revision 1.3 1999/06/06 01:23:00 mdw
40 * Fix signal handling.
41 *
898dd094 42 * Revision 1.2 1999/05/26 20:53:40 mdw
43 * Fixes for stupid bugs.
44 *
edb89af3 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>
988b0fdb 53#include <setjmp.h>
edb89af3 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
988b0fdb 70/*----- Static variables --------------------------------------------------*/
71
8e94a44e 72static jmp_buf jmp; /* Jump here to interrup @fcntl@ */
988b0fdb 73
edb89af3 74/*----- Main code ---------------------------------------------------------*/
75
988b0fdb 76/* --- @sigalrm@ --- *
edb89af3 77 *
78 * Arguments: @int sig@ = signal number
79 *
80 * Returns: ---
81 *
82 * Use: Makes sure that a @SIGALRM@ signal interrupts system calls.
83 */
84
988b0fdb 85static void sigalrm(int sig) { longjmp(jmp, 1); }
edb89af3 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;
988b0fdb 105 struct sigaction sa, osa;
106 sigset_t ss, oss;
edb89af3 107 int e;
988b0fdb 108 int al, d, left;
edb89af3 109
110 /* --- Fill in the easy bits --- */
111
112 fk.l_whence = SEEK_SET;
113 fk.l_start = 0;
898dd094 114 fk.l_len = 0;
edb89af3 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
55ed379c 123 /* --- Decide how to do the locking --- */
edb89af3 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
988b0fdb 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 --- */
55ed379c 145
988b0fdb 146 sa.sa_handler = sigalrm;
55ed379c 147 sa.sa_flags = 0;
988b0fdb 148#ifdef SA_INTERRUPT
149 sa.sa_flags |= SA_INTERRUPT;
150#endif
55ed379c 151 sigemptyset(&sa.sa_mask);
988b0fdb 152 if (sigaction(SIGALRM, &sa, &osa))
55ed379c 153 return (-1);
154
988b0fdb 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);
55ed379c 163
988b0fdb 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;
edb89af3 179 }
55ed379c 180
988b0fdb 181 /* --- Do it --- */
182
183 e = fcntl(fd, F_SETLKW, &fk);
184
185 /* --- Tidy up the mess I left --- */
55ed379c 186
988b0fdb 187 left = alarm(0);
188 if (al)
189 alarm(al - d + left);
190done:
191 sigaction(SIGALRM, &osa, 0);
edb89af3 192 return (e);
193}
194
195/*----- That's all, fokls -------------------------------------------------*/