3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
|
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
+
-
-
+
+
-
-
-
+
-
-
+
+
-
-
-
+
-
-
-
-
-
+
+
-
-
-
|
sqlite3_free(p);
}else{
pp = &p->pNext;
}
}
}
/*
** Query the status of the DMS lock for the specified file. Returns
** SQLITE_OK upon success. Upon success, the integer pointed to by
** the pLockType argument will be set to the lock type held by the
** other process, as follows:
**
** WINSHM_UNLCK -- No locks are held on the DMS.
** WINSHM_RDLCK -- A SHARED lock is held on the DMS.
** WINSHM_WRLCK -- An EXCLUSIVE lock is held on the DMS.
*/
static int winGetShmDmsLockType(
winFile *pFile, /* File handle object */
int bReadOnly, /* Non-zero if the SHM was opened read-only */
int *pLockType /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */
){
#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
OVERLAPPED overlapped; /* The offset for ReadFile/WriteFile. */
#endif
LPVOID pOverlapped = 0;
sqlite3_int64 offset = WIN_SHM_DMS;
BYTE notUsed1 = 0;
DWORD notUsed2 = 0;
#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
if( winSeekFile(pFile, offset) ){
return SQLITE_IOERR_SEEK;
}
#else
memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.Offset = (LONG)(offset & 0xffffffff);
overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
pOverlapped = &overlapped;
#endif
if( bReadOnly ||
!osWriteFile(pFile->h, ¬Used1, 1, ¬Used2, pOverlapped) ){
DWORD lastErrno = bReadOnly ? NO_ERROR : osGetLastError();
if( !osReadFile(pFile->h, ¬Used1, 1, ¬Used2, pOverlapped) ){
lastErrno = osGetLastError();
if( winIsLockConflict(lastErrno) ){
if( pLockType ) *pLockType = WINSHM_WRLCK;
}else if( winIsLockMissing(lastErrno) ){
assert( bReadOnly );
if( pLockType ) *pLockType = WINSHM_UNLCK;
}else{
return SQLITE_IOERR_READ;
}
}else{
if( winIsLockConflict(lastErrno) ){
if( pLockType ) *pLockType = WINSHM_RDLCK;
}else{
return SQLITE_IOERR_WRITE;
}
}
}else{
if( pLockType ) *pLockType = WINSHM_UNLCK;
}
return SQLITE_OK;
}
/*
** The DMS lock has not yet been taken on shm file pShmNode. Attempt to
** take it now. Return SQLITE_OK if successful, or an SQLite error
** code otherwise.
**
** If the DMS cannot be locked because this is a readonly_shm=1
** connection and no other process already holds a lock, return
** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1.
*/
static int winLockSharedMemory(winShmNode *pShmNode){
int lockType;
int rc = SQLITE_OK;
int rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1);
/* Use ReadFile/WriteFile to determine the locks other processes are
** holding on the DMS byte. If it indicates that another process is
** holding a SHARED lock, then this process may also take a SHARED
** lock and proceed with opening the *-shm file.
**
** Or, if no other process is holding any lock, then this process
** is the first to open it. In this case take an EXCLUSIVE lock on the
** DMS byte and truncate the *-shm file to zero bytes in size. Then
** downgrade to a SHARED lock on the DMS byte.
**
** If another process is holding an EXCLUSIVE lock on the DMS byte,
** return SQLITE_BUSY to the caller (it will try again). An earlier
** version of this code attempted the SHARED lock at this point. But
** this introduced a subtle race condition: if the process holding
** EXCLUSIVE failed just before truncating the *-shm file, then this
** process might open and use the *-shm file without truncating it.
** And if the *-shm file has been corrupted by a power failure or
** system crash, the database itself may also become corrupt. */
if( winGetShmDmsLockType(&pShmNode->hFile, pShmNode->isReadonly,
&lockType)!=SQLITE_OK ){
if( rc==SQLITE_OK ){
rc = SQLITE_IOERR_LOCK;
}else if( lockType==WINSHM_UNLCK ){
if( pShmNode->isReadonly ){
pShmNode->isUnlocked = 1;
winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
rc = SQLITE_READONLY_CANTINIT;
}else{
return SQLITE_READONLY_CANTINIT;
}else if( winTruncate((sqlite3_file*)&pShmNode->hFile, 0) ){
winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1);
if( rc==SQLITE_OK && winTruncate((sqlite3_file*)&pShmNode->hFile, 0) ){
rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
return winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
"winLockSharedMemory", pShmNode->zFilename);
}
}
}
}
}else if( lockType==WINSHM_WRLCK ){
rc = SQLITE_BUSY;
}
if( rc==SQLITE_OK ){
assert( lockType==WINSHM_UNLCK || lockType==WINSHM_RDLCK );
winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1);
winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
return winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1);
}
return rc;
}
/*
** Open the shared-memory area associated with database file pDbFd.
**
** When opening a new shared-memory file, if no other instances of that
** file are currently open, in this process or in other processes, then
|