1 /* $Id: flock.c,v 1.8 2006-06-27 11:56:29 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;
118 ZebraLockHandle h = 0;
122 zebra_mutex_lock(&lock_list_mutex);
123 for (p = lock_list; p ; p = p->next)
124 if (!strcmp(p->fname, fname))
128 p = (struct zebra_lock_info *) xmalloc(sizeof(*p));
132 p->fd = open(name, O_BINARY|O_RDONLY);
134 p->fd = open(fname, (O_BINARY|O_CREAT|O_RDWR), 0666);
136 p->fd = open(fname, (O_BINARY|O_CREAT|O_RDWR), 0666);
141 yaz_log(YLOG_WARN | YLOG_ERRNO,
142 "zebra_lock_create fail fname=%s", fname);
148 fname = 0; /* fname buffer now owned by p->fname */
149 yaz_log(log_level, "zebra_lock_create fd=%d p=%p fname=%s",
152 zebra_lock_rdwr_init(&p->rdwr_lock);
153 zebra_mutex_init(&p->file_mutex);
154 p->no_file_write_lock = 0;
155 p->no_file_read_lock = 0;
164 h = (ZebraLockHandle) xmalloc(sizeof(*h));
168 zebra_mutex_unlock(&lock_list_mutex);
169 xfree(fname); /* free it - if it's still there */
174 void zebra_lock_destroy(ZebraLockHandle h)
178 yaz_log(log_level, "zebra_lock_destroy fd=%d p=%p fname=%s",
179 h->p->fd, h, h->p->fname);
180 zebra_mutex_lock(&lock_list_mutex);
181 yaz_log(log_level, "zebra_lock_destroy fd=%d p=%p fname=%s 1",
182 h->p->fd, h, h->p->fname);
183 assert(h->p->ref_count > 0);
185 if (h->p->ref_count == 0)
187 struct zebra_lock_info **hp = &lock_list;
199 zebra_lock_rdwr_destroy(&h->p->rdwr_lock);
200 zebra_mutex_destroy(&h->p->file_mutex);
208 zebra_mutex_unlock(&lock_list_mutex);
212 static int unixLock(int fd, int type, int cmd)
216 area.l_whence = SEEK_SET;
217 area.l_len = area.l_start = 0L;
218 return fcntl(fd, cmd, &area);
222 int zebra_lock_w(ZebraLockHandle h)
225 yaz_log(log_level, "zebra_lock_w fd=%d p=%p fname=%s",
226 h->p->fd, h, h->p->fname);
229 while ((r = _locking(h->p->fd, _LK_LOCK, 1)))
232 zebra_mutex_lock(&h->p->file_mutex);
233 if (h->p->no_file_write_lock == 0)
235 /* if there is already a read lock.. upgrade to write lock */
236 r = unixLock(h->p->fd, F_WRLCK, F_SETLKW);
238 h->p->no_file_write_lock++;
239 zebra_mutex_unlock(&h->p->file_mutex);
241 zebra_lock_rdwr_wlock(&h->p->rdwr_lock);
247 int zebra_lock_r(ZebraLockHandle h)
250 yaz_log(log_level, "zebra_lock_r fd=%d p=%p fname=%s",
251 h->p->fd, h, h->p->fname);
253 while ((r = _locking(h->p->fd, _LK_LOCK, 1)))
256 zebra_mutex_lock(&h->p->file_mutex);
257 if (h->p->no_file_read_lock == 0 && h->p->no_file_write_lock == 0)
259 /* only read lock if no write locks already */
260 r = unixLock(h->p->fd, F_RDLCK, F_SETLKW);
262 h->p->no_file_read_lock++;
263 zebra_mutex_unlock(&h->p->file_mutex);
265 zebra_lock_rdwr_rlock(&h->p->rdwr_lock);
271 int zebra_unlock(ZebraLockHandle h)
274 yaz_log(log_level, "zebra_unlock fd=%d p=%p fname=%s",
275 h->p->fd, h, h->p->fname);
277 r = _locking(h->p->fd, _LK_UNLCK, 1);
280 zebra_lock_rdwr_wunlock(&h->p->rdwr_lock);
282 zebra_lock_rdwr_runlock(&h->p->rdwr_lock);
284 zebra_mutex_lock(&h->p->file_mutex);
286 h->p->no_file_write_lock--;
288 h->p->no_file_read_lock--;
289 if (h->p->no_file_read_lock == 0 && h->p->no_file_write_lock == 0)
291 r = unixLock(h->p->fd, F_UNLCK, F_SETLKW);
293 zebra_mutex_unlock(&h->p->file_mutex);
298 void zebra_flock_init()
302 log_level = yaz_log_module_level("flock");
304 zebra_mutex_init(&lock_list_mutex);
311 * indent-tabs-mode: nil
313 * vim: shiftwidth=4 tabstop=8 expandtab