1 /* $Id: flock.c,v 1.9 2006-06-27 12:24:14 adam Exp $
2 Copyright (C) 1995-2006
5 This file is part of the Zebra server.
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra. If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
29 #include <sys/types.h>
32 #include <sys/locking.h>
38 #include <idzebra/flock.h>
39 #include <zebra-lock.h>
40 #include <yaz/xmalloc.h>
43 /** have this module (mutex) been initialized? */
44 static int initialized = 0;
46 /** mutex for lock_list below */
47 Zebra_mutex lock_list_mutex;
49 /** our list of file locked files */
50 static struct zebra_lock_info *lock_list = 0;
52 /** the internal handle, with a pointer to each lock file info */
53 struct zebra_lock_handle {
55 /** so we can call zebra_lock_rdwr_wunlock or zebra_lock_lock_runlock */
58 struct zebra_lock_info *p;
61 struct zebra_lock_info {
62 /** file descriptor */
64 /** full path (xmalloc'ed) */
66 /** reference counter: number of zebra_lock_handles pointing to us */
69 /** number of file write locks/read locks */
70 int no_file_write_lock;
71 int no_file_read_lock;
72 Zebra_lock_rdwr rdwr_lock;
73 Zebra_mutex file_mutex;
75 /** next in lock list */
76 struct zebra_lock_info *next;
79 static int log_level = 0;
81 char *zebra_mk_fname(const char *dir, const char *name)
83 int dlen = dir ? strlen(dir) : 0;
84 char *fname = xmalloc(dlen + strlen(name) + 3);
89 int last_one = dir[dlen-1];
91 if (!strchr("/\\:", last_one))
92 sprintf(fname, "%s\\%s", dir, name);
94 sprintf(fname, "%s%s", dir, name);
97 sprintf(fname, "%s", name);
101 int last_one = dir[dlen-1];
103 if (!strchr("/", last_one))
104 sprintf(fname, "%s/%s", dir, name);
106 sprintf(fname, "%s%s", dir, name);
109 sprintf(fname, "%s", name);
114 ZebraLockHandle zebra_lock_create(const char *dir, const char *name)
116 char *fname = zebra_mk_fname(dir, name);
117 struct zebra_lock_info *p = 0;
118 ZebraLockHandle h = 0;
122 zebra_mutex_lock(&lock_list_mutex);
124 for (p = lock_list; p ; p = p->next)
125 if (!strcmp(p->fname, fname))
130 p = (struct zebra_lock_info *) xmalloc(sizeof(*p));
134 p->fd = open(name, O_BINARY|O_RDONLY);
136 p->fd = open(fname, (O_BINARY|O_CREAT|O_RDWR), 0666);
138 p->fd = open(fname, (O_BINARY|O_CREAT|O_RDWR), 0666);
143 yaz_log(YLOG_WARN | YLOG_ERRNO,
144 "zebra_lock_create fail fname=%s", fname);
150 fname = 0; /* fname buffer now owned by p->fname */
151 yaz_log(log_level, "zebra_lock_create fd=%d p=%p fname=%s",
154 zebra_lock_rdwr_init(&p->rdwr_lock);
155 zebra_mutex_init(&p->file_mutex);
156 p->no_file_write_lock = 0;
157 p->no_file_read_lock = 0;
166 h = (ZebraLockHandle) xmalloc(sizeof(*h));
172 zebra_mutex_unlock(&lock_list_mutex);
173 xfree(fname); /* free it - if it's still there */
178 void zebra_lock_destroy(ZebraLockHandle h)
182 yaz_log(log_level, "zebra_lock_destroy fd=%d p=%p fname=%s",
183 h->p->fd, h, h->p->fname);
184 zebra_mutex_lock(&lock_list_mutex);
185 yaz_log(log_level, "zebra_lock_destroy fd=%d p=%p fname=%s 1",
186 h->p->fd, h, h->p->fname);
187 assert(h->p->ref_count > 0);
189 if (h->p->ref_count == 0)
191 struct zebra_lock_info **hp = &lock_list;
203 zebra_lock_rdwr_destroy(&h->p->rdwr_lock);
204 zebra_mutex_destroy(&h->p->file_mutex);
212 zebra_mutex_unlock(&lock_list_mutex);
216 static int unixLock(int fd, int type, int cmd)
220 area.l_whence = SEEK_SET;
221 area.l_len = area.l_start = 0L;
222 return fcntl(fd, cmd, &area);
226 int zebra_lock_w(ZebraLockHandle h)
229 yaz_log(log_level, "zebra_lock_w fd=%d p=%p fname=%s",
230 h->p->fd, h, h->p->fname);
233 while ((r = _locking(h->p->fd, _LK_LOCK, 1)))
236 zebra_mutex_lock(&h->p->file_mutex);
237 if (h->p->no_file_write_lock == 0)
239 /* if there is already a read lock.. upgrade to write lock */
240 r = unixLock(h->p->fd, F_WRLCK, F_SETLKW);
242 h->p->no_file_write_lock++;
243 zebra_mutex_unlock(&h->p->file_mutex);
245 zebra_lock_rdwr_wlock(&h->p->rdwr_lock);
251 int zebra_lock_r(ZebraLockHandle h)
254 yaz_log(log_level, "zebra_lock_r fd=%d p=%p fname=%s",
255 h->p->fd, h, h->p->fname);
257 while ((r = _locking(h->p->fd, _LK_LOCK, 1)))
260 zebra_mutex_lock(&h->p->file_mutex);
261 if (h->p->no_file_read_lock == 0 && h->p->no_file_write_lock == 0)
263 /* only read lock if no write locks already */
264 r = unixLock(h->p->fd, F_RDLCK, F_SETLKW);
266 h->p->no_file_read_lock++;
267 zebra_mutex_unlock(&h->p->file_mutex);
269 zebra_lock_rdwr_rlock(&h->p->rdwr_lock);
275 int zebra_unlock(ZebraLockHandle h)
278 yaz_log(log_level, "zebra_unlock fd=%d p=%p fname=%s",
279 h->p->fd, h, h->p->fname);
281 r = _locking(h->p->fd, _LK_UNLCK, 1);
284 zebra_lock_rdwr_wunlock(&h->p->rdwr_lock);
286 zebra_lock_rdwr_runlock(&h->p->rdwr_lock);
288 zebra_mutex_lock(&h->p->file_mutex);
290 h->p->no_file_write_lock--;
292 h->p->no_file_read_lock--;
293 if (h->p->no_file_read_lock == 0 && h->p->no_file_write_lock == 0)
295 r = unixLock(h->p->fd, F_UNLCK, F_SETLKW);
297 zebra_mutex_unlock(&h->p->file_mutex);
302 void zebra_flock_init()
306 log_level = yaz_log_module_level("flock");
308 zebra_mutex_init(&lock_list_mutex);
310 yaz_log(log_level, "zebra_flock_init");
316 * indent-tabs-mode: nil
318 * vim: shiftwidth=4 tabstop=8 expandtab