mirror of
https://github.com/sqlite/sqlite.git
synced 2025-12-21 13:38:01 +03:00
Supports SQLITE_ENABLE_SETLK_TIMEOUT on windows. Does not work properly yet.
FossilOrigin-Name: 737ca8a9fb9dc74b28f2186d93c5101463497445d0fabba3def61fee29abf2c8
This commit is contained in:
10
Makefile.msc
10
Makefile.msc
@@ -292,6 +292,12 @@ SESSION = 0
|
|||||||
RBU = 0
|
RBU = 0
|
||||||
!ENDIF
|
!ENDIF
|
||||||
|
|
||||||
|
# Set this to non-0 to enable support for blocking locks.
|
||||||
|
#
|
||||||
|
!IFNDEF SETLK_TIMEOUT
|
||||||
|
SETLK_TIMEOUT = 0
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
# Set the source code file to be used by executables and libraries when
|
# Set the source code file to be used by executables and libraries when
|
||||||
# they need the amalgamation.
|
# they need the amalgamation.
|
||||||
#
|
#
|
||||||
@@ -448,6 +454,10 @@ EXT_FEATURE_FLAGS =
|
|||||||
!ENDIF
|
!ENDIF
|
||||||
!ENDIF
|
!ENDIF
|
||||||
|
|
||||||
|
!IF $(SETLK_TIMEOUT)!=0
|
||||||
|
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
############################### END OF OPTIONS ################################
|
############################### END OF OPTIONS ################################
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|||||||
27
manifest
27
manifest
@@ -1,11 +1,11 @@
|
|||||||
C Fix\sanother\sissue\sin\sargument\sexpansion\son\sWindows\sfor\stclsqlite3.c\sin\ninterpreter\smode.\s\sProblem\sintroduced\sby\scheck-in\s[9b87ea219bce5689]\sand\nunfixed\sby\s[cd942dce148c9d8f].
|
C Supports\sSQLITE_ENABLE_SETLK_TIMEOUT\son\swindows.\sDoes\snot\swork\sproperly\syet.
|
||||||
D 2024-11-22T17:41:00.227
|
D 2024-11-22T21:24:08.721
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
F LICENSE.md e108e1e69ae8e8a59e93c455654b8ac9356a11720d3345df2a4743e9590fb20d
|
F LICENSE.md e108e1e69ae8e8a59e93c455654b8ac9356a11720d3345df2a4743e9590fb20d
|
||||||
F Makefile.in 85f2c740cadf969abbd9a6210b8b76636dbf231b9d3efe977b060c3055fac5b9
|
F Makefile.in 85f2c740cadf969abbd9a6210b8b76636dbf231b9d3efe977b060c3055fac5b9
|
||||||
F Makefile.linux-generic bd3e3cacd369821a6241d4ea1967395c962dfe3057e38cb0a435cee0e8b789d0
|
F Makefile.linux-generic bd3e3cacd369821a6241d4ea1967395c962dfe3057e38cb0a435cee0e8b789d0
|
||||||
F Makefile.msc a92237976eb92c5efaa0dd2524746aec12c196e12df8d4dbff9543a4648c3312
|
F Makefile.msc 9a975438b8e06da44bc169b74aa9601cd48da52abd2c88e8a349c7d82b59d250
|
||||||
F README.md c3c0f19532ce28f6297a71870f3c7b424729f0e6d9ab889616d3587dd2332159
|
F README.md c3c0f19532ce28f6297a71870f3c7b424729f0e6d9ab889616d3587dd2332159
|
||||||
F VERSION 8dc0c3df15fd5ff0622f88fc483533fce990b1cbb2f5fb9fdfb4dbd71eef2889
|
F VERSION 8dc0c3df15fd5ff0622f88fc483533fce990b1cbb2f5fb9fdfb4dbd71eef2889
|
||||||
F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5
|
F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5
|
||||||
@@ -751,15 +751,15 @@ F src/mutex.c 06bcd9c3dbf2d9b21fcd182606c00fafb9bfe0287983c8e17acd13d2c81a2fa9
|
|||||||
F src/mutex.h a7b2293c48db5f27007c3bdb21d438873637d12658f5a0bf8ad025bb96803c4a
|
F src/mutex.h a7b2293c48db5f27007c3bdb21d438873637d12658f5a0bf8ad025bb96803c4a
|
||||||
F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4
|
F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4
|
||||||
F src/mutex_unix.c f7ee5a2061a4c11815a2bf4fc0e2bfa6fb8d9dc89390eb613ca0cec32fc9a3d1
|
F src/mutex_unix.c f7ee5a2061a4c11815a2bf4fc0e2bfa6fb8d9dc89390eb613ca0cec32fc9a3d1
|
||||||
F src/mutex_w32.c 28f8d480387db5b2ef5248705dd4e19db0cfc12c3ba426695a7d2c45c48e6885
|
F src/mutex_w32.c db182bf5aac08a16fbf5916d94974f5a11556fe150142fcabe36d6454e0d93a1
|
||||||
F src/notify.c 57c2d1a2805d6dee32acd5d250d928ab94e02d76369ae057dee7d445fd64e878
|
F src/notify.c 57c2d1a2805d6dee32acd5d250d928ab94e02d76369ae057dee7d445fd64e878
|
||||||
F src/os.c 509452169d5ea739723e213b8e2481cf0e587f0e88579a912d200db5269f5f6d
|
F src/os.c 509452169d5ea739723e213b8e2481cf0e587f0e88579a912d200db5269f5f6d
|
||||||
F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63
|
F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63
|
||||||
F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e06
|
F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e06
|
||||||
F src/os_kv.c 4d39e1f1c180b11162c6dc4aa8ad34053873a639bac6baae23272fc03349986a
|
F src/os_kv.c 4d39e1f1c180b11162c6dc4aa8ad34053873a639bac6baae23272fc03349986a
|
||||||
F src/os_setup.h 6011ad7af5db4e05155f385eb3a9b4470688de6f65d6166b8956e58a3d872107
|
F src/os_setup.h 6011ad7af5db4e05155f385eb3a9b4470688de6f65d6166b8956e58a3d872107
|
||||||
F src/os_unix.c d2edbd92b07a3f778c2defa8a2e9d75acceb6267bda56948c41e8cdda65224d6
|
F src/os_unix.c d4a33e8fbd1c6eb722a21b6ce1eee1213ec856170a2f256d99f3d2978f054f5a
|
||||||
F src/os_win.c 49c7725b500f5867e8360e75eeb30f9d70b62fa1f05c8a101da627210578df32
|
F src/os_win.c 2ed170fb6dba67952b7f07dfee71bb854463fb2fb51b0289fce5dec0fd075b0f
|
||||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||||
F src/pager.c 9656ad4e8331efb8a4f94f7a0c6440b98caea073950a367ea0c728a53b8e62c9
|
F src/pager.c 9656ad4e8331efb8a4f94f7a0c6440b98caea073950a367ea0c728a53b8e62c9
|
||||||
F src/pager.h 4b1140d691860de0be1347474c51fee07d5420bd7f802d38cbab8ea4ab9f538a
|
F src/pager.h 4b1140d691860de0be1347474c51fee07d5420bd7f802d38cbab8ea4ab9f538a
|
||||||
@@ -1702,7 +1702,7 @@ F test/swarmvtab2.test c948cb2fdfc5b01d85e8f6d6504854202dc1a0782ab2a0ed61538f27c
|
|||||||
F test/swarmvtab3.test 41a3ab47cb7a834d4e5336425103b617410a67bb95d335ef536f887587ece073
|
F test/swarmvtab3.test 41a3ab47cb7a834d4e5336425103b617410a67bb95d335ef536f887587ece073
|
||||||
F test/swarmvtabfault.test 8a67a9f27c61073a47990829e92bc0c64420a807cb642b15a25f6c788210ed95
|
F test/swarmvtabfault.test 8a67a9f27c61073a47990829e92bc0c64420a807cb642b15a25f6c788210ed95
|
||||||
F test/symlink.test 4368af0e213dd6e726a6240a16f2bb96a5a58f83f2d5d60652f27547b28cbf06
|
F test/symlink.test 4368af0e213dd6e726a6240a16f2bb96a5a58f83f2d5d60652f27547b28cbf06
|
||||||
F test/symlink2.test bf932ff7fe95c9dbb39d2a990df9098b0ea943233c97e40098e0a8d6b559a96f
|
F test/symlink2.test 0b7734533f198bbc46fb8ea984ffaea537c8ee949eaba8805a92ed9969573956
|
||||||
F test/sync.test 89539f4973c010eda5638407e71ca7fddbcd8e0594f4c9980229f804d4333092
|
F test/sync.test 89539f4973c010eda5638407e71ca7fddbcd8e0594f4c9980229f804d4333092
|
||||||
F test/sync2.test 8f9f7d4f6d5be8ca8941a8dadcc4299e558cb6a1ff653a9469146c7a76ef2039
|
F test/sync2.test 8f9f7d4f6d5be8ca8941a8dadcc4299e558cb6a1ff653a9469146c7a76ef2039
|
||||||
F test/syscall.test a067468b43b8cb2305e9f9fe414e5f40c875bb5d2cba5f00b8154396e95fcf37
|
F test/syscall.test a067468b43b8cb2305e9f9fe414e5f40c875bb5d2cba5f00b8154396e95fcf37
|
||||||
@@ -1986,7 +1986,7 @@ F test/vtab_shared.test 5253bff2355a9a3f014c15337da7e177ab0ef8ad
|
|||||||
F test/vtabdistinct.test 7688f0889358f849fd60bbfde1ded38b014b18066076d4bfbb75395804dfe072
|
F test/vtabdistinct.test 7688f0889358f849fd60bbfde1ded38b014b18066076d4bfbb75395804dfe072
|
||||||
F test/vtabdrop.test 65d4cf6722972e5499bdaf0c0d70ee3b8133944a4e4bc31862563f32a7edca12
|
F test/vtabdrop.test 65d4cf6722972e5499bdaf0c0d70ee3b8133944a4e4bc31862563f32a7edca12
|
||||||
F test/vtabrhs1.test 9b5ecbc74a689500c33a4b2b36761f9bcc22fcc4e3f9d21066ee0c9c74cf5f6c
|
F test/vtabrhs1.test 9b5ecbc74a689500c33a4b2b36761f9bcc22fcc4e3f9d21066ee0c9c74cf5f6c
|
||||||
F test/wal.test 519c550255c78f55959e9159b93ebbfad2b4e9f36f5b76284da41f572f9d27da
|
F test/wal.test 3628a18ed2ba1cad58978802381f89e6076d225d5c93836d3eed464f867fa288
|
||||||
F test/wal2.test e89ca97593b5e92849039f6b68ce1719a853ef20fa22c669ec1ac452fbc31cab
|
F test/wal2.test e89ca97593b5e92849039f6b68ce1719a853ef20fa22c669ec1ac452fbc31cab
|
||||||
F test/wal3.test 5de023bb862fd1eb9d2ad26fa8d9c43abb5370582e5b08b2ae0d6f93661bc310
|
F test/wal3.test 5de023bb862fd1eb9d2ad26fa8d9c43abb5370582e5b08b2ae0d6f93661bc310
|
||||||
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
|
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
|
||||||
@@ -2199,8 +2199,11 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350
|
|||||||
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
|
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
|
||||||
F tool/warnings.sh 49a486c5069de041aedcbde4de178293e0463ae9918ecad7539eedf0ec77a139
|
F tool/warnings.sh 49a486c5069de041aedcbde4de178293e0463ae9918ecad7539eedf0ec77a139
|
||||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||||
P 3d6ae13805bdba4c73b7443f20073264cdd157299cb911228600e1528a136bb1
|
P 0fe1622cec95b7ebecc127ee57a08113d3da1dadbe72c03a13d6751b3043e50f
|
||||||
R f112fd2beffd3eb814301c3676676b3e
|
R ee8b39ab71f10eb6a0db7f5e0c48bbd2
|
||||||
U drh
|
T *branch * win32-enable-setlk
|
||||||
Z 113c5b5aab1719624bc6c7ebe0ae9b2d
|
T *sym-win32-enable-setlk *
|
||||||
|
T -sym-trunk *
|
||||||
|
U dan
|
||||||
|
Z e8f9e025559e2dfd331c377d699a5f1c
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
0fe1622cec95b7ebecc127ee57a08113d3da1dadbe72c03a13d6751b3043e50f
|
737ca8a9fb9dc74b28f2186d93c5101463497445d0fabba3def61fee29abf2c8
|
||||||
|
|||||||
@@ -314,22 +314,12 @@ static int winMutexTry(sqlite3_mutex *p){
|
|||||||
/*
|
/*
|
||||||
** The sqlite3_mutex_try() routine is very rarely used, and when it
|
** The sqlite3_mutex_try() routine is very rarely used, and when it
|
||||||
** is used it is merely an optimization. So it is OK for it to always
|
** is used it is merely an optimization. So it is OK for it to always
|
||||||
** fail.
|
** fail on some platforms. But - it is required for ENABLE_SETLK_TIMEOUT
|
||||||
**
|
** builds.
|
||||||
** The TryEnterCriticalSection() interface is only available on WinNT.
|
|
||||||
** And some windows compilers complain if you try to use it without
|
|
||||||
** first doing some #defines that prevent SQLite from building on Win98.
|
|
||||||
** For that reason, we will omit this optimization for now. See
|
|
||||||
** ticket #2685.
|
|
||||||
*/
|
*/
|
||||||
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0400
|
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0400
|
||||||
assert( winMutex_isInit==1 );
|
assert( winMutex_isInit==1 );
|
||||||
assert( winMutex_isNt>=-1 && winMutex_isNt<=1 );
|
if( sqlite3_win32_is_nt() && TryEnterCriticalSection(&p->mutex) ){
|
||||||
if( winMutex_isNt<0 ){
|
|
||||||
winMutex_isNt = sqlite3_win32_is_nt();
|
|
||||||
}
|
|
||||||
assert( winMutex_isNt==0 || winMutex_isNt==1 );
|
|
||||||
if( winMutex_isNt && TryEnterCriticalSection(&p->mutex) ){
|
|
||||||
#ifdef SQLITE_DEBUG
|
#ifdef SQLITE_DEBUG
|
||||||
p->owner = tid;
|
p->owner = tid;
|
||||||
p->nRef++;
|
p->nRef++;
|
||||||
|
|||||||
@@ -4290,7 +4290,6 @@ static int unixGetpagesize(void){
|
|||||||
**
|
**
|
||||||
** nRef
|
** nRef
|
||||||
**
|
**
|
||||||
** The following fields are read-only after the object is created:
|
|
||||||
**
|
**
|
||||||
** hShm
|
** hShm
|
||||||
** zFilename
|
** zFilename
|
||||||
|
|||||||
410
src/os_win.c
410
src/os_win.c
@@ -287,6 +287,9 @@ struct winFile {
|
|||||||
sqlite3_int64 mmapSize; /* Size of mapped region */
|
sqlite3_int64 mmapSize; /* Size of mapped region */
|
||||||
sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
|
sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
unsigned iBusyTimeout; /* Wait this many millisec on locks */
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1453,6 +1456,9 @@ int sqlite3_win32_is_nt(void){
|
|||||||
}
|
}
|
||||||
return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
|
return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
|
||||||
#elif SQLITE_TEST
|
#elif SQLITE_TEST
|
||||||
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
|
return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
|
||||||
#else
|
#else
|
||||||
/*
|
/*
|
||||||
@@ -2540,6 +2546,73 @@ static BOOL winLockFile(
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Lock a region of nByte bytes starting at offset offset of file phFile.
|
||||||
|
** Take an EXCLUSIVE lock if parameter bExclusive is true, or a SHARED lock
|
||||||
|
** otherwise. If nMs is greater than zero and the lock cannot be obtained
|
||||||
|
** immediately, block for that many ms before giving up.
|
||||||
|
**
|
||||||
|
** If parameter pMutex is not NULL, then
|
||||||
|
**
|
||||||
|
** This function returns SQLITE_OK if the lock is obtained successfully. If
|
||||||
|
** some other process holds the lock, SQLITE_BUSY is returned if nMs==0, or
|
||||||
|
** SQLITE_BUSY_TIMEOUT otherwise. Or, if an error occurs, SQLITE_IOERR.
|
||||||
|
*/
|
||||||
|
static int winLockFileTimeout(
|
||||||
|
LPHANDLE phFile,
|
||||||
|
sqlite3_mutex *pMutex,
|
||||||
|
DWORD offset,
|
||||||
|
DWORD nByte,
|
||||||
|
int bExcl,
|
||||||
|
int nMs
|
||||||
|
){
|
||||||
|
DWORD flags = LOCKFILE_FAIL_IMMEDIATELY | (bExcl?LOCKFILE_EXCLUSIVE_LOCK:0);
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
|
#if !defined(SQLITE_ENABLE_SETLK_TIMEOUT)
|
||||||
|
ret = winLockFile(phFile, flags, offset, 0, nByte, 0);
|
||||||
|
#else
|
||||||
|
if( !osIsNT() ){
|
||||||
|
ret = winLockFile(phFile, flags, offset, 0, nByte, 0);
|
||||||
|
}else{
|
||||||
|
OVERLAPPED ovlp;
|
||||||
|
memset(&ovlp, 0, sizeof(OVERLAPPED));
|
||||||
|
ovlp.Offset = offset;
|
||||||
|
if( nMs>0 ){
|
||||||
|
ovlp.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
if( ovlp.hEvent==NULL ){
|
||||||
|
return SQLITE_IOERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = osLockFileEx(*phFile, flags, 0, nByte, 0, &ovlp);
|
||||||
|
|
||||||
|
if( nMs>0 ){
|
||||||
|
if( !ret ){
|
||||||
|
DWORD res = WaitForSingleObject(ovlp.hEvent, (DWORD)nMs);
|
||||||
|
if( res==WAIT_OBJECT_0 ){
|
||||||
|
/* Successfully obtained the lock. */
|
||||||
|
ret = TRUE;
|
||||||
|
}else if( res==WAIT_TIMEOUT ){
|
||||||
|
/* Timeout */
|
||||||
|
rc = SQLITE_BUSY_TIMEOUT;
|
||||||
|
}else{
|
||||||
|
/* Some other error has occurred */
|
||||||
|
rc = SQLITE_IOERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CloseHandle(ovlp.hEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* defined(SQLITE_ENABLE_SETLK_TIMEOUT) */
|
||||||
|
|
||||||
|
if( rc==SQLITE_OK && !ret ){
|
||||||
|
rc = SQLITE_BUSY;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Unlock a file region.
|
** Unlock a file region.
|
||||||
*/
|
*/
|
||||||
@@ -3640,6 +3713,22 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
case SQLITE_FCNTL_LOCK_TIMEOUT: {
|
||||||
|
int iOld = pFile->iBusyTimeout;
|
||||||
|
#if SQLITE_ENABLE_SETLK_TIMEOUT==1
|
||||||
|
pFile->iBusyTimeout = *(int*)pArg;
|
||||||
|
#elif SQLITE_ENABLE_SETLK_TIMEOUT==2
|
||||||
|
pFile->iBusyTimeout = !!(*(int*)pArg);
|
||||||
|
#else
|
||||||
|
# error "SQLITE_ENABLE_SETLK_TIMEOUT must be set to 1 or 2"
|
||||||
|
#endif
|
||||||
|
*(int*)pArg = iOld;
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h));
|
OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h));
|
||||||
return SQLITE_NOTFOUND;
|
return SQLITE_NOTFOUND;
|
||||||
@@ -3720,13 +3809,31 @@ static int winShmMutexHeld(void) {
|
|||||||
**
|
**
|
||||||
** The following fields are read-only after the object is created:
|
** The following fields are read-only after the object is created:
|
||||||
**
|
**
|
||||||
** fid
|
** hFile
|
||||||
** zFilename
|
** zFilename
|
||||||
**
|
**
|
||||||
** Either winShmNode.mutex must be held or winShmNode.nRef==0 and
|
** Either winShmNode.mutex must be held or winShmNode.nRef==0 and
|
||||||
** winShmMutexHeld() is true when reading or writing any other field
|
** winShmMutexHeld() is true when reading or writing any other field
|
||||||
** in this structure.
|
** in this structure.
|
||||||
**
|
**
|
||||||
|
** aMutex[SQLITE_SHM_NLOCK]:
|
||||||
|
** Normally, when SQLITE_ENABLE_SETLK_TIMEOUT is not defined, mutex
|
||||||
|
** winShmNode.mutex is used to serialize calls to the xShmLock()
|
||||||
|
** method.
|
||||||
|
**
|
||||||
|
** For SQLITE_ENABLE_SETLK_TIMEOUT builds, xShmLock() only takes the
|
||||||
|
** mutexes in the aMutex[] array that correspond to locks being taken
|
||||||
|
** or released. This means that:
|
||||||
|
**
|
||||||
|
** * Modifying the winShmNode.pFirst list requires holding *all*
|
||||||
|
** the locks in the aMutex[] array.
|
||||||
|
**
|
||||||
|
** * Reads and writes to winShm.sharedMask and winShm.exclMask must
|
||||||
|
** use AtomicLoad() and AtomicStore(). This is because it may be
|
||||||
|
** read by other threads while it is being modified.
|
||||||
|
**
|
||||||
|
** TODO: winShmNode.mutex is held for the space of time when LockFileEx()
|
||||||
|
** is called on winShmNode.hFile.
|
||||||
*/
|
*/
|
||||||
struct winShmNode {
|
struct winShmNode {
|
||||||
sqlite3_mutex *mutex; /* Mutex to access this object */
|
sqlite3_mutex *mutex; /* Mutex to access this object */
|
||||||
@@ -3747,11 +3854,38 @@ struct winShmNode {
|
|||||||
int nRef; /* Number of winShm objects pointing to this */
|
int nRef; /* Number of winShm objects pointing to this */
|
||||||
winShm *pFirst; /* All winShm objects pointing to this */
|
winShm *pFirst; /* All winShm objects pointing to this */
|
||||||
winShmNode *pNext; /* Next in list of all winShmNode objects */
|
winShmNode *pNext; /* Next in list of all winShmNode objects */
|
||||||
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
sqlite3_mutex *aMutex[SQLITE_SHM_NLOCK];
|
||||||
|
#endif
|
||||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
|
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
|
||||||
u8 nextShmId; /* Next available winShm.id value */
|
u8 nextShmId; /* Next available winShm.id value */
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Enter/leave the mutex required to modify the winShmNode.pFirst list.
|
||||||
|
*/
|
||||||
|
static void winShmListMutexEnter(winShmNode *pShmNode){
|
||||||
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
int ii;
|
||||||
|
for(ii=0; ii<SQLITE_SHM_NLOCK; ii++){
|
||||||
|
sqlite3_mutex_enter(pShmNode->aMutex[ii]);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
sqlite3_mutex_enter(pShmNode->mutex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
static void winShmListMutexLeave(winShmNode *pShmNode){
|
||||||
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
int ii;
|
||||||
|
for(ii=0; ii<SQLITE_SHM_NLOCK; ii++){
|
||||||
|
sqlite3_mutex_leave(pShmNode->aMutex[ii]);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
sqlite3_mutex_leave(pShmNode->mutex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** A global array of all winShmNode objects.
|
** A global array of all winShmNode objects.
|
||||||
**
|
**
|
||||||
@@ -3796,39 +3930,48 @@ struct winShm {
|
|||||||
#define WINSHM_RDLCK 2
|
#define WINSHM_RDLCK 2
|
||||||
#define WINSHM_WRLCK 3
|
#define WINSHM_WRLCK 3
|
||||||
static int winShmSystemLock(
|
static int winShmSystemLock(
|
||||||
winShmNode *pFile, /* Apply locks to this open shared-memory segment */
|
winFile *pDbFd, /* Apply locks to this open shared-memory segment */
|
||||||
int lockType, /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */
|
int lockType, /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */
|
||||||
int ofst, /* Offset to first byte to be locked/unlocked */
|
int ofst, /* Offset to first byte to be locked/unlocked */
|
||||||
int nByte /* Number of bytes to lock or unlock */
|
int nByte /* Number of bytes to lock or unlock */
|
||||||
){
|
){
|
||||||
|
winShmNode *pShmNode = pDbFd->pShm->pShmNode;
|
||||||
int rc = 0; /* Result code form Lock/UnlockFileEx() */
|
int rc = 0; /* Result code form Lock/UnlockFileEx() */
|
||||||
|
|
||||||
/* Access to the winShmNode object is serialized by the caller */
|
/* Access to the winShmNode object is serialized by the caller */
|
||||||
assert( pFile->nRef==0 || sqlite3_mutex_held(pFile->mutex) );
|
/* assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->mutex) ); */
|
||||||
|
|
||||||
OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n",
|
OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n",
|
||||||
pFile->hFile.h, lockType, ofst, nByte));
|
pShmNode->hFile.h, lockType, ofst, nByte));
|
||||||
|
|
||||||
/* Release/Acquire the system-level lock */
|
/* Release/Acquire the system-level lock */
|
||||||
if( lockType==WINSHM_UNLCK ){
|
if( lockType==WINSHM_UNLCK ){
|
||||||
rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0);
|
int ret = winUnlockFile(&pShmNode->hFile.h, ofst, 0, nByte, 0);
|
||||||
|
if( ret==0 ){
|
||||||
|
pShmNode->lastErrno = osGetLastError();
|
||||||
|
rc = SQLITE_ERROR;
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
/* Initialize the locking parameters */
|
/* Initialize the locking parameters */
|
||||||
|
#if SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
rc = winLockFileTimeout(&pShmNode->hFile.h, pShmNode->mutex, ofst, nByte,
|
||||||
|
(lockType==WINSHM_WRLCK), pDbFd->iBusyTimeout);
|
||||||
|
#else
|
||||||
DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
|
DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
|
||||||
if( lockType == WINSHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
|
if( lockType == WINSHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
|
||||||
rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0);
|
rc = winLockFile(&pShmNode->hFile.h, dwFlags, ofst, 0, nByte, 0);
|
||||||
}
|
|
||||||
|
|
||||||
if( rc!=0 ){
|
if( rc!=0 ){
|
||||||
rc = SQLITE_OK;
|
rc = SQLITE_OK;
|
||||||
}else{
|
}else{
|
||||||
pFile->lastErrno = osGetLastError();
|
pShmNode->lastErrno = osGetLastError();
|
||||||
rc = SQLITE_BUSY;
|
rc = SQLITE_BUSY;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n",
|
OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n",
|
||||||
pFile->hFile.h, (lockType == WINSHM_UNLCK) ? "winUnlockFile" :
|
pShmNode->hFile.h, (lockType == WINSHM_UNLCK) ? "winUnlockFile" :
|
||||||
"winLockFile", pFile->lastErrno, sqlite3ErrName(rc)));
|
"winLockFile", pShmNode->lastErrno, sqlite3ErrName(rc)));
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -3854,6 +3997,12 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
|
|||||||
if( p->nRef==0 ){
|
if( p->nRef==0 ){
|
||||||
int i;
|
int i;
|
||||||
if( p->mutex ){ sqlite3_mutex_free(p->mutex); }
|
if( p->mutex ){ sqlite3_mutex_free(p->mutex); }
|
||||||
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
/* Free the contents of the winShmNode.aMutex[] array */
|
||||||
|
for(i=0; i<SQLITE_SHM_NLOCK; i++){
|
||||||
|
sqlite3_mutex_free(p->aMutex[i]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
for(i=0; i<p->nRegion; i++){
|
for(i=0; i<p->nRegion; i++){
|
||||||
BOOL bRc = osUnmapViewOfFile(p->aRegion[i].pMap);
|
BOOL bRc = osUnmapViewOfFile(p->aRegion[i].pMap);
|
||||||
OSTRACE(("SHM-PURGE-UNMAP pid=%lu, region=%d, rc=%s\n",
|
OSTRACE(("SHM-PURGE-UNMAP pid=%lu, region=%d, rc=%s\n",
|
||||||
@@ -3886,34 +4035,35 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The DMS lock has not yet been taken on shm file pShmNode. Attempt to
|
** The DMS lock has not yet been taken on the shm file attached to
|
||||||
** take it now. Return SQLITE_OK if successful, or an SQLite error
|
** pDbFd. Attempt to take it now. Return SQLITE_OK if successful, or an
|
||||||
** code otherwise.
|
** SQLite error code otherwise.
|
||||||
**
|
**
|
||||||
** If the DMS cannot be locked because this is a readonly_shm=1
|
** If the DMS cannot be locked because this is a readonly_shm=1
|
||||||
** connection and no other process already holds a lock, return
|
** connection and no other process already holds a lock, return
|
||||||
** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1.
|
** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1.
|
||||||
*/
|
*/
|
||||||
static int winLockSharedMemory(winShmNode *pShmNode){
|
static int winLockSharedMemory(winFile *pDbFd){
|
||||||
int rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1);
|
winShmNode *pShmNode = pDbFd->pShm->pShmNode;
|
||||||
|
int rc = winShmSystemLock(pDbFd, WINSHM_WRLCK, WIN_SHM_DMS, 1);
|
||||||
|
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
if( pShmNode->isReadonly ){
|
if( pShmNode->isReadonly ){
|
||||||
pShmNode->isUnlocked = 1;
|
pShmNode->isUnlocked = 1;
|
||||||
winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
|
winShmSystemLock(pDbFd, WINSHM_UNLCK, WIN_SHM_DMS, 1);
|
||||||
return SQLITE_READONLY_CANTINIT;
|
return SQLITE_READONLY_CANTINIT;
|
||||||
}else if( winTruncate((sqlite3_file*)&pShmNode->hFile, 0) ){
|
}else if( winTruncate((sqlite3_file*)&pShmNode->hFile, 0) ){
|
||||||
winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
|
winShmSystemLock(pDbFd, WINSHM_UNLCK, WIN_SHM_DMS, 1);
|
||||||
return winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
|
return winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
|
||||||
"winLockSharedMemory", pShmNode->zFilename);
|
"winLockSharedMemory", pShmNode->zFilename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
|
winShmSystemLock(pDbFd, WINSHM_UNLCK, WIN_SHM_DMS, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1);
|
return winShmSystemLock(pDbFd, WINSHM_RDLCK, WIN_SHM_DMS, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3975,6 +4125,20 @@ static int winOpenSharedMemory(winFile *pDbFd){
|
|||||||
rc = SQLITE_IOERR_NOMEM_BKPT;
|
rc = SQLITE_IOERR_NOMEM_BKPT;
|
||||||
goto shm_open_err;
|
goto shm_open_err;
|
||||||
}
|
}
|
||||||
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
/* If SETLK_TIMEOUT is defined, also allocate the array of mutexes
|
||||||
|
** stored in pShmNode->aMutex[]. */
|
||||||
|
{
|
||||||
|
int ii;
|
||||||
|
for(ii=0; ii<SQLITE_SHM_NLOCK; ii++){
|
||||||
|
pShmNode->aMutex[ii] = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
|
||||||
|
if( pShmNode->aMutex[ii]==0 ){
|
||||||
|
rc = SQLITE_IOERR_NOMEM_BKPT;
|
||||||
|
goto shm_open_err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
|
if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
|
||||||
@@ -3992,7 +4156,10 @@ static int winOpenSharedMemory(winFile *pDbFd){
|
|||||||
}
|
}
|
||||||
if( outFlags==SQLITE_OPEN_READONLY ) pShmNode->isReadonly = 1;
|
if( outFlags==SQLITE_OPEN_READONLY ) pShmNode->isReadonly = 1;
|
||||||
|
|
||||||
rc = winLockSharedMemory(pShmNode);
|
p->pShmNode = pShmNode;
|
||||||
|
pDbFd->pShm = p;
|
||||||
|
rc = winLockSharedMemory(pDbFd);
|
||||||
|
pDbFd->pShm = 0;
|
||||||
if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err;
|
if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4012,15 +4179,16 @@ static int winOpenSharedMemory(winFile *pDbFd){
|
|||||||
** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex
|
** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex
|
||||||
** mutex.
|
** mutex.
|
||||||
*/
|
*/
|
||||||
sqlite3_mutex_enter(pShmNode->mutex);
|
winShmListMutexEnter(pShmNode);
|
||||||
p->pNext = pShmNode->pFirst;
|
p->pNext = pShmNode->pFirst;
|
||||||
pShmNode->pFirst = p;
|
pShmNode->pFirst = p;
|
||||||
sqlite3_mutex_leave(pShmNode->mutex);
|
winShmListMutexLeave(pShmNode);
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
/* Jump here on any error */
|
/* Jump here on any error */
|
||||||
shm_open_err:
|
shm_open_err:
|
||||||
winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
|
|
||||||
|
winUnlockFile(&pShmNode->hFile.h, WIN_SHM_DMS, 0, 1, 0);
|
||||||
winShmPurge(pDbFd->pVfs, 0); /* This call frees pShmNode if required */
|
winShmPurge(pDbFd->pVfs, 0); /* This call frees pShmNode if required */
|
||||||
sqlite3_free(p);
|
sqlite3_free(p);
|
||||||
sqlite3_free(pNew);
|
sqlite3_free(pNew);
|
||||||
@@ -4048,14 +4216,14 @@ static int winShmUnmap(
|
|||||||
|
|
||||||
/* Remove connection p from the set of connections associated
|
/* Remove connection p from the set of connections associated
|
||||||
** with pShmNode */
|
** with pShmNode */
|
||||||
sqlite3_mutex_enter(pShmNode->mutex);
|
winShmListMutexEnter(pShmNode);
|
||||||
for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){}
|
for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){}
|
||||||
*pp = p->pNext;
|
*pp = p->pNext;
|
||||||
|
winShmListMutexLeave(pShmNode);
|
||||||
|
|
||||||
/* Free the connection p */
|
/* Free the connection p */
|
||||||
sqlite3_free(p);
|
sqlite3_free(p);
|
||||||
pDbFd->pShm = 0;
|
pDbFd->pShm = 0;
|
||||||
sqlite3_mutex_leave(pShmNode->mutex);
|
|
||||||
|
|
||||||
/* If pShmNode->nRef has reached 0, then close the underlying
|
/* If pShmNode->nRef has reached 0, then close the underlying
|
||||||
** shared-memory file, too */
|
** shared-memory file, too */
|
||||||
@@ -4084,7 +4252,7 @@ static int winShmLock(
|
|||||||
winShm *pX; /* For looping over all siblings */
|
winShm *pX; /* For looping over all siblings */
|
||||||
winShmNode *pShmNode;
|
winShmNode *pShmNode;
|
||||||
int rc = SQLITE_OK; /* Result code */
|
int rc = SQLITE_OK; /* Result code */
|
||||||
u16 mask; /* Mask of locks to take or release */
|
u16 mask = (u16)((1U<<(ofst+n)) - (1U<<ofst)); /* Mask of locks to take/untake */
|
||||||
|
|
||||||
if( p==0 ) return SQLITE_IOERR_SHMLOCK;
|
if( p==0 ) return SQLITE_IOERR_SHMLOCK;
|
||||||
pShmNode = p->pShmNode;
|
pShmNode = p->pShmNode;
|
||||||
@@ -4098,84 +4266,168 @@ static int winShmLock(
|
|||||||
|| flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
|
|| flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
|
||||||
assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
|
assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
|
||||||
|
|
||||||
mask = (u16)((1U<<(ofst+n)) - (1U<<ofst));
|
/* Check that, if this to be a blocking lock, no locks that occur later
|
||||||
assert( n>1 || mask==(1<<ofst) );
|
** in the following list than the lock being obtained are already held:
|
||||||
|
**
|
||||||
|
** 1. Checkpointer lock (ofst==1).
|
||||||
|
** 2. Write lock (ofst==0).
|
||||||
|
** 3. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
|
||||||
|
**
|
||||||
|
** In other words, if this is a blocking lock, none of the locks that
|
||||||
|
** occur later in the above list than the lock being obtained may be
|
||||||
|
** held.
|
||||||
|
**
|
||||||
|
** It is not permitted to block on the RECOVER lock.
|
||||||
|
*/
|
||||||
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
{
|
||||||
|
u16 lockMask = (p->exclMask|p->sharedMask);
|
||||||
|
assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
|
||||||
|
(ofst!=2) /* not RECOVER */
|
||||||
|
&& (ofst!=1 || lockMask==0 || lockMask==2)
|
||||||
|
&& (ofst!=0 || lockMask<3)
|
||||||
|
&& (ofst<3 || lockMask<(1<<ofst))
|
||||||
|
));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Check if there is any work to do. There are three cases:
|
||||||
|
**
|
||||||
|
** a) An unlock operation where there are locks to unlock,
|
||||||
|
** b) An shared lock where the requested lock is not already held
|
||||||
|
** c) An exclusive lock where the requested lock is not already held
|
||||||
|
**
|
||||||
|
** The SQLite core never requests an exclusive lock that it already holds.
|
||||||
|
** This is assert()ed below.
|
||||||
|
*/
|
||||||
|
assert( flags!=(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK)
|
||||||
|
|| 0==(p->exclMask & mask)
|
||||||
|
);
|
||||||
|
if( ((flags & SQLITE_SHM_UNLOCK) && ((p->exclMask|p->sharedMask) & mask))
|
||||||
|
|| (flags==(SQLITE_SHM_SHARED|SQLITE_SHM_LOCK) && 0==(p->sharedMask & mask))
|
||||||
|
|| (flags==(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK))
|
||||||
|
){
|
||||||
|
|
||||||
|
/* Take the required mutexes. In SETLK_TIMEOUT mode (blocking locks), if
|
||||||
|
** this is an attempt on an exclusive lock use sqlite3_mutex_try(). If any
|
||||||
|
** other thread is holding this mutex, then it is either holding or about
|
||||||
|
** to hold a lock exclusive to the one being requested, and we may
|
||||||
|
** therefore return SQLITE_BUSY to the caller.
|
||||||
|
**
|
||||||
|
** Doing this prevents some deadlock scenarios. For example, thread 1 may
|
||||||
|
** be a checkpointer blocked waiting on the WRITER lock. And thread 2
|
||||||
|
** may be a normal SQL client upgrading to a write transaction. In this
|
||||||
|
** case thread 2 does a non-blocking request for the WRITER lock. But -
|
||||||
|
** if it were to use sqlite3_mutex_enter() then it would effectively
|
||||||
|
** become a (doomed) blocking request, as thread 2 would block until thread
|
||||||
|
** 1 obtained WRITER and released the mutex. Since thread 2 already holds
|
||||||
|
** a lock on a read-locking slot at this point, this breaks the
|
||||||
|
** anti-deadlock rules (see above). */
|
||||||
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
int iMutex;
|
||||||
|
for(iMutex=ofst; iMutex<ofst+n; iMutex++){
|
||||||
|
if( flags==(SQLITE_SHM_LOCK|SQLITE_SHM_EXCLUSIVE) ){
|
||||||
|
rc = sqlite3_mutex_try(pShmNode->aMutex[iMutex]);
|
||||||
|
if( rc!=SQLITE_OK ) break;
|
||||||
|
}else{
|
||||||
|
sqlite3_mutex_enter(pShmNode->aMutex[iMutex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
sqlite3_mutex_enter(pShmNode->mutex);
|
sqlite3_mutex_enter(pShmNode->mutex);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
if( flags & SQLITE_SHM_UNLOCK ){
|
if( flags & SQLITE_SHM_UNLOCK ){
|
||||||
|
/* Case (a) - unlock. */
|
||||||
u16 allMask = 0; /* Mask of locks held by siblings */
|
u16 allMask = 0; /* Mask of locks held by siblings */
|
||||||
|
|
||||||
/* See if any siblings hold this same lock */
|
assert( (p->exclMask & p->sharedMask)==0 );
|
||||||
|
assert( !(flags & SQLITE_SHM_EXCLUSIVE) || (p->exclMask & mask)==mask );
|
||||||
|
assert( !(flags & SQLITE_SHM_SHARED) || (p->sharedMask & mask)==mask );
|
||||||
|
|
||||||
|
/* If this is a shared lock, check if any other connection in this
|
||||||
|
** process is holding the same shared lock. If one or more are, then
|
||||||
|
** do not unlock the system-level lock held on the file-handle. */
|
||||||
|
if( flags & SQLITE_SHM_SHARED ){
|
||||||
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
|
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
|
||||||
if( pX==p ) continue;
|
if( pX==p ) continue;
|
||||||
assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 );
|
allMask |= AtomicLoad(&pX->sharedMask);
|
||||||
allMask |= pX->sharedMask;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unlock the system-level locks */
|
|
||||||
if( (mask & allMask)==0 ){
|
if( (mask & allMask)==0 ){
|
||||||
rc = winShmSystemLock(pShmNode, WINSHM_UNLCK, ofst+WIN_SHM_BASE, n);
|
rc = winShmSystemLock(pDbFd, WINSHM_UNLCK, ofst+WIN_SHM_BASE, n);
|
||||||
}else{
|
|
||||||
rc = SQLITE_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Undo the local locks */
|
/* Undo the local locks */
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
p->exclMask &= ~mask;
|
AtomicStore(&p->exclMask, p->exclMask & ~mask);
|
||||||
p->sharedMask &= ~mask;
|
AtomicStore(&p->sharedMask, p->sharedMask & ~mask);
|
||||||
}
|
}
|
||||||
}else if( flags & SQLITE_SHM_SHARED ){
|
}else if( flags & SQLITE_SHM_SHARED ){
|
||||||
u16 allShared = 0; /* Union of locks held by connections other than "p" */
|
/* Case (b) - a shared lock. */
|
||||||
|
int bLocked = 0; /* True if process already holds shared lock */
|
||||||
|
assert( n==1 );
|
||||||
|
|
||||||
/* Find out which shared locks are already held by sibling connections.
|
/* See what locks are held by other connections within this process. If
|
||||||
** If any sibling already holds an exclusive lock, go ahead and return
|
** any are holding an EXCLUSIVE lock, then this call will return
|
||||||
** SQLITE_BUSY.
|
** SQLITE_BUSY. Or, if any are holding a SHARED lock, then there is no
|
||||||
*/
|
** need to obtain a new system-level lock. */
|
||||||
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
|
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
|
||||||
if( (pX->exclMask & mask)!=0 ){
|
u16 mExcl = AtomicLoad(&pX->exclMask);
|
||||||
rc = SQLITE_BUSY;
|
u16 mShared = AtomicLoad(&pX->sharedMask);
|
||||||
break;
|
if( mExcl & mask ) rc = SQLITE_BUSY;
|
||||||
}
|
if( mShared & mask ){
|
||||||
allShared |= pX->sharedMask;
|
bLocked = 1;
|
||||||
}
|
|
||||||
|
|
||||||
/* Get shared locks at the system level, if necessary */
|
|
||||||
if( rc==SQLITE_OK ){
|
|
||||||
if( (allShared & mask)==0 ){
|
|
||||||
rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, ofst+WIN_SHM_BASE, n);
|
|
||||||
}else{
|
|
||||||
rc = SQLITE_OK;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the local shared locks */
|
if( rc==SQLITE_OK && bLocked==0 ){
|
||||||
|
rc = winShmSystemLock(pDbFd, WINSHM_RDLCK, ofst+WIN_SHM_BASE, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the local shared lock */
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
p->sharedMask |= mask;
|
AtomicStore(&p->sharedMask, p->sharedMask | mask);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
/* Make sure no sibling connections hold locks that will block this
|
/* Case (c) - an exclusive lock. */
|
||||||
** lock. If any do, return SQLITE_BUSY right away.
|
assert( flags==(SQLITE_SHM_LOCK|SQLITE_SHM_EXCLUSIVE) );
|
||||||
*/
|
|
||||||
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
|
|
||||||
if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){
|
|
||||||
rc = SQLITE_BUSY;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the exclusive locks at the system level. Then if successful
|
|
||||||
** also mark the local connection as being locked.
|
|
||||||
*/
|
|
||||||
if( rc==SQLITE_OK ){
|
|
||||||
rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, ofst+WIN_SHM_BASE, n);
|
|
||||||
if( rc==SQLITE_OK ){
|
|
||||||
assert( (p->sharedMask & mask)==0 );
|
assert( (p->sharedMask & mask)==0 );
|
||||||
p->exclMask |= mask;
|
assert( (p->exclMask & mask)==0 );
|
||||||
|
|
||||||
|
/* Make sure no sibling connections hold locks that will block this
|
||||||
|
** lock. If any do, return SQLITE_BUSY right away. */
|
||||||
|
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
|
||||||
|
u16 mExcl = AtomicLoad(&pX->exclMask);
|
||||||
|
u16 mShared = AtomicLoad(&pX->sharedMask);
|
||||||
|
if( (mExcl|mShared) & mask ) rc = SQLITE_BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the exclusive locks at the system level. If successful,
|
||||||
|
** also update the in-memory values. */
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
rc = winShmSystemLock(pDbFd, WINSHM_WRLCK, ofst+WIN_SHM_BASE, n);
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
AtomicStore(&p->exclMask, p->exclMask | mask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release the mutex(es) taken at the top of this block */
|
||||||
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
for(iMutex--; iMutex>=ofst; iMutex--){
|
||||||
|
sqlite3_mutex_leave(pShmNode->aMutex[iMutex]);
|
||||||
|
}
|
||||||
|
#else
|
||||||
sqlite3_mutex_leave(pShmNode->mutex);
|
sqlite3_mutex_leave(pShmNode->mutex);
|
||||||
OSTRACE(("SHM-LOCK pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x, rc=%s\n",
|
#endif
|
||||||
osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask,
|
}
|
||||||
|
|
||||||
|
OSTRACE((
|
||||||
|
"SHM-LOCK(%d,%d,%d) pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x, rc=%s\n",
|
||||||
|
ofst, n, flags, osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask,
|
||||||
sqlite3ErrName(rc)));
|
sqlite3ErrName(rc)));
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -4238,7 +4490,7 @@ static int winShmMap(
|
|||||||
|
|
||||||
sqlite3_mutex_enter(pShmNode->mutex);
|
sqlite3_mutex_enter(pShmNode->mutex);
|
||||||
if( pShmNode->isUnlocked ){
|
if( pShmNode->isUnlocked ){
|
||||||
rc = winLockSharedMemory(pShmNode);
|
rc = winLockSharedMemory(pDbFd);
|
||||||
if( rc!=SQLITE_OK ) goto shmpage_out;
|
if( rc!=SQLITE_OK ) goto shmpage_out;
|
||||||
pShmNode->isUnlocked = 0;
|
pShmNode->isUnlocked = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,10 +37,11 @@ proc canCreateWin32Symlink {} {
|
|||||||
set link [file join $::testdir lnk[pid].sym]
|
set link [file join $::testdir lnk[pid].sym]
|
||||||
if {[file exists $link]} { return 0 }
|
if {[file exists $link]} { return 0 }
|
||||||
set target [info nameofexecutable]
|
set target [info nameofexecutable]
|
||||||
if {[catch {createWin32Symlink $link $target}] == 0} {
|
if {[catch {createWin32Symlink $link $target} msg] == 0} {
|
||||||
deleteWin32Symlink $link
|
deleteWin32Symlink $link
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
puts $msg
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -506,7 +506,7 @@ do_multiclient_test tn {
|
|||||||
do_test wal-10.$tn.6 {
|
do_test wal-10.$tn.6 {
|
||||||
sql3 {SELECT * FROM t1}
|
sql3 {SELECT * FROM t1}
|
||||||
} {1 2 3 4 5 6}
|
} {1 2 3 4 5 6}
|
||||||
do_test wal-10.$tn.7 {
|
do_test wal-10.$tn.7a {
|
||||||
sql2 COMMIT
|
sql2 COMMIT
|
||||||
} {}
|
} {}
|
||||||
|
|
||||||
@@ -521,7 +521,7 @@ do_multiclient_test tn {
|
|||||||
# to the database (as it is not locked and [db] is reading the latest
|
# to the database (as it is not locked and [db] is reading the latest
|
||||||
# snapshot).
|
# snapshot).
|
||||||
#
|
#
|
||||||
do_test wal-10.$tn.7 {
|
do_test wal-10.$tn.7b {
|
||||||
sql2 { BEGIN; INSERT INTO t1 VALUES(7, 8) ; }
|
sql2 { BEGIN; INSERT INTO t1 VALUES(7, 8) ; }
|
||||||
catchsql { INSERT INTO t1 VALUES(9, 10) }
|
catchsql { INSERT INTO t1 VALUES(9, 10) }
|
||||||
} {1 {database is locked}}
|
} {1 {database is locked}}
|
||||||
|
|||||||
Reference in New Issue
Block a user