12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064 |
- /*
- ** 2011-12-03
- **
- ** The author disclaims copyright to this source code. In place of
- ** a legal notice, here is a blessing:
- **
- ** May you do good and not evil.
- ** May you find forgiveness for yourself and forgive others.
- ** May you share freely, never taking more than you give.
- **
- *************************************************************************
- **
- ** Win32-specific run-time environment implementation for LSM.
- */
- #ifdef _WIN32
- #include <assert.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <ctype.h>
- #include "windows.h"
- #include "lsmInt.h"
- /*
- ** An open file is an instance of the following object
- */
- typedef struct Win32File Win32File;
- struct Win32File {
- lsm_env *pEnv; /* The run-time environment */
- const char *zName; /* Full path to file */
- HANDLE hFile; /* Open file handle */
- HANDLE hShmFile; /* File handle for *-shm file */
- SYSTEM_INFO sysInfo; /* Operating system information */
- HANDLE hMap; /* File handle for mapping */
- LPVOID pMap; /* Pointer to mapping of file fd */
- size_t nMap; /* Size of mapping at pMap in bytes */
- int nShm; /* Number of entries in ahShm[]/apShm[] */
- LPHANDLE ahShm; /* Array of handles for shared mappings */
- LPVOID *apShm; /* Array of 32K shared memory segments */
- };
- static char *win32ShmFile(Win32File *pWin32File){
- char *zShm;
- int nName = strlen(pWin32File->zName);
- zShm = (char *)lsmMallocZero(pWin32File->pEnv, nName+4+1);
- if( zShm ){
- memcpy(zShm, pWin32File->zName, nName);
- memcpy(&zShm[nName], "-shm", 5);
- }
- return zShm;
- }
- static int win32Sleep(int us){
- Sleep((us + 999) / 1000);
- return LSM_OK;
- }
- /*
- ** The number of times that an I/O operation will be retried following a
- ** locking error - probably caused by antivirus software. Also the initial
- ** delay before the first retry. The delay increases linearly with each
- ** retry.
- */
- #ifndef LSM_WIN32_IOERR_RETRY
- # define LSM_WIN32_IOERR_RETRY 10
- #endif
- #ifndef LSM_WIN32_IOERR_RETRY_DELAY
- # define LSM_WIN32_IOERR_RETRY_DELAY 25000
- #endif
- static int win32IoerrRetry = LSM_WIN32_IOERR_RETRY;
- static int win32IoerrRetryDelay = LSM_WIN32_IOERR_RETRY_DELAY;
- /*
- ** The "win32IoerrCanRetry1" macro is used to determine if a particular
- ** I/O error code obtained via GetLastError() is eligible to be retried.
- ** It must accept the error code DWORD as its only argument and should
- ** return non-zero if the error code is transient in nature and the
- ** operation responsible for generating the original error might succeed
- ** upon being retried. The argument to this macro should be a variable.
- **
- ** Additionally, a macro named "win32IoerrCanRetry2" may be defined. If
- ** it is defined, it will be consulted only when the macro
- ** "win32IoerrCanRetry1" returns zero. The "win32IoerrCanRetry2" macro
- ** is completely optional and may be used to include additional error
- ** codes in the set that should result in the failing I/O operation being
- ** retried by the caller. If defined, the "win32IoerrCanRetry2" macro
- ** must exhibit external semantics identical to those of the
- ** "win32IoerrCanRetry1" macro.
- */
- #if !defined(win32IoerrCanRetry1)
- #define win32IoerrCanRetry1(a) (((a)==ERROR_ACCESS_DENIED) || \
- ((a)==ERROR_SHARING_VIOLATION) || \
- ((a)==ERROR_LOCK_VIOLATION) || \
- ((a)==ERROR_DEV_NOT_EXIST) || \
- ((a)==ERROR_NETNAME_DELETED) || \
- ((a)==ERROR_SEM_TIMEOUT) || \
- ((a)==ERROR_NETWORK_UNREACHABLE))
- #endif
- /*
- ** If an I/O error occurs, invoke this routine to see if it should be
- ** retried. Return TRUE to retry. Return FALSE to give up with an
- ** error.
- */
- static int win32RetryIoerr(
- lsm_env *pEnv,
- int *pnRetry
- ){
- DWORD lastErrno;
- if( *pnRetry>=win32IoerrRetry ){
- return 0;
- }
- lastErrno = GetLastError();
- if( win32IoerrCanRetry1(lastErrno) ){
- win32Sleep(win32IoerrRetryDelay*(1+*pnRetry));
- ++*pnRetry;
- return 1;
- }
- #if defined(win32IoerrCanRetry2)
- else if( win32IoerrCanRetry2(lastErrno) ){
- win32Sleep(win32IoerrRetryDelay*(1+*pnRetry));
- ++*pnRetry;
- return 1;
- }
- #endif
- return 0;
- }
- /*
- ** Convert a UTF-8 string to Microsoft Unicode.
- **
- ** Space to hold the returned string is obtained from lsmMalloc().
- */
- static LPWSTR win32Utf8ToUnicode(lsm_env *pEnv, const char *zText){
- int nChar;
- LPWSTR zWideText;
- nChar = MultiByteToWideChar(CP_UTF8, 0, zText, -1, NULL, 0);
- if( nChar==0 ){
- return 0;
- }
- zWideText = lsmMallocZero(pEnv, nChar * sizeof(WCHAR));
- if( zWideText==0 ){
- return 0;
- }
- nChar = MultiByteToWideChar(CP_UTF8, 0, zText, -1, zWideText, nChar);
- if( nChar==0 ){
- lsmFree(pEnv, zWideText);
- zWideText = 0;
- }
- return zWideText;
- }
- /*
- ** Convert a Microsoft Unicode string to UTF-8.
- **
- ** Space to hold the returned string is obtained from lsmMalloc().
- */
- static char *win32UnicodeToUtf8(lsm_env *pEnv, LPCWSTR zWideText){
- int nByte;
- char *zText;
- nByte = WideCharToMultiByte(CP_UTF8, 0, zWideText, -1, 0, 0, 0, 0);
- if( nByte == 0 ){
- return 0;
- }
- zText = lsmMallocZero(pEnv, nByte);
- if( zText==0 ){
- return 0;
- }
- nByte = WideCharToMultiByte(CP_UTF8, 0, zWideText, -1, zText, nByte, 0, 0);
- if( nByte == 0 ){
- lsmFree(pEnv, zText);
- zText = 0;
- }
- return zText;
- }
- #if !defined(win32IsNotFound)
- #define win32IsNotFound(a) (((a)==ERROR_FILE_NOT_FOUND) || \
- ((a)==ERROR_PATH_NOT_FOUND))
- #endif
- static int win32Open(
- lsm_env *pEnv,
- const char *zFile,
- int flags,
- LPHANDLE phFile
- ){
- int rc;
- LPWSTR zConverted;
- zConverted = win32Utf8ToUnicode(pEnv, zFile);
- if( zConverted==0 ){
- rc = LSM_NOMEM_BKPT;
- }else{
- int bReadonly = (flags & LSM_OPEN_READONLY);
- DWORD dwDesiredAccess;
- DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
- DWORD dwCreationDisposition;
- DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
- HANDLE hFile;
- int nRetry = 0;
- if( bReadonly ){
- dwDesiredAccess = GENERIC_READ;
- dwCreationDisposition = OPEN_EXISTING;
- }else{
- dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
- dwCreationDisposition = OPEN_ALWAYS;
- }
- while( (hFile = CreateFileW((LPCWSTR)zConverted,
- dwDesiredAccess,
- dwShareMode, NULL,
- dwCreationDisposition,
- dwFlagsAndAttributes,
- NULL))==INVALID_HANDLE_VALUE &&
- win32RetryIoerr(pEnv, &nRetry) ){
- /* Noop */
- }
- lsmFree(pEnv, zConverted);
- if( hFile!=INVALID_HANDLE_VALUE ){
- *phFile = hFile;
- rc = LSM_OK;
- }else{
- if( win32IsNotFound(GetLastError()) ){
- rc = lsmErrorBkpt(LSM_IOERR_NOENT);
- }else{
- rc = LSM_IOERR_BKPT;
- }
- }
- }
- return rc;
- }
- static int lsmWin32OsOpen(
- lsm_env *pEnv,
- const char *zFile,
- int flags,
- lsm_file **ppFile
- ){
- int rc = LSM_OK;
- Win32File *pWin32File;
- pWin32File = lsmMallocZero(pEnv, sizeof(Win32File));
- if( pWin32File==0 ){
- rc = LSM_NOMEM_BKPT;
- }else{
- HANDLE hFile = NULL;
- rc = win32Open(pEnv, zFile, flags, &hFile);
- if( rc==LSM_OK ){
- memset(&pWin32File->sysInfo, 0, sizeof(SYSTEM_INFO));
- GetSystemInfo(&pWin32File->sysInfo);
- pWin32File->pEnv = pEnv;
- pWin32File->zName = zFile;
- pWin32File->hFile = hFile;
- }else{
- lsmFree(pEnv, pWin32File);
- pWin32File = 0;
- }
- }
- *ppFile = (lsm_file *)pWin32File;
- return rc;
- }
- static int lsmWin32OsWrite(
- lsm_file *pFile, /* File to write to */
- lsm_i64 iOff, /* Offset to write to */
- void *pData, /* Write data from this buffer */
- int nData /* Bytes of data to write */
- ){
- Win32File *pWin32File = (Win32File *)pFile;
- OVERLAPPED overlapped; /* The offset for WriteFile. */
- u8 *aRem = (u8 *)pData; /* Data yet to be written */
- int nRem = nData; /* Number of bytes yet to be written */
- int nRetry = 0; /* Number of retrys */
- memset(&overlapped, 0, sizeof(OVERLAPPED));
- overlapped.Offset = (LONG)(iOff & 0XFFFFFFFF);
- overlapped.OffsetHigh = (LONG)((iOff>>32) & 0x7FFFFFFF);
- while( nRem>0 ){
- DWORD nWrite = 0; /* Bytes written using WriteFile */
- if( !WriteFile(pWin32File->hFile, aRem, nRem, &nWrite, &overlapped) ){
- if( win32RetryIoerr(pWin32File->pEnv, &nRetry) ) continue;
- break;
- }
- assert( nWrite==0 || nWrite<=(DWORD)nRem );
- if( nWrite==0 || nWrite>(DWORD)nRem ){
- break;
- }
- iOff += nWrite;
- overlapped.Offset = (LONG)(iOff & 0xFFFFFFFF);
- overlapped.OffsetHigh = (LONG)((iOff>>32) & 0x7FFFFFFF);
- aRem += nWrite;
- nRem -= nWrite;
- }
- if( nRem!=0 ) return LSM_IOERR_BKPT;
- return LSM_OK;
- }
- static int win32Truncate(
- HANDLE hFile,
- lsm_i64 nSize
- ){
- LARGE_INTEGER offset;
- offset.QuadPart = nSize;
- if( !SetFilePointerEx(hFile, offset, 0, FILE_BEGIN) ){
- return LSM_IOERR_BKPT;
- }
- if (!SetEndOfFile(hFile) ){
- return LSM_IOERR_BKPT;
- }
- return LSM_OK;
- }
- static int lsmWin32OsTruncate(
- lsm_file *pFile, /* File to write to */
- lsm_i64 nSize /* Size to truncate file to */
- ){
- Win32File *pWin32File = (Win32File *)pFile;
- return win32Truncate(pWin32File->hFile, nSize);
- }
- static int lsmWin32OsRead(
- lsm_file *pFile, /* File to read from */
- lsm_i64 iOff, /* Offset to read from */
- void *pData, /* Read data into this buffer */
- int nData /* Bytes of data to read */
- ){
- Win32File *pWin32File = (Win32File *)pFile;
- OVERLAPPED overlapped; /* The offset for ReadFile */
- DWORD nRead = 0; /* Bytes read using ReadFile */
- int nRetry = 0; /* Number of retrys */
- memset(&overlapped, 0, sizeof(OVERLAPPED));
- overlapped.Offset = (LONG)(iOff & 0XFFFFFFFF);
- overlapped.OffsetHigh = (LONG)((iOff>>32) & 0X7FFFFFFF);
- while( !ReadFile(pWin32File->hFile, pData, nData, &nRead, &overlapped) &&
- GetLastError()!=ERROR_HANDLE_EOF ){
- if( win32RetryIoerr(pWin32File->pEnv, &nRetry) ) continue;
- return LSM_IOERR_BKPT;
- }
- if( nRead<(DWORD)nData ){
- /* Unread parts of the buffer must be zero-filled */
- memset(&((char*)pData)[nRead], 0, nData - nRead);
- }
- return LSM_OK;
- }
- static int lsmWin32OsSync(lsm_file *pFile){
- int rc = LSM_OK;
- #ifndef LSM_NO_SYNC
- Win32File *pWin32File = (Win32File *)pFile;
- if( pWin32File->pMap!=NULL ){
- if( !FlushViewOfFile(pWin32File->pMap, 0) ){
- rc = LSM_IOERR_BKPT;
- }
- }
- if( rc==LSM_OK && !FlushFileBuffers(pWin32File->hFile) ){
- rc = LSM_IOERR_BKPT;
- }
- #else
- unused_parameter(pFile);
- #endif
- return rc;
- }
- static int lsmWin32OsSectorSize(lsm_file *pFile){
- return 512;
- }
- static void win32Unmap(Win32File *pWin32File){
- if( pWin32File->pMap!=NULL ){
- UnmapViewOfFile(pWin32File->pMap);
- pWin32File->pMap = NULL;
- pWin32File->nMap = 0;
- }
- if( pWin32File->hMap!=NULL ){
- CloseHandle(pWin32File->hMap);
- pWin32File->hMap = NULL;
- }
- }
- static int lsmWin32OsRemap(
- lsm_file *pFile,
- lsm_i64 iMin,
- void **ppOut,
- lsm_i64 *pnOut
- ){
- Win32File *pWin32File = (Win32File *)pFile;
- /* If the file is between 0 and 2MB in size, extend it in chunks of 256K.
- ** Thereafter, in chunks of 1MB at a time. */
- const int aIncrSz[] = {256*1024, 1024*1024};
- int nIncrSz = aIncrSz[iMin>(2*1024*1024)];
- *ppOut = NULL;
- *pnOut = 0;
- win32Unmap(pWin32File);
- if( iMin>=0 ){
- LARGE_INTEGER fileSize;
- DWORD dwSizeHigh;
- DWORD dwSizeLow;
- HANDLE hMap;
- LPVOID pMap;
- memset(&fileSize, 0, sizeof(LARGE_INTEGER));
- if( !GetFileSizeEx(pWin32File->hFile, &fileSize) ){
- return LSM_IOERR_BKPT;
- }
- assert( fileSize.QuadPart>=0 );
- if( fileSize.QuadPart<iMin ){
- int rc;
- fileSize.QuadPart = ((iMin + nIncrSz-1) / nIncrSz) * nIncrSz;
- rc = lsmWin32OsTruncate(pFile, fileSize.QuadPart);
- if( rc!=LSM_OK ){
- return rc;
- }
- }
- dwSizeLow = (DWORD)(fileSize.QuadPart & 0xFFFFFFFF);
- dwSizeHigh = (DWORD)((fileSize.QuadPart & 0x7FFFFFFFFFFFFFFF) >> 32);
- hMap = CreateFileMappingW(pWin32File->hFile, NULL, PAGE_READWRITE,
- dwSizeHigh, dwSizeLow, NULL);
- if( hMap==NULL ){
- return LSM_IOERR_BKPT;
- }
- pWin32File->hMap = hMap;
- assert( fileSize.QuadPart<=0xFFFFFFFF );
- pMap = MapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0,
- (SIZE_T)fileSize.QuadPart);
- if( pMap==NULL ){
- return LSM_IOERR_BKPT;
- }
- pWin32File->pMap = pMap;
- pWin32File->nMap = (SIZE_T)fileSize.QuadPart;
- }
- *ppOut = pWin32File->pMap;
- *pnOut = pWin32File->nMap;
- return LSM_OK;
- }
- static BOOL win32IsDriveLetterAndColon(
- const char *zPathname
- ){
- return ( isalpha(zPathname[0]) && zPathname[1]==':' );
- }
- static int lsmWin32OsFullpath(
- lsm_env *pEnv,
- const char *zName,
- char *zOut,
- int *pnOut
- ){
- DWORD nByte;
- void *zConverted;
- LPWSTR zTempWide;
- char *zTempUtf8;
- if( zName[0]=='/' && win32IsDriveLetterAndColon(zName+1) ){
- zName++;
- }
- zConverted = win32Utf8ToUnicode(pEnv, zName);
- if( zConverted==0 ){
- return LSM_NOMEM_BKPT;
- }
- nByte = GetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0);
- if( nByte==0 ){
- lsmFree(pEnv, zConverted);
- return LSM_IOERR_BKPT;
- }
- nByte += 3;
- zTempWide = lsmMallocZero(pEnv, nByte * sizeof(zTempWide[0]));
- if( zTempWide==0 ){
- lsmFree(pEnv, zConverted);
- return LSM_NOMEM_BKPT;
- }
- nByte = GetFullPathNameW((LPCWSTR)zConverted, nByte, zTempWide, 0);
- if( nByte==0 ){
- lsmFree(pEnv, zConverted);
- lsmFree(pEnv, zTempWide);
- return LSM_IOERR_BKPT;
- }
- lsmFree(pEnv, zConverted);
- zTempUtf8 = win32UnicodeToUtf8(pEnv, zTempWide);
- lsmFree(pEnv, zTempWide);
- if( zTempUtf8 ){
- int nOut = *pnOut;
- int nLen = strlen(zTempUtf8) + 1;
- if( nLen<=nOut ){
- snprintf(zOut, nOut, "%s", zTempUtf8);
- }
- lsmFree(pEnv, zTempUtf8);
- *pnOut = nLen;
- return LSM_OK;
- }else{
- return LSM_NOMEM_BKPT;
- }
- }
- static int lsmWin32OsFileid(
- lsm_file *pFile,
- void *pBuf,
- int *pnBuf
- ){
- int nBuf;
- int nReq;
- u8 *pBuf2 = (u8 *)pBuf;
- Win32File *pWin32File = (Win32File *)pFile;
- BY_HANDLE_FILE_INFORMATION fileInfo;
- nBuf = *pnBuf;
- nReq = (sizeof(fileInfo.dwVolumeSerialNumber) +
- sizeof(fileInfo.nFileIndexHigh) +
- sizeof(fileInfo.nFileIndexLow));
- *pnBuf = nReq;
- if( nReq>nBuf ) return LSM_OK;
- memset(&fileInfo, 0, sizeof(BY_HANDLE_FILE_INFORMATION));
- if( !GetFileInformationByHandle(pWin32File->hFile, &fileInfo) ){
- return LSM_IOERR_BKPT;
- }
- nReq = sizeof(fileInfo.dwVolumeSerialNumber);
- memcpy(pBuf2, &fileInfo.dwVolumeSerialNumber, nReq);
- pBuf2 += nReq;
- nReq = sizeof(fileInfo.nFileIndexHigh);
- memcpy(pBuf, &fileInfo.nFileIndexHigh, nReq);
- pBuf2 += nReq;
- nReq = sizeof(fileInfo.nFileIndexLow);
- memcpy(pBuf2, &fileInfo.nFileIndexLow, nReq);
- return LSM_OK;
- }
- static int win32Delete(
- lsm_env *pEnv,
- const char *zFile
- ){
- int rc;
- LPWSTR zConverted;
- zConverted = win32Utf8ToUnicode(pEnv, zFile);
- if( zConverted==0 ){
- rc = LSM_NOMEM_BKPT;
- }else{
- int nRetry = 0;
- DWORD attr;
- do {
- attr = GetFileAttributesW(zConverted);
- if ( attr==INVALID_FILE_ATTRIBUTES ){
- rc = LSM_IOERR_BKPT;
- break;
- }
- if ( attr&FILE_ATTRIBUTE_DIRECTORY ){
- rc = LSM_IOERR_BKPT; /* Files only. */
- break;
- }
- if ( DeleteFileW(zConverted) ){
- rc = LSM_OK; /* Deleted OK. */
- break;
- }
- if ( !win32RetryIoerr(pEnv, &nRetry) ){
- rc = LSM_IOERR_BKPT; /* No more retries. */
- break;
- }
- }while( 1 );
- }
- lsmFree(pEnv, zConverted);
- return rc;
- }
- static int lsmWin32OsUnlink(lsm_env *pEnv, const char *zFile){
- return win32Delete(pEnv, zFile);
- }
- #if !defined(win32IsLockBusy)
- #define win32IsLockBusy(a) (((a)==ERROR_LOCK_VIOLATION) || \
- ((a)==ERROR_IO_PENDING))
- #endif
- static int win32LockFile(
- Win32File *pWin32File,
- int iLock,
- int nLock,
- int eType
- ){
- OVERLAPPED ovlp;
- assert( LSM_LOCK_UNLOCK==0 );
- assert( LSM_LOCK_SHARED==1 );
- assert( LSM_LOCK_EXCL==2 );
- assert( eType>=LSM_LOCK_UNLOCK && eType<=LSM_LOCK_EXCL );
- assert( nLock>=0 );
- assert( iLock>0 && iLock<=32 );
- memset(&ovlp, 0, sizeof(OVERLAPPED));
- ovlp.Offset = (4096-iLock-nLock+1);
- if( eType>LSM_LOCK_UNLOCK ){
- DWORD flags = LOCKFILE_FAIL_IMMEDIATELY;
- if( eType>=LSM_LOCK_EXCL ) flags |= LOCKFILE_EXCLUSIVE_LOCK;
- if( !LockFileEx(pWin32File->hFile, flags, 0, (DWORD)nLock, 0, &ovlp) ){
- if( win32IsLockBusy(GetLastError()) ){
- return LSM_BUSY;
- }else{
- return LSM_IOERR_BKPT;
- }
- }
- }else{
- if( !UnlockFileEx(pWin32File->hFile, 0, (DWORD)nLock, 0, &ovlp) ){
- return LSM_IOERR_BKPT;
- }
- }
- return LSM_OK;
- }
- static int lsmWin32OsLock(lsm_file *pFile, int iLock, int eType){
- Win32File *pWin32File = (Win32File *)pFile;
- return win32LockFile(pWin32File, iLock, 1, eType);
- }
- static int lsmWin32OsTestLock(lsm_file *pFile, int iLock, int nLock, int eType){
- int rc;
- Win32File *pWin32File = (Win32File *)pFile;
- rc = win32LockFile(pWin32File, iLock, nLock, eType);
- if( rc!=LSM_OK ) return rc;
- win32LockFile(pWin32File, iLock, nLock, LSM_LOCK_UNLOCK);
- return LSM_OK;
- }
- static int lsmWin32OsShmMap(lsm_file *pFile, int iChunk, int sz, void **ppShm){
- int rc;
- Win32File *pWin32File = (Win32File *)pFile;
- int iOffset = iChunk * sz;
- int iOffsetShift = iOffset % pWin32File->sysInfo.dwAllocationGranularity;
- int nNew = iChunk + 1;
- lsm_i64 nReq = nNew * sz;
- *ppShm = NULL;
- assert( sz>=0 );
- assert( sz==LSM_SHM_CHUNK_SIZE );
- if( iChunk>=pWin32File->nShm ){
- LPHANDLE ahNew;
- LPVOID *apNew;
- LARGE_INTEGER fileSize;
- /* If the shared-memory file has not been opened, open it now. */
- if( pWin32File->hShmFile==NULL ){
- char *zShm = win32ShmFile(pWin32File);
- if( !zShm ) return LSM_NOMEM_BKPT;
- rc = win32Open(pWin32File->pEnv, zShm, 0, &pWin32File->hShmFile);
- lsmFree(pWin32File->pEnv, zShm);
- if( rc!=LSM_OK ){
- return rc;
- }
- }
- /* If the shared-memory file is not large enough to contain the
- ** requested chunk, cause it to grow. */
- memset(&fileSize, 0, sizeof(LARGE_INTEGER));
- if( !GetFileSizeEx(pWin32File->hShmFile, &fileSize) ){
- return LSM_IOERR_BKPT;
- }
- assert( fileSize.QuadPart>=0 );
- if( fileSize.QuadPart<nReq ){
- rc = win32Truncate(pWin32File->hShmFile, nReq);
- if( rc!=LSM_OK ){
- return rc;
- }
- }
- ahNew = (LPHANDLE)lsmMallocZero(pWin32File->pEnv, sizeof(HANDLE) * nNew);
- if( !ahNew ) return LSM_NOMEM_BKPT;
- apNew = (LPVOID *)lsmMallocZero(pWin32File->pEnv, sizeof(LPVOID) * nNew);
- if( !apNew ){
- lsmFree(pWin32File->pEnv, ahNew);
- return LSM_NOMEM_BKPT;
- }
- memcpy(ahNew, pWin32File->ahShm, sizeof(HANDLE) * pWin32File->nShm);
- memcpy(apNew, pWin32File->apShm, sizeof(LPVOID) * pWin32File->nShm);
- lsmFree(pWin32File->pEnv, pWin32File->ahShm);
- pWin32File->ahShm = ahNew;
- lsmFree(pWin32File->pEnv, pWin32File->apShm);
- pWin32File->apShm = apNew;
- pWin32File->nShm = nNew;
- }
- if( pWin32File->ahShm[iChunk]==NULL ){
- HANDLE hMap;
- assert( nReq<=0xFFFFFFFF );
- hMap = CreateFileMappingW(pWin32File->hShmFile, NULL, PAGE_READWRITE, 0,
- (DWORD)nReq, NULL);
- if( hMap==NULL ){
- return LSM_IOERR_BKPT;
- }
- pWin32File->ahShm[iChunk] = hMap;
- }
- if( pWin32File->apShm[iChunk]==NULL ){
- LPVOID pMap;
- pMap = MapViewOfFile(pWin32File->ahShm[iChunk],
- FILE_MAP_WRITE | FILE_MAP_READ, 0,
- iOffset - iOffsetShift, sz + iOffsetShift);
- if( pMap==NULL ){
- return LSM_IOERR_BKPT;
- }
- pWin32File->apShm[iChunk] = pMap;
- }
- if( iOffsetShift!=0 ){
- char *p = (char *)pWin32File->apShm[iChunk];
- *ppShm = (void *)&p[iOffsetShift];
- }else{
- *ppShm = pWin32File->apShm[iChunk];
- }
- return LSM_OK;
- }
- static void lsmWin32OsShmBarrier(void){
- MemoryBarrier();
- }
- static int lsmWin32OsShmUnmap(lsm_file *pFile, int bDelete){
- Win32File *pWin32File = (Win32File *)pFile;
- if( pWin32File->hShmFile!=NULL ){
- int i;
- for(i=0; i<pWin32File->nShm; i++){
- if( pWin32File->apShm[i]!=NULL ){
- UnmapViewOfFile(pWin32File->apShm[i]);
- pWin32File->apShm[i] = NULL;
- }
- if( pWin32File->ahShm[i]!=NULL ){
- CloseHandle(pWin32File->ahShm[i]);
- pWin32File->ahShm[i] = NULL;
- }
- }
- CloseHandle(pWin32File->hShmFile);
- pWin32File->hShmFile = NULL;
- if( bDelete ){
- char *zShm = win32ShmFile(pWin32File);
- if( zShm ){ win32Delete(pWin32File->pEnv, zShm); }
- lsmFree(pWin32File->pEnv, zShm);
- }
- }
- return LSM_OK;
- }
- #define MX_CLOSE_ATTEMPT 3
- static int lsmWin32OsClose(lsm_file *pFile){
- int rc;
- int nRetry = 0;
- Win32File *pWin32File = (Win32File *)pFile;
- lsmWin32OsShmUnmap(pFile, 0);
- win32Unmap(pWin32File);
- do{
- if( pWin32File->hFile==NULL ){
- rc = LSM_IOERR_BKPT;
- break;
- }
- rc = CloseHandle(pWin32File->hFile);
- if( rc ){
- pWin32File->hFile = NULL;
- rc = LSM_OK;
- break;
- }
- if( ++nRetry>=MX_CLOSE_ATTEMPT ){
- rc = LSM_IOERR_BKPT;
- break;
- }
- }while( 1 );
- lsmFree(pWin32File->pEnv, pWin32File->ahShm);
- lsmFree(pWin32File->pEnv, pWin32File->apShm);
- lsmFree(pWin32File->pEnv, pWin32File);
- return rc;
- }
- static int lsmWin32OsSleep(lsm_env *pEnv, int us){
- unused_parameter(pEnv);
- return win32Sleep(us);
- }
- /****************************************************************************
- ** Memory allocation routines.
- */
- static void *lsmWin32OsMalloc(lsm_env *pEnv, size_t N){
- assert( HeapValidate(GetProcessHeap(), 0, NULL) );
- return HeapAlloc(GetProcessHeap(), 0, (SIZE_T)N);
- }
- static void lsmWin32OsFree(lsm_env *pEnv, void *p){
- assert( HeapValidate(GetProcessHeap(), 0, NULL) );
- if( p ){
- HeapFree(GetProcessHeap(), 0, p);
- }
- }
- static void *lsmWin32OsRealloc(lsm_env *pEnv, void *p, size_t N){
- unsigned char *m = (unsigned char *)p;
- assert( HeapValidate(GetProcessHeap(), 0, NULL) );
- if( 1>N ){
- lsmWin32OsFree(pEnv, p);
- return NULL;
- }else if( NULL==p ){
- return lsmWin32OsMalloc(pEnv, N);
- }else{
- #if 0 /* arguable: don't shrink */
- SIZE_T sz = HeapSize(GetProcessHeap(), 0, m);
- if( sz>=(SIZE_T)N ){
- return p;
- }
- #endif
- return HeapReAlloc(GetProcessHeap(), 0, m, N);
- }
- }
- static size_t lsmWin32OsMSize(lsm_env *pEnv, void *p){
- assert( HeapValidate(GetProcessHeap(), 0, NULL) );
- return (size_t)HeapSize(GetProcessHeap(), 0, p);
- }
- #ifdef LSM_MUTEX_WIN32
- /*************************************************************************
- ** Mutex methods for Win32 based systems. If LSM_MUTEX_WIN32 is
- ** missing then a no-op implementation of mutexes found below will be
- ** used instead.
- */
- #include "windows.h"
- typedef struct Win32Mutex Win32Mutex;
- struct Win32Mutex {
- lsm_env *pEnv;
- CRITICAL_SECTION mutex;
- #ifdef LSM_DEBUG
- DWORD owner;
- #endif
- };
- #ifndef WIN32_MUTEX_INITIALIZER
- # define WIN32_MUTEX_INITIALIZER { 0 }
- #endif
- #ifdef LSM_DEBUG
- # define LSM_WIN32_STATIC_MUTEX { 0, WIN32_MUTEX_INITIALIZER, 0 }
- #else
- # define LSM_WIN32_STATIC_MUTEX { 0, WIN32_MUTEX_INITIALIZER }
- #endif
- static int lsmWin32OsMutexStatic(
- lsm_env *pEnv,
- int iMutex,
- lsm_mutex **ppStatic
- ){
- static volatile LONG initialized = 0;
- static Win32Mutex sMutex[2] = {
- LSM_WIN32_STATIC_MUTEX,
- LSM_WIN32_STATIC_MUTEX
- };
- assert( iMutex==LSM_MUTEX_GLOBAL || iMutex==LSM_MUTEX_HEAP );
- assert( LSM_MUTEX_GLOBAL==1 && LSM_MUTEX_HEAP==2 );
- if( InterlockedCompareExchange(&initialized, 1, 0)==0 ){
- int i;
- for(i=0; i<array_size(sMutex); i++){
- InitializeCriticalSection(&sMutex[i].mutex);
- }
- }
- *ppStatic = (lsm_mutex *)&sMutex[iMutex-1];
- return LSM_OK;
- }
- static int lsmWin32OsMutexNew(lsm_env *pEnv, lsm_mutex **ppNew){
- Win32Mutex *pMutex; /* Pointer to new mutex */
- pMutex = (Win32Mutex *)lsmMallocZero(pEnv, sizeof(Win32Mutex));
- if( !pMutex ) return LSM_NOMEM_BKPT;
- pMutex->pEnv = pEnv;
- InitializeCriticalSection(&pMutex->mutex);
- *ppNew = (lsm_mutex *)pMutex;
- return LSM_OK;
- }
- static void lsmWin32OsMutexDel(lsm_mutex *p){
- Win32Mutex *pMutex = (Win32Mutex *)p;
- DeleteCriticalSection(&pMutex->mutex);
- lsmFree(pMutex->pEnv, pMutex);
- }
- static void lsmWin32OsMutexEnter(lsm_mutex *p){
- Win32Mutex *pMutex = (Win32Mutex *)p;
- EnterCriticalSection(&pMutex->mutex);
- #ifdef LSM_DEBUG
- assert( pMutex->owner!=GetCurrentThreadId() );
- pMutex->owner = GetCurrentThreadId();
- assert( pMutex->owner==GetCurrentThreadId() );
- #endif
- }
- static int lsmWin32OsMutexTry(lsm_mutex *p){
- BOOL bRet;
- Win32Mutex *pMutex = (Win32Mutex *)p;
- bRet = TryEnterCriticalSection(&pMutex->mutex);
- #ifdef LSM_DEBUG
- if( bRet ){
- assert( pMutex->owner!=GetCurrentThreadId() );
- pMutex->owner = GetCurrentThreadId();
- assert( pMutex->owner==GetCurrentThreadId() );
- }
- #endif
- return !bRet;
- }
- static void lsmWin32OsMutexLeave(lsm_mutex *p){
- Win32Mutex *pMutex = (Win32Mutex *)p;
- #ifdef LSM_DEBUG
- assert( pMutex->owner==GetCurrentThreadId() );
- pMutex->owner = 0;
- assert( pMutex->owner!=GetCurrentThreadId() );
- #endif
- LeaveCriticalSection(&pMutex->mutex);
- }
- #ifdef LSM_DEBUG
- static int lsmWin32OsMutexHeld(lsm_mutex *p){
- Win32Mutex *pMutex = (Win32Mutex *)p;
- return pMutex ? pMutex->owner==GetCurrentThreadId() : 1;
- }
- static int lsmWin32OsMutexNotHeld(lsm_mutex *p){
- Win32Mutex *pMutex = (Win32Mutex *)p;
- return pMutex ? pMutex->owner!=GetCurrentThreadId() : 1;
- }
- #endif
- /*
- ** End of Win32 mutex implementation.
- *************************************************************************/
- #else
- /*************************************************************************
- ** Noop mutex implementation
- */
- typedef struct NoopMutex NoopMutex;
- struct NoopMutex {
- lsm_env *pEnv; /* Environment handle (for xFree()) */
- int bHeld; /* True if mutex is held */
- int bStatic; /* True for a static mutex */
- };
- static NoopMutex aStaticNoopMutex[2] = {
- {0, 0, 1},
- {0, 0, 1},
- };
- static int lsmWin32OsMutexStatic(
- lsm_env *pEnv,
- int iMutex,
- lsm_mutex **ppStatic
- ){
- assert( iMutex>=1 && iMutex<=(int)array_size(aStaticNoopMutex) );
- *ppStatic = (lsm_mutex *)&aStaticNoopMutex[iMutex-1];
- return LSM_OK;
- }
- static int lsmWin32OsMutexNew(lsm_env *pEnv, lsm_mutex **ppNew){
- NoopMutex *p;
- p = (NoopMutex *)lsmMallocZero(pEnv, sizeof(NoopMutex));
- if( p ) p->pEnv = pEnv;
- *ppNew = (lsm_mutex *)p;
- return (p ? LSM_OK : LSM_NOMEM_BKPT);
- }
- static void lsmWin32OsMutexDel(lsm_mutex *pMutex) {
- NoopMutex *p = (NoopMutex *)pMutex;
- assert( p->bStatic==0 && p->pEnv );
- lsmFree(p->pEnv, p);
- }
- static void lsmWin32OsMutexEnter(lsm_mutex *pMutex){
- NoopMutex *p = (NoopMutex *)pMutex;
- assert( p->bHeld==0 );
- p->bHeld = 1;
- }
- static int lsmWin32OsMutexTry(lsm_mutex *pMutex){
- NoopMutex *p = (NoopMutex *)pMutex;
- assert( p->bHeld==0 );
- p->bHeld = 1;
- return 0;
- }
- static void lsmWin32OsMutexLeave(lsm_mutex *pMutex){
- NoopMutex *p = (NoopMutex *)pMutex;
- assert( p->bHeld==1 );
- p->bHeld = 0;
- }
- #ifdef LSM_DEBUG
- static int lsmWin32OsMutexHeld(lsm_mutex *pMutex){
- NoopMutex *p = (NoopMutex *)pMutex;
- return p ? p->bHeld : 1;
- }
- static int lsmWin32OsMutexNotHeld(lsm_mutex *pMutex){
- NoopMutex *p = (NoopMutex *)pMutex;
- return p ? !p->bHeld : 1;
- }
- #endif
- /***************************************************************************/
- #endif /* else LSM_MUTEX_NONE */
- /* Without LSM_DEBUG, the MutexHeld tests are never called */
- #ifndef LSM_DEBUG
- # define lsmWin32OsMutexHeld 0
- # define lsmWin32OsMutexNotHeld 0
- #endif
- lsm_env *lsm_default_env(void){
- static lsm_env win32_env = {
- sizeof(lsm_env), /* nByte */
- 1, /* iVersion */
- /***** file i/o ******************/
- 0, /* pVfsCtx */
- lsmWin32OsFullpath, /* xFullpath */
- lsmWin32OsOpen, /* xOpen */
- lsmWin32OsRead, /* xRead */
- lsmWin32OsWrite, /* xWrite */
- lsmWin32OsTruncate, /* xTruncate */
- lsmWin32OsSync, /* xSync */
- lsmWin32OsSectorSize, /* xSectorSize */
- lsmWin32OsRemap, /* xRemap */
- lsmWin32OsFileid, /* xFileid */
- lsmWin32OsClose, /* xClose */
- lsmWin32OsUnlink, /* xUnlink */
- lsmWin32OsLock, /* xLock */
- lsmWin32OsTestLock, /* xTestLock */
- lsmWin32OsShmMap, /* xShmMap */
- lsmWin32OsShmBarrier, /* xShmBarrier */
- lsmWin32OsShmUnmap, /* xShmUnmap */
- /***** memory allocation *********/
- 0, /* pMemCtx */
- lsmWin32OsMalloc, /* xMalloc */
- lsmWin32OsRealloc, /* xRealloc */
- lsmWin32OsFree, /* xFree */
- lsmWin32OsMSize, /* xSize */
- /***** mutexes *********************/
- 0, /* pMutexCtx */
- lsmWin32OsMutexStatic, /* xMutexStatic */
- lsmWin32OsMutexNew, /* xMutexNew */
- lsmWin32OsMutexDel, /* xMutexDel */
- lsmWin32OsMutexEnter, /* xMutexEnter */
- lsmWin32OsMutexTry, /* xMutexTry */
- lsmWin32OsMutexLeave, /* xMutexLeave */
- lsmWin32OsMutexHeld, /* xMutexHeld */
- lsmWin32OsMutexNotHeld, /* xMutexNotHeld */
- /***** other *********************/
- lsmWin32OsSleep, /* xSleep */
- };
- return &win32_env;
- }
- #endif
|