4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 *************************************************************************
13 ** Win32-specific run-time environment implementation for LSM.
31 ** An open file is an instance of the following object
33 typedef struct Win32File Win32File
;
35 lsm_env
*pEnv
; /* The run-time environment */
36 const char *zName
; /* Full path to file */
38 HANDLE hFile
; /* Open file handle */
39 HANDLE hShmFile
; /* File handle for *-shm file */
41 SYSTEM_INFO sysInfo
; /* Operating system information */
42 HANDLE hMap
; /* File handle for mapping */
43 LPVOID pMap
; /* Pointer to mapping of file fd */
44 size_t nMap
; /* Size of mapping at pMap in bytes */
45 int nShm
; /* Number of entries in ahShm[]/apShm[] */
46 LPHANDLE ahShm
; /* Array of handles for shared mappings */
47 LPVOID
*apShm
; /* Array of 32K shared memory segments */
50 static char *win32ShmFile(Win32File
*pWin32File
){
52 int nName
= strlen(pWin32File
->zName
);
53 zShm
= (char *)lsmMallocZero(pWin32File
->pEnv
, nName
+4+1);
55 memcpy(zShm
, pWin32File
->zName
, nName
);
56 memcpy(&zShm
[nName
], "-shm", 5);
61 static int win32Sleep(int us
){
62 Sleep((us
+ 999) / 1000);
67 ** The number of times that an I/O operation will be retried following a
68 ** locking error - probably caused by antivirus software. Also the initial
69 ** delay before the first retry. The delay increases linearly with each
72 #ifndef LSM_WIN32_IOERR_RETRY
73 # define LSM_WIN32_IOERR_RETRY 10
75 #ifndef LSM_WIN32_IOERR_RETRY_DELAY
76 # define LSM_WIN32_IOERR_RETRY_DELAY 25000
78 static int win32IoerrRetry
= LSM_WIN32_IOERR_RETRY
;
79 static int win32IoerrRetryDelay
= LSM_WIN32_IOERR_RETRY_DELAY
;
82 ** The "win32IoerrCanRetry1" macro is used to determine if a particular
83 ** I/O error code obtained via GetLastError() is eligible to be retried.
84 ** It must accept the error code DWORD as its only argument and should
85 ** return non-zero if the error code is transient in nature and the
86 ** operation responsible for generating the original error might succeed
87 ** upon being retried. The argument to this macro should be a variable.
89 ** Additionally, a macro named "win32IoerrCanRetry2" may be defined. If
90 ** it is defined, it will be consulted only when the macro
91 ** "win32IoerrCanRetry1" returns zero. The "win32IoerrCanRetry2" macro
92 ** is completely optional and may be used to include additional error
93 ** codes in the set that should result in the failing I/O operation being
94 ** retried by the caller. If defined, the "win32IoerrCanRetry2" macro
95 ** must exhibit external semantics identical to those of the
96 ** "win32IoerrCanRetry1" macro.
98 #if !defined(win32IoerrCanRetry1)
99 #define win32IoerrCanRetry1(a) (((a)==ERROR_ACCESS_DENIED) || \
100 ((a)==ERROR_SHARING_VIOLATION) || \
101 ((a)==ERROR_LOCK_VIOLATION) || \
102 ((a)==ERROR_DEV_NOT_EXIST) || \
103 ((a)==ERROR_NETNAME_DELETED) || \
104 ((a)==ERROR_SEM_TIMEOUT) || \
105 ((a)==ERROR_NETWORK_UNREACHABLE))
109 ** If an I/O error occurs, invoke this routine to see if it should be
110 ** retried. Return TRUE to retry. Return FALSE to give up with an
113 static int win32RetryIoerr(
118 if( *pnRetry
>=win32IoerrRetry
){
121 lastErrno
= GetLastError();
122 if( win32IoerrCanRetry1(lastErrno
) ){
123 win32Sleep(win32IoerrRetryDelay
*(1+*pnRetry
));
127 #if defined(win32IoerrCanRetry2)
128 else if( win32IoerrCanRetry2(lastErrno
) ){
129 win32Sleep(win32IoerrRetryDelay
*(1+*pnRetry
));
138 ** Convert a UTF-8 string to Microsoft Unicode.
140 ** Space to hold the returned string is obtained from lsmMalloc().
142 static LPWSTR
win32Utf8ToUnicode(lsm_env
*pEnv
, const char *zText
){
146 nChar
= MultiByteToWideChar(CP_UTF8
, 0, zText
, -1, NULL
, 0);
150 zWideText
= lsmMallocZero(pEnv
, nChar
* sizeof(WCHAR
));
154 nChar
= MultiByteToWideChar(CP_UTF8
, 0, zText
, -1, zWideText
, nChar
);
156 lsmFree(pEnv
, zWideText
);
163 ** Convert a Microsoft Unicode string to UTF-8.
165 ** Space to hold the returned string is obtained from lsmMalloc().
167 static char *win32UnicodeToUtf8(lsm_env
*pEnv
, LPCWSTR zWideText
){
171 nByte
= WideCharToMultiByte(CP_UTF8
, 0, zWideText
, -1, 0, 0, 0, 0);
175 zText
= lsmMallocZero(pEnv
, nByte
);
179 nByte
= WideCharToMultiByte(CP_UTF8
, 0, zWideText
, -1, zText
, nByte
, 0, 0);
181 lsmFree(pEnv
, zText
);
187 #if !defined(win32IsNotFound)
188 #define win32IsNotFound(a) (((a)==ERROR_FILE_NOT_FOUND) || \
189 ((a)==ERROR_PATH_NOT_FOUND))
192 static int win32Open(
201 zConverted
= win32Utf8ToUnicode(pEnv
, zFile
);
205 int bReadonly
= (flags
& LSM_OPEN_READONLY
);
206 DWORD dwDesiredAccess
;
207 DWORD dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
208 DWORD dwCreationDisposition
;
209 DWORD dwFlagsAndAttributes
= FILE_ATTRIBUTE_NORMAL
;
213 dwDesiredAccess
= GENERIC_READ
;
214 dwCreationDisposition
= OPEN_EXISTING
;
216 dwDesiredAccess
= GENERIC_READ
| GENERIC_WRITE
;
217 dwCreationDisposition
= OPEN_ALWAYS
;
219 while( (hFile
= CreateFileW((LPCWSTR
)zConverted
,
222 dwCreationDisposition
,
223 dwFlagsAndAttributes
,
224 NULL
))==INVALID_HANDLE_VALUE
&&
225 win32RetryIoerr(pEnv
, &nRetry
) ){
228 lsmFree(pEnv
, zConverted
);
229 if( hFile
!=INVALID_HANDLE_VALUE
){
233 if( win32IsNotFound(GetLastError()) ){
234 rc
= lsmErrorBkpt(LSM_IOERR_NOENT
);
243 static int lsmWin32OsOpen(
250 Win32File
*pWin32File
;
252 pWin32File
= lsmMallocZero(pEnv
, sizeof(Win32File
));
258 rc
= win32Open(pEnv
, zFile
, flags
, &hFile
);
260 memset(&pWin32File
->sysInfo
, 0, sizeof(SYSTEM_INFO
));
261 GetSystemInfo(&pWin32File
->sysInfo
);
262 pWin32File
->pEnv
= pEnv
;
263 pWin32File
->zName
= zFile
;
264 pWin32File
->hFile
= hFile
;
266 lsmFree(pEnv
, pWin32File
);
270 *ppFile
= (lsm_file
*)pWin32File
;
274 static int lsmWin32OsWrite(
275 lsm_file
*pFile
, /* File to write to */
276 lsm_i64 iOff
, /* Offset to write to */
277 void *pData
, /* Write data from this buffer */
278 int nData
/* Bytes of data to write */
280 Win32File
*pWin32File
= (Win32File
*)pFile
;
281 OVERLAPPED overlapped
; /* The offset for WriteFile. */
282 u8
*aRem
= (u8
*)pData
; /* Data yet to be written */
283 int nRem
= nData
; /* Number of bytes yet to be written */
284 int nRetry
= 0; /* Number of retrys */
286 memset(&overlapped
, 0, sizeof(OVERLAPPED
));
287 overlapped
.Offset
= (LONG
)(iOff
& 0XFFFFFFFF);
288 overlapped
.OffsetHigh
= (LONG
)((iOff
>>32) & 0x7FFFFFFF);
290 DWORD nWrite
= 0; /* Bytes written using WriteFile */
291 if( !WriteFile(pWin32File
->hFile
, aRem
, nRem
, &nWrite
, &overlapped
) ){
292 if( win32RetryIoerr(pWin32File
->pEnv
, &nRetry
) ) continue;
295 assert( nWrite
==0 || nWrite
<=(DWORD
)nRem
);
296 if( nWrite
==0 || nWrite
>(DWORD
)nRem
){
300 overlapped
.Offset
= (LONG
)(iOff
& 0xFFFFFFFF);
301 overlapped
.OffsetHigh
= (LONG
)((iOff
>>32) & 0x7FFFFFFF);
305 if( nRem
!=0 ) return LSM_IOERR_BKPT
;
309 static int win32Truncate(
313 LARGE_INTEGER offset
;
314 offset
.QuadPart
= nSize
;
315 if( !SetFilePointerEx(hFile
, offset
, 0, FILE_BEGIN
) ){
316 return LSM_IOERR_BKPT
;
318 if (!SetEndOfFile(hFile
) ){
319 return LSM_IOERR_BKPT
;
324 static int lsmWin32OsTruncate(
325 lsm_file
*pFile
, /* File to write to */
326 lsm_i64 nSize
/* Size to truncate file to */
328 Win32File
*pWin32File
= (Win32File
*)pFile
;
329 return win32Truncate(pWin32File
->hFile
, nSize
);
332 static int lsmWin32OsRead(
333 lsm_file
*pFile
, /* File to read from */
334 lsm_i64 iOff
, /* Offset to read from */
335 void *pData
, /* Read data into this buffer */
336 int nData
/* Bytes of data to read */
338 Win32File
*pWin32File
= (Win32File
*)pFile
;
339 OVERLAPPED overlapped
; /* The offset for ReadFile */
340 DWORD nRead
= 0; /* Bytes read using ReadFile */
341 int nRetry
= 0; /* Number of retrys */
343 memset(&overlapped
, 0, sizeof(OVERLAPPED
));
344 overlapped
.Offset
= (LONG
)(iOff
& 0XFFFFFFFF);
345 overlapped
.OffsetHigh
= (LONG
)((iOff
>>32) & 0X7FFFFFFF);
346 while( !ReadFile(pWin32File
->hFile
, pData
, nData
, &nRead
, &overlapped
) &&
347 GetLastError()!=ERROR_HANDLE_EOF
){
348 if( win32RetryIoerr(pWin32File
->pEnv
, &nRetry
) ) continue;
349 return LSM_IOERR_BKPT
;
351 if( nRead
<(DWORD
)nData
){
352 /* Unread parts of the buffer must be zero-filled */
353 memset(&((char*)pData
)[nRead
], 0, nData
- nRead
);
358 static int lsmWin32OsSync(lsm_file
*pFile
){
362 Win32File
*pWin32File
= (Win32File
*)pFile
;
364 if( pWin32File
->pMap
!=NULL
){
365 if( !FlushViewOfFile(pWin32File
->pMap
, 0) ){
369 if( rc
==LSM_OK
&& !FlushFileBuffers(pWin32File
->hFile
) ){
373 unused_parameter(pFile
);
379 static int lsmWin32OsSectorSize(lsm_file
*pFile
){
383 static void win32Unmap(Win32File
*pWin32File
){
384 if( pWin32File
->pMap
!=NULL
){
385 UnmapViewOfFile(pWin32File
->pMap
);
386 pWin32File
->pMap
= NULL
;
387 pWin32File
->nMap
= 0;
389 if( pWin32File
->hMap
!=NULL
){
390 CloseHandle(pWin32File
->hMap
);
391 pWin32File
->hMap
= NULL
;
395 static int lsmWin32OsRemap(
401 Win32File
*pWin32File
= (Win32File
*)pFile
;
403 /* If the file is between 0 and 2MB in size, extend it in chunks of 256K.
404 ** Thereafter, in chunks of 1MB at a time. */
405 const int aIncrSz
[] = {256*1024, 1024*1024};
406 int nIncrSz
= aIncrSz
[iMin
>(2*1024*1024)];
411 win32Unmap(pWin32File
);
413 LARGE_INTEGER fileSize
;
418 memset(&fileSize
, 0, sizeof(LARGE_INTEGER
));
419 if( !GetFileSizeEx(pWin32File
->hFile
, &fileSize
) ){
420 return LSM_IOERR_BKPT
;
422 assert( fileSize
.QuadPart
>=0 );
423 if( fileSize
.QuadPart
<iMin
){
425 fileSize
.QuadPart
= ((iMin
+ nIncrSz
-1) / nIncrSz
) * nIncrSz
;
426 rc
= lsmWin32OsTruncate(pFile
, fileSize
.QuadPart
);
431 dwSizeLow
= (DWORD
)(fileSize
.QuadPart
& 0xFFFFFFFF);
432 dwSizeHigh
= (DWORD
)((fileSize
.QuadPart
& 0x7FFFFFFFFFFFFFFF) >> 32);
433 hMap
= CreateFileMappingW(pWin32File
->hFile
, NULL
, PAGE_READWRITE
,
434 dwSizeHigh
, dwSizeLow
, NULL
);
436 return LSM_IOERR_BKPT
;
438 pWin32File
->hMap
= hMap
;
439 assert( fileSize
.QuadPart
<=0xFFFFFFFF );
440 pMap
= MapViewOfFile(hMap
, FILE_MAP_WRITE
| FILE_MAP_READ
, 0, 0,
441 (SIZE_T
)fileSize
.QuadPart
);
443 return LSM_IOERR_BKPT
;
445 pWin32File
->pMap
= pMap
;
446 pWin32File
->nMap
= (SIZE_T
)fileSize
.QuadPart
;
448 *ppOut
= pWin32File
->pMap
;
449 *pnOut
= pWin32File
->nMap
;
453 static BOOL
win32IsDriveLetterAndColon(
454 const char *zPathname
456 return ( isalpha(zPathname
[0]) && zPathname
[1]==':' );
459 static int lsmWin32OsFullpath(
470 if( zName
[0]=='/' && win32IsDriveLetterAndColon(zName
+1) ){
473 zConverted
= win32Utf8ToUnicode(pEnv
, zName
);
475 return LSM_NOMEM_BKPT
;
477 nByte
= GetFullPathNameW((LPCWSTR
)zConverted
, 0, 0, 0);
479 lsmFree(pEnv
, zConverted
);
480 return LSM_IOERR_BKPT
;
483 zTempWide
= lsmMallocZero(pEnv
, nByte
* sizeof(zTempWide
[0]));
485 lsmFree(pEnv
, zConverted
);
486 return LSM_NOMEM_BKPT
;
488 nByte
= GetFullPathNameW((LPCWSTR
)zConverted
, nByte
, zTempWide
, 0);
490 lsmFree(pEnv
, zConverted
);
491 lsmFree(pEnv
, zTempWide
);
492 return LSM_IOERR_BKPT
;
494 lsmFree(pEnv
, zConverted
);
495 zTempUtf8
= win32UnicodeToUtf8(pEnv
, zTempWide
);
496 lsmFree(pEnv
, zTempWide
);
499 int nLen
= strlen(zTempUtf8
) + 1;
501 snprintf(zOut
, nOut
, "%s", zTempUtf8
);
503 lsmFree(pEnv
, zTempUtf8
);
507 return LSM_NOMEM_BKPT
;
511 static int lsmWin32OsFileid(
518 u8
*pBuf2
= (u8
*)pBuf
;
519 Win32File
*pWin32File
= (Win32File
*)pFile
;
520 BY_HANDLE_FILE_INFORMATION fileInfo
;
523 nReq
= (sizeof(fileInfo
.dwVolumeSerialNumber
) +
524 sizeof(fileInfo
.nFileIndexHigh
) +
525 sizeof(fileInfo
.nFileIndexLow
));
527 if( nReq
>nBuf
) return LSM_OK
;
528 memset(&fileInfo
, 0, sizeof(BY_HANDLE_FILE_INFORMATION
));
529 if( !GetFileInformationByHandle(pWin32File
->hFile
, &fileInfo
) ){
530 return LSM_IOERR_BKPT
;
532 nReq
= sizeof(fileInfo
.dwVolumeSerialNumber
);
533 memcpy(pBuf2
, &fileInfo
.dwVolumeSerialNumber
, nReq
);
535 nReq
= sizeof(fileInfo
.nFileIndexHigh
);
536 memcpy(pBuf
, &fileInfo
.nFileIndexHigh
, nReq
);
538 nReq
= sizeof(fileInfo
.nFileIndexLow
);
539 memcpy(pBuf2
, &fileInfo
.nFileIndexLow
, nReq
);
543 static int win32Delete(
550 zConverted
= win32Utf8ToUnicode(pEnv
, zFile
);
558 attr
= GetFileAttributesW(zConverted
);
559 if ( attr
==INVALID_FILE_ATTRIBUTES
){
563 if ( attr
&FILE_ATTRIBUTE_DIRECTORY
){
564 rc
= LSM_IOERR_BKPT
; /* Files only. */
567 if ( DeleteFileW(zConverted
) ){
568 rc
= LSM_OK
; /* Deleted OK. */
571 if ( !win32RetryIoerr(pEnv
, &nRetry
) ){
572 rc
= LSM_IOERR_BKPT
; /* No more retries. */
577 lsmFree(pEnv
, zConverted
);
581 static int lsmWin32OsUnlink(lsm_env
*pEnv
, const char *zFile
){
582 return win32Delete(pEnv
, zFile
);
585 #if !defined(win32IsLockBusy)
586 #define win32IsLockBusy(a) (((a)==ERROR_LOCK_VIOLATION) || \
587 ((a)==ERROR_IO_PENDING))
590 static int win32LockFile(
591 Win32File
*pWin32File
,
598 assert( LSM_LOCK_UNLOCK
==0 );
599 assert( LSM_LOCK_SHARED
==1 );
600 assert( LSM_LOCK_EXCL
==2 );
601 assert( eType
>=LSM_LOCK_UNLOCK
&& eType
<=LSM_LOCK_EXCL
);
603 assert( iLock
>0 && iLock
<=32 );
605 memset(&ovlp
, 0, sizeof(OVERLAPPED
));
606 ovlp
.Offset
= (4096-iLock
-nLock
+1);
607 if( eType
>LSM_LOCK_UNLOCK
){
608 DWORD flags
= LOCKFILE_FAIL_IMMEDIATELY
;
609 if( eType
>=LSM_LOCK_EXCL
) flags
|= LOCKFILE_EXCLUSIVE_LOCK
;
610 if( !LockFileEx(pWin32File
->hFile
, flags
, 0, (DWORD
)nLock
, 0, &ovlp
) ){
611 if( win32IsLockBusy(GetLastError()) ){
614 return LSM_IOERR_BKPT
;
618 if( !UnlockFileEx(pWin32File
->hFile
, 0, (DWORD
)nLock
, 0, &ovlp
) ){
619 return LSM_IOERR_BKPT
;
625 static int lsmWin32OsLock(lsm_file
*pFile
, int iLock
, int eType
){
626 Win32File
*pWin32File
= (Win32File
*)pFile
;
627 return win32LockFile(pWin32File
, iLock
, 1, eType
);
630 static int lsmWin32OsTestLock(lsm_file
*pFile
, int iLock
, int nLock
, int eType
){
632 Win32File
*pWin32File
= (Win32File
*)pFile
;
633 rc
= win32LockFile(pWin32File
, iLock
, nLock
, eType
);
634 if( rc
!=LSM_OK
) return rc
;
635 win32LockFile(pWin32File
, iLock
, nLock
, LSM_LOCK_UNLOCK
);
639 static int lsmWin32OsShmMap(lsm_file
*pFile
, int iChunk
, int sz
, void **ppShm
){
641 Win32File
*pWin32File
= (Win32File
*)pFile
;
642 int iOffset
= iChunk
* sz
;
643 int iOffsetShift
= iOffset
% pWin32File
->sysInfo
.dwAllocationGranularity
;
644 int nNew
= iChunk
+ 1;
645 lsm_i64 nReq
= nNew
* sz
;
649 assert( sz
==LSM_SHM_CHUNK_SIZE
);
650 if( iChunk
>=pWin32File
->nShm
){
653 LARGE_INTEGER fileSize
;
655 /* If the shared-memory file has not been opened, open it now. */
656 if( pWin32File
->hShmFile
==NULL
){
657 char *zShm
= win32ShmFile(pWin32File
);
658 if( !zShm
) return LSM_NOMEM_BKPT
;
659 rc
= win32Open(pWin32File
->pEnv
, zShm
, 0, &pWin32File
->hShmFile
);
660 lsmFree(pWin32File
->pEnv
, zShm
);
666 /* If the shared-memory file is not large enough to contain the
667 ** requested chunk, cause it to grow. */
668 memset(&fileSize
, 0, sizeof(LARGE_INTEGER
));
669 if( !GetFileSizeEx(pWin32File
->hShmFile
, &fileSize
) ){
670 return LSM_IOERR_BKPT
;
672 assert( fileSize
.QuadPart
>=0 );
673 if( fileSize
.QuadPart
<nReq
){
674 rc
= win32Truncate(pWin32File
->hShmFile
, nReq
);
680 ahNew
= (LPHANDLE
)lsmMallocZero(pWin32File
->pEnv
, sizeof(HANDLE
) * nNew
);
681 if( !ahNew
) return LSM_NOMEM_BKPT
;
682 apNew
= (LPVOID
*)lsmMallocZero(pWin32File
->pEnv
, sizeof(LPVOID
) * nNew
);
684 lsmFree(pWin32File
->pEnv
, ahNew
);
685 return LSM_NOMEM_BKPT
;
687 memcpy(ahNew
, pWin32File
->ahShm
, sizeof(HANDLE
) * pWin32File
->nShm
);
688 memcpy(apNew
, pWin32File
->apShm
, sizeof(LPVOID
) * pWin32File
->nShm
);
689 lsmFree(pWin32File
->pEnv
, pWin32File
->ahShm
);
690 pWin32File
->ahShm
= ahNew
;
691 lsmFree(pWin32File
->pEnv
, pWin32File
->apShm
);
692 pWin32File
->apShm
= apNew
;
693 pWin32File
->nShm
= nNew
;
696 if( pWin32File
->ahShm
[iChunk
]==NULL
){
698 assert( nReq
<=0xFFFFFFFF );
699 hMap
= CreateFileMappingW(pWin32File
->hShmFile
, NULL
, PAGE_READWRITE
, 0,
702 return LSM_IOERR_BKPT
;
704 pWin32File
->ahShm
[iChunk
] = hMap
;
706 if( pWin32File
->apShm
[iChunk
]==NULL
){
708 pMap
= MapViewOfFile(pWin32File
->ahShm
[iChunk
],
709 FILE_MAP_WRITE
| FILE_MAP_READ
, 0,
710 iOffset
- iOffsetShift
, sz
+ iOffsetShift
);
712 return LSM_IOERR_BKPT
;
714 pWin32File
->apShm
[iChunk
] = pMap
;
716 if( iOffsetShift
!=0 ){
717 char *p
= (char *)pWin32File
->apShm
[iChunk
];
718 *ppShm
= (void *)&p
[iOffsetShift
];
720 *ppShm
= pWin32File
->apShm
[iChunk
];
725 static void lsmWin32OsShmBarrier(void){
729 static int lsmWin32OsShmUnmap(lsm_file
*pFile
, int bDelete
){
730 Win32File
*pWin32File
= (Win32File
*)pFile
;
732 if( pWin32File
->hShmFile
!=NULL
){
734 for(i
=0; i
<pWin32File
->nShm
; i
++){
735 if( pWin32File
->apShm
[i
]!=NULL
){
736 UnmapViewOfFile(pWin32File
->apShm
[i
]);
737 pWin32File
->apShm
[i
] = NULL
;
739 if( pWin32File
->ahShm
[i
]!=NULL
){
740 CloseHandle(pWin32File
->ahShm
[i
]);
741 pWin32File
->ahShm
[i
] = NULL
;
744 CloseHandle(pWin32File
->hShmFile
);
745 pWin32File
->hShmFile
= NULL
;
747 char *zShm
= win32ShmFile(pWin32File
);
748 if( zShm
){ win32Delete(pWin32File
->pEnv
, zShm
); }
749 lsmFree(pWin32File
->pEnv
, zShm
);
755 #define MX_CLOSE_ATTEMPT 3
756 static int lsmWin32OsClose(lsm_file
*pFile
){
759 Win32File
*pWin32File
= (Win32File
*)pFile
;
760 lsmWin32OsShmUnmap(pFile
, 0);
761 win32Unmap(pWin32File
);
763 if( pWin32File
->hFile
==NULL
){
767 rc
= CloseHandle(pWin32File
->hFile
);
769 pWin32File
->hFile
= NULL
;
773 if( ++nRetry
>=MX_CLOSE_ATTEMPT
){
778 lsmFree(pWin32File
->pEnv
, pWin32File
->ahShm
);
779 lsmFree(pWin32File
->pEnv
, pWin32File
->apShm
);
780 lsmFree(pWin32File
->pEnv
, pWin32File
);
784 static int lsmWin32OsSleep(lsm_env
*pEnv
, int us
){
785 unused_parameter(pEnv
);
786 return win32Sleep(us
);
789 /****************************************************************************
790 ** Memory allocation routines.
793 static void *lsmWin32OsMalloc(lsm_env
*pEnv
, size_t N
){
794 assert( HeapValidate(GetProcessHeap(), 0, NULL
) );
795 return HeapAlloc(GetProcessHeap(), 0, (SIZE_T
)N
);
798 static void lsmWin32OsFree(lsm_env
*pEnv
, void *p
){
799 assert( HeapValidate(GetProcessHeap(), 0, NULL
) );
801 HeapFree(GetProcessHeap(), 0, p
);
805 static void *lsmWin32OsRealloc(lsm_env
*pEnv
, void *p
, size_t N
){
806 unsigned char *m
= (unsigned char *)p
;
807 assert( HeapValidate(GetProcessHeap(), 0, NULL
) );
809 lsmWin32OsFree(pEnv
, p
);
812 return lsmWin32OsMalloc(pEnv
, N
);
814 #if 0 /* arguable: don't shrink */
815 SIZE_T sz
= HeapSize(GetProcessHeap(), 0, m
);
820 return HeapReAlloc(GetProcessHeap(), 0, m
, N
);
824 static size_t lsmWin32OsMSize(lsm_env
*pEnv
, void *p
){
825 assert( HeapValidate(GetProcessHeap(), 0, NULL
) );
826 return (size_t)HeapSize(GetProcessHeap(), 0, p
);
830 #ifdef LSM_MUTEX_WIN32
831 /*************************************************************************
832 ** Mutex methods for Win32 based systems. If LSM_MUTEX_WIN32 is
833 ** missing then a no-op implementation of mutexes found below will be
838 typedef struct Win32Mutex Win32Mutex
;
841 CRITICAL_SECTION mutex
;
847 #ifndef WIN32_MUTEX_INITIALIZER
848 # define WIN32_MUTEX_INITIALIZER { 0 }
852 # define LSM_WIN32_STATIC_MUTEX { 0, WIN32_MUTEX_INITIALIZER, 0 }
854 # define LSM_WIN32_STATIC_MUTEX { 0, WIN32_MUTEX_INITIALIZER }
857 static int lsmWin32OsMutexStatic(
862 static volatile LONG initialized
= 0;
863 static Win32Mutex sMutex
[2] = {
864 LSM_WIN32_STATIC_MUTEX
,
865 LSM_WIN32_STATIC_MUTEX
868 assert( iMutex
==LSM_MUTEX_GLOBAL
|| iMutex
==LSM_MUTEX_HEAP
);
869 assert( LSM_MUTEX_GLOBAL
==1 && LSM_MUTEX_HEAP
==2 );
871 if( InterlockedCompareExchange(&initialized
, 1, 0)==0 ){
873 for(i
=0; i
<array_size(sMutex
); i
++){
874 InitializeCriticalSection(&sMutex
[i
].mutex
);
877 *ppStatic
= (lsm_mutex
*)&sMutex
[iMutex
-1];
881 static int lsmWin32OsMutexNew(lsm_env
*pEnv
, lsm_mutex
**ppNew
){
882 Win32Mutex
*pMutex
; /* Pointer to new mutex */
884 pMutex
= (Win32Mutex
*)lsmMallocZero(pEnv
, sizeof(Win32Mutex
));
885 if( !pMutex
) return LSM_NOMEM_BKPT
;
888 InitializeCriticalSection(&pMutex
->mutex
);
890 *ppNew
= (lsm_mutex
*)pMutex
;
894 static void lsmWin32OsMutexDel(lsm_mutex
*p
){
895 Win32Mutex
*pMutex
= (Win32Mutex
*)p
;
896 DeleteCriticalSection(&pMutex
->mutex
);
897 lsmFree(pMutex
->pEnv
, pMutex
);
900 static void lsmWin32OsMutexEnter(lsm_mutex
*p
){
901 Win32Mutex
*pMutex
= (Win32Mutex
*)p
;
902 EnterCriticalSection(&pMutex
->mutex
);
905 assert( pMutex
->owner
!=GetCurrentThreadId() );
906 pMutex
->owner
= GetCurrentThreadId();
907 assert( pMutex
->owner
==GetCurrentThreadId() );
911 static int lsmWin32OsMutexTry(lsm_mutex
*p
){
913 Win32Mutex
*pMutex
= (Win32Mutex
*)p
;
914 bRet
= TryEnterCriticalSection(&pMutex
->mutex
);
917 assert( pMutex
->owner
!=GetCurrentThreadId() );
918 pMutex
->owner
= GetCurrentThreadId();
919 assert( pMutex
->owner
==GetCurrentThreadId() );
925 static void lsmWin32OsMutexLeave(lsm_mutex
*p
){
926 Win32Mutex
*pMutex
= (Win32Mutex
*)p
;
928 assert( pMutex
->owner
==GetCurrentThreadId() );
930 assert( pMutex
->owner
!=GetCurrentThreadId() );
932 LeaveCriticalSection(&pMutex
->mutex
);
936 static int lsmWin32OsMutexHeld(lsm_mutex
*p
){
937 Win32Mutex
*pMutex
= (Win32Mutex
*)p
;
938 return pMutex
? pMutex
->owner
==GetCurrentThreadId() : 1;
940 static int lsmWin32OsMutexNotHeld(lsm_mutex
*p
){
941 Win32Mutex
*pMutex
= (Win32Mutex
*)p
;
942 return pMutex
? pMutex
->owner
!=GetCurrentThreadId() : 1;
946 ** End of Win32 mutex implementation.
947 *************************************************************************/
949 /*************************************************************************
950 ** Noop mutex implementation
952 typedef struct NoopMutex NoopMutex
;
954 lsm_env
*pEnv
; /* Environment handle (for xFree()) */
955 int bHeld
; /* True if mutex is held */
956 int bStatic
; /* True for a static mutex */
958 static NoopMutex aStaticNoopMutex
[2] = {
963 static int lsmWin32OsMutexStatic(
968 assert( iMutex
>=1 && iMutex
<=(int)array_size(aStaticNoopMutex
) );
969 *ppStatic
= (lsm_mutex
*)&aStaticNoopMutex
[iMutex
-1];
972 static int lsmWin32OsMutexNew(lsm_env
*pEnv
, lsm_mutex
**ppNew
){
974 p
= (NoopMutex
*)lsmMallocZero(pEnv
, sizeof(NoopMutex
));
975 if( p
) p
->pEnv
= pEnv
;
976 *ppNew
= (lsm_mutex
*)p
;
977 return (p
? LSM_OK
: LSM_NOMEM_BKPT
);
979 static void lsmWin32OsMutexDel(lsm_mutex
*pMutex
) {
980 NoopMutex
*p
= (NoopMutex
*)pMutex
;
981 assert( p
->bStatic
==0 && p
->pEnv
);
984 static void lsmWin32OsMutexEnter(lsm_mutex
*pMutex
){
985 NoopMutex
*p
= (NoopMutex
*)pMutex
;
986 assert( p
->bHeld
==0 );
989 static int lsmWin32OsMutexTry(lsm_mutex
*pMutex
){
990 NoopMutex
*p
= (NoopMutex
*)pMutex
;
991 assert( p
->bHeld
==0 );
995 static void lsmWin32OsMutexLeave(lsm_mutex
*pMutex
){
996 NoopMutex
*p
= (NoopMutex
*)pMutex
;
997 assert( p
->bHeld
==1 );
1001 static int lsmWin32OsMutexHeld(lsm_mutex
*pMutex
){
1002 NoopMutex
*p
= (NoopMutex
*)pMutex
;
1003 return p
? p
->bHeld
: 1;
1005 static int lsmWin32OsMutexNotHeld(lsm_mutex
*pMutex
){
1006 NoopMutex
*p
= (NoopMutex
*)pMutex
;
1007 return p
? !p
->bHeld
: 1;
1010 /***************************************************************************/
1011 #endif /* else LSM_MUTEX_NONE */
1013 /* Without LSM_DEBUG, the MutexHeld tests are never called */
1015 # define lsmWin32OsMutexHeld 0
1016 # define lsmWin32OsMutexNotHeld 0
1019 lsm_env
*lsm_default_env(void){
1020 static lsm_env win32_env
= {
1021 sizeof(lsm_env
), /* nByte */
1023 /***** file i/o ******************/
1025 lsmWin32OsFullpath
, /* xFullpath */
1026 lsmWin32OsOpen
, /* xOpen */
1027 lsmWin32OsRead
, /* xRead */
1028 lsmWin32OsWrite
, /* xWrite */
1029 lsmWin32OsTruncate
, /* xTruncate */
1030 lsmWin32OsSync
, /* xSync */
1031 lsmWin32OsSectorSize
, /* xSectorSize */
1032 lsmWin32OsRemap
, /* xRemap */
1033 lsmWin32OsFileid
, /* xFileid */
1034 lsmWin32OsClose
, /* xClose */
1035 lsmWin32OsUnlink
, /* xUnlink */
1036 lsmWin32OsLock
, /* xLock */
1037 lsmWin32OsTestLock
, /* xTestLock */
1038 lsmWin32OsShmMap
, /* xShmMap */
1039 lsmWin32OsShmBarrier
, /* xShmBarrier */
1040 lsmWin32OsShmUnmap
, /* xShmUnmap */
1041 /***** memory allocation *********/
1043 lsmWin32OsMalloc
, /* xMalloc */
1044 lsmWin32OsRealloc
, /* xRealloc */
1045 lsmWin32OsFree
, /* xFree */
1046 lsmWin32OsMSize
, /* xSize */
1047 /***** mutexes *********************/
1049 lsmWin32OsMutexStatic
, /* xMutexStatic */
1050 lsmWin32OsMutexNew
, /* xMutexNew */
1051 lsmWin32OsMutexDel
, /* xMutexDel */
1052 lsmWin32OsMutexEnter
, /* xMutexEnter */
1053 lsmWin32OsMutexTry
, /* xMutexTry */
1054 lsmWin32OsMutexLeave
, /* xMutexLeave */
1055 lsmWin32OsMutexHeld
, /* xMutexHeld */
1056 lsmWin32OsMutexNotHeld
, /* xMutexNotHeld */
1057 /***** other *********************/
1058 lsmWin32OsSleep
, /* xSleep */