chiark / gitweb /
More sophisticated and excessive signal and alarm handling.
[mLib] / lock.c
CommitLineData
edb89af3 1/* -*-c-*-
2 *
988b0fdb 3 * $Id: lock.c,v 1.4 1999/06/19 20:33:16 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 $
988b0fdb 33 * Revision 1.4 1999/06/19 20:33:16 mdw
34 * More sophisticated and excessive signal and alarm handling.
35 *
55ed379c 36 * Revision 1.3 1999/06/06 01:23:00 mdw
37 * Fix signal handling.
38 *
898dd094 39 * Revision 1.2 1999/05/26 20:53:40 mdw
40 * Fixes for stupid bugs.
41 *
edb89af3 42 * Revision 1.1 1999/05/15 10:33:53 mdw
43 * Add simplified locking code.
44 *
45 */
46
47/*----- Header files ------------------------------------------------------*/
48
49#include <errno.h>
988b0fdb 50#include <setjmp.h>
edb89af3 51#include <signal.h>
52#include <stdio.h>
53#include <stdlib.h>
54#include <string.h>
55#include <time.h>
56
57#include <sys/types.h>
58#include <unistd.h>
59#include <fcntl.h>
60
61#include "lock.h"
62
63/*----- Tunable constants -------------------------------------------------*/
64
65#define LOCK_TIMEOUT 10 /* Maximum time in seconds to wait */
66
988b0fdb 67/*----- Static variables --------------------------------------------------*/
68
69static sigjmp_buf jmp; /* Jump here to interrup @fcntl@ */
70
edb89af3 71/*----- Main code ---------------------------------------------------------*/
72
988b0fdb 73/* --- @sigalrm@ --- *
edb89af3 74 *
75 * Arguments: @int sig@ = signal number
76 *
77 * Returns: ---
78 *
79 * Use: Makes sure that a @SIGALRM@ signal interrupts system calls.
80 */
81
988b0fdb 82static void sigalrm(int sig) { longjmp(jmp, 1); }
edb89af3 83
84/* --- @lock_file@ --- *
85 *
86 * Arguments: @int fd@ = file descriptor to lock
87 * @unsigned how@ = type of lock required
88 *
89 * Returns: 0 if OK, -1 if it failed.
90 *
91 * Use: Acquires a lock on the given file. The value @how@
92 * specifies the type of lock to acquire: @LOCK_EXCL@ gets
93 * an exclusive (write) lock; @LOCK_NONEXCL@ gets a non-
94 * exclusive (read) lock and @LOCK_UNLOCK@ releases any locks.
95 * Acquiring a lock gets timed out after a while with an
96 * error.
97 */
98
99int lock_file(int fd, unsigned how)
100{
101 struct flock fk;
988b0fdb 102 struct sigaction sa, osa;
103 sigset_t ss, oss;
edb89af3 104 int e;
988b0fdb 105 int al, d, left;
edb89af3 106
107 /* --- Fill in the easy bits --- */
108
109 fk.l_whence = SEEK_SET;
110 fk.l_start = 0;
898dd094 111 fk.l_len = 0;
edb89af3 112
113 /* --- Unlocking is really easy --- */
114
115 if (how == LOCK_UNLOCK) {
116 fk.l_type = F_UNLCK;
117 return (fcntl(fd, F_SETLK, &fk));
118 }
119
55ed379c 120 /* --- Decide how to do the locking --- */
edb89af3 121
122 if (how == LOCK_EXCL)
123 fk.l_type = F_WRLCK;
124 else if (how == LOCK_NONEXCL)
125 fk.l_type = F_RDLCK;
126 else {
127 errno = EINVAL;
128 return (-1);
129 }
130
988b0fdb 131 /* --- Block @SIGALRM@ for a while --- *
132 *
133 * I don't want stray alarms going off while I'm busy here.
134 */
135
136 sigemptyset(&ss);
137 sigaddset(&ss, SIGALRM);
138 if (sigprocmask(SIG_BLOCK, &ss, &oss))
139 return (-1);
140
141 /* --- Set up the signal handler --- */
55ed379c 142
988b0fdb 143 sa.sa_handler = sigalrm;
55ed379c 144 sa.sa_flags = 0;
988b0fdb 145#ifdef SA_INTERRUPT
146 sa.sa_flags |= SA_INTERRUPT;
147#endif
55ed379c 148 sigemptyset(&sa.sa_mask);
988b0fdb 149 if (sigaction(SIGALRM, &sa, &osa))
55ed379c 150 return (-1);
151
988b0fdb 152 /* --- Set up the alarm, remembering when it's meant to go off --- */
153
154 al = alarm(0);
155 if (al && al < LOCK_TIMEOUT)
156 d = al;
157 else
158 d = LOCK_TIMEOUT;
159 alarm(d);
55ed379c 160
988b0fdb 161 /* --- Set up the return context for the signal handler --- */
162
163 if (setjmp(jmp)) {
164 sigprocmask(SIG_SETMASK, &oss, 0);
165 errno = EINTR;
166 e = -1;
167 goto done;
168 }
169
170 /* --- Unblock the signal and we're ready --- */
171
172 if (sigprocmask(SIG_SETMASK, &oss, 0)) {
173 alarm(al);
174 e = -1;
175 goto done;
edb89af3 176 }
55ed379c 177
988b0fdb 178 /* --- Do it --- */
179
180 e = fcntl(fd, F_SETLKW, &fk);
181
182 /* --- Tidy up the mess I left --- */
55ed379c 183
988b0fdb 184 left = alarm(0);
185 if (al)
186 alarm(al - d + left);
187done:
188 sigaction(SIGALRM, &osa, 0);
edb89af3 189 return (e);
190}
191
192/*----- That's all, fokls -------------------------------------------------*/