modernc.org/cc@v1.0.1/v2/testdata/_sqlite/ext/lsm1/lsm_win32.c (about) 1 /* 2 ** 2011-12-03 3 ** 4 ** The author disclaims copyright to this source code. In place of 5 ** a legal notice, here is a blessing: 6 ** 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. 10 ** 11 ************************************************************************* 12 ** 13 ** Win32-specific run-time environment implementation for LSM. 14 */ 15 16 #ifdef _WIN32 17 18 #include <assert.h> 19 #include <string.h> 20 21 #include <stdlib.h> 22 #include <stdarg.h> 23 #include <stdio.h> 24 #include <ctype.h> 25 26 #include "windows.h" 27 28 #include "lsmInt.h" 29 30 /* 31 ** An open file is an instance of the following object 32 */ 33 typedef struct Win32File Win32File; 34 struct Win32File { 35 lsm_env *pEnv; /* The run-time environment */ 36 const char *zName; /* Full path to file */ 37 38 HANDLE hFile; /* Open file handle */ 39 HANDLE hShmFile; /* File handle for *-shm file */ 40 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 */ 48 }; 49 50 static char *win32ShmFile(Win32File *pWin32File){ 51 char *zShm; 52 int nName = strlen(pWin32File->zName); 53 zShm = (char *)lsmMallocZero(pWin32File->pEnv, nName+4+1); 54 if( zShm ){ 55 memcpy(zShm, pWin32File->zName, nName); 56 memcpy(&zShm[nName], "-shm", 5); 57 } 58 return zShm; 59 } 60 61 static int win32Sleep(int us){ 62 Sleep((us + 999) / 1000); 63 return LSM_OK; 64 } 65 66 /* 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 70 ** retry. 71 */ 72 #ifndef LSM_WIN32_IOERR_RETRY 73 # define LSM_WIN32_IOERR_RETRY 10 74 #endif 75 #ifndef LSM_WIN32_IOERR_RETRY_DELAY 76 # define LSM_WIN32_IOERR_RETRY_DELAY 25000 77 #endif 78 static int win32IoerrRetry = LSM_WIN32_IOERR_RETRY; 79 static int win32IoerrRetryDelay = LSM_WIN32_IOERR_RETRY_DELAY; 80 81 /* 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. 88 ** 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. 97 */ 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)) 106 #endif 107 108 /* 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 111 ** error. 112 */ 113 static int win32RetryIoerr( 114 lsm_env *pEnv, 115 int *pnRetry 116 ){ 117 DWORD lastErrno; 118 if( *pnRetry>=win32IoerrRetry ){ 119 return 0; 120 } 121 lastErrno = GetLastError(); 122 if( win32IoerrCanRetry1(lastErrno) ){ 123 win32Sleep(win32IoerrRetryDelay*(1+*pnRetry)); 124 ++*pnRetry; 125 return 1; 126 } 127 #if defined(win32IoerrCanRetry2) 128 else if( win32IoerrCanRetry2(lastErrno) ){ 129 win32Sleep(win32IoerrRetryDelay*(1+*pnRetry)); 130 ++*pnRetry; 131 return 1; 132 } 133 #endif 134 return 0; 135 } 136 137 /* 138 ** Convert a UTF-8 string to Microsoft Unicode. 139 ** 140 ** Space to hold the returned string is obtained from lsmMalloc(). 141 */ 142 static LPWSTR win32Utf8ToUnicode(lsm_env *pEnv, const char *zText){ 143 int nChar; 144 LPWSTR zWideText; 145 146 nChar = MultiByteToWideChar(CP_UTF8, 0, zText, -1, NULL, 0); 147 if( nChar==0 ){ 148 return 0; 149 } 150 zWideText = lsmMallocZero(pEnv, nChar * sizeof(WCHAR)); 151 if( zWideText==0 ){ 152 return 0; 153 } 154 nChar = MultiByteToWideChar(CP_UTF8, 0, zText, -1, zWideText, nChar); 155 if( nChar==0 ){ 156 lsmFree(pEnv, zWideText); 157 zWideText = 0; 158 } 159 return zWideText; 160 } 161 162 /* 163 ** Convert a Microsoft Unicode string to UTF-8. 164 ** 165 ** Space to hold the returned string is obtained from lsmMalloc(). 166 */ 167 static char *win32UnicodeToUtf8(lsm_env *pEnv, LPCWSTR zWideText){ 168 int nByte; 169 char *zText; 170 171 nByte = WideCharToMultiByte(CP_UTF8, 0, zWideText, -1, 0, 0, 0, 0); 172 if( nByte == 0 ){ 173 return 0; 174 } 175 zText = lsmMallocZero(pEnv, nByte); 176 if( zText==0 ){ 177 return 0; 178 } 179 nByte = WideCharToMultiByte(CP_UTF8, 0, zWideText, -1, zText, nByte, 0, 0); 180 if( nByte == 0 ){ 181 lsmFree(pEnv, zText); 182 zText = 0; 183 } 184 return zText; 185 } 186 187 #if !defined(win32IsNotFound) 188 #define win32IsNotFound(a) (((a)==ERROR_FILE_NOT_FOUND) || \ 189 ((a)==ERROR_PATH_NOT_FOUND)) 190 #endif 191 192 static int win32Open( 193 lsm_env *pEnv, 194 const char *zFile, 195 int flags, 196 LPHANDLE phFile 197 ){ 198 int rc; 199 LPWSTR zConverted; 200 201 zConverted = win32Utf8ToUnicode(pEnv, zFile); 202 if( zConverted==0 ){ 203 rc = LSM_NOMEM_BKPT; 204 }else{ 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; 210 HANDLE hFile; 211 int nRetry = 0; 212 if( bReadonly ){ 213 dwDesiredAccess = GENERIC_READ; 214 dwCreationDisposition = OPEN_EXISTING; 215 }else{ 216 dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; 217 dwCreationDisposition = OPEN_ALWAYS; 218 } 219 while( (hFile = CreateFileW((LPCWSTR)zConverted, 220 dwDesiredAccess, 221 dwShareMode, NULL, 222 dwCreationDisposition, 223 dwFlagsAndAttributes, 224 NULL))==INVALID_HANDLE_VALUE && 225 win32RetryIoerr(pEnv, &nRetry) ){ 226 /* Noop */ 227 } 228 lsmFree(pEnv, zConverted); 229 if( hFile!=INVALID_HANDLE_VALUE ){ 230 *phFile = hFile; 231 rc = LSM_OK; 232 }else{ 233 if( win32IsNotFound(GetLastError()) ){ 234 rc = lsmErrorBkpt(LSM_IOERR_NOENT); 235 }else{ 236 rc = LSM_IOERR_BKPT; 237 } 238 } 239 } 240 return rc; 241 } 242 243 static int lsmWin32OsOpen( 244 lsm_env *pEnv, 245 const char *zFile, 246 int flags, 247 lsm_file **ppFile 248 ){ 249 int rc = LSM_OK; 250 Win32File *pWin32File; 251 252 pWin32File = lsmMallocZero(pEnv, sizeof(Win32File)); 253 if( pWin32File==0 ){ 254 rc = LSM_NOMEM_BKPT; 255 }else{ 256 HANDLE hFile = NULL; 257 258 rc = win32Open(pEnv, zFile, flags, &hFile); 259 if( rc==LSM_OK ){ 260 memset(&pWin32File->sysInfo, 0, sizeof(SYSTEM_INFO)); 261 GetSystemInfo(&pWin32File->sysInfo); 262 pWin32File->pEnv = pEnv; 263 pWin32File->zName = zFile; 264 pWin32File->hFile = hFile; 265 }else{ 266 lsmFree(pEnv, pWin32File); 267 pWin32File = 0; 268 } 269 } 270 *ppFile = (lsm_file *)pWin32File; 271 return rc; 272 } 273 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 */ 279 ){ 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 */ 285 286 memset(&overlapped, 0, sizeof(OVERLAPPED)); 287 overlapped.Offset = (LONG)(iOff & 0XFFFFFFFF); 288 overlapped.OffsetHigh = (LONG)((iOff>>32) & 0x7FFFFFFF); 289 while( nRem>0 ){ 290 DWORD nWrite = 0; /* Bytes written using WriteFile */ 291 if( !WriteFile(pWin32File->hFile, aRem, nRem, &nWrite, &overlapped) ){ 292 if( win32RetryIoerr(pWin32File->pEnv, &nRetry) ) continue; 293 break; 294 } 295 assert( nWrite==0 || nWrite<=(DWORD)nRem ); 296 if( nWrite==0 || nWrite>(DWORD)nRem ){ 297 break; 298 } 299 iOff += nWrite; 300 overlapped.Offset = (LONG)(iOff & 0xFFFFFFFF); 301 overlapped.OffsetHigh = (LONG)((iOff>>32) & 0x7FFFFFFF); 302 aRem += nWrite; 303 nRem -= nWrite; 304 } 305 if( nRem!=0 ) return LSM_IOERR_BKPT; 306 return LSM_OK; 307 } 308 309 static int win32Truncate( 310 HANDLE hFile, 311 lsm_i64 nSize 312 ){ 313 LARGE_INTEGER offset; 314 offset.QuadPart = nSize; 315 if( !SetFilePointerEx(hFile, offset, 0, FILE_BEGIN) ){ 316 return LSM_IOERR_BKPT; 317 } 318 if (!SetEndOfFile(hFile) ){ 319 return LSM_IOERR_BKPT; 320 } 321 return LSM_OK; 322 } 323 324 static int lsmWin32OsTruncate( 325 lsm_file *pFile, /* File to write to */ 326 lsm_i64 nSize /* Size to truncate file to */ 327 ){ 328 Win32File *pWin32File = (Win32File *)pFile; 329 return win32Truncate(pWin32File->hFile, nSize); 330 } 331 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 */ 337 ){ 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 */ 342 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; 350 } 351 if( nRead<(DWORD)nData ){ 352 /* Unread parts of the buffer must be zero-filled */ 353 memset(&((char*)pData)[nRead], 0, nData - nRead); 354 } 355 return LSM_OK; 356 } 357 358 static int lsmWin32OsSync(lsm_file *pFile){ 359 int rc = LSM_OK; 360 361 #ifndef LSM_NO_SYNC 362 Win32File *pWin32File = (Win32File *)pFile; 363 364 if( pWin32File->pMap!=NULL ){ 365 if( !FlushViewOfFile(pWin32File->pMap, 0) ){ 366 rc = LSM_IOERR_BKPT; 367 } 368 } 369 if( rc==LSM_OK && !FlushFileBuffers(pWin32File->hFile) ){ 370 rc = LSM_IOERR_BKPT; 371 } 372 #else 373 unused_parameter(pFile); 374 #endif 375 376 return rc; 377 } 378 379 static int lsmWin32OsSectorSize(lsm_file *pFile){ 380 return 512; 381 } 382 383 static void win32Unmap(Win32File *pWin32File){ 384 if( pWin32File->pMap!=NULL ){ 385 UnmapViewOfFile(pWin32File->pMap); 386 pWin32File->pMap = NULL; 387 pWin32File->nMap = 0; 388 } 389 if( pWin32File->hMap!=NULL ){ 390 CloseHandle(pWin32File->hMap); 391 pWin32File->hMap = NULL; 392 } 393 } 394 395 static int lsmWin32OsRemap( 396 lsm_file *pFile, 397 lsm_i64 iMin, 398 void **ppOut, 399 lsm_i64 *pnOut 400 ){ 401 Win32File *pWin32File = (Win32File *)pFile; 402 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)]; 407 408 *ppOut = NULL; 409 *pnOut = 0; 410 411 win32Unmap(pWin32File); 412 if( iMin>=0 ){ 413 LARGE_INTEGER fileSize; 414 DWORD dwSizeHigh; 415 DWORD dwSizeLow; 416 HANDLE hMap; 417 LPVOID pMap; 418 memset(&fileSize, 0, sizeof(LARGE_INTEGER)); 419 if( !GetFileSizeEx(pWin32File->hFile, &fileSize) ){ 420 return LSM_IOERR_BKPT; 421 } 422 assert( fileSize.QuadPart>=0 ); 423 if( fileSize.QuadPart<iMin ){ 424 int rc; 425 fileSize.QuadPart = ((iMin + nIncrSz-1) / nIncrSz) * nIncrSz; 426 rc = lsmWin32OsTruncate(pFile, fileSize.QuadPart); 427 if( rc!=LSM_OK ){ 428 return rc; 429 } 430 } 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); 435 if( hMap==NULL ){ 436 return LSM_IOERR_BKPT; 437 } 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); 442 if( pMap==NULL ){ 443 return LSM_IOERR_BKPT; 444 } 445 pWin32File->pMap = pMap; 446 pWin32File->nMap = (SIZE_T)fileSize.QuadPart; 447 } 448 *ppOut = pWin32File->pMap; 449 *pnOut = pWin32File->nMap; 450 return LSM_OK; 451 } 452 453 static BOOL win32IsDriveLetterAndColon( 454 const char *zPathname 455 ){ 456 return ( isalpha(zPathname[0]) && zPathname[1]==':' ); 457 } 458 459 static int lsmWin32OsFullpath( 460 lsm_env *pEnv, 461 const char *zName, 462 char *zOut, 463 int *pnOut 464 ){ 465 DWORD nByte; 466 void *zConverted; 467 LPWSTR zTempWide; 468 char *zTempUtf8; 469 470 if( zName[0]=='/' && win32IsDriveLetterAndColon(zName+1) ){ 471 zName++; 472 } 473 zConverted = win32Utf8ToUnicode(pEnv, zName); 474 if( zConverted==0 ){ 475 return LSM_NOMEM_BKPT; 476 } 477 nByte = GetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0); 478 if( nByte==0 ){ 479 lsmFree(pEnv, zConverted); 480 return LSM_IOERR_BKPT; 481 } 482 nByte += 3; 483 zTempWide = lsmMallocZero(pEnv, nByte * sizeof(zTempWide[0])); 484 if( zTempWide==0 ){ 485 lsmFree(pEnv, zConverted); 486 return LSM_NOMEM_BKPT; 487 } 488 nByte = GetFullPathNameW((LPCWSTR)zConverted, nByte, zTempWide, 0); 489 if( nByte==0 ){ 490 lsmFree(pEnv, zConverted); 491 lsmFree(pEnv, zTempWide); 492 return LSM_IOERR_BKPT; 493 } 494 lsmFree(pEnv, zConverted); 495 zTempUtf8 = win32UnicodeToUtf8(pEnv, zTempWide); 496 lsmFree(pEnv, zTempWide); 497 if( zTempUtf8 ){ 498 int nOut = *pnOut; 499 int nLen = strlen(zTempUtf8) + 1; 500 if( nLen<=nOut ){ 501 snprintf(zOut, nOut, "%s", zTempUtf8); 502 } 503 lsmFree(pEnv, zTempUtf8); 504 *pnOut = nLen; 505 return LSM_OK; 506 }else{ 507 return LSM_NOMEM_BKPT; 508 } 509 } 510 511 static int lsmWin32OsFileid( 512 lsm_file *pFile, 513 void *pBuf, 514 int *pnBuf 515 ){ 516 int nBuf; 517 int nReq; 518 u8 *pBuf2 = (u8 *)pBuf; 519 Win32File *pWin32File = (Win32File *)pFile; 520 BY_HANDLE_FILE_INFORMATION fileInfo; 521 522 nBuf = *pnBuf; 523 nReq = (sizeof(fileInfo.dwVolumeSerialNumber) + 524 sizeof(fileInfo.nFileIndexHigh) + 525 sizeof(fileInfo.nFileIndexLow)); 526 *pnBuf = nReq; 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; 531 } 532 nReq = sizeof(fileInfo.dwVolumeSerialNumber); 533 memcpy(pBuf2, &fileInfo.dwVolumeSerialNumber, nReq); 534 pBuf2 += nReq; 535 nReq = sizeof(fileInfo.nFileIndexHigh); 536 memcpy(pBuf, &fileInfo.nFileIndexHigh, nReq); 537 pBuf2 += nReq; 538 nReq = sizeof(fileInfo.nFileIndexLow); 539 memcpy(pBuf2, &fileInfo.nFileIndexLow, nReq); 540 return LSM_OK; 541 } 542 543 static int win32Delete( 544 lsm_env *pEnv, 545 const char *zFile 546 ){ 547 int rc; 548 LPWSTR zConverted; 549 550 zConverted = win32Utf8ToUnicode(pEnv, zFile); 551 if( zConverted==0 ){ 552 rc = LSM_NOMEM_BKPT; 553 }else{ 554 int nRetry = 0; 555 DWORD attr; 556 557 do { 558 attr = GetFileAttributesW(zConverted); 559 if ( attr==INVALID_FILE_ATTRIBUTES ){ 560 rc = LSM_IOERR_BKPT; 561 break; 562 } 563 if ( attr&FILE_ATTRIBUTE_DIRECTORY ){ 564 rc = LSM_IOERR_BKPT; /* Files only. */ 565 break; 566 } 567 if ( DeleteFileW(zConverted) ){ 568 rc = LSM_OK; /* Deleted OK. */ 569 break; 570 } 571 if ( !win32RetryIoerr(pEnv, &nRetry) ){ 572 rc = LSM_IOERR_BKPT; /* No more retries. */ 573 break; 574 } 575 }while( 1 ); 576 } 577 lsmFree(pEnv, zConverted); 578 return rc; 579 } 580 581 static int lsmWin32OsUnlink(lsm_env *pEnv, const char *zFile){ 582 return win32Delete(pEnv, zFile); 583 } 584 585 #if !defined(win32IsLockBusy) 586 #define win32IsLockBusy(a) (((a)==ERROR_LOCK_VIOLATION) || \ 587 ((a)==ERROR_IO_PENDING)) 588 #endif 589 590 static int win32LockFile( 591 Win32File *pWin32File, 592 int iLock, 593 int nLock, 594 int eType 595 ){ 596 OVERLAPPED ovlp; 597 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 ); 602 assert( nLock>=0 ); 603 assert( iLock>0 && iLock<=32 ); 604 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()) ){ 612 return LSM_BUSY; 613 }else{ 614 return LSM_IOERR_BKPT; 615 } 616 } 617 }else{ 618 if( !UnlockFileEx(pWin32File->hFile, 0, (DWORD)nLock, 0, &ovlp) ){ 619 return LSM_IOERR_BKPT; 620 } 621 } 622 return LSM_OK; 623 } 624 625 static int lsmWin32OsLock(lsm_file *pFile, int iLock, int eType){ 626 Win32File *pWin32File = (Win32File *)pFile; 627 return win32LockFile(pWin32File, iLock, 1, eType); 628 } 629 630 static int lsmWin32OsTestLock(lsm_file *pFile, int iLock, int nLock, int eType){ 631 int rc; 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); 636 return LSM_OK; 637 } 638 639 static int lsmWin32OsShmMap(lsm_file *pFile, int iChunk, int sz, void **ppShm){ 640 int rc; 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; 646 647 *ppShm = NULL; 648 assert( sz>=0 ); 649 assert( sz==LSM_SHM_CHUNK_SIZE ); 650 if( iChunk>=pWin32File->nShm ){ 651 LPHANDLE ahNew; 652 LPVOID *apNew; 653 LARGE_INTEGER fileSize; 654 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); 661 if( rc!=LSM_OK ){ 662 return rc; 663 } 664 } 665 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; 671 } 672 assert( fileSize.QuadPart>=0 ); 673 if( fileSize.QuadPart<nReq ){ 674 rc = win32Truncate(pWin32File->hShmFile, nReq); 675 if( rc!=LSM_OK ){ 676 return rc; 677 } 678 } 679 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); 683 if( !apNew ){ 684 lsmFree(pWin32File->pEnv, ahNew); 685 return LSM_NOMEM_BKPT; 686 } 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; 694 } 695 696 if( pWin32File->ahShm[iChunk]==NULL ){ 697 HANDLE hMap; 698 assert( nReq<=0xFFFFFFFF ); 699 hMap = CreateFileMappingW(pWin32File->hShmFile, NULL, PAGE_READWRITE, 0, 700 (DWORD)nReq, NULL); 701 if( hMap==NULL ){ 702 return LSM_IOERR_BKPT; 703 } 704 pWin32File->ahShm[iChunk] = hMap; 705 } 706 if( pWin32File->apShm[iChunk]==NULL ){ 707 LPVOID pMap; 708 pMap = MapViewOfFile(pWin32File->ahShm[iChunk], 709 FILE_MAP_WRITE | FILE_MAP_READ, 0, 710 iOffset - iOffsetShift, sz + iOffsetShift); 711 if( pMap==NULL ){ 712 return LSM_IOERR_BKPT; 713 } 714 pWin32File->apShm[iChunk] = pMap; 715 } 716 if( iOffsetShift!=0 ){ 717 char *p = (char *)pWin32File->apShm[iChunk]; 718 *ppShm = (void *)&p[iOffsetShift]; 719 }else{ 720 *ppShm = pWin32File->apShm[iChunk]; 721 } 722 return LSM_OK; 723 } 724 725 static void lsmWin32OsShmBarrier(void){ 726 MemoryBarrier(); 727 } 728 729 static int lsmWin32OsShmUnmap(lsm_file *pFile, int bDelete){ 730 Win32File *pWin32File = (Win32File *)pFile; 731 732 if( pWin32File->hShmFile!=NULL ){ 733 int i; 734 for(i=0; i<pWin32File->nShm; i++){ 735 if( pWin32File->apShm[i]!=NULL ){ 736 UnmapViewOfFile(pWin32File->apShm[i]); 737 pWin32File->apShm[i] = NULL; 738 } 739 if( pWin32File->ahShm[i]!=NULL ){ 740 CloseHandle(pWin32File->ahShm[i]); 741 pWin32File->ahShm[i] = NULL; 742 } 743 } 744 CloseHandle(pWin32File->hShmFile); 745 pWin32File->hShmFile = NULL; 746 if( bDelete ){ 747 char *zShm = win32ShmFile(pWin32File); 748 if( zShm ){ win32Delete(pWin32File->pEnv, zShm); } 749 lsmFree(pWin32File->pEnv, zShm); 750 } 751 } 752 return LSM_OK; 753 } 754 755 #define MX_CLOSE_ATTEMPT 3 756 static int lsmWin32OsClose(lsm_file *pFile){ 757 int rc; 758 int nRetry = 0; 759 Win32File *pWin32File = (Win32File *)pFile; 760 lsmWin32OsShmUnmap(pFile, 0); 761 win32Unmap(pWin32File); 762 do{ 763 if( pWin32File->hFile==NULL ){ 764 rc = LSM_IOERR_BKPT; 765 break; 766 } 767 rc = CloseHandle(pWin32File->hFile); 768 if( rc ){ 769 pWin32File->hFile = NULL; 770 rc = LSM_OK; 771 break; 772 } 773 if( ++nRetry>=MX_CLOSE_ATTEMPT ){ 774 rc = LSM_IOERR_BKPT; 775 break; 776 } 777 }while( 1 ); 778 lsmFree(pWin32File->pEnv, pWin32File->ahShm); 779 lsmFree(pWin32File->pEnv, pWin32File->apShm); 780 lsmFree(pWin32File->pEnv, pWin32File); 781 return rc; 782 } 783 784 static int lsmWin32OsSleep(lsm_env *pEnv, int us){ 785 unused_parameter(pEnv); 786 return win32Sleep(us); 787 } 788 789 /**************************************************************************** 790 ** Memory allocation routines. 791 */ 792 793 static void *lsmWin32OsMalloc(lsm_env *pEnv, size_t N){ 794 assert( HeapValidate(GetProcessHeap(), 0, NULL) ); 795 return HeapAlloc(GetProcessHeap(), 0, (SIZE_T)N); 796 } 797 798 static void lsmWin32OsFree(lsm_env *pEnv, void *p){ 799 assert( HeapValidate(GetProcessHeap(), 0, NULL) ); 800 if( p ){ 801 HeapFree(GetProcessHeap(), 0, p); 802 } 803 } 804 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) ); 808 if( 1>N ){ 809 lsmWin32OsFree(pEnv, p); 810 return NULL; 811 }else if( NULL==p ){ 812 return lsmWin32OsMalloc(pEnv, N); 813 }else{ 814 #if 0 /* arguable: don't shrink */ 815 SIZE_T sz = HeapSize(GetProcessHeap(), 0, m); 816 if( sz>=(SIZE_T)N ){ 817 return p; 818 } 819 #endif 820 return HeapReAlloc(GetProcessHeap(), 0, m, N); 821 } 822 } 823 824 static size_t lsmWin32OsMSize(lsm_env *pEnv, void *p){ 825 assert( HeapValidate(GetProcessHeap(), 0, NULL) ); 826 return (size_t)HeapSize(GetProcessHeap(), 0, p); 827 } 828 829 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 834 ** used instead. 835 */ 836 #include "windows.h" 837 838 typedef struct Win32Mutex Win32Mutex; 839 struct Win32Mutex { 840 lsm_env *pEnv; 841 CRITICAL_SECTION mutex; 842 #ifdef LSM_DEBUG 843 DWORD owner; 844 #endif 845 }; 846 847 #ifndef WIN32_MUTEX_INITIALIZER 848 # define WIN32_MUTEX_INITIALIZER { 0 } 849 #endif 850 851 #ifdef LSM_DEBUG 852 # define LSM_WIN32_STATIC_MUTEX { 0, WIN32_MUTEX_INITIALIZER, 0 } 853 #else 854 # define LSM_WIN32_STATIC_MUTEX { 0, WIN32_MUTEX_INITIALIZER } 855 #endif 856 857 static int lsmWin32OsMutexStatic( 858 lsm_env *pEnv, 859 int iMutex, 860 lsm_mutex **ppStatic 861 ){ 862 static volatile LONG initialized = 0; 863 static Win32Mutex sMutex[2] = { 864 LSM_WIN32_STATIC_MUTEX, 865 LSM_WIN32_STATIC_MUTEX 866 }; 867 868 assert( iMutex==LSM_MUTEX_GLOBAL || iMutex==LSM_MUTEX_HEAP ); 869 assert( LSM_MUTEX_GLOBAL==1 && LSM_MUTEX_HEAP==2 ); 870 871 if( InterlockedCompareExchange(&initialized, 1, 0)==0 ){ 872 int i; 873 for(i=0; i<array_size(sMutex); i++){ 874 InitializeCriticalSection(&sMutex[i].mutex); 875 } 876 } 877 *ppStatic = (lsm_mutex *)&sMutex[iMutex-1]; 878 return LSM_OK; 879 } 880 881 static int lsmWin32OsMutexNew(lsm_env *pEnv, lsm_mutex **ppNew){ 882 Win32Mutex *pMutex; /* Pointer to new mutex */ 883 884 pMutex = (Win32Mutex *)lsmMallocZero(pEnv, sizeof(Win32Mutex)); 885 if( !pMutex ) return LSM_NOMEM_BKPT; 886 887 pMutex->pEnv = pEnv; 888 InitializeCriticalSection(&pMutex->mutex); 889 890 *ppNew = (lsm_mutex *)pMutex; 891 return LSM_OK; 892 } 893 894 static void lsmWin32OsMutexDel(lsm_mutex *p){ 895 Win32Mutex *pMutex = (Win32Mutex *)p; 896 DeleteCriticalSection(&pMutex->mutex); 897 lsmFree(pMutex->pEnv, pMutex); 898 } 899 900 static void lsmWin32OsMutexEnter(lsm_mutex *p){ 901 Win32Mutex *pMutex = (Win32Mutex *)p; 902 EnterCriticalSection(&pMutex->mutex); 903 904 #ifdef LSM_DEBUG 905 assert( pMutex->owner!=GetCurrentThreadId() ); 906 pMutex->owner = GetCurrentThreadId(); 907 assert( pMutex->owner==GetCurrentThreadId() ); 908 #endif 909 } 910 911 static int lsmWin32OsMutexTry(lsm_mutex *p){ 912 BOOL bRet; 913 Win32Mutex *pMutex = (Win32Mutex *)p; 914 bRet = TryEnterCriticalSection(&pMutex->mutex); 915 #ifdef LSM_DEBUG 916 if( bRet ){ 917 assert( pMutex->owner!=GetCurrentThreadId() ); 918 pMutex->owner = GetCurrentThreadId(); 919 assert( pMutex->owner==GetCurrentThreadId() ); 920 } 921 #endif 922 return !bRet; 923 } 924 925 static void lsmWin32OsMutexLeave(lsm_mutex *p){ 926 Win32Mutex *pMutex = (Win32Mutex *)p; 927 #ifdef LSM_DEBUG 928 assert( pMutex->owner==GetCurrentThreadId() ); 929 pMutex->owner = 0; 930 assert( pMutex->owner!=GetCurrentThreadId() ); 931 #endif 932 LeaveCriticalSection(&pMutex->mutex); 933 } 934 935 #ifdef LSM_DEBUG 936 static int lsmWin32OsMutexHeld(lsm_mutex *p){ 937 Win32Mutex *pMutex = (Win32Mutex *)p; 938 return pMutex ? pMutex->owner==GetCurrentThreadId() : 1; 939 } 940 static int lsmWin32OsMutexNotHeld(lsm_mutex *p){ 941 Win32Mutex *pMutex = (Win32Mutex *)p; 942 return pMutex ? pMutex->owner!=GetCurrentThreadId() : 1; 943 } 944 #endif 945 /* 946 ** End of Win32 mutex implementation. 947 *************************************************************************/ 948 #else 949 /************************************************************************* 950 ** Noop mutex implementation 951 */ 952 typedef struct NoopMutex NoopMutex; 953 struct 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 */ 957 }; 958 static NoopMutex aStaticNoopMutex[2] = { 959 {0, 0, 1}, 960 {0, 0, 1}, 961 }; 962 963 static int lsmWin32OsMutexStatic( 964 lsm_env *pEnv, 965 int iMutex, 966 lsm_mutex **ppStatic 967 ){ 968 assert( iMutex>=1 && iMutex<=(int)array_size(aStaticNoopMutex) ); 969 *ppStatic = (lsm_mutex *)&aStaticNoopMutex[iMutex-1]; 970 return LSM_OK; 971 } 972 static int lsmWin32OsMutexNew(lsm_env *pEnv, lsm_mutex **ppNew){ 973 NoopMutex *p; 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); 978 } 979 static void lsmWin32OsMutexDel(lsm_mutex *pMutex) { 980 NoopMutex *p = (NoopMutex *)pMutex; 981 assert( p->bStatic==0 && p->pEnv ); 982 lsmFree(p->pEnv, p); 983 } 984 static void lsmWin32OsMutexEnter(lsm_mutex *pMutex){ 985 NoopMutex *p = (NoopMutex *)pMutex; 986 assert( p->bHeld==0 ); 987 p->bHeld = 1; 988 } 989 static int lsmWin32OsMutexTry(lsm_mutex *pMutex){ 990 NoopMutex *p = (NoopMutex *)pMutex; 991 assert( p->bHeld==0 ); 992 p->bHeld = 1; 993 return 0; 994 } 995 static void lsmWin32OsMutexLeave(lsm_mutex *pMutex){ 996 NoopMutex *p = (NoopMutex *)pMutex; 997 assert( p->bHeld==1 ); 998 p->bHeld = 0; 999 } 1000 #ifdef LSM_DEBUG 1001 static int lsmWin32OsMutexHeld(lsm_mutex *pMutex){ 1002 NoopMutex *p = (NoopMutex *)pMutex; 1003 return p ? p->bHeld : 1; 1004 } 1005 static int lsmWin32OsMutexNotHeld(lsm_mutex *pMutex){ 1006 NoopMutex *p = (NoopMutex *)pMutex; 1007 return p ? !p->bHeld : 1; 1008 } 1009 #endif 1010 /***************************************************************************/ 1011 #endif /* else LSM_MUTEX_NONE */ 1012 1013 /* Without LSM_DEBUG, the MutexHeld tests are never called */ 1014 #ifndef LSM_DEBUG 1015 # define lsmWin32OsMutexHeld 0 1016 # define lsmWin32OsMutexNotHeld 0 1017 #endif 1018 1019 lsm_env *lsm_default_env(void){ 1020 static lsm_env win32_env = { 1021 sizeof(lsm_env), /* nByte */ 1022 1, /* iVersion */ 1023 /***** file i/o ******************/ 1024 0, /* pVfsCtx */ 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 *********/ 1042 0, /* pMemCtx */ 1043 lsmWin32OsMalloc, /* xMalloc */ 1044 lsmWin32OsRealloc, /* xRealloc */ 1045 lsmWin32OsFree, /* xFree */ 1046 lsmWin32OsMSize, /* xSize */ 1047 /***** mutexes *********************/ 1048 0, /* pMutexCtx */ 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 */ 1059 }; 1060 return &win32_env; 1061 } 1062 1063 #endif