1 /* $Id: flock.c,v 1.10 2006-06-30 11:10:17 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>
45 #define ALWAYS_FLOCK 1
47 /** have this module (mutex) been initialized? */
48 static int initialized = 0;
50 /** mutex for lock_list below */
51 Zebra_mutex lock_list_mutex;
53 /** our list of file locked files */
54 static struct zebra_lock_info *lock_list = 0;
56 /** the internal handle, with a pointer to each lock file info */
57 struct zebra_lock_handle {
59 /** so we can call zebra_lock_rdwr_wunlock or zebra_lock_lock_runlock */
62 struct zebra_lock_info *p;
65 struct zebra_lock_info {
66 /** file descriptor */
68 /** full path (xmalloc'ed) */
70 /** reference counter: number of zebra_lock_handles pointing to us */
73 /** number of file write locks/read locks */
74 int no_file_write_lock;
75 int no_file_read_lock;
76 Zebra_lock_rdwr rdwr_lock;
77 Zebra_mutex file_mutex;
79 /** next in lock list */
80 struct zebra_lock_info *next;
83 static int log_level = 0;
85 char *zebra_mk_fname(const char *dir, const char *name)
87 int dlen = dir ? strlen(dir) : 0;
88 char *fname = xmalloc(dlen + strlen(name) + 3);
93 int last_one = dir[dlen-1];
95 if (!strchr("/\\:", last_one))
96 sprintf(fname, "%s\\%s", dir, name);
98 sprintf(fname, "%s%s", dir, name);
101 sprintf(fname, "%s", name);
105 int last_one = dir[dlen-1];
107 if (!strchr("/", last_one))
108 sprintf(fname, "%s/%s", dir, name);
110 sprintf(fname, "%s%s", dir, name);
113 sprintf(fname, "%s", name);
118 ZebraLockHandle zebra_lock_create(const char *dir, const char *name)
120 char *fname = zebra_mk_fname(dir, name);
121 struct zebra_lock_info *p = 0;
122 ZebraLockHandle h = 0;
126 zebra_mutex_lock(&lock_list_mutex);
128 for (p = lock_list; p ; p = p->next)
129 if (!strcmp(p->fname, fname))
134 p = (struct zebra_lock_info *) xmalloc(sizeof(*p));
138 p->fd = open(name, O_BINARY|O_RDONLY);
140 p->fd = open(fname, (O_BINARY|O_CREAT|O_RDWR), 0666);
142 p->fd = open(fname, (O_BINARY|O_CREAT|O_RDWR), 0666);
147 yaz_log(YLOG_WARN | YLOG_ERRNO,
148 "zebra_lock_create fail fname=%s", fname);
154 fname = 0; /* fname buffer now owned by p->fname */
156 zebra_lock_rdwr_init(&p->rdwr_lock);
157 zebra_mutex_init(&p->file_mutex);
158 p->no_file_write_lock = 0;
159 p->no_file_read_lock = 0;
168 h = (ZebraLockHandle) xmalloc(sizeof(*h));
173 yaz_log(log_level, "zebra_lock_create fd=%d p=%p fname=%s",
174 h->p->fd, h, p->fname);
176 zebra_mutex_unlock(&lock_list_mutex);
177 xfree(fname); /* free it - if it's still there */
182 void zebra_lock_destroy(ZebraLockHandle h)
186 yaz_log(log_level, "zebra_lock_destroy fd=%d p=%p fname=%s",
187 h->p->fd, h, h->p->fname);
188 zebra_mutex_lock(&lock_list_mutex);
189 yaz_log(log_level, "zebra_lock_destroy fd=%d p=%p fname=%s refcount=%d",
190 h->p->fd, h, h->p->fname, h->p->ref_count);
191 assert(h->p->ref_count > 0);
193 if (h->p->ref_count == 0)
195 struct zebra_lock_info **hp = &lock_list;
196 yaz_log(log_level, "zebra_lock_destroy fd=%d p=%p fname=%s remove",
197 h->p->fd, h, h->p->fname);
209 zebra_lock_rdwr_destroy(&h->p->rdwr_lock);
210 zebra_mutex_destroy(&h->p->file_mutex);
218 zebra_mutex_unlock(&lock_list_mutex);
222 static int unixLock(int fd, int type, int cmd)
227 area.l_whence = SEEK_SET;
228 area.l_len = area.l_start = 0L;
230 yaz_log(log_level, "fcntl begin type=%d fd=%d", type, fd);
231 r = fcntl(fd, cmd, &area);
233 yaz_log(YLOG_WARN|YLOG_ERRNO, "fcntl FAIL type=%d fd=%d", type, fd);
235 yaz_log(log_level, "fcntl type=%d OK fd=%d", type, fd);
241 int zebra_lock_w(ZebraLockHandle h)
244 int do_lock = ALWAYS_FLOCK;
245 yaz_log(log_level, "zebra_lock_w fd=%d p=%p fname=%s begin",
246 h->p->fd, h, h->p->fname);
249 while ((r = _locking(h->p->fd, _LK_LOCK, 1)))
252 zebra_mutex_lock(&h->p->file_mutex);
253 if (h->p->no_file_write_lock == 0)
255 h->p->no_file_write_lock++;
256 zebra_mutex_unlock(&h->p->file_mutex);
259 yaz_log(log_level, "zebra_lock_w fd=%d p=%p fname=%s 2",
260 h->p->fd, h, h->p->fname);
261 /* if there is already a read lock.. upgrade to write lock */
262 r = unixLock(h->p->fd, F_WRLCK, F_SETLKW);
264 yaz_log(log_level, "zebra_lock_w fd=%d p=%p fname=%s 3",
265 h->p->fd, h, h->p->fname);
267 zebra_lock_rdwr_wlock(&h->p->rdwr_lock);
269 yaz_log(log_level, "zebra_lock_w fd=%d p=%p fname=%s end",
270 h->p->fd, h, h->p->fname);
276 int zebra_lock_r(ZebraLockHandle h)
279 int do_lock = ALWAYS_FLOCK;
281 yaz_log(log_level, "zebra_lock_r fd=%d p=%p fname=%s",
282 h->p->fd, h, h->p->fname);
284 while ((r = _locking(h->p->fd, _LK_LOCK, 1)))
287 zebra_mutex_lock(&h->p->file_mutex);
288 if (h->p->no_file_read_lock == 0 && h->p->no_file_write_lock == 0)
290 h->p->no_file_read_lock++;
291 zebra_mutex_unlock(&h->p->file_mutex);
295 /* only read lock if no write locks already */
296 r = unixLock(h->p->fd, F_RDLCK, F_SETLKW);
299 zebra_lock_rdwr_rlock(&h->p->rdwr_lock);
305 int zebra_unlock(ZebraLockHandle h)
308 int do_unlock = ALWAYS_FLOCK;
309 yaz_log(log_level, "zebra_unlock fd=%d p=%p fname=%s begin",
310 h->p->fd, h, h->p->fname);
312 r = _locking(h->p->fd, _LK_UNLCK, 1);
315 zebra_lock_rdwr_wunlock(&h->p->rdwr_lock);
317 zebra_lock_rdwr_runlock(&h->p->rdwr_lock);
319 zebra_mutex_lock(&h->p->file_mutex);
321 h->p->no_file_write_lock--;
323 h->p->no_file_read_lock--;
324 if (h->p->no_file_read_lock == 0 && h->p->no_file_write_lock == 0)
327 yaz_log(log_level, "zebra_unlock fd=%d p=%p fname=%s 2",
328 h->p->fd, h, h->p->fname);
330 zebra_mutex_unlock(&h->p->file_mutex);
333 r = unixLock(h->p->fd, F_UNLCK, F_SETLKW);
334 yaz_log(log_level, "zebra_unlock fd=%d p=%p fname=%s end",
335 h->p->fd, h, h->p->fname);
340 void zebra_flock_init()
344 log_level = yaz_log_module_level("flock");
346 log_level = YLOG_LOG|YLOG_FLUSH;
349 zebra_mutex_init(&lock_list_mutex);
351 yaz_log(log_level, "zebra_flock_init");
357 * indent-tabs-mode: nil
359 * vim: shiftwidth=4 tabstop=8 expandtab