-/* $Id: flock.c,v 1.10 2006-06-30 11:10:17 adam Exp $
+/* $Id: flock.c,v 1.11 2006-06-30 13:02:20 adam Exp $
Copyright (C) 1995-2006
Index Data ApS
#include <yaz/xmalloc.h>
#include <yaz/log.h>
-#define DEBUG_FLOCK 1
+/** whether lock file desciptors are shared within one process' threads */
+#define ZEBRA_FLOCK_SHARE_FD_IN_THREADS 1
-#define ALWAYS_FLOCK 1
+/** whether we always lock on the file - even if rd/wr locks should do */
+#define ZEBRA_FLOCK_FILE_LOCK_ALWAYS 1
+
+/** whether we should also use pthreads locking to do "extra" rd/wr locks */
+#define ZEBRA_FLOCK_EXTRA_RDWR_LOCKS 1
+
+/** whether this module should debug */
+#define DEBUG_FLOCK 0
/** have this module (mutex) been initialized? */
static int initialized = 0;
/** number of file write locks/read locks */
int no_file_write_lock;
int no_file_read_lock;
+#if ZEBRA_FLOCK_EXTRA_RDWR_LOCKS
Zebra_lock_rdwr rdwr_lock;
+#endif
Zebra_mutex file_mutex;
#endif
/** next in lock list */
assert(initialized);
zebra_mutex_lock(&lock_list_mutex);
-#ifndef WIN32
+ /* see if we have the same filename in a global list of "lock files" */
+#ifndef WIN32
+#if ZEBRA_FLOCK_SHARE_FD_IN_THREADS
for (p = lock_list; p ; p = p->next)
if (!strcmp(p->fname, fname))
break;
#endif
+#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 */
#ifndef WIN32
+#if ZEBRA_FLOCK_EXTRA_RDWR_LOCKS
zebra_lock_rdwr_init(&p->rdwr_lock);
+#endif
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;
--(h->p->ref_count);
if (h->p->ref_count == 0)
{
+ /* must remove shared info from lock_list */
struct zebra_lock_info **hp = &lock_list;
- yaz_log(log_level, "zebra_lock_destroy fd=%d p=%p fname=%s remove",
- h->p->fd, h, h->p->fname);
while (*hp)
{
if (*hp == h->p)
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
+#if ZEBRA_FLOCK_EXTRA_RDWR_LOCKS
zebra_lock_rdwr_destroy(&h->p->rdwr_lock);
+#endif
zebra_mutex_destroy(&h->p->file_mutex);
#endif
if (h->p->fd != -1)
int zebra_lock_w(ZebraLockHandle h)
{
int r;
- int do_lock = ALWAYS_FLOCK;
+ int do_lock = ZEBRA_FLOCK_FILE_LOCK_ALWAYS;
yaz_log(log_level, "zebra_lock_w fd=%d p=%p fname=%s begin",
h->p->fd, h, h->p->fname);
yaz_log(log_level, "zebra_lock_w fd=%d p=%p fname=%s 3",
h->p->fd, h, h->p->fname);
+#if ZEBRA_FLOCK_EXTRA_RDWR_LOCKS
zebra_lock_rdwr_wlock(&h->p->rdwr_lock);
+#endif
h->write_flag = 1;
yaz_log(log_level, "zebra_lock_w fd=%d p=%p fname=%s end",
h->p->fd, h, h->p->fname);
int zebra_lock_r(ZebraLockHandle h)
{
int r;
- int do_lock = ALWAYS_FLOCK;
+ int do_lock = ZEBRA_FLOCK_FILE_LOCK_ALWAYS;
yaz_log(log_level, "zebra_lock_r fd=%d p=%p fname=%s",
h->p->fd, h, h->p->fname);
r = unixLock(h->p->fd, F_RDLCK, F_SETLKW);
}
+#if ZEBRA_FLOCK_EXTRA_RDWR_LOCKS
zebra_lock_rdwr_rlock(&h->p->rdwr_lock);
+#endif
h->write_flag = 0;
#endif
return r;
int zebra_unlock(ZebraLockHandle h)
{
int r = 0;
- int do_unlock = ALWAYS_FLOCK;
+ int do_unlock = ZEBRA_FLOCK_FILE_LOCK_ALWAYS;
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 ZEBRA_FLOCK_EXTRA_RDWR_LOCKS
if (h->write_flag)
zebra_lock_rdwr_wunlock(&h->p->rdwr_lock);
else
zebra_lock_rdwr_runlock(&h->p->rdwr_lock);
+#endif
zebra_mutex_lock(&h->p->file_mutex);
if (h->write_flag)
else
h->p->no_file_read_lock--;
if (h->p->no_file_read_lock == 0 && h->p->no_file_write_lock == 0)
- {
do_unlock = 1;
- yaz_log(log_level, "zebra_unlock fd=%d p=%p fname=%s 2",
- h->p->fd, h, h->p->fname);
- }
zebra_mutex_unlock(&h->p->file_mutex);
if (do_unlock)
* Copyright (C) 1995-2006, Index Data ApS
* See the file LICENSE for details.
*
- * $Id: tstflock.c,v 1.9 2006-06-30 11:10:17 adam Exp $
+ * $Id: tstflock.c,v 1.10 2006-06-30 13:02:20 adam Exp $
*/
#include <assert.h>
+#include <stdlib.h>
#include <yaz/test.h>
+#include <yaz/log.h>
#if YAZ_POSIX_THREADS
#include <pthread.h>
#endif
#endif
#include <string.h>
-static char seq[40];
-static char *seqp = seq;
+static char seq[1000];
+static char *seqp = 0;
-#define NUM_THREADS 5
+#define NUM_THREADS 100
static void small_sleep()
{
ZebraLockHandle lh = zebra_lock_create(0, "my.LCK");
for (i = 0; i<2; i++)
{
- if (use_write_lock)
+ int write_lock;
+
+ if (use_write_lock == 2)
+ write_lock = (rand() & 3) == 3 ? 1 : 0;
+ else
+ write_lock = use_write_lock;
+
+ if (write_lock)
{
zebra_lock_w(lh);
run_func(p);
return 0;
}
+#endif
-static void tst_win32(int num)
+static void tst_thread(int num, int write_flag)
{
+#ifdef WIN32
HANDLE handles[NUM_THREADS];
DWORD dwThreadId[NUM_THREADS];
- int i, id[NUM_THREADS];
-
- assert (num <= NUM_THREADS);
- for (i = 0; i<num; i++)
- {
- void *pData = &id[i];
- id[i] = i >= 2 ? 0 : 1; /* first two are writing.. rest is reading */
- handles[i] = CreateThread(
- NULL, /* default security attributes */
- 0, /* use default stack size */
- ThreadProc, /* thread function */
- pData, /* argument to thread function */
- 0, /* use default creation flags */
- &dwThreadId[i]); /* returns the thread identifier */
- }
- /* join */
- WaitForMultipleObjects(num, handles, TRUE, INFINITE);
-}
#endif
-
#if YAZ_POSIX_THREADS
-static void tst_pthread(int num)
-{
pthread_t child_thread[NUM_THREADS];
+#endif
int i, id[NUM_THREADS];
+ seqp = seq;
assert (num <= NUM_THREADS);
- for (i = 0; i<num; i++)
+ for (i = 0; i < num; i++)
{
- id[i] = i >= 2 ? 0 : 1; /* first two are writing.. rest is reading */
+ id[i] = write_flag;
+#if YAZ_POSIX_THREADS
pthread_create(&child_thread[i], 0 /* attr */, run_func, &id[i]);
- }
+#endif
+#ifdef WIN32
+ if (1)
+ {
+ void *pData = &id[i];
+ handles[i] = CreateThread(
+ NULL, /* default security attributes */
+ 0, /* use default stack size */
+ ThreadProc, /* thread function */
+ pData, /* argument to thread function */
+ 0, /* use default creation flags */
+ &dwThreadId[i]); /* returns the thread identifier */
+ }
+#endif
+ }
+#if YAZ_POSIX_THREADS
for (i = 0; i<num; i++)
pthread_join(child_thread[i], 0);
-
- for (i = 0; i<num; i++)
+#endif
+#ifdef WIN32
+ WaitForMultipleObjects(num, handles, TRUE, INFINITE);
+#endif
+ for (i = 0; i < num; i++)
YAZ_CHECK(id[i] == 123);
+ *seqp++ = '\0';
}
+
+static void tst()
+{
+ tst_thread(4, 1); /* write locks */
+#if 0
+ printf("seq=%s\n", seq);
#endif
+ if (1)
+ {
+ int i = 0;
+ while (seq[i])
+ {
+ YAZ_CHECK_EQ(seq[i], 'L');
+ YAZ_CHECK_EQ(seq[i+1], 'U');
+ i = i + 2;
+ }
+ }
+
+#if 0
+ tst_thread(6, 0); /* read locks */
+ printf("seq=%s\n", seq);
+#endif
+#if 0
+ tst_thread(20, 2); /* random locks */
+ printf("seq=%s\n", seq);
+#endif
+}
int main(int argc, char **argv)
{
yaz_log_time_format("%s:%!");
zebra_flock_init();
-#ifdef WIN32
- tst_win32(2);
-#endif
-#if YAZ_POSIX_THREADS
- tst_pthread(2);
-#endif
- *seqp++ = '\0';
-#if 0
- printf("seq=%s\n", seq);
-#endif
-#if 1
- /* does not pass.. for bug 529 */
- YAZ_CHECK(strcmp(seq, "LULULULU") == 0); /* for tst_pthread when num=2 */
-#endif
+ tst();
+
YAZ_CHECK_TERM;
}