745 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			745 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*  $Id$
 | 
						|
 | 
						|
    Part of the SWI-Prolog Semweb package
 | 
						|
 | 
						|
    Author:        Jan Wielemaker
 | 
						|
    E-mail:        wielemak@science.uva.nl
 | 
						|
    WWW:           http://www.swi-prolog.org
 | 
						|
    Copyright (C): 2006, University of Amsterdam
 | 
						|
 | 
						|
    This program is free software; you can redistribute it and/or
 | 
						|
    modify it under the terms of the GNU General Public License
 | 
						|
    as published by the Free Software Foundation; either version 2
 | 
						|
    of the License, or (at your option) any later version.
 | 
						|
 | 
						|
    This program is distributed in the hope that it will be useful,
 | 
						|
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
    GNU General Public License for more details.
 | 
						|
 | 
						|
    You should have received a copy of the GNU Lesser General Public
 | 
						|
    License along with this library; if not, write to the Free Software
 | 
						|
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
						|
*/
 | 
						|
 | 
						|
#include <SWI-Stream.h>
 | 
						|
#include <SWI-Prolog.h>
 | 
						|
#include "lock.h"
 | 
						|
#include "debug.h"
 | 
						|
#include <assert.h>
 | 
						|
#include <string.h>
 | 
						|
 | 
						|
static int
 | 
						|
permission_error(const char *op, const char *type, const char *obj,
 | 
						|
		 const char *msg)
 | 
						|
{ term_t ex, ctx;
 | 
						|
 | 
						|
  if ( !(ex = PL_new_term_ref()) ||
 | 
						|
       !(ctx = PL_new_term_ref()) )
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
  if ( msg )
 | 
						|
  { if ( !PL_unify_term(ctx, PL_FUNCTOR_CHARS, "context", 2,
 | 
						|
			       PL_VARIABLE,
 | 
						|
			       PL_CHARS, msg) )
 | 
						|
      return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  if ( !PL_unify_term(ex, PL_FUNCTOR_CHARS, "error", 2,
 | 
						|
		      PL_FUNCTOR_CHARS, "permission_error", 3,
 | 
						|
		        PL_CHARS, op,
 | 
						|
		        PL_CHARS, type,
 | 
						|
		        PL_CHARS, obj,
 | 
						|
		      PL_TERM, ctx) )
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
  return PL_raise_exception(ex);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#ifdef _REENTRANT
 | 
						|
 | 
						|
 | 
						|
		 /*******************************
 | 
						|
		 *	   COMMON STUFF		*
 | 
						|
		 *******************************/
 | 
						|
 | 
						|
static void
 | 
						|
register_reader(rwlock *lock, int tid)
 | 
						|
{ while ( tid >= lock->thread_max )
 | 
						|
  { size_t osize = lock->thread_max*sizeof(lock->read_by_thread[0]);
 | 
						|
 | 
						|
    lock->read_by_thread = realloc(lock->read_by_thread, osize*2);
 | 
						|
    memset((char*)lock->read_by_thread+osize, 0, osize);
 | 
						|
    lock->thread_max *= 2;
 | 
						|
  }
 | 
						|
 | 
						|
  lock->read_by_thread[tid]++;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
		 /*******************************
 | 
						|
		 *	 WINDOWS VERSION	*
 | 
						|
		 *******************************/
 | 
						|
 | 
						|
#ifdef __WINDOWS__
 | 
						|
 | 
						|
#include <windows.h>
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
						|
This  is  a  slightly  simplified  version  of  the  condition  variable
 | 
						|
emulation used in SWI-Prolog. We have   deleted the broadcast facilities
 | 
						|
of the CVs as this is not used in this code.
 | 
						|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
 | 
						|
static int
 | 
						|
win32_cond_init(win32_cond_t *cv)
 | 
						|
{ cv->events[SIGNAL]    = CreateEvent(NULL, FALSE, FALSE, NULL);
 | 
						|
  cv->waiters = 0;
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
win32_cond_destroy(win32_cond_t *cv)
 | 
						|
{ CloseHandle(cv->events[SIGNAL]);
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
#define WAIT_INTR (-1)
 | 
						|
 | 
						|
static int
 | 
						|
win32_cond_wait(win32_cond_t *cv,
 | 
						|
		CRITICAL_SECTION *external_mutex)
 | 
						|
{ int rc;
 | 
						|
 | 
						|
  cv->waiters++;
 | 
						|
 | 
						|
  LeaveCriticalSection(external_mutex);
 | 
						|
  rc = MsgWaitForMultipleObjects(1,
 | 
						|
				 cv->events,
 | 
						|
				 FALSE,	/* wait for either event */
 | 
						|
				 INFINITE,
 | 
						|
				 QS_ALLINPUT);
 | 
						|
  if ( rc == WAIT_OBJECT_0+1 )
 | 
						|
  { MSG msg;
 | 
						|
 | 
						|
    while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
 | 
						|
    { TranslateMessage(&msg);
 | 
						|
      DispatchMessage(&msg);
 | 
						|
    }
 | 
						|
 | 
						|
    if ( PL_handle_signals() < 0 )
 | 
						|
    { EnterCriticalSection(external_mutex);
 | 
						|
      return WAIT_INTR;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  EnterCriticalSection(external_mutex);
 | 
						|
 | 
						|
  cv->waiters--;
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
win32_cond_signal(win32_cond_t *cv)	/* must be holding associated mutex */
 | 
						|
{ if ( cv->waiters > 0 )
 | 
						|
    SetEvent(cv->events[SIGNAL]);
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
rdlock(rwlock *lock)
 | 
						|
{ int self = PL_thread_self();
 | 
						|
 | 
						|
  if ( lock->writer == self )
 | 
						|
  { lock->lock_level++;			/* read nested in write */
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  EnterCriticalSection(&lock->mutex);
 | 
						|
 | 
						|
  if ( lock->allow_readers == TRUE )
 | 
						|
  { ok:
 | 
						|
 | 
						|
    lock->readers++;
 | 
						|
    register_reader(lock, self);
 | 
						|
    LeaveCriticalSection(&lock->mutex);
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  lock->waiting_readers++;
 | 
						|
 | 
						|
  for(;;)
 | 
						|
  { int rc = win32_cond_wait(&lock->rdcondvar, &lock->mutex);
 | 
						|
 | 
						|
    if ( rc == WAIT_INTR )
 | 
						|
    { lock->waiting_readers--;
 | 
						|
      LeaveCriticalSection(&lock->mutex);
 | 
						|
      return FALSE;
 | 
						|
    } else if ( rc == 0 )
 | 
						|
    { if ( lock->allow_readers == TRUE )
 | 
						|
      { lock->waiting_readers--;
 | 
						|
	goto ok;
 | 
						|
      }
 | 
						|
    } else
 | 
						|
    { assert(0);			/* TBD: OS errors */
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
wrlock(rwlock *lock, int allow_readers)
 | 
						|
{ int self = PL_thread_self();
 | 
						|
 | 
						|
  if ( lock->writer == self )		/* recursive write lock, used for */
 | 
						|
  { lock->lock_level++;			/* nested transactions */
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  EnterCriticalSection(&lock->mutex);
 | 
						|
 | 
						|
  if ( lock->writer == -1 && lock->readers == 0 )
 | 
						|
  { ok:
 | 
						|
 | 
						|
    lock->writer = self;
 | 
						|
    lock->lock_level = 1;
 | 
						|
    lock->allow_readers = allow_readers;
 | 
						|
    LeaveCriticalSection(&lock->mutex);
 | 
						|
    DEBUG(3, Sdprintf("WRLOCK(%d): OK\n", self));
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  if ( self < lock->thread_max && lock->read_by_thread[self] > 0 )
 | 
						|
  { LeaveCriticalSection(&lock->mutex);
 | 
						|
    return permission_error("write", "rdf_db", "default",
 | 
						|
			    "Operation would deadlock");
 | 
						|
  }
 | 
						|
 | 
						|
  lock->waiting_writers++;
 | 
						|
  DEBUG(3, Sdprintf("WRLOCK(%d): waiting ...\n", self));
 | 
						|
 | 
						|
  for(;;)
 | 
						|
  { int rc = win32_cond_wait(&lock->wrcondvar, &lock->mutex);
 | 
						|
 | 
						|
    if ( rc == WAIT_INTR )
 | 
						|
    { lock->waiting_writers--;
 | 
						|
      LeaveCriticalSection(&lock->mutex);
 | 
						|
      return FALSE;
 | 
						|
    } else if ( rc == 0 )
 | 
						|
    { if ( lock->writer == -1 && lock->readers == 0 )
 | 
						|
      { lock->waiting_writers--;
 | 
						|
	goto ok;
 | 
						|
      }
 | 
						|
    } else
 | 
						|
    { assert(0);			/* TBD: OS errors */
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
lockout_readers(rwlock *lock)
 | 
						|
{ EnterCriticalSection(&lock->mutex);
 | 
						|
 | 
						|
  if ( lock->readers == 0 )
 | 
						|
  { ok:
 | 
						|
 | 
						|
    lock->allow_readers = FALSE;
 | 
						|
    LeaveCriticalSection(&lock->mutex);
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  lock->waiting_upgrade++;
 | 
						|
 | 
						|
  for(;;)
 | 
						|
  { int rc = win32_cond_wait(&lock->upcondvar, &lock->mutex);
 | 
						|
 | 
						|
    if ( rc == WAIT_INTR )
 | 
						|
    { lock->waiting_upgrade--;
 | 
						|
      LeaveCriticalSection(&lock->mutex);
 | 
						|
      return FALSE;
 | 
						|
    } else if ( rc == 0 )
 | 
						|
    { if ( lock->readers == 0 )
 | 
						|
      { lock->waiting_upgrade--;
 | 
						|
	goto ok;
 | 
						|
      }
 | 
						|
    } else
 | 
						|
    { assert(0);			/* TBD: OS errors */
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void
 | 
						|
reallow_readers(rwlock *lock)
 | 
						|
{ EnterCriticalSection(&lock->mutex);
 | 
						|
  lock->allow_readers = TRUE;
 | 
						|
  LeaveCriticalSection(&lock->mutex);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
unlock(rwlock *lock, int rd)
 | 
						|
{ int self = PL_thread_self();
 | 
						|
  int signal;
 | 
						|
 | 
						|
  if ( lock->writer == self && lock->lock_level > 1 )
 | 
						|
  { lock->lock_level--;
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  EnterCriticalSection(&lock->mutex);
 | 
						|
  if ( rd )				/* must be a read lock */
 | 
						|
  { lock->readers--;
 | 
						|
    lock->read_by_thread[self]--;
 | 
						|
    signal = (lock->readers == 0);
 | 
						|
  } else
 | 
						|
  { lock->writer = -1;
 | 
						|
    lock->allow_readers = TRUE;
 | 
						|
    signal = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  if ( signal )
 | 
						|
  { enum { NONE, READ, WRITE, UPGRADE } waiting;
 | 
						|
 | 
						|
    waiting = (lock->waiting_upgrade ? UPGRADE :
 | 
						|
	       lock->waiting_writers ? WRITE :
 | 
						|
	       lock->waiting_readers ? READ : NONE);
 | 
						|
 | 
						|
    switch(waiting)
 | 
						|
    { case UPGRADE:
 | 
						|
	win32_cond_signal(&lock->upcondvar);
 | 
						|
	break;
 | 
						|
      case WRITE:
 | 
						|
	win32_cond_signal(&lock->wrcondvar);
 | 
						|
	break;
 | 
						|
      case READ:
 | 
						|
	win32_cond_signal(&lock->rdcondvar);
 | 
						|
	break;
 | 
						|
      default:
 | 
						|
	;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  LeaveCriticalSection(&lock->mutex);	/* In our __WINDOWS__ emulation we */
 | 
						|
					/* must hold the associated mutex */
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
lock_misc(rwlock *lock)
 | 
						|
{ EnterCriticalSection(&lock->misc_mutex);
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
unlock_misc(rwlock *lock)
 | 
						|
{ LeaveCriticalSection(&lock->misc_mutex);
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
init_lock(rwlock *lock)
 | 
						|
{ InitializeCriticalSection(&lock->mutex);
 | 
						|
  InitializeCriticalSection(&lock->misc_mutex);
 | 
						|
 | 
						|
  if ( !win32_cond_init(&lock->wrcondvar) == 0 ||
 | 
						|
       !win32_cond_init(&lock->rdcondvar) == 0 ||
 | 
						|
       !win32_cond_init(&lock->upcondvar) == 0 )
 | 
						|
  {					/* TBD: System error */
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  lock->writer          = -1;
 | 
						|
  lock->allow_readers   = TRUE;
 | 
						|
  lock->readers         = 0;
 | 
						|
  lock->waiting_readers = 0;
 | 
						|
  lock->waiting_writers = 0;
 | 
						|
  lock->waiting_upgrade = 0;
 | 
						|
  lock->lock_level      = 0;
 | 
						|
 | 
						|
  lock->thread_max = 4;
 | 
						|
  if ( !(lock->read_by_thread = malloc(lock->thread_max*sizeof(int))) )
 | 
						|
    return FALSE;
 | 
						|
  memset(lock->read_by_thread, 0, lock->thread_max*sizeof(int));
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
destroy_lock(rwlock *lock)
 | 
						|
{ DeleteCriticalSection(&lock->mutex);
 | 
						|
  DeleteCriticalSection(&lock->misc_mutex);
 | 
						|
  win32_cond_destroy(&lock->wrcondvar);
 | 
						|
  win32_cond_destroy(&lock->rdcondvar);
 | 
						|
  win32_cond_destroy(&lock->upcondvar);
 | 
						|
 | 
						|
  free(lock->read_by_thread);
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
#else /*__WINDOWS__*/
 | 
						|
 | 
						|
		 /*******************************
 | 
						|
		 *	   POSIX VERSION	*
 | 
						|
		 *******************************/
 | 
						|
 | 
						|
#include <errno.h>
 | 
						|
 | 
						|
int
 | 
						|
rdlock(rwlock *lock)
 | 
						|
{ int self = PL_thread_self();
 | 
						|
 | 
						|
  if ( lock->writer == self )
 | 
						|
  { lock->lock_level++;			/* read nested in write */
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  pthread_mutex_lock(&lock->mutex);
 | 
						|
 | 
						|
  if ( lock->allow_readers == TRUE )
 | 
						|
  { ok:
 | 
						|
 | 
						|
    lock->readers++;
 | 
						|
    register_reader(lock, self);
 | 
						|
    pthread_mutex_unlock(&lock->mutex);
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  lock->waiting_readers++;
 | 
						|
 | 
						|
  for(;;)
 | 
						|
  { int rc = pthread_cond_wait(&lock->rdcondvar, &lock->mutex);
 | 
						|
 | 
						|
    if ( rc == EINTR )
 | 
						|
    { if ( PL_handle_signals() < 0 )
 | 
						|
      { lock->waiting_readers--;
 | 
						|
	pthread_mutex_unlock(&lock->mutex);
 | 
						|
	return FALSE;
 | 
						|
      }
 | 
						|
      continue;
 | 
						|
    } else if ( rc == 0 )
 | 
						|
    { if ( lock->allow_readers == TRUE )
 | 
						|
      { lock->waiting_readers--;
 | 
						|
	goto ok;
 | 
						|
      }
 | 
						|
    } else
 | 
						|
    { assert(0);			/* TBD: OS errors */
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
						|
WRLOCK() and LOCKOUT_READERS() can be  used   in  two ways. Conventional
 | 
						|
write locks are established using   WRLOCK(db,  FALSE) ... WRUNLOCK(db).
 | 
						|
For transactions, we allow concurrent  readers   until  we  are ready to
 | 
						|
commit, in which case we use  WRLOCK(db, TRUE) ... LOCKOUT_READERS() ...
 | 
						|
WRUNLOCK(db)
 | 
						|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
 | 
						|
int
 | 
						|
wrlock(rwlock *lock, int allow_readers)
 | 
						|
{ int self = PL_thread_self();
 | 
						|
 | 
						|
  if ( lock->writer == self )		/* recursive write lock, used for */
 | 
						|
  { lock->lock_level++;			/* nested transactions */
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  pthread_mutex_lock(&lock->mutex);
 | 
						|
 | 
						|
  if ( lock->writer == -1 && lock->readers == 0 )
 | 
						|
  { ok:
 | 
						|
 | 
						|
    lock->writer = self;
 | 
						|
    lock->lock_level = 1;
 | 
						|
    lock->allow_readers = allow_readers;
 | 
						|
    pthread_mutex_unlock(&lock->mutex);
 | 
						|
    DEBUG(3, Sdprintf("WRLOCK(%d): OK\n", self));
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  if ( self < lock->thread_max && lock->read_by_thread[self] > 0 )
 | 
						|
  { DEBUG(1, Sdprintf("SELF(%d) has %d readers\n",
 | 
						|
		      self, lock->read_by_thread[self]));
 | 
						|
    pthread_mutex_unlock(&lock->mutex);
 | 
						|
    return permission_error("write", "rdf_db", "default",
 | 
						|
			    "Operation would deadlock");
 | 
						|
  }
 | 
						|
 | 
						|
  lock->waiting_writers++;
 | 
						|
  DEBUG(3, Sdprintf("WRLOCK(%d): waiting ...\n", self));
 | 
						|
 | 
						|
  for(;;)
 | 
						|
  { int rc = pthread_cond_wait(&lock->wrcondvar, &lock->mutex);
 | 
						|
 | 
						|
    if ( rc == EINTR )
 | 
						|
    { if ( PL_handle_signals() < 0 )
 | 
						|
      { lock->waiting_writers--;
 | 
						|
	pthread_mutex_unlock(&lock->mutex);
 | 
						|
	return FALSE;
 | 
						|
      }
 | 
						|
      continue;
 | 
						|
    } else if ( rc == 0 )
 | 
						|
    { if ( lock->writer == -1 && lock->readers == 0 )
 | 
						|
      { lock->waiting_writers--;
 | 
						|
	goto ok;
 | 
						|
      }
 | 
						|
    } else
 | 
						|
    { assert(0);			/* TBD: OS errors */
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
lockout_readers(rwlock *lock)
 | 
						|
{ pthread_mutex_lock(&lock->mutex);
 | 
						|
 | 
						|
  if ( lock->readers == 0 )
 | 
						|
  { ok:
 | 
						|
 | 
						|
    lock->allow_readers = FALSE;
 | 
						|
    pthread_mutex_unlock(&lock->mutex);
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  lock->waiting_upgrade++;
 | 
						|
 | 
						|
  for(;;)
 | 
						|
  { int rc = pthread_cond_wait(&lock->upcondvar, &lock->mutex);
 | 
						|
 | 
						|
    if ( rc == EINTR )
 | 
						|
    { if ( PL_handle_signals() < 0 )
 | 
						|
      { lock->waiting_upgrade--;
 | 
						|
	pthread_mutex_unlock(&lock->mutex);
 | 
						|
	return FALSE;
 | 
						|
      }
 | 
						|
      continue;
 | 
						|
    } else if ( rc == 0 )
 | 
						|
    { if ( lock->readers == 0 )
 | 
						|
      { lock->waiting_upgrade--;
 | 
						|
	goto ok;
 | 
						|
      }
 | 
						|
    } else
 | 
						|
    { assert(0);			/* TBD: OS errors */
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void
 | 
						|
reallow_readers(rwlock *lock)
 | 
						|
{ pthread_mutex_lock(&lock->mutex);
 | 
						|
  lock->allow_readers = TRUE;
 | 
						|
  pthread_mutex_unlock(&lock->mutex);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
unlock(rwlock *lock, int rd)		/* TRUE: read lock */
 | 
						|
{ int self = PL_thread_self();
 | 
						|
  int signal;
 | 
						|
 | 
						|
  if ( lock->writer == self && lock->lock_level > 1 )
 | 
						|
  { lock->lock_level--;
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  pthread_mutex_lock(&lock->mutex);
 | 
						|
  if ( rd )				/* read lock */
 | 
						|
  { lock->readers--;
 | 
						|
    lock->read_by_thread[self]--;
 | 
						|
    signal = (lock->readers == 0);
 | 
						|
  } else
 | 
						|
  { lock->writer = -1;
 | 
						|
    lock->allow_readers = TRUE;
 | 
						|
    signal = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  if ( signal )
 | 
						|
  { enum { NONE, READ, WRITE, UPGRADE } waiting;
 | 
						|
 | 
						|
    waiting = (lock->waiting_upgrade ? UPGRADE :
 | 
						|
	       lock->waiting_writers ? WRITE :
 | 
						|
	       lock->waiting_readers ? READ : NONE);
 | 
						|
    pthread_mutex_unlock(&lock->mutex);
 | 
						|
 | 
						|
    switch(waiting)
 | 
						|
    { case UPGRADE:
 | 
						|
	pthread_cond_signal(&lock->upcondvar);
 | 
						|
	break;
 | 
						|
      case WRITE:
 | 
						|
	pthread_cond_signal(&lock->wrcondvar);
 | 
						|
	break;
 | 
						|
      case READ:
 | 
						|
	pthread_cond_signal(&lock->rdcondvar);
 | 
						|
	break;
 | 
						|
      default:
 | 
						|
	;
 | 
						|
    }
 | 
						|
  } else
 | 
						|
  { pthread_mutex_unlock(&lock->mutex);
 | 
						|
  }
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
lock_misc(rwlock *lock)
 | 
						|
{ return pthread_mutex_lock(&lock->misc_mutex) == 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
unlock_misc(rwlock *lock)
 | 
						|
{ return pthread_mutex_unlock(&lock->misc_mutex) == 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
init_lock(rwlock *lock)
 | 
						|
{ if ( !pthread_mutex_init(&lock->mutex, NULL) == 0 ||
 | 
						|
       !pthread_mutex_init(&lock->misc_mutex, NULL) == 0 ||
 | 
						|
       !pthread_cond_init(&lock->wrcondvar, NULL) == 0 ||
 | 
						|
       !pthread_cond_init(&lock->rdcondvar, NULL) == 0 ||
 | 
						|
       !pthread_cond_init(&lock->upcondvar, NULL) == 0 )
 | 
						|
  {					/* TBD: System error */
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  lock->writer          = -1;
 | 
						|
  lock->readers	        = 0;
 | 
						|
  lock->allow_readers   = TRUE;
 | 
						|
  lock->waiting_readers = 0;
 | 
						|
  lock->waiting_writers = 0;
 | 
						|
  lock->waiting_upgrade = 0;
 | 
						|
  lock->lock_level      = 0;
 | 
						|
 | 
						|
  lock->thread_max = 4;
 | 
						|
  if ( !(lock->read_by_thread = malloc(lock->thread_max*sizeof(int))) )
 | 
						|
    return FALSE;
 | 
						|
  memset(lock->read_by_thread, 0, lock->thread_max*sizeof(int));
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
destroy_lock(rwlock *lock)
 | 
						|
{ if ( !pthread_mutex_destroy(&lock->mutex) ||
 | 
						|
       !pthread_mutex_destroy(&lock->misc_mutex) ||
 | 
						|
       !pthread_cond_destroy(&lock->wrcondvar) ||
 | 
						|
       !pthread_cond_destroy(&lock->rdcondvar) ||
 | 
						|
       !pthread_cond_destroy(&lock->upcondvar) )
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
  free(lock->read_by_thread);
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
#endif /*__WINDOWS__*/
 | 
						|
 | 
						|
 | 
						|
#else /*_REENTRANT*/
 | 
						|
 | 
						|
int
 | 
						|
rdlock(rwlock *lock)
 | 
						|
{ lock->readers++;
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
wrlock(rwlock *lock, int allow_readers)
 | 
						|
{ if ( lock->readers )
 | 
						|
    return permission_error("write", "rdf_db", "default",
 | 
						|
			    "Operation would deadlock");
 | 
						|
 | 
						|
  lock->writer = 0;
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
unlock(rwlock *lock, int rd)
 | 
						|
{ if ( rd )
 | 
						|
  { lock->readers--;
 | 
						|
  } else
 | 
						|
  { lock->writer = -1;
 | 
						|
  }
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
lock_misc(rwlock *lock)
 | 
						|
{ return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
unlock_misc(rwlock *lock)
 | 
						|
{ return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
init_lock(rwlock *lock)
 | 
						|
{ lock->writer = -1;
 | 
						|
  lock->readers = 0;
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
lockout_readers(rwlock *lock)
 | 
						|
{ return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void
 | 
						|
reallow_readers(rwlock *lock)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
destroy_lock(rwlock *lock)
 | 
						|
{ return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
#endif /*_REENTRANT*/
 | 
						|
 |