diff options
author | drh <drh@noemail.net> | 2007-08-15 13:04:54 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2007-08-15 13:04:54 +0000 |
commit | 90f6a5beff55f81faa7135189c65cbd8a569e63c (patch) | |
tree | 900595d8e00a7a44978f9686322a3ed50a73dcbc /src | |
parent | d84f946be8340e2c9c7d86475665ae1610608e0e (diff) | |
download | sqlite-90f6a5beff55f81faa7135189c65cbd8a569e63c.tar.gz sqlite-90f6a5beff55f81faa7135189c65cbd8a569e63c.zip |
Add initial implementations of mutex and memory subsystem modules. (CVS 4226)
FossilOrigin-Name: c0fa3769790af199a4c8715c80bb8ff900730520
Diffstat (limited to 'src')
-rw-r--r-- | src/main.c | 26 | ||||
-rw-r--r-- | src/mem1.c | 204 | ||||
-rw-r--r-- | src/mutex.c | 238 | ||||
-rw-r--r-- | src/sqlite.h.in | 13 | ||||
-rw-r--r-- | src/sqliteInt.h | 3 |
5 files changed, 450 insertions, 34 deletions
diff --git a/src/main.c b/src/main.c index a8c69cbe1..b797f774f 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.378 2007/08/13 15:28:34 danielk1977 Exp $ +** $Id: main.c,v 1.379 2007/08/15 13:04:54 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -421,30 +421,6 @@ void sqlite3_interrupt(sqlite3 *db){ } } -/* -** Memory allocation routines that use SQLites internal memory -** memory allocator. Depending on how SQLite is compiled, the -** internal memory allocator might be just an alias for the -** system default malloc/realloc/free. Or the built-in allocator -** might do extra stuff like put sentinals around buffers to -** check for overruns or look for memory leaks. -** -** Use sqlite3_free() to free memory returned by sqlite3_mprintf(). -*/ -void sqlite3_free(void *p){ if( p ) sqlite3OsFree(p); } -void *sqlite3_malloc(int nByte){ return nByte>0 ? sqlite3OsMalloc(nByte) : 0; } -void *sqlite3_realloc(void *pOld, int nByte){ - if( pOld ){ - if( nByte>0 ){ - return sqlite3OsRealloc(pOld, nByte); - }else{ - sqlite3OsFree(pOld); - return 0; - } - }else{ - return sqlite3_malloc(nByte); - } -} /* ** This function is exactly the same as sqlite3_create_function(), except diff --git a/src/mem1.c b/src/mem1.c new file mode 100644 index 000000000..ba4c8e950 --- /dev/null +++ b/src/mem1.c @@ -0,0 +1,204 @@ +/* +** 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 a memory +** allocation subsystem for use by SQLite. +** +** $Id: mem1.c,v 1.1 2007/08/15 13:04:54 drh Exp $ +*/ + +/* +** We will eventually construct multiple memory allocation subsystems +** suitable for use in various contexts: +** +** * Normal multi-threaded builds +** * Normal single-threaded builds +** * Debugging builds +** +** This initial version is suitable for use in normal multi-threaded +** builds. We envision that alternative versions will be stored in +** separate source files. #ifdefs will be used to select the code from +** one of the various memN.c source files for use in any given build. +*/ +#include "sqliteInt.h" + + +/* +** Mutex to control access to the memory allocation subsystem. +*/ +static sqlite3_mutex *memMutex = 0; + +/* +** Current allocation and high-water mark. +*/ +static sqlite3_uint64 nowUsed = 0; +static sqlite3_uint64 mxUsed = 0; + +/* +** The alarm callback and its arguments. The memMutex lock will +** be held while the callback is running. Recursive calls into +** the memory subsystem are allowed, but no new callbacks will be +** issued. The alarmBusy variable is set to prevent recursive +** callbacks. +*/ +static void (*alarmCallback)(void*, sqlite3_uint64, unsigned) = 0; +static void *alarmArg = 0; +static sqlite3_uint64 alarmThreshold = (((sqlite3_uint64)1)<<63); +static int alarmBusy = 0; + + +/* +** Return the amount of memory currently checked out. +*/ +sqlite3_uint64 sqlite3_memory_used(void){ + sqlite3_uint64 n; + if( memMutex==0 ){ + memMutex = sqlite3_mutex_alloc(1); + } + sqlite3_mutex_enter(memMutex, 1); + n = nowUsed; + sqlite3_mutex_leave(memMutex); + return n; +} + +/* +** Return the maximum amount of memory that has ever been +** checked out since either the beginning of this process +** or since the most recent reset. +*/ +sqlite3_uint64 sqlite3_memory_highwater(int resetFlag){ + sqlite3_uint64 n; + if( memMutex==0 ){ + memMutex = sqlite3_mutex_alloc(1); + } + sqlite3_mutex_enter(memMutex, 1); + n = mxUsed; + if( resetFlag ){ + mxUsed = nowUsed; + } + sqlite3_mutex_leave(memMutex); + return n; +} + +/* +** Change the alarm callback +*/ +int sqlite3_memory_alarm( + void(*xCallback)(void *pArg, sqlite3_uint64 used, unsigned int N), + void *pArg, + sqlite3_uint64 iThreshold +){ + if( memMutex==0 ){ + memMutex = sqlite3_mutex_alloc(1); + } + sqlite3_mutex_enter(memMutex, 1); + alarmCallback = xCallback; + alarmArg = pArg; + alarmThreshold = iThreshold; + sqlite3_mutex_leave(memMutex); + return SQLITE_OK; +} + +/* +** Trigger the alarm +*/ +static void sqlite3MemsysAlarm(unsigned nByte){ + if( alarmCallback==0 || alarmBusy ) return; + alarmBusy = 1; + alarmCallback(alarmArg, nowUsed, nByte); + alarmBusy = 0; +} + +/* +** Allocate nBytes of memory +*/ +void *sqlite3_malloc(unsigned int nBytes){ + sqlite3_uint64 *p; + if( memMutex==0 ){ + memMutex = sqlite3_mutex_alloc(1); + } + sqlite3_mutex_enter(memMutex, 1); + if( nowUsed+nBytes>=alarmThreshold ){ + sqlite3MemsysAlarm(nBytes); + } + p = malloc(nBytes+8); + if( p==0 ){ + sqlite3MemsysAlarm(nBytes); + p = malloc(nBytes+8); + } + if( p ){ + p[0] = nBytes; + p++; + nowUsed += nBytes; + if( nowUsed>mxUsed ){ + mxUsed = nowUsed; + } + } + sqlite3_mutex_leave(memMutex); + return (void*)p; +} + +/* +** Free memory. +*/ +void sqlite3_free(void *pPrior){ + sqlite3_uint64 *p; + unsigned nByte; + if( pPrior==0 ){ + return; + } + assert( memMutex!=0 ); + p = pPrior; + p--; + nByte = (unsigned int)*p; + sqlite3_mutex_enter(memMutex, 1); + nowUsed -= nByte; + free(p); + sqlite3_mutex_leave(memMutex); +} + +/* +** Change the size of an existing memory allocation +*/ +void *sqlite3_realloc(void *pPrior, unsigned int nBytes){ + unsigned nOld; + sqlite3_uint64 *p; + if( pPrior==0 ){ + return sqlite3_malloc(nBytes); + } + if( nBytes==0 ){ + sqlite3_free(pPrior); + return; + } + p = pPrior; + p--; + nOld = (unsigned int)p[0]; + assert( memMutex!=0 ); + sqlite3_mutex_enter(memMutex, 1); + if( nowUsed+nBytes-nOld>=alarmThreshold ){ + sqlite3MemsysAlarm(nBytes-nOld); + } + p = realloc(p, nBytes+8); + if( p==0 ){ + sqlite3MemsysAlarm(nBytes); + p = realloc(p, nBytes+8); + } + if( p ){ + p[0] = nBytes; + p++; + nowUsed += nBytes-nOld; + if( nowUsed>mxUsed ){ + mxUsed = nowUsed; + } + } + sqlite3_mutex_leave(memMutex); + return (void*)p; +} 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) */ diff --git a/src/sqlite.h.in b/src/sqlite.h.in index aaedaded9..c614201cf 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -30,7 +30,7 @@ ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. ** -** @(#) $Id: sqlite.h.in,v 1.222 2007/08/15 11:28:56 drh Exp $ +** @(#) $Id: sqlite.h.in,v 1.223 2007/08/15 13:04:54 drh Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ @@ -1020,10 +1020,7 @@ char *sqlite3_vmprintf(const char*, va_list); char *sqlite3_snprintf(int,char*,const char*, ...); /* -** CAPI3REF: Memory Allocation Functions -** -** The SQLite sources include a memory allocation subsystem -** that implements the interfaces shown here. +** CAPI3REF: Memory Allocation Subsystem ** ** The SQLite core uses these three routines for all of its own ** internal memory allocation needs. The default implementation @@ -1031,14 +1028,14 @@ char *sqlite3_snprintf(int,char*,const char*, ...); ** and free() provided by the standard C library. However, if ** SQLite is compiled with the following C preprocessor macro ** -** <blockquote>SQLITE_OMIT_MEMORY_ALLOCATION</blockquote> +** <blockquote> SQLITE_OMIT_MEMORY_ALLOCATION </blockquote> ** ** then no implementation is provided for these routines by ** SQLite. The application that links against SQLite is ** expected to provide its own implementation. */ -void *sqlite3_malloc(int); -void *sqlite3_realloc(void*, int); +void *sqlite3_malloc(unsigned int); +void *sqlite3_realloc(void*, unsigned int); void sqlite3_free(void*); /* diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 21e5dbd3c..019b0ef04 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.585 2007/08/08 12:11:21 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.586 2007/08/15 13:04:54 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -441,6 +441,7 @@ struct Schema { ** consistently. */ struct sqlite3 { + sqlite3_vfs *pVfs; /* OS Interface */ int nDb; /* Number of backends currently in use */ Db *aDb; /* All backends */ int flags; /* Miscellanous flags. See below */ |