aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2007-08-15 13:04:54 +0000
committerdrh <drh@noemail.net>2007-08-15 13:04:54 +0000
commit90f6a5beff55f81faa7135189c65cbd8a569e63c (patch)
tree900595d8e00a7a44978f9686322a3ed50a73dcbc /src
parentd84f946be8340e2c9c7d86475665ae1610608e0e (diff)
downloadsqlite-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.c26
-rw-r--r--src/mem1.c204
-rw-r--r--src/mutex.c238
-rw-r--r--src/sqlite.h.in13
-rw-r--r--src/sqliteInt.h3
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 */