From: drh Date: Tue, 12 Aug 2008 15:21:11 +0000 (+0000) Subject: Revise the initialization and shutdown logic so that it no longer keeps X-Git-Tag: version-3.6.10~618 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=93ed56d9ea71c0d6a6a135a368102101a293a384;p=thirdparty%2Fsqlite.git Revise the initialization and shutdown logic so that it no longer keeps 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 --- diff --git a/manifest b/manifest index 1ded3f90d1..326fa310cd 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 255d19bf24..ad9ca33c3d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -42247b917ae5a5c0d81b934200810755d0040282 \ No newline at end of file +697fe7a3167c22a3232ce154e9d47cf75af613c4 \ No newline at end of file diff --git a/src/main.c b/src/main.c index e23a010126..af8aadc1d0 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.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 @@ -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(); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 68de4a1573..43271a0528 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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); diff --git a/src/status.c b/src/status.c index a60a8535a1..272ce841b5 100644 --- a/src/status.c +++ b/src/status.c @@ -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. */ diff --git a/test/memsubsys1.test b/test/memsubsys1.test index 4d96df8700..fafb701415 100644 --- a/test/memsubsys1.test +++ b/test/memsubsys1.test @@ -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; diff --git a/test/memsubsys2.test b/test/memsubsys2.test index 3bae5da97c..ec554775d2 100644 --- a/test/memsubsys2.test +++ b/test/memsubsys2.test @@ -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