diff options
Diffstat (limited to 'ext/lsm1/lsm_win32.c')
-rw-r--r-- | ext/lsm1/lsm_win32.c | 743 |
1 files changed, 351 insertions, 392 deletions
diff --git a/ext/lsm1/lsm_win32.c b/ext/lsm1/lsm_win32.c index 73e5bcb5b..8c047bcbc 100644 --- a/ext/lsm1/lsm_win32.c +++ b/ext/lsm1/lsm_win32.c @@ -10,23 +10,11 @@ ** ************************************************************************* ** -** Unix-specific run-time environment implementation for LSM. +** Win32-specific run-time environment implementation for LSM. */ -#ifdef WIN32 +#ifdef _WIN32 -#if defined(__GNUC__) || defined(__TINYC__) -/* workaround for ftruncate() visibility on gcc. */ -# ifndef _XOPEN_SOURCE -# define _XOPEN_SOURCE 500 -# endif -#endif - -#include <unistd.h> -#include <sys/types.h> - -#include <sys/stat.h> -#include <fcntl.h> #include <assert.h> #include <string.h> @@ -35,8 +23,7 @@ #include <stdio.h> #include <ctype.h> -#include <unistd.h> -#include <errno.h> +#include "windows.h" #include "lsmInt.h" @@ -48,19 +35,22 @@ struct Win32File { lsm_env *pEnv; /* The run-time environment */ const char *zName; /* Full path to file */ - HANDLE h; /* Open file descriptor */ - HANDLE shmh; /* File descriptor for *-shm file */ + HANDLE hFile; /* Open file handle */ + HANDLE hShmFile; /* File handle for *-shm file */ + HANDLE hMap; /* File handle for mapping */ void *pMap; /* Pointer to mapping of file fd */ - off_t nMap; /* Size of mapping at pMap in bytes */ + size_t nMap; /* Size of mapping at pMap in bytes */ int nShm; /* Number of entries in array apShm[] */ void **apShm; /* Array of 32K shared memory segments */ }; +int lsmWin32OsSleep(lsm_env *pEnv, int us); + static char *win32ShmFile(Win32File *p){ char *zShm; int nName = strlen(p->zName); - zShm = (char *)lsmMalloc(p->pEnv, nName+4+1); + zShm = (char *)lsmMallocZero(p->pEnv, nName+4+1); if( zShm ){ memcpy(zShm, p->zName, nName); memcpy(&zShm[nName], "-shm", 5); @@ -68,6 +58,107 @@ static char *win32ShmFile(Win32File *p){ return zShm; } +/* +** 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) ){ + lsmWin32OsSleep(pEnv, win32IoerrRetryDelay*(1+*pnRetry)); + ++*pnRetry; + return 1; + } +#if defined(win32IoerrCanRetry2) + else if( win32IoerrCanRetry2(lastErrno) ){ + lsmWin32OsSleep(pEnv, 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; +} + +#if !defined(win32IsNotFound) +#define win32IsNotFound(a) (((a)==ERROR_FILE_NOT_FOUND) || \ + ((a)==ERROR_PATH_NOT_FOUND)) +#endif + static int lsmWin32OsOpen( lsm_env *pEnv, const char *zFile, @@ -75,122 +166,155 @@ static int lsmWin32OsOpen( lsm_file **ppFile ){ int rc = LSM_OK; - Win32File *p; + Win32File *pWin32File; - p = lsm_malloc(pEnv, sizeof(Win32File)); - if( p==0 ){ - rc = LSM_NOMEM; + pWin32File = lsmMallocZero(pEnv, sizeof(Win32File)); + if( pWin32File==0 ){ + rc = LSM_NOMEM_BKPT; }else{ + LPCWSTR zConverted; int bReadonly = (flags & LSM_OPEN_READONLY); - int oflags = (bReadonly ? O_RDONLY : (O_RDWR|O_CREAT)); - memset(p, 0, sizeof(Win32File)); - p->zName = zFile; - p->pEnv = pEnv; - - CreateFile((LPCWSTR)zConverted, - dwDesiredAccess, - dwShareMode, NULL, - dwCreationDisposition, - dwFlagsAndAttributes, - NULL))==INVALID_HANDLE_VALUE && - winRetryIoerr(&cnt, &lastErrno) ){ - - - p->fd = open(zFile, oflags, 0644); - if( p->fd<0 ){ - lsm_free(pEnv, p); - p = 0; - if( errno==ENOENT ){ - rc = lsmErrorBkpt(LSM_IOERR_NOENT); + DWORD dwDesiredAccess; + DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; + DWORD dwCreationDisposition; + DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; + HANDLE hFile; + + zConverted = win32Utf8ToUnicode(pEnv, zFile); + if( zConverted==0 ){ + lsmFree(pEnv, pWin32File); + pWin32File = 0; + rc = LSM_NOMEM_BKPT; + }else{ + 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 */ + } + if( hFile!=INVALID_HANDLE_VALUE ){ + pWin32File->pEnv = pEnv; + pWin32File->zName = zFile; + pWin32File->hFile = hFile; }else{ - rc = LSM_IOERR_BKPT; + lsmFree(pEnv, pWin32File); + pWin32File = 0; + if( win32IsNotFound(GetLastError()) ){ + rc = lsmErrorBkpt(LSM_IOERR_NOENT); + }else{ + rc = LSM_IOERR_BKPT; + } } } } - - *ppFile = (lsm_file *)p; + *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 */ + 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 */ ){ - int rc = LSM_OK; - Win32File *p = (Win32File *)pFile; - off_t offset; - - offset = lseek(p->fd, (off_t)iOff, SEEK_SET); - if( offset!=iOff ){ - rc = LSM_IOERR_BKPT; - }else{ - ssize_t prc = write(p->fd, pData, (size_t)nData); - if( prc<0 ) rc = LSM_IOERR_BKPT; + 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; } - - return rc; + if( nRem!=0 ) 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 */ + lsm_file *pFile, /* File to write to */ + lsm_i64 nSize /* Size to truncate file to */ ){ - Win32File *p = (Win32File *)pFile; - int rc = LSM_OK; /* Return code */ - int prc; /* Posix Return Code */ - struct stat sStat; /* Result of fstat() invocation */ - - prc = fstat(p->fd, &sStat); - if( prc==0 && sStat.st_size>nSize ){ - prc = ftruncate(p->fd, (off_t)nSize); - } - if( prc<0 ) rc = LSM_IOERR_BKPT; + Win32File *pWin32File = (Win32File *)pFile; + LARGE_INTEGER largeInteger; /* The new offset */ - return rc; + largeInteger.QuadPart = nSize; + if( !SetFilePointerEx(pWin32File->hFile, largeInteger, 0, FILE_BEGIN) ){ + return LSM_IOERR_BKPT; + } + if (!SetEndOfFile(pWin32File->hFile) ){ + return LSM_IOERR_BKPT; + } + return LSM_OK; } 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 */ + 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 */ ){ - int rc = LSM_OK; - Win32File *p = (Win32File *)pFile; - off_t offset; - - offset = lseek(p->fd, (off_t)iOff, SEEK_SET); - if( offset!=iOff ){ - rc = LSM_IOERR_BKPT; - }else{ - ssize_t prc = read(p->fd, pData, (size_t)nData); - if( prc<0 ){ - rc = LSM_IOERR_BKPT; - }else if( prc<nData ){ - memset(&((u8 *)pData)[prc], 0, nData - prc); - } - + 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; } - - return rc; + 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 *p = (Win32File *)pFile; - int prc = 0; + Win32File *pWin32File = (Win32File *)pFile; - if( p->pMap ){ - prc = msync(p->pMap, p->nMap, MS_SYNC); + if( pWin32File->pMap ){ + if( !FlushViewOfFile(pWin32File->pMap, 0) ){ + rc = LSM_IOERR_BKPT; + } + } + if( rc==LSM_OK && !FlushFileBuffers(pWin32File->hFile) ){ + rc = LSM_IOERR_BKPT; } - if( prc==0 ) prc = fdatasync(p->fd); - if( prc<0 ) rc = LSM_IOERR_BKPT; #else - (void)pFile; #endif return rc; @@ -201,45 +325,12 @@ static int lsmWin32OsSectorSize(lsm_file *pFile){ } static int lsmWin32OsRemap( - lsm_file *pFile, - lsm_i64 iMin, + lsm_file *pFile, + lsm_i64 iMin, void **ppOut, lsm_i64 *pnOut ){ - off_t iSz; - int prc; - Win32File *p = (Win32File *)pFile; - struct stat buf; - - /* 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)]; - - if( p->pMap ){ - munmap(p->pMap, p->nMap); - *ppOut = p->pMap = 0; - *pnOut = p->nMap = 0; - } - - if( iMin>=0 ){ - memset(&buf, 0, sizeof(buf)); - prc = fstat(p->fd, &buf); - if( prc!=0 ) return LSM_IOERR_BKPT; - iSz = buf.st_size; - if( iSz<iMin ){ - iSz = ((iMin + nIncrSz-1) / nIncrSz) * nIncrSz; - prc = ftruncate(p->fd, iSz); - if( prc!=0 ) return LSM_IOERR_BKPT; - } - - p->pMap = mmap(0, iSz, PROT_READ|PROT_WRITE, MAP_SHARED, p->fd, 0); - p->nMap = iSz; - } - - *ppOut = p->pMap; - *pnOut = p->nMap; - return LSM_OK; + return LSM_ERROR; } static int lsmWin32OsFullpath( @@ -248,298 +339,163 @@ static int lsmWin32OsFullpath( char *zOut, int *pnOut ){ - int nBuf = *pnOut; - int nReq; - - if( zName[0]!='/' ){ - char *z; - char *zTmp; - int nTmp = 512; - zTmp = lsmMalloc(pEnv, nTmp); - while( zTmp ){ - z = getcwd(zTmp, nTmp); - if( z || errno!=ERANGE ) break; - nTmp = nTmp*2; - zTmp = lsmReallocOrFree(pEnv, zTmp, nTmp); - } - if( zTmp==0 ) return LSM_NOMEM_BKPT; - if( z==0 ) return LSM_IOERR_BKPT; - assert( z==zTmp ); - - nTmp = strlen(zTmp); - nReq = nTmp + 1 + strlen(zName) + 1; - if( nReq<=nBuf ){ - memcpy(zOut, zTmp, nTmp); - zOut[nTmp] = '/'; - memcpy(&zOut[nTmp+1], zName, strlen(zName)+1); - } - lsmFree(pEnv, zTmp); - }else{ - nReq = strlen(zName)+1; - if( nReq<=nBuf ){ - memcpy(zOut, zName, strlen(zName)+1); - } - } - - *pnOut = nReq; - return LSM_OK; + return LSM_ERROR; } static int lsmWin32OsFileid( - lsm_file *pFile, + lsm_file *pFile, void *pBuf, int *pnBuf ){ - int prc; int nBuf; int nReq; - Win32File *p = (Win32File *)pFile; - struct stat buf; + u8 *pBuf2 = (u8 *)pBuf; + Win32File *pWin32File = (Win32File *)pFile; + BY_HANDLE_FILE_INFORMATION fileInfo; nBuf = *pnBuf; - nReq = (sizeof(buf.st_dev) + sizeof(buf.st_ino)); + nReq = (sizeof(fileInfo.dwVolumeSerialNumber) + + sizeof(fileInfo.nFileIndexHigh) + + sizeof(fileInfo.nFileIndexLow)); *pnBuf = nReq; if( nReq>nBuf ) return LSM_OK; - - memset(&buf, 0, sizeof(buf)); - prc = fstat(p->fd, &buf); - if( prc!=0 ) return LSM_IOERR_BKPT; - - memcpy(pBuf, &buf.st_dev, sizeof(buf.st_dev)); - memcpy(&(((u8 *)pBuf)[sizeof(buf.st_dev)]), &buf.st_ino, sizeof(buf.st_ino)); + 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 lsmWin32OsUnlink(lsm_env *pEnv, const char *zFile){ - int prc = unlink(zFile); - return prc ? LSM_IOERR_BKPT : LSM_OK; + return LSM_ERROR; } int lsmWin32OsLock(lsm_file *pFile, int iLock, int eType){ - int rc = LSM_OK; - Win32File *p = (Win32File *)pFile; - static const short aType[3] = { F_UNLCK, F_RDLCK, F_WRLCK }; - struct flock lock; - - assert( aType[LSM_LOCK_UNLOCK]==F_UNLCK ); - assert( aType[LSM_LOCK_SHARED]==F_RDLCK ); - assert( aType[LSM_LOCK_EXCL]==F_WRLCK ); - assert( eType>=0 && eType<array_size(aType) ); - assert( iLock>0 && iLock<=32 ); - - memset(&lock, 0, sizeof(lock)); - lock.l_whence = SEEK_SET; - lock.l_len = 1; - lock.l_type = aType[eType]; - lock.l_start = (4096-iLock); - - if( fcntl(p->fd, F_SETLK, &lock) ){ - int e = errno; - if( e==EACCES || e==EAGAIN ){ - rc = LSM_BUSY; - }else{ - rc = LSM_IOERR_BKPT; - } - } - - return rc; + return LSM_ERROR; } int lsmWin32OsTestLock(lsm_file *pFile, int iLock, int nLock, int eType){ - int rc = LSM_OK; - Win32File *p = (Win32File *)pFile; - static const short aType[3] = { 0, F_RDLCK, F_WRLCK }; - struct flock lock; - - assert( eType==LSM_LOCK_SHARED || eType==LSM_LOCK_EXCL ); - assert( aType[LSM_LOCK_SHARED]==F_RDLCK ); - assert( aType[LSM_LOCK_EXCL]==F_WRLCK ); - assert( eType>=0 && eType<array_size(aType) ); - assert( iLock>0 && iLock<=32 ); - - memset(&lock, 0, sizeof(lock)); - lock.l_whence = SEEK_SET; - lock.l_len = nLock; - lock.l_type = aType[eType]; - lock.l_start = (4096-iLock); - - if( fcntl(p->fd, F_GETLK, &lock) ){ - rc = LSM_IOERR_BKPT; - }else if( lock.l_type!=F_UNLCK ){ - rc = LSM_BUSY; - } - - return rc; + return LSM_ERROR; } int lsmWin32OsShmMap(lsm_file *pFile, int iChunk, int sz, void **ppShm){ - Win32File *p = (Win32File *)pFile; - - *ppShm = 0; - assert( sz==LSM_SHM_CHUNK_SIZE ); - if( iChunk>=p->nShm ){ - int i; - void **apNew; - int nNew = iChunk+1; - off_t nReq = nNew * LSM_SHM_CHUNK_SIZE; - struct stat sStat; - - /* If the shared-memory file has not been opened, open it now. */ - if( p->shmfd<=0 ){ - char *zShm = win32ShmFile(p); - if( !zShm ) return LSM_NOMEM_BKPT; - p->shmfd = open(zShm, O_RDWR|O_CREAT, 0644); - lsmFree(p->pEnv, zShm); - if( p->shmfd<0 ){ - return LSM_IOERR_BKPT; - } - } - - /* If the shared-memory file is not large enough to contain the - ** requested chunk, cause it to grow. */ - if( fstat(p->shmfd, &sStat) ){ - return LSM_IOERR_BKPT; - } - if( sStat.st_size<nReq ){ - if( ftruncate(p->shmfd, nReq) ){ - return LSM_IOERR_BKPT; - } - } - - apNew = (void **)lsmRealloc(p->pEnv, p->apShm, sizeof(void *) * nNew); - if( !apNew ) return LSM_NOMEM_BKPT; - for(i=p->nShm; i<nNew; i++){ - apNew[i] = 0; - } - p->apShm = apNew; - p->nShm = nNew; - } - - if( p->apShm[iChunk]==0 ){ - p->apShm[iChunk] = mmap(0, LSM_SHM_CHUNK_SIZE, - PROT_READ|PROT_WRITE, MAP_SHARED, p->shmfd, iChunk*LSM_SHM_CHUNK_SIZE - ); - if( p->apShm[iChunk]==0 ) return LSM_IOERR_BKPT; - } - - *ppShm = p->apShm[iChunk]; - return LSM_OK; + return LSM_ERROR; } void lsmWin32OsShmBarrier(void){ + MemoryBarrier(); } int lsmWin32OsShmUnmap(lsm_file *pFile, int bDelete){ - Win32File *p = (Win32File *)pFile; - if( p->shmfd>0 ){ - int i; - for(i=0; i<p->nShm; i++){ - if( p->apShm[i] ){ - munmap(p->apShm[i], LSM_SHM_CHUNK_SIZE); - p->apShm[i] = 0; - } - } - close(p->shmfd); - p->shmfd = 0; - if( bDelete ){ - char *zShm = win32ShmFile(p); - if( zShm ) unlink(zShm); - lsmFree(p->pEnv, zShm); - } - } - return LSM_OK; + return LSM_ERROR; } - +#define MX_CLOSE_ATTEMPT 3 static int lsmWin32OsClose(lsm_file *pFile){ - Win32File *p = (Win32File *)pFile; + int rc; + int nRetry = 0; + Win32File *pWin32File = (Win32File *)pFile; lsmWin32OsShmUnmap(pFile, 0); - if( p->pMap ) munmap(p->pMap, p->nMap); - close(p->fd); - lsm_free(p->pEnv, p->apShm); - lsm_free(p->pEnv, p); - return LSM_OK; + if( pWin32File->pMap ){ + UnmapViewOfFile(pWin32File->pMap); + pWin32File->pMap = 0; + } + if( pWin32File->hMap!=NULL ){ + CloseHandle(pWin32File->hMap); + pWin32File->hMap = NULL; + } + do{ + rc = CloseHandle(pWin32File->hFile); + if( rc ){ + rc = LSM_OK; + break; + } + if( ++nRetry>=MX_CLOSE_ATTEMPT ){ + rc = LSM_IOERR_BKPT; + break; + } + }while( 1 ); + lsmFree(pWin32File->pEnv, pWin32File->apShm); + lsmFree(pWin32File->pEnv, pWin32File); + return rc; } static int lsmWin32OsSleep(lsm_env *pEnv, int us){ - usleep(us); + unused_parameter(pEnv); + Sleep((us + 999) / 1000); return LSM_OK; } /**************************************************************************** ** Memory allocation routines. */ -#define BLOCK_HDR_SIZE ROUND8( sizeof(size_t) ) static void *lsmWin32OsMalloc(lsm_env *pEnv, size_t N){ - unsigned char * m; - N += BLOCK_HDR_SIZE; - m = (unsigned char *)malloc(N); - *((size_t*)m) = N; - return m + BLOCK_HDR_SIZE; + return HeapAlloc(GetProcessHeap(), 0, (SIZE_T)N); } static void lsmWin32OsFree(lsm_env *pEnv, void *p){ - if(p){ - free( ((unsigned char *)p) - BLOCK_HDR_SIZE ); + if( p ){ + HeapFree(GetProcessHeap(), 0, p); } } static void *lsmWin32OsRealloc(lsm_env *pEnv, void *p, size_t N){ - unsigned char * m = (unsigned char *)p; - if(1>N){ - lsmWin32OsFree( pEnv, p ); + unsigned char *m = (unsigned char *)p; + if( 1>N ){ + lsmWin32OsFree(pEnv, p); return NULL; - }else if(NULL==p){ + }else if( NULL==p ){ return lsmWin32OsMalloc(pEnv, N); }else{ - void * re = NULL; - m -= BLOCK_HDR_SIZE; #if 0 /* arguable: don't shrink */ - size_t * sz = (size_t*)m; - if(*sz >= (size_t)N){ + SIZE_T sz = HeapSize(GetProcessHeap(), 0, m); + if( sz>=(SIZE_T)N ){ return p; } #endif - re = realloc( m, N + BLOCK_HDR_SIZE ); - if(re){ - m = (unsigned char *)re; - *((size_t*)m) = N; - return m + BLOCK_HDR_SIZE; - }else{ - return NULL; - } + return HeapReAlloc(GetProcessHeap(), 0, m, N); } } static size_t lsmWin32OsMSize(lsm_env *pEnv, void *p){ - unsigned char * m = (unsigned char *)p; - return *((size_t*)(m-BLOCK_HDR_SIZE)); + return (size_t)HeapSize(GetProcessHeap(), 0, p); } -#undef BLOCK_HDR_SIZE -#ifdef LSM_MUTEX_WIN32 +#ifdef LSM_MUTEX_WIN32 /************************************************************************* -** Mutex methods for pthreads based systems. If LSM_MUTEX_WIN32 is -** missing then a no-op implementation of mutexes found below will be +** 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 <pthread.h> +#include "windows.h" -typedef struct PthreadMutex PthreadMutex; -struct PthreadMutex { +typedef struct Win32Mutex Win32Mutex; +struct Win32Mutex { lsm_env *pEnv; - pthread_mutex_t mutex; + CRITICAL_SECTION mutex; #ifdef LSM_DEBUG - pthread_t owner; + DWORD owner; #endif }; +#ifndef WIN32_MUTEX_INITIALIZER +# define WIN32_MUTEX_INITIALIZER { 0 } +#endif + #ifdef LSM_DEBUG -# define LSM_PTHREAD_STATIC_MUTEX { 0, PTHREAD_MUTEX_INITIALIZER, 0 } +# define LSM_WIN32_STATIC_MUTEX { 0, WIN32_MUTEX_INITIALIZER, 0 } #else -# define LSM_PTHREAD_STATIC_MUTEX { 0, PTHREAD_MUTEX_INITIALIZER } +# define LSM_WIN32_STATIC_MUTEX { 0, WIN32_MUTEX_INITIALIZER } #endif static int lsmWin32OsMutexStatic( @@ -547,84 +503,87 @@ static int lsmWin32OsMutexStatic( int iMutex, lsm_mutex **ppStatic ){ - static PthreadMutex sMutex[2] = { - LSM_PTHREAD_STATIC_MUTEX, - LSM_PTHREAD_STATIC_MUTEX + 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){ - PthreadMutex *pMutex; /* Pointer to new mutex */ - pthread_mutexattr_t attr; /* Attributes object */ + Win32Mutex *pMutex; /* Pointer to new mutex */ - pMutex = (PthreadMutex *)lsmMallocZero(pEnv, sizeof(PthreadMutex)); + pMutex = (Win32Mutex *)lsmMallocZero(pEnv, sizeof(Win32Mutex)); if( !pMutex ) return LSM_NOMEM_BKPT; pMutex->pEnv = pEnv; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&pMutex->mutex, &attr); - pthread_mutexattr_destroy(&attr); + InitializeCriticalSection(&pMutex->mutex); *ppNew = (lsm_mutex *)pMutex; return LSM_OK; } static void lsmWin32OsMutexDel(lsm_mutex *p){ - PthreadMutex *pMutex = (PthreadMutex *)p; - pthread_mutex_destroy(&pMutex->mutex); + Win32Mutex *pMutex = (Win32Mutex *)p; + DeleteCriticalSection(&pMutex->mutex); lsmFree(pMutex->pEnv, pMutex); } static void lsmWin32OsMutexEnter(lsm_mutex *p){ - PthreadMutex *pMutex = (PthreadMutex *)p; - pthread_mutex_lock(&pMutex->mutex); + Win32Mutex *pMutex = (Win32Mutex *)p; + EnterCriticalSection(&pMutex->mutex); #ifdef LSM_DEBUG - assert( !pthread_equal(pMutex->owner, pthread_self()) ); - pMutex->owner = pthread_self(); - assert( pthread_equal(pMutex->owner, pthread_self()) ); + assert( pMutex->owner!=GetCurrentThreadId() ); + pMutex->owner = GetCurrentThreadId(); + assert( pMutex->owner==GetCurrentThreadId() ); #endif } static int lsmWin32OsMutexTry(lsm_mutex *p){ - int ret; - PthreadMutex *pMutex = (PthreadMutex *)p; - ret = pthread_mutex_trylock(&pMutex->mutex); + BOOL bRet; + Win32Mutex *pMutex = (Win32Mutex *)p; + bRet = TryEnterCriticalSection(&pMutex->mutex); #ifdef LSM_DEBUG - if( ret==0 ){ - assert( !pthread_equal(pMutex->owner, pthread_self()) ); - pMutex->owner = pthread_self(); - assert( pthread_equal(pMutex->owner, pthread_self()) ); + if( bRet ){ + assert( pMutex->owner!=GetCurrentThreadId() ); + pMutex->owner = GetCurrentThreadId(); + assert( pMutex->owner==GetCurrentThreadId() ); } #endif - return ret; + return !bRet; } static void lsmWin32OsMutexLeave(lsm_mutex *p){ - PthreadMutex *pMutex = (PthreadMutex *)p; + Win32Mutex *pMutex = (Win32Mutex *)p; #ifdef LSM_DEBUG - assert( pthread_equal(pMutex->owner, pthread_self()) ); + assert( pMutex->owner==GetCurrentThreadId() ); pMutex->owner = 0; - assert( !pthread_equal(pMutex->owner, pthread_self()) ); + assert( pMutex->owner!=GetCurrentThreadId() ); #endif - pthread_mutex_unlock(&pMutex->mutex); + LeaveCriticalSection(&pMutex->mutex); } #ifdef LSM_DEBUG static int lsmWin32OsMutexHeld(lsm_mutex *p){ - PthreadMutex *pMutex = (PthreadMutex *)p; - return pMutex ? pthread_equal(pMutex->owner, pthread_self()) : 1; + Win32Mutex *pMutex = (Win32Mutex *)p; + return pMutex ? pMutex->owner==GetCurrentThreadId() : 1; } static int lsmWin32OsMutexNotHeld(lsm_mutex *p){ - PthreadMutex *pMutex = (PthreadMutex *)p; - return pMutex ? !pthread_equal(pMutex->owner, pthread_self()) : 1; + Win32Mutex *pMutex = (Win32Mutex *)p; + return pMutex ? pMutex->owner!=GetCurrentThreadId() : 1; } #endif /* @@ -661,12 +620,12 @@ static int lsmWin32OsMutexNew(lsm_env *pEnv, lsm_mutex **ppNew){ *ppNew = (lsm_mutex *)p; return (p ? LSM_OK : LSM_NOMEM_BKPT); } -static void lsmWin32OsMutexDel(lsm_mutex *pMutex) { +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){ +static void lsmWin32OsMutexEnter(lsm_mutex *pMutex){ NoopMutex *p = (NoopMutex *)pMutex; assert( p->bHeld==0 ); p->bHeld = 1; @@ -677,17 +636,17 @@ static int lsmWin32OsMutexTry(lsm_mutex *pMutex){ p->bHeld = 1; return 0; } -static void lsmWin32OsMutexLeave(lsm_mutex *pMutex){ +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){ +static int lsmWin32OsMutexHeld(lsm_mutex *pMutex){ NoopMutex *p = (NoopMutex *)pMutex; return p ? p->bHeld : 1; } -static int lsmWin32OsMutexNotHeld(lsm_mutex *pMutex){ +static int lsmWin32OsMutexNotHeld(lsm_mutex *pMutex){ NoopMutex *p = (NoopMutex *)pMutex; return p ? !p->bHeld : 1; } |