]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Revise the initialization and shutdown logic so that it no longer keeps
authordrh <drh@noemail.net>
Tue, 12 Aug 2008 15:21:11 +0000 (15:21 +0000)
committerdrh <drh@noemail.net>
Tue, 12 Aug 2008 15:21:11 +0000 (15:21 +0000)
a recursive mutex allocated for the whole interval but instead releases
the mutex as soon as possible.  Do not reset status values upon initialization. (CVS 5559)

FossilOrigin-Name: 697fe7a3167c22a3232ce154e9d47cf75af613c4

manifest
manifest.uuid
src/main.c
src/sqliteInt.h
src/status.c
test/memsubsys1.test
test/memsubsys2.test

index 1ded3f90d1d7ef3760ceda8fba64af915f91cdf5..326fa310cd186972f680ca896bfa33816717bf06 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sfurther\swarnings/compilation\serrors\sin\stest\scode.\s(CVS\s5558)
-D 2008-08-12T15:04:59
+C Revise\sthe\sinitialization\sand\sshutdown\slogic\sso\sthat\sit\sno\slonger\skeeps\na\srecursive\smutex\sallocated\sfor\sthe\swhole\sinterval\sbut\sinstead\sreleases\nthe\smutex\sas\ssoon\sas\spossible.\s\sDo\snot\sreset\sstatus\svalues\supon\sinitialization.\s(CVS\s5559)
+D 2008-08-12T15:21:12
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in 2713ea64947be3b35f35d9a3158bb8299c90b019
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -115,7 +115,7 @@ F src/insert.c 89cd9af52a5ea6fb7d0cfc9c3b935d6406c360c4
 F src/journal.c cffd2cd214e58c0e99c3ff632b3bee6c7cbb260e
 F src/legacy.c aac57bd984e666059011ea01ec4383892a253be3
 F src/loadext.c eb1fe4f44d7c8ff53fc0c6a4388ab79fbd34cd64
-F src/main.c 9707706f62adc7a6830f7128eaaae6f3410046ae
+F src/main.c c5ed24ad2b27bc93aea580a17f370a19897165f6
 F src/malloc.c 22c68fc62f0c2df0f1deb8cd9a5ea968f995cac2
 F src/md5.c 008216bbb5d34c6fbab5357aa68575ad8a31516a
 F src/mem1.c 3a7fe31d8290baa3bb203af72f7dfd6323966bcd
@@ -146,9 +146,9 @@ F src/select.c 390d1bdde0c24f0225e369896da8e60ef2aeffbe
 F src/shell.c d83b578a8ccdd3e0e7fef4388a0887ce9f810967
 F src/sqlite.h.in 54e51c22e2294c5989156b0aec87aa44168ac1f0
 F src/sqlite3ext.h 1e3887c9bd3ae66cb599e922824b04cd0d0f2c3e
-F src/sqliteInt.h 685b9cf6537e59e4453269b43acb33c59b566346
+F src/sqliteInt.h be39605e2deee45c1004c8bf3927bdab2ec97e0c
 F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
-F src/status.c b39b4468fe97c7d26be2de052804887c099312e7
+F src/status.c 8caa772cd9310bc297280f7cf0ede4d69ed5b801
 F src/table.c 22744786199c9195720c15a7a42cb97b2e2728d8
 F src/tclsqlite.c ec46084184f033ba396a9ee7b5514b695083d0f3
 F src/test1.c 0ae2203b03dec8ecf8ad731038df47ba27bfe68c
@@ -417,8 +417,8 @@ F test/malloc_common.tcl e082fe4791dad22b49d2ad3f7dcf1dcbee1a4cec
 F test/manydb.test 8de36b8d33aab5ef295b11d9e95310aeded31af8
 F test/memdb.test a67bda4ff90a38f2b19f6c7f95aa7289e051d893
 F test/memleak.test d2d2a1ff7105d32dc3fdf691458cf6cba58c7217
-F test/memsubsys1.test 4896d75373f55e61d80b12261d88192861d18b53
-F test/memsubsys2.test c05b541f9c2a1234a9dc2ff2233b3a9544fa5139
+F test/memsubsys1.test 3cfd3237dbbceaf65673be7265c58d8a34d63cbb
+F test/memsubsys2.test 72a731225997ad5e8df89fdbeae9224616b6aecc
 F test/minmax.test 722d80816f7e096bf2c04f4111f1a6c1ba65453d
 F test/minmax2.test 33504c01a03bd99226144e4b03f7631a274d66e0
 F test/minmax3.test 94742aa922153953ce3562702815e4f1f079bdb8
@@ -617,7 +617,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
-P e3935502fdca486613c8116b6057bfdd37545e58
-R 81992e6503b50b00362c1f386109d2c1
-U danielk1977
-Z 15fdebe7ba6a81553a61856d47818587
+P 42247b917ae5a5c0d81b934200810755d0040282
+R 69ce11efb4890d98b6c9a2863d484581
+U drh
+Z be8367a1b5dd5ee08063dfae6619d193
index 255d19bf24f68f247db8b88ec0fe0c2e144ad7ea..ad9ca33c3d61e3196758e2cc5a58a82ed70f1f4f 100644 (file)
@@ -1 +1 @@
-42247b917ae5a5c0d81b934200810755d0040282
\ No newline at end of file
+697fe7a3167c22a3232ce154e9d47cf75af613c4
\ No newline at end of file
index e23a01012614107d68863d46cc3fae27d243736a..af8aadc1d05925eac48a2117a411ee5e04005d21 100644 (file)
@@ -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.487 2008/08/08 14:33:13 drh Exp $
+** $Id: main.c,v 1.488 2008/08/12 15:21:12 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -57,68 +57,119 @@ char *sqlite3_temp_directory = 0;
 ** Initialize SQLite.  
 **
 ** This routine must be called to initialize the memory allocation,
-** VFS, and mutex subsystesms prior to doing any serious work with
+** VFS, and mutex subsystems prior to doing any serious work with
 ** SQLite.  But as long as you do not compile with SQLITE_OMIT_AUTOINIT
 ** this routine will be called automatically by key routines such as
 ** sqlite3_open().  
 **
 ** This routine is a no-op except on its very first call for the process,
 ** or for the first call after a call to sqlite3_shutdown.
+**
+** The first thread to call this routine runs the initialization to
+** completion.  If subsequent threads call this routine before the first
+** thread has finished the initialization process, then the subsequent
+** threads must block until the first thread finishes with the initialization.
+**
+** The first thread might call this routine recursively.  Recursive
+** calls to this routine should not block, of course.  Otherwise the
+** initialization process would never complete.
+**
+** Let X be the first thread to enter this routine.  Let Y be some other
+** thread.  Then while the initial invocation of this routine by X is
+** incomplete, it is required that:
+**
+**    *  Calls to this routine from Y must block until the outer-most
+**       call by X completes.
+**
+**    *  Recursive calls to this routine from thread X return immediately
+**       without blocking.
 */
 int sqlite3_initialize(void){
-  static int inProgress = 0;
-  int rc;
-
-  /* If SQLite is already initialized, this call is a no-op. */
+  static int inProgress = 0;        /* Prevent recursion */
+  sqlite3_mutex *pMaster;           /* The main static mutex */
+  int rc;                           /* Result code */
+
+  /* If SQLite is already completely initialized, then this call
+  ** to sqlite3_initialize() should be a no-op.  But the initialization
+  ** must be complete.  So isInit must not be set until the very end
+  ** of this routine.
+  */
   if( sqlite3Config.isInit ) return SQLITE_OK;
 
-  /* Make sure the mutex system is initialized. */
+  /* Make sure the mutex subsystem is initialized.  If unable to 
+  ** initialize the mutex subsystem, return early with the error.
+  ** If the system is so sick that we are unable to allocate a mutex,
+  ** there is not much SQLite is going to be able to do.
+  **
+  ** The mutex subsystem must take care of serializing its own
+  ** initialization.
+  */
   rc = sqlite3MutexInit();
+  if( rc ) return rc;
 
+  /* Initialize the malloc() system and the recursive pInitMutex mutex.
+  ** This operation is protected by the STATIC_MASTER mutex.  Note that
+  ** MutexAlloc() is called for a static mutex prior to initializing the
+  ** malloc subsystem - this implies that the allocation of a static
+  ** mutex must not require support from the malloc subsystem.
+  */
+  pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+  sqlite3_mutex_enter(pMaster);
+  if( !sqlite3Config.isMallocInit ){
+    rc = sqlite3MallocInit();
+  }
   if( rc==SQLITE_OK ){
-
-    /* Initialize the malloc() system and the recursive pInitMutex mutex.
-    ** This operation is protected by the STATIC_MASTER mutex.
-    */
-    sqlite3_mutex *pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
-    sqlite3_mutex_enter(pMaster);
-    if( !sqlite3Config.isMallocInit ){
-      rc = sqlite3MallocInit();
-    }
-    if( rc==SQLITE_OK ){
-      sqlite3Config.isMallocInit = 1;
-      if( !sqlite3Config.pInitMutex ){
-        sqlite3Config.pInitMutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
-        if( sqlite3Config.bCoreMutex && !sqlite3Config.pInitMutex ){
-          rc = SQLITE_NOMEM;
-        }
+    sqlite3Config.isMallocInit = 1;
+    if( !sqlite3Config.pInitMutex ){
+      sqlite3Config.pInitMutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
+      if( sqlite3Config.bCoreMutex && !sqlite3Config.pInitMutex ){
+        rc = SQLITE_NOMEM;
       }
     }
-    sqlite3_mutex_leave(pMaster);
-    if( rc!=SQLITE_OK ){
-      return rc;
-    }
+    sqlite3Config.nRefInitMutex++;
+  }
+  sqlite3_mutex_leave(pMaster);
 
-    /* Enter the recursive pInitMutex mutex. After doing so, if the
-    ** sqlite3Config.isInit flag is true, then some other thread has
-    ** finished doing the initialization. If the inProgress flag is
-    ** true, then this function is being called recursively from within
-    ** the sqlite3_os_init() call below. In either case, exit early.
-    */
-    sqlite3_mutex_enter(sqlite3Config.pInitMutex);
-    if( sqlite3Config.isInit || inProgress ){
-      sqlite3_mutex_leave(sqlite3Config.pInitMutex);
-      return SQLITE_OK;
-    }
-    sqlite3StatusReset();
+  /* If unable to initialize the malloc subsystem, then return early.
+  ** There is little hope of getting SQLite to run if the malloc
+  ** subsystem cannot be initialized.
+  */
+  if( rc!=SQLITE_OK ){
+    return rc;
+  }
+
+  /* Do the rest of the initialization under the recursive mutex so
+  ** that we will be able to handle recursive calls into
+  ** sqlite3_initialize().  The recursive calls normally come through
+  ** sqlite3_os_init() when it invokes sqlite3_vfs_register(), but other
+  ** recursive calls might also be possible.
+  */
+  sqlite3_mutex_enter(sqlite3Config.pInitMutex);
+  if( sqlite3Config.isInit==0 && inProgress==0 ){
     inProgress = 1;
     rc = sqlite3_os_init();
     inProgress = 0;
     sqlite3Config.isInit = (rc==SQLITE_OK ? 1 : 0);
-    sqlite3_mutex_leave(sqlite3Config.pInitMutex);
   }
+  sqlite3_mutex_leave(sqlite3Config.pInitMutex);
 
-  /* Check NaN support. */
+  /* Go back under the static mutex and clean up the recursive
+  ** mutex to prevent a resource leak.
+  */
+  sqlite3_mutex_enter(pMaster);
+  sqlite3Config.nRefInitMutex--;
+  if( sqlite3Config.nRefInitMutex<=0 ){
+    assert( sqlite3Config.nRefInitMutex==0 );
+    sqlite3_mutex_free(sqlite3Config.pInitMutex);
+    sqlite3Config.pInitMutex = 0;
+  }
+  sqlite3_mutex_leave(pMaster);
+
+  /* The following is just a sanity check to make sure SQLite has
+  ** been compiled correctly.  It is important to run this code, but
+  ** we don't want to run it too often and soak up CPU cycles for no
+  ** reason.  So we run it once during initialization.
+  */
 #ifndef NDEBUG
   /* This section of code's only "output" is via assert() statements. */
   if ( rc==SQLITE_OK ){
@@ -141,8 +192,6 @@ int sqlite3_initialize(void){
 ** routine is not threadsafe.  Not by a long shot.
 */
 int sqlite3_shutdown(void){
-  sqlite3_mutex_free(sqlite3Config.pInitMutex);
-  sqlite3Config.pInitMutex = 0;
   sqlite3Config.isMallocInit = 0;
   if( sqlite3Config.isInit ){
     sqlite3_os_end();
index 68de4a157344ac310eb68bad1726a35ccf653a07..43271a0528b529fa040be57dd8f4258d1aa4b011 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.752 2008/08/04 20:13:27 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.753 2008/08/12 15:21:12 drh Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -1831,6 +1831,7 @@ struct Sqlite3Config {
   int isInit;                       /* True after initialization has finished */
   int isMallocInit;                 /* True after malloc is initialized */
   sqlite3_mutex *pInitMutex;        /* Mutex used by sqlite3_initialize() */
+  int nRefInitMutex;                /* Number of users of pInitMutex */
   int nSmall;                       /* alloc size threshold used by mem6.c */
   int mxParserStack;                /* maximum depth of the parser stack */
 };
@@ -1898,7 +1899,6 @@ void sqlite3BenignMallocHooks(void (*)(void), void (*)(void));
   int sqlite3MutexEnd(void);
 #endif
 
-void sqlite3StatusReset(void);
 int sqlite3StatusValue(int);
 void sqlite3StatusAdd(int, int);
 void sqlite3StatusSet(int, int);
index a60a8535a1caa4bbe95c011ec72d6905be2c7be1..272ce841b5cf9f945b113163fa807ea06887240b 100644 (file)
@@ -13,7 +13,7 @@
 ** This module implements the sqlite3_status() interface and related
 ** functionality.
 **
-** $Id: status.c,v 1.7 2008/08/05 17:53:23 drh Exp $
+** $Id: status.c,v 1.8 2008/08/12 15:21:12 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -26,14 +26,6 @@ static struct {
 } sqlite3Stat;
 
 
-/*
-** Reset the status records.  This routine is called by
-** sqlite3_initialize().
-*/
-void sqlite3StatusReset(void){
-  memset(&sqlite3Stat, 0, sizeof(sqlite3Stat));
-}
-
 /*
 ** Return the current value of a status parameter.
 */
index 4d96df8700c552b95f6a4cf9b5b0a86ca98dbb44..fafb701415f1bb66554b5cb321476a5270eeb6aa 100644 (file)
@@ -11,7 +11,7 @@
 #
 # This file contains tests of the memory allocation subsystem
 #
-# $Id: memsubsys1.test,v 1.8 2008/08/04 20:13:27 drh Exp $
+# $Id: memsubsys1.test,v 1.9 2008/08/12 15:21:12 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -46,12 +46,27 @@ proc build_test_db {testname pragmas} {
   integrity_check $testname.2
 }
 
+# Reset all of the highwater marks.
+#
+proc reset_highwater_marks {} {
+  sqlite3_status SQLITE_STATUS_MEMORY_USED 1
+  sqlite3_status SQLITE_STATUS_MALLOC_SIZE 1
+  sqlite3_status SQLITE_STATUS_PAGECACHE_USED 1
+  sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 1
+  sqlite3_status SQLITE_STATUS_PAGECACHE_SIZE 1
+  sqlite3_status SQLITE_STATUS_SCRATCH_USED 1
+  sqlite3_status SQLITE_STATUS_SCRATCH_OVERFLOW 1
+  sqlite3_status SQLITE_STATUS_SCRATCH_SIZE 1
+  sqlite3_status SQLITE_STATUS_PARSER_STACK 1
+}
+
 # Test 1:  Both PAGECACHE and SCRATCH are shut down.
 #
 db close
 sqlite3_shutdown
 sqlite3_config_lookaside 0 0
 sqlite3_initialize
+reset_highwater_marks
 build_test_db memsubsys1-1 {PRAGMA page_size=1024}
 do_test memsubsys1-1.3 {
   set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2]
@@ -68,6 +83,7 @@ db close
 sqlite3_shutdown
 sqlite3_config_pagecache 1024 20
 sqlite3_initialize
+reset_highwater_marks
 build_test_db memsubsys1-2 {PRAGMA page_size=1024}
 #show_memstats
 do_test memsubsys1-2.3 {
@@ -89,6 +105,7 @@ db close
 sqlite3_shutdown
 sqlite3_config_pagecache 512 20
 sqlite3_initialize
+reset_highwater_marks
 build_test_db memsubsys1-3.1 {PRAGMA page_size=1024}
 #show_memstats
 do_test memsubsys1-3.1.3 {
@@ -104,6 +121,7 @@ db close
 sqlite3_shutdown
 sqlite3_config_pagecache 2048 20
 sqlite3_initialize
+reset_highwater_marks
 build_test_db memsubsys1-3.2 {PRAGMA page_size=2048}
 #show_memstats
 do_test memsubsys1-3.2.3 {
@@ -123,6 +141,7 @@ sqlite3_shutdown
 sqlite3_config_pagecache 1024 50
 sqlite3_config_scratch 6000 2
 sqlite3_initialize
+reset_highwater_marks
 build_test_db memsubsys1-4 {PRAGMA page_size=1024}
 #show_memstats
 do_test memsubsys1-4.3 {
@@ -149,6 +168,7 @@ sqlite3_shutdown
 sqlite3_config_pagecache 4096 24
 sqlite3_config_scratch 6000 2
 sqlite3_initialize
+reset_highwater_marks
 build_test_db memsubsys1-5 {PRAGMA page_size=4096}
 #show_memstats
 do_test memsubsys1-5.3 {
@@ -174,6 +194,7 @@ sqlite3_shutdown
 sqlite3_config_pagecache 4096 24
 sqlite3_config_scratch 25000 1
 sqlite3_initialize
+reset_highwater_marks
 build_test_db memsubsys1-6 {PRAGMA page_size=4096}
 #show_memstats
 do_test memsubsys1-6.3 {
@@ -198,6 +219,7 @@ sqlite3_shutdown
 sqlite3_config_pagecache 4096 24
 sqlite3_config_scratch 25000 1
 sqlite3_initialize
+reset_highwater_marks
 build_test_db memsubsys1-7 {
   PRAGMA page_size=4096;
   PRAGMA cache_size=10;
index 3bae5da97c78329d15543cc2a71bb6d40e5c3025..ec554775d256763bd2fe256e0852c019cf44f9b5 100644 (file)
@@ -11,7 +11,7 @@
 #
 # This file contains tests of the memory allocation subsystem.
 #
-# $Id: memsubsys2.test,v 1.1 2008/07/10 18:13:43 drh Exp $
+# $Id: memsubsys2.test,v 1.2 2008/08/12 15:21:12 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -45,6 +45,20 @@ proc build_test_db {testname pragmas} {
   integrity_check $testname.2
 }
 
+# Reset all of the highwater marks.
+#
+proc reset_highwater_marks {} {
+  sqlite3_status SQLITE_STATUS_MEMORY_USED 1
+  sqlite3_status SQLITE_STATUS_MALLOC_SIZE 1
+  sqlite3_status SQLITE_STATUS_PAGECACHE_USED 1
+  sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 1
+  sqlite3_status SQLITE_STATUS_PAGECACHE_SIZE 1
+  sqlite3_status SQLITE_STATUS_SCRATCH_USED 1
+  sqlite3_status SQLITE_STATUS_SCRATCH_OVERFLOW 1
+  sqlite3_status SQLITE_STATUS_SCRATCH_SIZE 1
+  sqlite3_status SQLITE_STATUS_PARSER_STACK 1
+}
+
 # Test 1:  Verify that calling sqlite3_malloc(0) returns a NULL
 # pointer.
 #
@@ -77,6 +91,7 @@ db close
 sqlite3_shutdown
 sqlite3_config_memstatus 0
 sqlite3_initialize
+reset_highwater_marks
 set highwater [sqlite3_memory_highwater 0]
 do_test memsubsys2-3.1 {
   set highwater
@@ -114,6 +129,7 @@ do_test memsubsys2-3.9 {
 sqlite3_shutdown
 sqlite3_config_memstatus 1
 sqlite3_initialize
+reset_highwater_marks
 set highwater [sqlite3_memory_highwater 0]
 do_test memsubsys2-4.1 {
   set highwater