**
*************************************************************************
**
-** 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>
#include <stdio.h>
#include <ctype.h>
-#include <unistd.h>
-#include <errno.h>
+#include "windows.h"
#include "lsmInt.h"
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);
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,
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;
}
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(
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(
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
/*
*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;
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;
}