-/* $Id: flock.c,v 1.9 2006-06-27 12:24:14 adam Exp $
+/* $Id: flock.c,v 1.17 2006-07-05 12:02:12 adam Exp $
Copyright (C) 1995-2006
Index Data ApS
/** have this module (mutex) been initialized? */
static int initialized = 0;
+/** whether fcntl locks are shared for all threads in a process (POSIX) */
+static int posix_locks = 1;
+
/** mutex for lock_list below */
Zebra_mutex lock_list_mutex;
assert(initialized);
zebra_mutex_lock(&lock_list_mutex);
-#ifndef WIN32
- for (p = lock_list; p ; p = p->next)
- if (!strcmp(p->fname, fname))
- break;
+ /* see if we have the same filename in a global list of "lock files" */
+#ifndef WIN32
+ if (posix_locks)
+ {
+ for (p = lock_list; p ; p = p->next)
+ if (!strcmp(p->fname, fname))
+ break;
+ }
#endif
if (!p)
- {
+ { /* didn't match (or we didn't want it to match! */
p = (struct zebra_lock_info *) xmalloc(sizeof(*p));
p->ref_count = 0;
{
p->fname = fname;
fname = 0; /* fname buffer now owned by p->fname */
- yaz_log(log_level, "zebra_lock_create fd=%d p=%p fname=%s",
- p->fd, p, p->fname);
#ifndef WIN32
- zebra_lock_rdwr_init(&p->rdwr_lock);
+ if (posix_locks)
+ zebra_lock_rdwr_init(&p->rdwr_lock);
+
zebra_mutex_init(&p->file_mutex);
p->no_file_write_lock = 0;
p->no_file_read_lock = 0;
}
if (p)
{
+ /* we have lock info so we can make a handle pointing to that */
p->ref_count++;
h = (ZebraLockHandle) xmalloc(sizeof(*h));
h->p = p;
#ifndef WIN32
h->write_flag = 0;
#endif
+ yaz_log(log_level, "zebra_lock_create fd=%d p=%p fname=%s",
+ h->p->fd, h, p->fname);
}
zebra_mutex_unlock(&lock_list_mutex);
xfree(fname); /* free it - if it's still there */
yaz_log(log_level, "zebra_lock_destroy fd=%d p=%p fname=%s",
h->p->fd, h, h->p->fname);
zebra_mutex_lock(&lock_list_mutex);
- yaz_log(log_level, "zebra_lock_destroy fd=%d p=%p fname=%s 1",
- h->p->fd, h, h->p->fname);
+ yaz_log(log_level, "zebra_lock_destroy fd=%d p=%p fname=%s refcount=%d",
+ h->p->fd, h, h->p->fname, h->p->ref_count);
assert(h->p->ref_count > 0);
--(h->p->ref_count);
if (h->p->ref_count == 0)
{
+ /* must remove shared info from lock_list */
struct zebra_lock_info **hp = &lock_list;
while (*hp)
{
else
hp = &(*hp)->next;
}
+
+ yaz_log(log_level, "zebra_lock_destroy fd=%d p=%p fname=%s remove",
+ h->p->fd, h, h->p->fname);
+
#ifndef WIN32
- zebra_lock_rdwr_destroy(&h->p->rdwr_lock);
+ if (posix_locks)
+ zebra_lock_rdwr_destroy(&h->p->rdwr_lock);
zebra_mutex_destroy(&h->p->file_mutex);
#endif
if (h->p->fd != -1)
static int unixLock(int fd, int type, int cmd)
{
struct flock area;
+ int r;
area.l_type = type;
area.l_whence = SEEK_SET;
area.l_len = area.l_start = 0L;
- return fcntl(fd, cmd, &area);
+
+ yaz_log(log_level, "fcntl begin type=%d fd=%d", type, fd);
+ r = fcntl(fd, cmd, &area);
+ if (r == -1)
+ yaz_log(YLOG_WARN|YLOG_ERRNO, "fcntl FAIL type=%d fd=%d", type, fd);
+ else
+ yaz_log(log_level, "fcntl type=%d OK fd=%d", type, fd);
+
+ return r;
}
#endif
int zebra_lock_w(ZebraLockHandle h)
{
int r;
- yaz_log(log_level, "zebra_lock_w fd=%d p=%p fname=%s",
+ int do_lock = 0;
+ yaz_log(log_level, "zebra_lock_w fd=%d p=%p fname=%s begin",
h->p->fd, h, h->p->fname);
-
+
#ifdef WIN32
while ((r = _locking(h->p->fd, _LK_LOCK, 1)))
;
#else
+ if (posix_locks)
+ zebra_lock_rdwr_wlock(&h->p->rdwr_lock);
+
zebra_mutex_lock(&h->p->file_mutex);
if (h->p->no_file_write_lock == 0)
+ do_lock = 1;
+ h->p->no_file_write_lock++;
+ if (do_lock)
{
/* if there is already a read lock.. upgrade to write lock */
r = unixLock(h->p->fd, F_WRLCK, F_SETLKW);
}
- h->p->no_file_write_lock++;
+ else
+ {
+ assert(posix_locks);
+ }
zebra_mutex_unlock(&h->p->file_mutex);
- zebra_lock_rdwr_wlock(&h->p->rdwr_lock);
h->write_flag = 1;
#endif
+ yaz_log(log_level, "zebra_lock_w fd=%d p=%p fname=%s end",
+ h->p->fd, h, h->p->fname);
+
return r;
}
int zebra_lock_r(ZebraLockHandle h)
{
int r;
- yaz_log(log_level, "zebra_lock_r fd=%d p=%p fname=%s",
+ int do_lock = 0;
+
+ yaz_log(log_level, "zebra_lock_r fd=%d p=%p fname=%s begin",
h->p->fd, h, h->p->fname);
#ifdef WIN32
while ((r = _locking(h->p->fd, _LK_LOCK, 1)))
;
#else
+ if (posix_locks)
+ zebra_lock_rdwr_rlock(&h->p->rdwr_lock);
+
zebra_mutex_lock(&h->p->file_mutex);
if (h->p->no_file_read_lock == 0 && h->p->no_file_write_lock == 0)
+ do_lock = 1;
+ h->p->no_file_read_lock++;
+ if (do_lock)
{
/* only read lock if no write locks already */
r = unixLock(h->p->fd, F_RDLCK, F_SETLKW);
}
- h->p->no_file_read_lock++;
+ else
+ {
+ assert(posix_locks);
+ }
zebra_mutex_unlock(&h->p->file_mutex);
-
- zebra_lock_rdwr_rlock(&h->p->rdwr_lock);
+
h->write_flag = 0;
#endif
+ yaz_log(log_level, "zebra_lock_r fd=%d p=%p fname=%s end",
+ h->p->fd, h, h->p->fname);
return r;
}
int zebra_unlock(ZebraLockHandle h)
{
int r = 0;
- yaz_log(log_level, "zebra_unlock fd=%d p=%p fname=%s",
+ yaz_log(log_level, "zebra_unlock fd=%d p=%p fname=%s begin",
h->p->fd, h, h->p->fname);
#ifdef WIN32
r = _locking(h->p->fd, _LK_UNLCK, 1);
#else
- if (h->write_flag)
- zebra_lock_rdwr_wunlock(&h->p->rdwr_lock);
- else
- zebra_lock_rdwr_runlock(&h->p->rdwr_lock);
-
zebra_mutex_lock(&h->p->file_mutex);
if (h->write_flag)
- h->p->no_file_write_lock--;
+ {
+ if (h->p->no_file_write_lock > 0)
+ h->p->no_file_write_lock--;
+ }
else
- h->p->no_file_read_lock--;
- if (h->p->no_file_read_lock == 0 && h->p->no_file_write_lock == 0)
{
+ if (h->p->no_file_read_lock > 0)
+ h->p->no_file_read_lock--;
+ }
+ if (h->p->no_file_read_lock == 0 && h->p->no_file_write_lock == 0)
r = unixLock(h->p->fd, F_UNLCK, F_SETLKW);
+ else
+ {
+ r = 0;
+ assert(posix_locks);
}
+
zebra_mutex_unlock(&h->p->file_mutex);
+
+ if (posix_locks)
+ {
+ if (h->write_flag)
+ zebra_lock_rdwr_wunlock(&h->p->rdwr_lock);
+ else
+ zebra_lock_rdwr_runlock(&h->p->rdwr_lock);
+ }
#endif
+ yaz_log(log_level, "zebra_unlock fd=%d p=%p fname=%s end",
+ h->p->fd, h, h->p->fname);
return r;
}
+/** \brief see if the fcntl locking is not POSIX
+ *
+ * The default posix_locks=1 is assumed.. This function sets posix_locks
+ * to zero if linuxthreads is in use.
+ */
+static int check_for_linuxthreads()
+{
+#if __linux
+#ifdef _CS_GNU_LIBPTHREAD_VERSION
+ char conf_buf[512];
+ size_t r = confstr(_CS_GNU_LIBPTHREAD_VERSION, conf_buf, sizeof(conf_buf));
+ if (r == 0)
+ {
+ yaz_log(YLOG_WARN|YLOG_ERRNO, "confstr failed");
+ return -1;
+ }
+ if (strncmp(conf_buf, "linuxthreads", 12) == 0)
+ posix_locks = 0; /* Using linuxthreads.. */
+#else
+ posix_locks = 0; /* Old GLIBC on Linux. Assume linuxthreads */
+#endif
+#endif
+ return 0;
+}
+
void zebra_flock_init()
{
if (!initialized)
{
- log_level = yaz_log_module_level("flock");
initialized = 1;
+ log_level = yaz_log_module_level("flock");
+ yaz_log(log_level, "zebra_flock_init");
+ check_for_linuxthreads();
zebra_mutex_init(&lock_list_mutex);
+ yaz_log(log_level, "posix_locks: %d", posix_locks);
}
- yaz_log(log_level, "zebra_flock_init");
}
/*