aboutsummaryrefslogtreecommitdiff
path: root/src/mutex.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mutex.c')
-rw-r--r--src/mutex.c238
1 files changed, 238 insertions, 0 deletions
diff --git a/src/mutex.c b/src/mutex.c
new file mode 100644
index 000000000..5c9e15120
--- /dev/null
+++ b/src/mutex.c
@@ -0,0 +1,238 @@
+/*
+** 2007 August 14
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file contains the C functions that implement mutexes for
+** use by the SQLite core.
+**
+** $Id: mutex.c,v 1.1 2007/08/15 13:04:54 drh Exp $
+*/
+
+/*
+** If SQLITE_MUTEX_APPDEF is defined, then this whole module is
+** omitted and equivalent functionality just be provided by the
+** application that links against the SQLite library.
+*/
+#ifndef SQLITE_MUTEX_APPDEF
+
+/*
+** The start of real code
+*/
+#include "sqliteInt.h"
+
+/************************ No-op Mutex Implementation **********************
+**
+** This first implementation of mutexes is really a no-op. In other words,
+** no real locking occurs. This implementation is appropriate for use
+** in single threaded applications which do not want the extra overhead
+** of thread locking primitives.
+*/
+
+/*
+** The sqlite3_mutex_alloc() routine allocates a new
+** mutex and returns a pointer to it. If it returns NULL
+** that means that a mutex could not be allocated. SQLite
+** will unwind its stack and return an error. The argument
+** to sqlite3_mutex_alloc() is usually zero, which causes
+** any space required for the mutex to be obtained from
+** sqlite3_malloc(). However if the argument is a positive
+** integer less than SQLITE_NUM_STATIC_MUTEX, then a pointer
+** to a static mutex is returned. There are a finite number
+** of static mutexes. Static mutexes should not be passed
+** to sqlite3_mutex_free(). The allocation of a static
+** mutex cannot fail.
+*/
+sqlite3_mutex *sqlite3_mutex_alloc(int idNotUsed){
+ return (sqlite3_mutex*)sqlite3_mutex_alloc;
+}
+
+/*
+** This routine deallocates a previously
+** allocated mutex. SQLite is careful to deallocate every
+** mutex that it allocates.
+*/
+void sqlite3_mutex_free(sqlite3_mutex *pNotUsed){}
+
+/*
+** The sqlite3_mutex_enter() routine attempts to enter a
+** mutex. If another thread is already within the mutex,
+** sqlite3_mutex_enter() will return SQLITE_BUSY if blockFlag
+** is zero, or it will block and wait for the other thread to
+** exit if blockFlag is non-zero. Mutexes are recursive. The
+** same thread can enter a single mutex multiple times. Each
+** entrance must be matched with a corresponding exit before
+** another thread is able to enter the mutex.
+*/
+int sqlite3_mutex_enter(sqlite3_mutex *pNotUsed, int blockFlag){
+ return SQLITE_OK;
+}
+
+/*
+** The sqlite3_mutex_exit() routine exits a mutex that was
+** previously entered by the same thread. The behavior
+** is undefined if the mutex is not currently entered or
+** is not currently allocated. SQLite will never do either.
+*/
+void sqlite3_mutex_leave(sqlite3_mutex *pNotUsed){
+ return;
+}
+
+/*
+** The sqlite3_mutex_serialize() routine is used to serialize
+** execution of a subroutine. The subroutine given in the argument
+** is invoked. But only one thread at a time is allowed to be
+** running a subroutine using sqlite3_mutex_serialize().
+*/
+int sqlite3_mutex_serialize(void (*xCallback)(void*), void *pArg){
+ xCallback(pArg);
+}
+
+#if 0
+/**************** Non-recursive Pthread Mutex Implementation *****************
+**
+** This implementation of mutexes is built using a version of pthreads that
+** does not have native support for recursive mutexes.
+*/
+
+/*
+** Each recursive mutex is an instance of the following structure.
+*/
+struct RMutex {
+ int nRef; /* Number of entrances */
+ pthread_mutex_t auxMutex; /* Mutex controlling access to nRef and owner */
+ pthread_mutex_t mainMutex; /* Mutex controlling the lock */
+ pthread_t owner; /* Thread that is within this mutex */
+};
+
+/*
+** Static mutexes
+*/
+static struct RMutex rmutexes[] = {
+ { 0, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, },
+ { 0, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, },
+ { 0, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, },
+};
+
+/*
+** A mutex used for serialization.
+*/
+static RMutex serialMutex =
+ {0, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, };
+
+/*
+** The sqlite3_mutex_alloc() routine allocates a new
+** mutex and returns a pointer to it. If it returns NULL
+** that means that a mutex could not be allocated. SQLite
+** will unwind its stack and return an error. The argument
+** to sqlite3_mutex_alloc() is usually zero, which causes
+** any space required for the mutex to be obtained from
+** sqlite3_malloc(). However if the argument is a positive
+** integer less than SQLITE_NUM_STATIC_MUTEX, then a pointer
+** to a static mutex is returned. There are a finite number
+** of static mutexes. Static mutexes should not be passed
+** to sqlite3_mutex_free(). The allocation of a static
+** mutex cannot fail.
+*/
+sqlite3_mutex *sqlite3_mutex_alloc(int id){
+ struct RMutex *p;
+ if( id>0 ){
+ if( id>sizeof(rmutexes)/sizeof(rmutexes[0]) ){
+ p = 0;
+ }else{
+ p = &rmutexes[id-1];
+ }
+ }else{
+ p = sqlite3_malloc( sizeof(*p) );
+ if( p ){
+ p->nRef = 0;
+ pthread_mutex_init(&p->mutex, 0);
+ }
+ }
+ return (sqlite3_mutex*)p;
+}
+
+/*
+** This routine deallocates a previously
+** allocated mutex. SQLite is careful to deallocate every
+** mutex that it allocates.
+*/
+void sqlite3_mutex_free(sqlite3_mutex *pMutex){
+ struct RMutex *p = (struct RMutex*)pMutex;
+ assert( p->nRef==0 );
+ pthread_mutex_destroy(&p->mutex);
+ sqlite3_free(p);
+}
+
+/*
+** The sqlite3_mutex_enter() routine attempts to enter a
+** mutex. If another thread is already within the mutex,
+** sqlite3_mutex_enter() will return SQLITE_BUSY if blockFlag
+** is zero, or it will block and wait for the other thread to
+** exit if blockFlag is non-zero. Mutexes are recursive. The
+** same thread can enter a single mutex multiple times. Each
+** entrance must be matched with a corresponding exit before
+** another thread is able to enter the mutex.
+*/
+int sqlite3_mutex_enter(sqlite3_mutex *pMutex, int blockFlag){
+ struct RMutex *p = (struct RMutex*)pMutex;
+ while(1){
+ pthread_mutex_lock(&p->auxMutex);
+ if( p->nRef==0 ){
+ p->nRef++;
+ p->owner = pthread_self();
+ pthread_mutex_lock(&p->mainMutex);
+ pthread_mutex_unlock(&p->auxMutex);
+ return SQLITE_OK;
+ }else if( pthread_equal(p->owner, pthread_self()) ){
+ p->nRef++;
+ pthread_mutex_unlock(&p->auxMutex);
+ return SQLITE_OK;
+ }else if( !blockFlag ){
+ pthread_mutex_unlock(&p->auxMutex);
+ return SQLITE_BUSY;
+ }else{
+ pthread_mutex_unlock(&p->auxMutex);
+ pthread_mutex_lock(&p->mainMutex);
+ pthread_mutex_unlock(&p->mainMutex);
+ }
+ }
+ /* NOTREACHED */
+}
+
+/*
+** The sqlite3_mutex_exit() routine exits a mutex that was
+** previously entered by the same thread. The behavior
+** is undefined if the mutex is not currently entered or
+** is not currently allocated. SQLite will never do either.
+*/
+void sqlite3_mutex_leave(sqlite3_mutex *pMutex){
+ struct RMutex *p = (struct RMutex*)pMutex;
+ pthread_mutex_lock(&p->auxMutex);
+ p->nRef--;
+ if( p->nRef<=0 ){
+ pthread_mutex_unlock(&p->mainMutex);
+ }
+ pthread_mutex_unlock(&p->auxMutex);
+}
+
+/*
+** The sqlite3_mutex_serialize() routine is used to serialize
+** execution of a subroutine. The subroutine given in the argument
+** is invoked. But only one thread at a time is allowed to be
+** running a subroutine using sqlite3_mutex_serialize().
+*/
+int sqlite3_mutex_serialize(void (*xCallback)(void*), void *pArg){
+ sqlite3_mutex_enter(&serialMutex, 1);
+ xCallback(pArg);
+ sqlite3_mutex_leave(&serialMutex);
+}
+#endif /* non-recursive pthreads */
+
+#endif /* !defined(SQLITE_MUTEX_APPDEF) */