1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-11 01:42:22 +03:00

Change the design of the mutex interface to allow for

both "fast" and "recursive" mutexes. (CVS 4238)

FossilOrigin-Name: 160593dcc5690af715b775c81137c6e09cca6454
This commit is contained in:
drh
2007-08-16 19:40:16 +00:00
parent dce8bdb8c0
commit 6bdec4afb4
6 changed files with 282 additions and 173 deletions

View File

@@ -1,5 +1,5 @@
C Remove\sthe\sthread\sspecific\sdata\ssubsystem\sfrom\sthe\sunix\sbuild.\s\sRemove\nlegacy\scruft\sfrom\ssqliteInt.h.\s\sUse\sthe\snew\smutex\ssubsystem\sin\sthe\sPRNG.\s(CVS\s4237) C Change\sthe\sdesign\sof\sthe\s\smutex\sinterface\sto\sallow\sfor\nboth\s"fast"\sand\s"recursive"\smutexes.\s(CVS\s4238)
D 2007-08-16T13:01:45 D 2007-08-16T19:40:17
F Makefile.in 0c0e53720f658c7a551046442dd7afba0b72bfbe F Makefile.in 0c0e53720f658c7a551046442dd7afba0b72bfbe
F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499 F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -88,9 +88,9 @@ F src/loadext.c aa1c6e584d39cc241226ec9390387bc2d4a23e8f
F src/main.c 996df547489d4826f70629b16623d7408f55ecd7 F src/main.c 996df547489d4826f70629b16623d7408f55ecd7
F src/malloc.c 613c65f12ff0ee4edd017aa458209ab7a23cd7b1 F src/malloc.c 613c65f12ff0ee4edd017aa458209ab7a23cd7b1
F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217 F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217
F src/mem1.c 08c4ee16393835b2d24ad39ce7b64c0f8c5b1df7 F src/mem1.c 2c6a6e3b2c9c7cb8d398a8468095032407c3e0b7
F src/mem2.c d0ba3b23da2e95bced1818ade8a8a2dc9526111c F src/mem2.c 661ca7ebf6e4b964fecc95d24e8c89dbcfc9dfea
F src/mutex.c b4f963ebdcb0622b3026937826afefd8a05884e1 F src/mutex.c 679d5d9c99bd302c0c43ee3eba61348c44aea366
F src/os.c e2faefbe0f5a8ca5e3b1c49ee1b5c6cfa0f0e279 F src/os.c e2faefbe0f5a8ca5e3b1c49ee1b5c6cfa0f0e279
F src/os.h 8eff07babf74e5bc3f895f8a6c7c294dad5ff997 F src/os.h 8eff07babf74e5bc3f895f8a6c7c294dad5ff997
F src/os_common.h a5c446d3b93f09f369d13bf217de4bed3437dd1c F src/os_common.h a5c446d3b93f09f369d13bf217de4bed3437dd1c
@@ -112,7 +112,7 @@ F src/random.c 6119474a6f6917f708c1dee25b9a8e519a620e88
F src/select.c 98c367bce3f38c5adfcc97de9ab5c79b0e5dc2b2 F src/select.c 98c367bce3f38c5adfcc97de9ab5c79b0e5dc2b2
F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
F src/shell.c ac29402b538515fa4697282387be9c1205e6e9eb F src/shell.c ac29402b538515fa4697282387be9c1205e6e9eb
F src/sqlite.h.in 1fb6748ebd4c36b8476c03791009585fd5cfcf3b F src/sqlite.h.in 8efd7d5aca057a793d221973da1f22a22e69f4db
F src/sqlite3ext.h 647a6b8a8f76ff6c9611e4a071531d8e63ff2d6b F src/sqlite3ext.h 647a6b8a8f76ff6c9611e4a071531d8e63ff2d6b
F src/sqliteInt.h fa9baff32aef7ca1ecebcd014b3bd75c981829d0 F src/sqliteInt.h fa9baff32aef7ca1ecebcd014b3bd75c981829d0
F src/sqliteLimit.h f14609c27636ebc217c9603ade26dbdd7d0f6afa F src/sqliteLimit.h f14609c27636ebc217c9603ade26dbdd7d0f6afa
@@ -529,7 +529,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
P ba80ee59a72afe36817997de705ef81d876b6f35 P 3d60c14a32955b69e714a73372924d421899f83b
R 4dbfd96f907def879d1b3bfd1f2c5bd5 R 79bf1accc56116075f09cd253592694c
U drh U drh
Z 6248f8cb69e3663b94e130d7ac9b903a Z e40cc1b0395242393945aa35a1600f4d

View File

@@ -1 +1 @@
3d60c14a32955b69e714a73372924d421899f83b 160593dcc5690af715b775c81137c6e09cca6454

View File

@@ -12,7 +12,7 @@
** This file contains the C functions that implement a memory ** This file contains the C functions that implement a memory
** allocation subsystem for use by SQLite. ** allocation subsystem for use by SQLite.
** **
** $Id: mem1.c,v 1.4 2007/08/16 13:01:45 drh Exp $ ** $Id: mem1.c,v 1.5 2007/08/16 19:40:17 drh Exp $
*/ */
/* /*
@@ -81,9 +81,9 @@ static struct {
sqlite3_uint64 sqlite3_memory_used(void){ sqlite3_uint64 sqlite3_memory_used(void){
sqlite3_uint64 n; sqlite3_uint64 n;
if( mem.mutex==0 ){ if( mem.mutex==0 ){
mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_MEM); mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM);
} }
sqlite3_mutex_enter(mem.mutex, 1); sqlite3_mutex_enter(mem.mutex);
n = mem.nowUsed; n = mem.nowUsed;
sqlite3_mutex_leave(mem.mutex); sqlite3_mutex_leave(mem.mutex);
return n; return n;
@@ -97,9 +97,9 @@ sqlite3_uint64 sqlite3_memory_used(void){
sqlite3_uint64 sqlite3_memory_highwater(int resetFlag){ sqlite3_uint64 sqlite3_memory_highwater(int resetFlag){
sqlite3_uint64 n; sqlite3_uint64 n;
if( mem.mutex==0 ){ if( mem.mutex==0 ){
mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_MEM); mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM);
} }
sqlite3_mutex_enter(mem.mutex, 1); sqlite3_mutex_enter(mem.mutex);
n = mem.mxUsed; n = mem.mxUsed;
if( resetFlag ){ if( resetFlag ){
mem.mxUsed = mem.nowUsed; mem.mxUsed = mem.nowUsed;
@@ -117,9 +117,9 @@ int sqlite3_memory_alarm(
sqlite3_uint64 iThreshold sqlite3_uint64 iThreshold
){ ){
if( mem.mutex==0 ){ if( mem.mutex==0 ){
mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_MEM); mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM);
} }
sqlite3_mutex_enter(mem.mutex, 1); sqlite3_mutex_enter(mem.mutex);
mem.alarmCallback = xCallback; mem.alarmCallback = xCallback;
mem.alarmArg = pArg; mem.alarmArg = pArg;
mem.alarmThreshold = iThreshold; mem.alarmThreshold = iThreshold;
@@ -131,9 +131,17 @@ int sqlite3_memory_alarm(
** Trigger the alarm ** Trigger the alarm
*/ */
static void sqlite3MemsysAlarm(unsigned nByte){ static void sqlite3MemsysAlarm(unsigned nByte){
void (*xCallback)(void*,sqlite3_uint64,unsigned);
sqlite3_uint64 nowUsed;
void *pArg;
if( mem.alarmCallback==0 || mem.alarmBusy ) return; if( mem.alarmCallback==0 || mem.alarmBusy ) return;
mem.alarmBusy = 1; mem.alarmBusy = 1;
mem.alarmCallback(mem.alarmArg, mem.nowUsed, nByte); xCallback = mem.alarmCallback;
nowUsed = mem.nowUsed;
pArg = mem.alarmArg;
sqlite3_mutex_leave(mem.mutex);
xCallback(pArg, nowUsed, nByte);
sqlite3_mutex_enter(mem.mutex);
mem.alarmBusy = 0; mem.alarmBusy = 0;
} }
@@ -143,9 +151,9 @@ static void sqlite3MemsysAlarm(unsigned nByte){
void *sqlite3_malloc(unsigned int nBytes){ void *sqlite3_malloc(unsigned int nBytes){
sqlite3_uint64 *p; sqlite3_uint64 *p;
if( mem.mutex==0 ){ if( mem.mutex==0 ){
mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_MEM); mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM);
} }
sqlite3_mutex_enter(mem.mutex, 1); sqlite3_mutex_enter(mem.mutex);
if( mem.nowUsed+nBytes>=mem.alarmThreshold ){ if( mem.nowUsed+nBytes>=mem.alarmThreshold ){
sqlite3MemsysAlarm(nBytes); sqlite3MemsysAlarm(nBytes);
} }
@@ -179,7 +187,7 @@ void sqlite3_free(void *pPrior){
p = pPrior; p = pPrior;
p--; p--;
nByte = (unsigned int)*p; nByte = (unsigned int)*p;
sqlite3_mutex_enter(mem.mutex, 1); sqlite3_mutex_enter(mem.mutex);
mem.nowUsed -= nByte; mem.nowUsed -= nByte;
free(p); free(p);
sqlite3_mutex_leave(mem.mutex); sqlite3_mutex_leave(mem.mutex);
@@ -202,7 +210,7 @@ void *sqlite3_realloc(void *pPrior, unsigned int nBytes){
p--; p--;
nOld = (unsigned int)p[0]; nOld = (unsigned int)p[0];
assert( mem.mutex!=0 ); assert( mem.mutex!=0 );
sqlite3_mutex_enter(mem.mutex, 1); sqlite3_mutex_enter(mem.mutex);
if( mem.nowUsed+nBytes-nOld>=mem.alarmThreshold ){ if( mem.nowUsed+nBytes-nOld>=mem.alarmThreshold ){
sqlite3MemsysAlarm(nBytes-nOld); sqlite3MemsysAlarm(nBytes-nOld);
} }

View File

@@ -12,7 +12,7 @@
** This file contains the C functions that implement a memory ** This file contains the C functions that implement a memory
** allocation subsystem for use by SQLite. ** allocation subsystem for use by SQLite.
** **
** $Id: mem2.c,v 1.3 2007/08/15 20:41:29 drh Exp $ ** $Id: mem2.c,v 1.4 2007/08/16 19:40:17 drh Exp $
*/ */
/* /*
@@ -147,9 +147,9 @@ static struct {
sqlite3_uint64 sqlite3_memory_used(void){ sqlite3_uint64 sqlite3_memory_used(void){
sqlite3_uint64 n; sqlite3_uint64 n;
if( mem.mutex==0 ){ if( mem.mutex==0 ){
mem.mutex = sqlite3_mutex_alloc(1); mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM);
} }
sqlite3_mutex_enter(mem.mutex, 1); sqlite3_mutex_enter(mem.mutex);
n = mem.nowUsed; n = mem.nowUsed;
sqlite3_mutex_leave(mem.mutex); sqlite3_mutex_leave(mem.mutex);
return n; return n;
@@ -163,9 +163,9 @@ sqlite3_uint64 sqlite3_memory_used(void){
sqlite3_uint64 sqlite3_memory_highwater(int resetFlag){ sqlite3_uint64 sqlite3_memory_highwater(int resetFlag){
sqlite3_uint64 n; sqlite3_uint64 n;
if( mem.mutex==0 ){ if( mem.mutex==0 ){
mem.mutex = sqlite3_mutex_alloc(1); mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM);
} }
sqlite3_mutex_enter(mem.mutex, 1); sqlite3_mutex_enter(mem.mutex);
n = mem.mxUsed; n = mem.mxUsed;
if( resetFlag ){ if( resetFlag ){
mem.mxUsed = mem.nowUsed; mem.mxUsed = mem.nowUsed;
@@ -183,9 +183,9 @@ int sqlite3_memory_alarm(
sqlite3_uint64 iThreshold sqlite3_uint64 iThreshold
){ ){
if( mem.mutex==0 ){ if( mem.mutex==0 ){
mem.mutex = sqlite3_mutex_alloc(1); mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM);
} }
sqlite3_mutex_enter(mem.mutex, 1); sqlite3_mutex_enter(mem.mutex);
mem.alarmCallback = xCallback; mem.alarmCallback = xCallback;
mem.alarmArg = pArg; mem.alarmArg = pArg;
mem.alarmThreshold = iThreshold; mem.alarmThreshold = iThreshold;
@@ -197,9 +197,17 @@ int sqlite3_memory_alarm(
** Trigger the alarm ** Trigger the alarm
*/ */
static void sqlite3MemsysAlarm(unsigned nByte){ static void sqlite3MemsysAlarm(unsigned nByte){
void (*xCallback)(void*,sqlite3_uint64,unsigned);
sqlite3_uint64 nowUsed;
void *pArg;
if( mem.alarmCallback==0 || mem.alarmBusy ) return; if( mem.alarmCallback==0 || mem.alarmBusy ) return;
mem.alarmBusy = 1; mem.alarmBusy = 1;
mem.alarmCallback(mem.alarmArg, mem.nowUsed, nByte); xCallback = mem.alarmCallback;
nowUsed = mem.nowUsed;
pArg = mem.alarmArg;
sqlite3_mutex_leave(mem.mutex);
xCallback(pArg, nowUsed, nByte);
sqlite3_mutex_enter(mem.mutex);
mem.alarmBusy = 0; mem.alarmBusy = 0;
} }
@@ -243,9 +251,9 @@ void *sqlite3_malloc(unsigned int nByte){
unsigned int totalSize; unsigned int totalSize;
if( mem.mutex==0 ){ if( mem.mutex==0 ){
mem.mutex = sqlite3_mutex_alloc(1); mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM);
} }
sqlite3_mutex_enter(mem.mutex, 1); sqlite3_mutex_enter(mem.mutex);
if( mem.nowUsed+nByte>=mem.alarmThreshold ){ if( mem.nowUsed+nByte>=mem.alarmThreshold ){
sqlite3MemsysAlarm(nByte); sqlite3MemsysAlarm(nByte);
} }
@@ -318,7 +326,7 @@ void sqlite3_free(void *pPrior){
pHdr = sqlite3MemsysGetHeader(pPrior); pHdr = sqlite3MemsysGetHeader(pPrior);
pBt = (void**)pHdr; pBt = (void**)pHdr;
pBt -= pHdr->nBacktraceSlots; pBt -= pHdr->nBacktraceSlots;
sqlite3_mutex_enter(mem.mutex, 1); sqlite3_mutex_enter(mem.mutex);
mem.nowUsed -= pHdr->iSize; mem.nowUsed -= pHdr->iSize;
if( pHdr->pPrev ){ if( pHdr->pPrev ){
assert( pHdr->pPrev->pNext==pHdr ); assert( pHdr->pPrev->pNext==pHdr );

View File

@@ -12,7 +12,7 @@
** This file contains the C functions that implement mutexes for ** This file contains the C functions that implement mutexes for
** use by the SQLite core. ** use by the SQLite core.
** **
** $Id: mutex.c,v 1.2 2007/08/16 10:09:03 danielk1977 Exp $ ** $Id: mutex.c,v 1.3 2007/08/16 19:40:17 drh Exp $
*/ */
/* /*
@@ -38,41 +38,30 @@
/* /*
** The sqlite3_mutex_alloc() routine allocates a new ** The sqlite3_mutex_alloc() routine allocates a new
** mutex and returns a pointer to it. If it returns NULL ** mutex and returns a pointer to it. If it returns NULL
** that means that a mutex could not be allocated. SQLite ** that means that a mutex could not be allocated.
** 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){ sqlite3_mutex *sqlite3_mutex_alloc(int idNotUsed){
return (sqlite3_mutex*)sqlite3_mutex_alloc; return (sqlite3_mutex*)sqlite3_mutex_alloc;
} }
/* /*
** This routine deallocates a previously ** This routine deallocates a previously allocated mutex.
** allocated mutex. SQLite is careful to deallocate every
** mutex that it allocates.
*/ */
void sqlite3_mutex_free(sqlite3_mutex *pNotUsed){} void sqlite3_mutex_free(sqlite3_mutex *pNotUsed){}
/* /*
** The sqlite3_mutex_enter() routine attempts to enter a ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
** mutex. If another thread is already within the mutex, ** to enter a mutex. If another thread is already within the mutex,
** sqlite3_mutex_enter() will return SQLITE_BUSY if blockFlag ** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
** is zero, or it will block and wait for the other thread to ** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK
** exit if blockFlag is non-zero. Mutexes are recursive. The ** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can
** same thread can enter a single mutex multiple times. Each ** be entered multiple times by the same thread. In such cases the,
** entrance must be matched with a corresponding exit before ** mutex must be exited an equal number of times before another thread
** another thread is able to enter the mutex. ** can enter. If the same thread tries to enter any other kind of mutex
** more than once, the behavior is undefined.
*/ */
int sqlite3_mutex_enter(sqlite3_mutex *pNotUsed, int blockFlag){ void sqlite3_mutex_enter(sqlite3_mutex *pNotUsed){}
return SQLITE_OK; int sqlite3_mutex_try(sqlite3_mutex *pNotUsed){ return SQLITE_OK; }
}
/* /*
** The sqlite3_mutex_exit() routine exits a mutex that was ** The sqlite3_mutex_exit() routine exits a mutex that was
@@ -80,20 +69,7 @@ int sqlite3_mutex_enter(sqlite3_mutex *pNotUsed, int blockFlag){
** is undefined if the mutex is not currently entered or ** is undefined if the mutex is not currently entered or
** is not currently allocated. SQLite will never do either. ** is not currently allocated. SQLite will never do either.
*/ */
void sqlite3_mutex_leave(sqlite3_mutex *pNotUsed){ 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);
return SQLITE_OK;
}
#if 0 #if 0
/**************** Non-recursive Pthread Mutex Implementation ***************** /**************** Non-recursive Pthread Mutex Implementation *****************
@@ -106,6 +82,7 @@ int sqlite3_mutex_serialize(void (*xCallback)(void*), void *pArg){
** Each recursive mutex is an instance of the following structure. ** Each recursive mutex is an instance of the following structure.
*/ */
struct RMutex { struct RMutex {
int recursiveMagic; /* Magic number identifying this as recursive */
int nRef; /* Number of entrances */ int nRef; /* Number of entrances */
pthread_mutex_t auxMutex; /* Mutex controlling access to nRef and owner */ pthread_mutex_t auxMutex; /* Mutex controlling access to nRef and owner */
pthread_mutex_t mainMutex; /* Mutex controlling the lock */ pthread_mutex_t mainMutex; /* Mutex controlling the lock */
@@ -113,98 +90,185 @@ struct RMutex {
}; };
/* /*
** Static mutexes ** Each fast mutex is an instance of the following structure
*/ */
static struct RMutex rmutexes[] = { struct FMutex {
{ 0, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, }, int fastMagic; /* Identifies this as a fast mutex */
{ 0, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, }, pthread_mutex_t mutex; /* The actual underlying mutex */
{ 0, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, },
}; };
/* /*
** A mutex used for serialization. ** Either of the above
*/
union AnyMutex {
struct RMutex r;
struct FMutex f;
};
/*
** Magic numbers
*/
#define SQLITE_MTX_RECURSIVE 0x4ED886ED
#define SQLITE_MTX_STATIC 0x56FCE1B4
#define SQLITE_MTX_FAST 0x245BFD4F
/*
** Static mutexes
*/ */
static RMutex serialMutex =
{0, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, };
/* /*
** The sqlite3_mutex_alloc() routine allocates a new ** The sqlite3_mutex_alloc() routine allocates a new
** mutex and returns a pointer to it. If it returns NULL ** mutex and returns a pointer to it. If it returns NULL
** that means that a mutex could not be allocated. SQLite ** that means that a mutex could not be allocated. SQLite
** will unwind its stack and return an error. The argument ** will unwind its stack and return an error. The argument
** to sqlite3_mutex_alloc() is usually zero, which causes ** to sqlite3_mutex_alloc() is one of these integer constants:
** any space required for the mutex to be obtained from **
** sqlite3_malloc(). However if the argument is a positive ** <ul>
** integer less than SQLITE_NUM_STATIC_MUTEX, then a pointer ** <li> SQLITE_MUTEX_FAST 0
** to a static mutex is returned. There are a finite number ** <li> SQLITE_MUTEX_RECURSIVE 1
** of static mutexes. Static mutexes should not be passed ** <li> SQLITE_MUTEX_STATIC_MASTER 2
** to sqlite3_mutex_free(). The allocation of a static ** <li> SQLITE_MUTEX_STATIC_MEM 3
** mutex cannot fail. ** <li> SQLITE_MUTEX_STATIC_PRNG 4
** </ul>
**
** The first two constants cause sqlite3_mutex_alloc() to create
** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
** The mutex implementation does not need to make a distinction
** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does
** not want to. But SQLite will only request a recursive mutex in
** cases where it really needs one. If a faster non-recursive mutex
** implementation is available on the host platform, the mutex subsystem
** might return such a mutex in response to SQLITE_MUTEX_FAST.
**
** The other allowed parameters to sqlite3_mutex_alloc() each return
** a pointer to a static preexisting mutex. Three static mutexes are
** used by the current version of SQLite. Future versions of SQLite
** may add additional static mutexes. Static mutexes are for internal
** use by SQLite only. Applications that use SQLite mutexes should
** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
** SQLITE_MUTEX_RECURSIVE.
**
** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
** returns a different mutex on every call. But for the static
** mutex types, the same mutex is returned on every call that has
** the same type number.
*/ */
sqlite3_mutex *sqlite3_mutex_alloc(int id){ sqlite3_mutex *sqlite3_mutex_alloc(int iType){
struct RMutex *p; static struct FMutex staticMutexes[] = {
if( id>0 ){ { SQLITE_MTX_STATIC, PTHREAD_MUTEX_INITIALIZER },
if( id>sizeof(rmutexes)/sizeof(rmutexes[0]) ){ { SQLITE_MTX_STATIC, PTHREAD_MUTEX_INITIALIZER },
p = 0; { SQLITE_MTX_STATIC, PTHREAD_MUTEX_INITIALIZER },
}else{ };
p = &rmutexes[id-1]; sqlite3_mutex *p;
switch( iType ){
case SQLITE_MUTEX_FAST: {
struct FMutex *px = sqlite3_malloc( sizeof(*px) );
if( px ){
px->fastMagic = SQLITE_MTX_FAST;
pthread_mutex_init(&px->mutex, 0);
}
p = (sqlite3_mutex*)px;
break;
} }
}else{ case SQLITE_MUTEX_RECURSIVE: {
p = sqlite3_malloc( sizeof(*p) ); struct RMutex *px = sqlite3_malloc( sizeof(*px) );
if( p ){ if( px ){
p->nRef = 0; px->recursiveMagic = SQLITE_MTX_RECURSIVE;
pthread_mutex_init(&p->mutex, 0); pthread_mutex_init(&px->auxMutex, 0);
pthread_mutex_init(&px->mainMutex, 0);
px->nRef = 0;
}
p = (sqlite3_mutex*)px;
break;
}
default: {
p = &staticMutexes[iType-2];
break;
} }
} }
return (sqlite3_mutex*)p; return p;
} }
/* /*
** This routine deallocates a previously ** This routine deallocates a previously
** allocated mutex. SQLite is careful to deallocate every ** allocated mutex. SQLite is careful to deallocate every
** mutex that it allocates. ** mutex that it allocates.
*/ */
void sqlite3_mutex_free(sqlite3_mutex *pMutex){ void sqlite3_mutex_free(sqlite3_mutex *pMutex){
struct RMutex *p = (struct RMutex*)pMutex; int iType = *(int*)pMutex;
assert( p->nRef==0 ); if( iType==SQLITE_MTX_FAST ){
pthread_mutex_destroy(&p->mutex); struct FMutex *p = (struct FMutex*)pMutex;
sqlite3_free(p); pthread_mutex_destroy(&p->mutex);
sqlite3_free(p);
}else if( iType==SQLITE_MTX_RECURSIVE ){
struct RMutex *p = (struct RMutex*)pMutex;
pthread_mutex_destroy(&p->auxMutex);
pthread_mutex_destroy(&p->mainMutex);
sqlite3_free(p);
}
} }
/* /*
** The sqlite3_mutex_enter() routine attempts to enter a ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
** mutex. If another thread is already within the mutex, ** to enter a mutex. If another thread is already within the mutex,
** sqlite3_mutex_enter() will return SQLITE_BUSY if blockFlag ** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
** is zero, or it will block and wait for the other thread to ** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK
** exit if blockFlag is non-zero. Mutexes are recursive. The ** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can
** same thread can enter a single mutex multiple times. Each ** be entered multiple times by the same thread. In such cases the,
** entrance must be matched with a corresponding exit before ** mutex must be exited an equal number of times before another thread
** another thread is able to enter the mutex. ** can enter. If the same thread tries to enter any other kind of mutex
** more than once, the behavior is undefined.
*/ */
int sqlite3_mutex_enter(sqlite3_mutex *pMutex, int blockFlag){ void sqlite3_mutex_enter(sqlite3_mutex *pMutex){
struct RMutex *p = (struct RMutex*)pMutex; if( SQLITE_MTX_FAST == *(int*)pMutex ){
while(1){ struct FMutex *p = (struct FMutex*)pMutex;
pthread_mutex_lock(&p->mutex);
}else{
struct RMutex *p = (struct RMutex*)pMutex;
pthread_mutex_lock(&p->auxMutex); pthread_mutex_lock(&p->auxMutex);
if( p->nRef==0 ){ if( p->nRef==0 ){
p->nRef++; p->nRef++;
p->owner = pthread_self(); p->owner = pthread_self();
pthread_mutex_lock(&p->mainMutex); pthread_mutex_lock(&p->mainMutex);
pthread_mutex_unlock(&p->auxMutex); pthread_mutex_unlock(&p->auxMutex);
return SQLITE_OK;
}else if( pthread_equal(p->owner, pthread_self()) ){ }else if( pthread_equal(p->owner, pthread_self()) ){
p->nRef++; p->nRef++;
pthread_mutex_unlock(&p->auxMutex); pthread_mutex_unlock(&p->auxMutex);
return SQLITE_OK;
}else if( !blockFlag ){
pthread_mutex_unlock(&p->auxMutex);
return SQLITE_BUSY;
}else{ }else{
pthread_mutex_unlock(&p->auxMutex); while( p->nRef ){
pthread_mutex_lock(&p->mainMutex); pthread_mutex_unlock(&p->auxMutex);
pthread_mutex_unlock(&p->mainMutex); pthread_mutex_lock(&p->mainMutex);
pthread_mutex_unlock(&p->mainMutex);
}
} }
} }
/* NOTREACHED */ }
int sqlite3_mutex_try(sqlite3_mutex *pMutex){
if( SQLITE_MTX_FAST == *(int*)pMutex ){
struct FMutex *p = (struct FMutex*)pMutex;
if( pthread_mutex_trylock(&p->mutex) ){
return SQLITE_BUSY;
}
}else{
struct RMutex *p = (struct RMutex*)pMutex;
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);
}else if( pthread_equal(p->owner, pthread_self()) ){
p->nRef++;
pthread_mutex_unlock(&p->auxMutex);
}else{
pthread_mutex_unlock(&p->auxMutex);
return SQLITE_BUSY;
}
}
return SQLITE_OK;
} }
/* /*
@@ -214,25 +278,18 @@ int sqlite3_mutex_enter(sqlite3_mutex *pMutex, int blockFlag){
** is not currently allocated. SQLite will never do either. ** is not currently allocated. SQLite will never do either.
*/ */
void sqlite3_mutex_leave(sqlite3_mutex *pMutex){ void sqlite3_mutex_leave(sqlite3_mutex *pMutex){
struct RMutex *p = (struct RMutex*)pMutex; if( SQLITE_MTX_FAST == *(int*)pMutex ){
pthread_mutex_lock(&p->auxMutex); struct FMutex *p = (struct FMutex*)pMutex;
p->nRef--; pthread_mutex_unlock(&p->mutex);
if( p->nRef<=0 ){ }else{
pthread_mutex_unlock(&p->mainMutex); 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);
} }
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 /* non-recursive pthreads */

View File

@@ -30,7 +30,7 @@
** the version number) and changes its name to "sqlite3.h" as ** the version number) and changes its name to "sqlite3.h" as
** part of the build process. ** part of the build process.
** **
** @(#) $Id: sqlite.h.in,v 1.225 2007/08/16 13:01:45 drh Exp $ ** @(#) $Id: sqlite.h.in,v 1.226 2007/08/16 19:40:17 drh Exp $
*/ */
#ifndef _SQLITE3_H_ #ifndef _SQLITE3_H_
#define _SQLITE3_H_ #define _SQLITE3_H_
@@ -508,6 +508,8 @@ struct sqlite3_io_methods {
** abstract type for a mutex object. The SQLite core never looks ** abstract type for a mutex object. The SQLite core never looks
** at the internal representation of an [sqlite3_mutex]. It only ** at the internal representation of an [sqlite3_mutex]. It only
** deals with pointers to the [sqlite3_mutex] object. ** deals with pointers to the [sqlite3_mutex] object.
**
** Mutexes are created using [sqlite3_mutex_alloc()].
*/ */
typedef struct sqlite3_mutex sqlite3_mutex; typedef struct sqlite3_mutex sqlite3_mutex;
@@ -519,19 +521,24 @@ typedef struct sqlite3_mutex sqlite3_mutex;
** in the name of the object stands for "virtual file system". ** in the name of the object stands for "virtual file system".
** **
** The iVersion field is initially 1 but may be larger for future ** The iVersion field is initially 1 but may be larger for future
** versions. szOsFile is the size of the subclassed sqlite3_file ** versions of SQLite. Additional fields may be appended to this
** object when the iVersion value is increased.
**
** The szOsFile field is the size of the subclassed sqlite3_file
** structure used by this VFS. mxPathname is the maximum length of ** structure used by this VFS. mxPathname is the maximum length of
** a pathname in this VFS. ** a pathname in this VFS.
** **
** The nRef field is incremented and decremented by SQLite to keep ** The nRef field is incremented and decremented by SQLite to keep
** count of the number of users of the VFS. This field and ** count of the number of users of the VFS. This field and
** vfsMutex, pNext, and pPrev are the only fields in the sqlite3_vfs ** vfsMutex, pNext, and pPrev are the only fields in the sqlite3_vfs
** structure that SQLite will ever modify. These fields are modified ** structure that SQLite will ever modify. SQLite will only access
** within an sqlite3_mutex_serialize() call so that updates are threadsafe. ** or modify these fields while holding a particular static mutex.
** The application should never modify any fields of the sqlite3_vfs
** object once the object has been registered.
** **
** The sqlite3_vfs.vfsMutex is a mutex used by the OS interface. ** The sqlite3_vfs.vfsMutex is a mutex used by the OS interface.
** It should initially be NULL. SQLite will initialize this field ** It should initially be NULL. SQLite will initialize this field
** using sqlite3_mutex_allocate() upon first use of the adaptor ** using sqlite3_mutex_alloc() upon first use of the adaptor
** by sqlite3_open_v2() and will deallocate the mutex when the ** by sqlite3_open_v2() and will deallocate the mutex when the
** last user closes. In other words, vfsMutex will be allocated ** last user closes. In other words, vfsMutex will be allocated
** when nRef transitions from 0 to 1 and will be deallocated when ** when nRef transitions from 0 to 1 and will be deallocated when
@@ -3190,43 +3197,72 @@ int sqlite3_unregister_vfs(sqlite3_vfs*);
** mutex and returns a pointer to it. If it returns NULL ** mutex and returns a pointer to it. If it returns NULL
** that means that a mutex could not be allocated. SQLite ** that means that a mutex could not be allocated. SQLite
** will unwind its stack and return an error. The argument ** will unwind its stack and return an error. The argument
** to sqlite3_mutex_alloc() is usually zero, which causes ** to sqlite3_mutex_alloc() is one of these integer constants:
** any space required for the mutex to be obtained from **
** sqlite3_malloc(). However if the argument is a positive ** <ul>
** integer less than or equal to SQLITE_MUTEX_STATIC_MAX, then a pointer ** <li> SQLITE_MUTEX_FAST
** to a static mutex is returned. There are a finite number ** <li> SQLITE_MUTEX_RECURSIVE
** of static mutexes. Static mutexes should not be passed ** <li> SQLITE_MUTEX_STATIC_MASTER
** to sqlite3_mutex_free(). Static mutexes are used internally ** <li> SQLITE_MUTEX_STATIC_MEM
** by the SQLite core and should not be used by the application. ** <li> SQLITE_MUTEX_STATIC_PRNG
** </ul>
**
** The first two constants cause sqlite3_mutex_alloc() to create
** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
** The mutex implementation does not need to make a distinction
** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does
** not want to. But SQLite will only request a recursive mutex in
** cases where it really needs one. If a faster non-recursive mutex
** implementation is available on the host platform, the mutex subsystem
** might return such a mutex in response to SQLITE_MUTEX_FAST.
**
** The other allowed parameters to sqlite3_mutex_alloc() each return
** a pointer to a static preexisting mutex. Three static mutexes are
** used by the current version of SQLite. Future versions of SQLite
** may add additional static mutexes. Static mutexes are for internal
** use by SQLite only. Applications that use SQLite mutexes should
** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
** SQLITE_MUTEX_RECURSIVE.
**
** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
** returns a different mutex on every call. But for the static
** mutex types, the same mutex is returned on every call that has
** the same type number.
** **
** The sqlite3_mutex_free() routine deallocates a previously ** The sqlite3_mutex_free() routine deallocates a previously
** allocated mutex. SQLite is careful to deallocate every ** allocated dynamic mutex. SQLite is careful to deallocate every
** mutex that it allocates. ** dynamic mutex that it allocates. The dynamic mutexes must not be in
** use when they are deallocated. Static mutexes do not need to be
** deallocated and SQLite never bothers to do so.
** **
** The sqlite3_mutex_enter() routine attempts to enter a ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
** mutex. If another thread is already within the mutex, ** to enter a mutex. If another thread is already within the mutex,
** sqlite3_mutex_enter() will return SQLITE_BUSY if blockFlag ** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
** is zero, or it will block and wait for the other thread to ** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK
** exit if blockFlag is non-zero. Mutexes are recursive. The ** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can
** same thread can enter a single mutex multiple times. Each ** be entered multiple times by the same thread. In such cases the,
** entrance must be matched with a corresponding exit before ** mutex must be exited an equal number of times before another thread
** another thread is able to enter the mutex. ** can enter. If the same thread tries to enter any other kind of mutex
** more than once, the behavior is undefined. SQLite will never exhibit
** such behavior in its own use of mutexes.
** **
** The sqlite3_mutex_exit() routine exits a mutex that was ** The sqlite3_mutex_exit() routine exits a mutex that was
** previously entered by the same thread. The behavior ** previously entered by the same thread. The behavior
** is undefined if the mutex is not currently entered or ** is undefined if the mutex is not currently entered or
** is not currently allocated. SQLite will never do either. ** is not currently allocated. SQLite will never do either.
**
** The sqlite3_mutex_serialize() routine is used to serialize
** a subroutine. The subroutine given in the argument is invoked
** while holding a static mutex. This ensures that no other
** thread is running this same subroutine at the same time.
*/ */
sqlite3_mutex *sqlite3_mutex_alloc(int); sqlite3_mutex *sqlite3_mutex_alloc(int);
void sqlite3_mutex_free(sqlite3_mutex*); void sqlite3_mutex_free(sqlite3_mutex*);
int sqlite3_mutex_enter(sqlite3_mutex*, int blockFlag); void sqlite3_mutex_enter(sqlite3_mutex*);
int sqlite3_mutex_try(sqlite3_mutex*);
void sqlite3_mutex_leave(sqlite3_mutex*); void sqlite3_mutex_leave(sqlite3_mutex*);
int sqlite3_mutex_serialize(void(*)(void*), void*); #define SQLITE_MUTEX_FAST 0
#define SQLITE_MUTEX_RECURSIVE 1
#define SQLITE_MUTEX_STATIC_MASTER 2
#define SQLITE_MUTEX_STATIC_MEM 3
#define SQLITE_MUTEX_STATIC_PRNG 4
/* /*