IDZEBRA 2.2.8
flock.c
Go to the documentation of this file.
1/* Thi½ file is part of the Zebra server.
2 Copyright (C) Index Data
3
4Zebra is free software; you can redistribute it and/or modify it under
5the terms of the GNU General Public License as published by the Free
6Software Foundation; either version 2, or (at your option) any later
7version.
8
9Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or
11FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
16Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18*/
19
20
21#if HAVE_CONFIG_H
22#include <config.h>
23#endif
24#include <stdio.h>
25#include <assert.h>
26#include <string.h>
27#include <errno.h>
28#include <fcntl.h>
29#include <sys/types.h>
30#ifdef WIN32
31#include <io.h>
32#include <sys/locking.h>
33#endif
34#if HAVE_UNISTD_H
35#include <unistd.h>
36#endif
37
38#include <idzebra/flock.h>
39#include <zebra-lock.h>
40#include <yaz/xmalloc.h>
41#include <yaz/log.h>
42
44static int initialized = 0;
45
47static int posix_locks = 1;
48
51
53static struct zebra_lock_info *lock_list = 0;
54
57#ifndef WIN32
60#endif
62};
63
81
82static int log_level = 0;
83
84char *zebra_mk_fname(const char *dir, const char *name)
85{
86 int dlen = dir ? strlen(dir) : 0;
87 char *fname = xmalloc(dlen + strlen(name) + 2);
88
89 *fname = '\0';
90 if (dlen)
91 {
92 int last_one = dir[dlen-1];
93 strcat(fname, dir);
94#ifdef WIN32
95 if (!strchr("/\\:", last_one))
96 strcat(fname, "\\");
97#else
98 if (!strchr("/", last_one))
99 strcat(fname, "/");
100#endif
101 }
102 strcat(fname, name);
103 return fname;
104}
105
106ZebraLockHandle zebra_lock_create(const char *dir, const char *name)
107{
108 char *fname = zebra_mk_fname(dir, name);
109 struct zebra_lock_info *p = 0;
110 ZebraLockHandle h = 0;
111
112 assert(initialized);
113
115 /* see if we have the same filename in a global list of "lock files" */
116#ifndef WIN32
117 if (posix_locks)
118 {
119 for (p = lock_list; p ; p = p->next)
120 if (!strcmp(p->fname, fname))
121 break;
122 }
123#endif
124 if (!p)
125 { /* didn't match (or we didn't want it to match! */
126 p = (struct zebra_lock_info *) xmalloc(sizeof(*p));
127
128 p->ref_count = 0;
129#ifdef WIN32
130 p->fd = open(name, O_BINARY|O_RDONLY);
131 if (p->fd == -1)
132 p->fd = open(fname, (O_BINARY|O_CREAT|O_RDWR), 0666);
133#else
134 p->fd = open(fname, (O_BINARY|O_CREAT|O_RDWR), 0666);
135#endif
136 if (p->fd == -1)
137 {
138 xfree(p);
139 yaz_log(YLOG_WARN | YLOG_ERRNO,
140 "zebra_lock_create fail fname=%s", fname);
141 p = 0;
142 }
143 else
144 {
145 p->fname = fname;
146 fname = 0; /* fname buffer now owned by p->fname */
147#ifndef WIN32
148 if (posix_locks)
150
152 p->no_file_write_lock = 0;
153 p->no_file_read_lock = 0;
154#endif
155 p->next = lock_list;
156 lock_list = p;
157 }
158 }
159 if (p)
160 {
161 /* we have lock info so we can make a handle pointing to that */
162 p->ref_count++;
163 h = (ZebraLockHandle) xmalloc(sizeof(*h));
164 h->p = p;
165#ifndef WIN32
166 h->write_flag = 0;
167#endif
168 yaz_log(log_level, "zebra_lock_create fd=%d p=%p fname=%s",
169 h->p->fd, h, p->fname);
170 }
172 xfree(fname); /* free it - if it's still there */
173
174 return h;
175}
176
178{
179 if (!h)
180 return;
181 yaz_log(log_level, "zebra_lock_destroy fd=%d p=%p fname=%s",
182 h->p->fd, h, h->p->fname);
184 yaz_log(log_level, "zebra_lock_destroy fd=%d p=%p fname=%s refcount=%d",
185 h->p->fd, h, h->p->fname, h->p->ref_count);
186 assert(h->p->ref_count > 0);
187 --(h->p->ref_count);
188 if (h->p->ref_count == 0)
189 {
190 /* must remove shared info from lock_list */
191 struct zebra_lock_info **hp = &lock_list;
192 while (*hp)
193 {
194 if (*hp == h->p)
195 {
196 *hp = h->p->next;
197 break;
198 }
199 else
200 hp = &(*hp)->next;
201 }
202
203 yaz_log(log_level, "zebra_lock_destroy fd=%d p=%p fname=%s remove",
204 h->p->fd, h, h->p->fname);
205
206#ifndef WIN32
207 if (posix_locks)
210#endif
211 if (h->p->fd != -1)
212 close(h->p->fd);
213 xfree(h->p->fname);
214 xfree(h->p);
215 }
216 xfree(h);
218}
219
220#ifndef WIN32
221static int unixLock(int fd, int type, int cmd)
222{
223 struct flock area;
224 int r;
225 area.l_type = type;
226 area.l_whence = SEEK_SET;
227 area.l_len = area.l_start = 0L;
228
229 yaz_log(log_level, "fcntl begin type=%d fd=%d", type, fd);
230 r = fcntl(fd, cmd, &area);
231 if (r == -1)
232 yaz_log(YLOG_WARN|YLOG_ERRNO, "fcntl FAIL type=%d fd=%d", type, fd);
233 else
234 yaz_log(log_level, "fcntl type=%d OK fd=%d", type, fd);
235
236 return r;
237}
238#endif
239
241{
242 int r = 0;
243 int do_lock = 0;
244 yaz_log(log_level, "zebra_lock_w fd=%d p=%p fname=%s begin",
245 h->p->fd, h, h->p->fname);
246
247#ifdef WIN32
248 while ((r = _locking(h->p->fd, _LK_LOCK, 1)))
249 ;
250#else
251 if (posix_locks)
253
255 if (h->p->no_file_write_lock == 0)
256 do_lock = 1;
257 h->p->no_file_write_lock++;
258 if (do_lock)
259 {
260 /* if there is already a read lock.. upgrade to write lock */
261 r = unixLock(h->p->fd, F_WRLCK, F_SETLKW);
262 }
263 else
264 {
265 assert(posix_locks);
266 }
268
269 h->write_flag = 1;
270#endif
271 yaz_log(log_level, "zebra_lock_w fd=%d p=%p fname=%s end",
272 h->p->fd, h, h->p->fname);
273
274 return r;
275}
276
278{
279 int r = 0;
280 int do_lock = 0;
281
282 yaz_log(log_level, "zebra_lock_r fd=%d p=%p fname=%s begin",
283 h->p->fd, h, h->p->fname);
284#ifdef WIN32
285 while ((r = _locking(h->p->fd, _LK_LOCK, 1)))
286 ;
287#else
288 if (posix_locks)
290
292 if (h->p->no_file_read_lock == 0 && h->p->no_file_write_lock == 0)
293 do_lock = 1;
294 h->p->no_file_read_lock++;
295 if (do_lock)
296 {
297 /* only read lock if no write locks already */
298 r = unixLock(h->p->fd, F_RDLCK, F_SETLKW);
299 }
300 else
301 {
302 assert(posix_locks);
303 }
305
306 h->write_flag = 0;
307#endif
308 yaz_log(log_level, "zebra_lock_r fd=%d p=%p fname=%s end",
309 h->p->fd, h, h->p->fname);
310 return r;
311}
312
314{
315 int r = 0;
316 yaz_log(log_level, "zebra_unlock fd=%d p=%p fname=%s begin",
317 h->p->fd, h, h->p->fname);
318#ifdef WIN32
319 r = _locking(h->p->fd, _LK_UNLCK, 1);
320#else
322 if (h->write_flag)
323 {
324 if (h->p->no_file_write_lock > 0)
325 h->p->no_file_write_lock--;
326 }
327 else
328 {
329 if (h->p->no_file_read_lock > 0)
330 h->p->no_file_read_lock--;
331 }
332 if (h->p->no_file_read_lock == 0 && h->p->no_file_write_lock == 0)
333 r = unixLock(h->p->fd, F_UNLCK, F_SETLKW);
334 else
335 {
336 r = 0;
337 assert(posix_locks);
338 }
339
341
342 if (posix_locks)
343 {
344 if (h->write_flag)
346 else
348 }
349#endif
350 yaz_log(log_level, "zebra_unlock fd=%d p=%p fname=%s end",
351 h->p->fd, h, h->p->fname);
352 return r;
353}
354
361{
362#if __linux
363#ifdef _CS_GNU_LIBPTHREAD_VERSION
364 char conf_buf[512];
365 size_t r = confstr(_CS_GNU_LIBPTHREAD_VERSION, conf_buf, sizeof(conf_buf));
366 if (r == 0)
367 {
368 yaz_log(YLOG_WARN|YLOG_ERRNO, "confstr failed");
369 return -1;
370 }
371 if (strncmp(conf_buf, "linuxthreads", 12) == 0)
372 posix_locks = 0; /* Using linuxthreads.. */
373#else
374 posix_locks = 0; /* Old GLIBC on Linux. Assume linuxthreads */
375#endif
376#endif
377 return 0;
378}
379
381{
382 if (!initialized)
383 {
384 initialized = 1;
385 log_level = yaz_log_module_level("flock");
386 yaz_log(log_level, "zebra_flock_init");
389 yaz_log(log_level, "posix_locks: %d", posix_locks);
390 }
391}
392
393/*
394 * Local variables:
395 * c-basic-offset: 4
396 * c-file-style: "Stroustrup"
397 * indent-tabs-mode: nil
398 * End:
399 * vim: shiftwidth=4 tabstop=8 expandtab
400 */
401
#define O_BINARY
Definition agrep.c:46
static int unixLock(int fd, int type, int cmd)
Definition flock.c:221
char * zebra_mk_fname(const char *dir, const char *name)
Definition flock.c:84
Zebra_mutex lock_list_mutex
Definition flock.c:50
static struct zebra_lock_info * lock_list
Definition flock.c:53
int zebra_lock_r(ZebraLockHandle h)
Definition flock.c:277
int zebra_lock_w(ZebraLockHandle h)
Definition flock.c:240
static int check_for_linuxthreads(void)
see if the fcntl locking is not POSIX
Definition flock.c:360
void zebra_lock_destroy(ZebraLockHandle h)
Definition flock.c:177
ZebraLockHandle zebra_lock_create(const char *dir, const char *name)
Definition flock.c:106
void zebra_flock_init()
Definition flock.c:380
static int log_level
Definition flock.c:82
static int initialized
Definition flock.c:44
int zebra_unlock(ZebraLockHandle h)
Definition flock.c:313
static int posix_locks
Definition flock.c:47
struct zebra_lock_handle * ZebraLockHandle
Definition flock.h:27
struct zebra_lock_info * p
Definition flock.c:61
char * fname
Definition flock.c:68
int ref_count
Definition flock.c:70
int no_file_read_lock
Definition flock.c:74
Zebra_mutex file_mutex
Definition flock.c:76
int no_file_write_lock
Definition flock.c:73
Zebra_lock_rdwr rdwr_lock
Definition flock.c:75
struct zebra_lock_info * next
Definition flock.c:79
int fd
int zebra_mutex_unlock(Zebra_mutex *p)
Definition zebra-lock.c:74
int zebra_mutex_init(Zebra_mutex *p)
Definition zebra-lock.c:31
int zebra_lock_rdwr_rlock(Zebra_lock_rdwr *p)
Definition zebra-lock.c:111
int zebra_lock_rdwr_wlock(Zebra_lock_rdwr *p)
Definition zebra-lock.c:123
int zebra_lock_rdwr_destroy(Zebra_lock_rdwr *p)
Definition zebra-lock.c:100
int zebra_lock_rdwr_wunlock(Zebra_lock_rdwr *p)
Definition zebra-lock.c:155
int zebra_lock_rdwr_runlock(Zebra_lock_rdwr *p)
Definition zebra-lock.c:135
int zebra_mutex_lock(Zebra_mutex *p)
Definition zebra-lock.c:59
int zebra_lock_rdwr_init(Zebra_lock_rdwr *p)
Definition zebra-lock.c:89
int zebra_mutex_destroy(Zebra_mutex *p)
Definition zebra-lock.c:43