📄 os_win.c
字号:
if( fileAttr == 0xffffffff ) return 0; if( (fileAttr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){ return 0; } return 1;}#endif /* SQLITE_OMIT_PAGER_PRAGMAS *//*** Lock the file with the lock specified by parameter locktype - one** of the following:**** (1) SHARED_LOCK** (2) RESERVED_LOCK** (3) PENDING_LOCK** (4) EXCLUSIVE_LOCK**** Sometimes when requesting one lock state, additional lock states** are inserted in between. The locking might fail on one of the later** transitions leaving the lock state different from what it started but** still short of its goal. The following chart shows the allowed** transitions and the inserted intermediate states:**** UNLOCKED -> SHARED** SHARED -> RESERVED** SHARED -> (PENDING) -> EXCLUSIVE** RESERVED -> (PENDING) -> EXCLUSIVE** PENDING -> EXCLUSIVE**** This routine will only increase a lock. The winUnlock() routine** erases all locks at once and returns us immediately to locking level 0.** It is not possible to lower the locking level one step at a time. You** must go straight to locking level 0.*/static int winLock(OsFile *id, int locktype){ int rc = SQLITE_OK; /* Return code from subroutines */ int res = 1; /* Result of a windows lock call */ int newLocktype; /* Set id->locktype to this value before exiting */ int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ winFile *pFile = (winFile*)id; assert( pFile!=0 ); TRACE5("LOCK %d %d was %d(%d)\n", pFile->h, locktype, pFile->locktype, pFile->sharedLockByte); /* If there is already a lock of this type or more restrictive on the ** OsFile, do nothing. Don't use the end_lock: exit path, as ** sqlite3OsEnterMutex() hasn't been called yet. */ if( pFile->locktype>=locktype ){ return SQLITE_OK; } /* Make sure the locking sequence is correct */ assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); assert( locktype!=PENDING_LOCK ); assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of ** the PENDING_LOCK byte is temporary. */ newLocktype = pFile->locktype; if( pFile->locktype==NO_LOCK || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK) ){ int cnt = 3; while( cnt-->0 && (res = LockFile(pFile->h, PENDING_BYTE, 0, 1, 0))==0 ){ /* Try 3 times to get the pending lock. The pending lock might be ** held by another reader process who will release it momentarily. */ TRACE2("could not get a PENDING lock. cnt=%d\n", cnt); Sleep(1); } gotPendingLock = res; } /* Acquire a shared lock */ if( locktype==SHARED_LOCK && res ){ assert( pFile->locktype==NO_LOCK ); res = getReadLock(pFile); if( res ){ newLocktype = SHARED_LOCK; } } /* Acquire a RESERVED lock */ if( locktype==RESERVED_LOCK && res ){ assert( pFile->locktype==SHARED_LOCK ); res = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); if( res ){ newLocktype = RESERVED_LOCK; } } /* Acquire a PENDING lock */ if( locktype==EXCLUSIVE_LOCK && res ){ newLocktype = PENDING_LOCK; gotPendingLock = 0; } /* Acquire an EXCLUSIVE lock */ if( locktype==EXCLUSIVE_LOCK && res ){ assert( pFile->locktype>=SHARED_LOCK ); res = unlockReadLock(pFile); TRACE2("unreadlock = %d\n", res); res = LockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); if( res ){ newLocktype = EXCLUSIVE_LOCK; }else{ TRACE2("error-code = %d\n", GetLastError()); } } /* If we are holding a PENDING lock that ought to be released, then ** release it now. */ if( gotPendingLock && locktype==SHARED_LOCK ){ UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0); } /* Update the state of the lock has held in the file descriptor then ** return the appropriate result code. */ if( res ){ rc = SQLITE_OK; }else{ TRACE4("LOCK FAILED %d trying for %d but got %d\n", pFile->h, locktype, newLocktype); rc = SQLITE_BUSY; } pFile->locktype = newLocktype; return rc;}/*** This routine checks if there is a RESERVED lock held on the specified** file by this or any other process. If such a lock is held, return** non-zero, otherwise zero.*/static int winCheckReservedLock(OsFile *id){ int rc; winFile *pFile = (winFile*)id; assert( pFile!=0 ); if( pFile->locktype>=RESERVED_LOCK ){ rc = 1; TRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc); }else{ rc = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); if( rc ){ UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); } rc = !rc; TRACE3("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc); } return rc;}/*** Lower the locking level on file descriptor id to locktype. locktype** must be either NO_LOCK or SHARED_LOCK.**** If the locking level of the file descriptor is already at or below** the requested locking level, this routine is a no-op.**** It is not possible for this routine to fail if the second argument** is NO_LOCK. If the second argument is SHARED_LOCK then this routine** might return SQLITE_IOERR;*/static int winUnlock(OsFile *id, int locktype){ int type; int rc = SQLITE_OK; winFile *pFile = (winFile*)id; assert( pFile!=0 ); assert( locktype<=SHARED_LOCK ); TRACE5("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype, pFile->locktype, pFile->sharedLockByte); type = pFile->locktype; if( type>=EXCLUSIVE_LOCK ){ UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); if( locktype==SHARED_LOCK && !getReadLock(pFile) ){ /* This should never happen. We should always be able to ** reacquire the read lock */ rc = SQLITE_IOERR; } } if( type>=RESERVED_LOCK ){ UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); } if( locktype==NO_LOCK && type>=SHARED_LOCK ){ unlockReadLock(pFile); } if( type>=PENDING_LOCK ){ UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0); } pFile->locktype = locktype; return rc;}/*** Turn a relative pathname into a full pathname. Return a pointer** to the full pathname stored in space obtained from sqliteMalloc().** The calling function is responsible for freeing this space once it** is no longer needed.*/char *sqlite3WinFullPathname(const char *zRelative){ char *zFull;#if defined(__CYGWIN__) int nByte; nByte = strlen(zRelative) + MAX_PATH + 1001; zFull = sqliteMalloc( nByte ); if( zFull==0 ) return 0; if( cygwin_conv_to_full_win32_path(zRelative, zFull) ) return 0;#elif OS_WINCE /* WinCE has no concept of a relative pathname, or so I am told. */ zFull = sqliteStrDup(zRelative);#else char *zNotUsed; WCHAR *zWide; int nByte; zWide = utf8ToUnicode(zRelative); if( zWide ){ WCHAR *zTemp, *zNotUsedW; nByte = GetFullPathNameW(zWide, 0, 0, &zNotUsedW) + 1; zTemp = sqliteMalloc( nByte*sizeof(zTemp[0]) ); if( zTemp==0 ) return 0; GetFullPathNameW(zWide, nByte, zTemp, &zNotUsedW); sqliteFree(zWide); zFull = unicodeToUtf8(zTemp); sqliteFree(zTemp); }else{ nByte = GetFullPathNameA(zRelative, 0, 0, &zNotUsed) + 1; zFull = sqliteMalloc( nByte*sizeof(zFull[0]) ); if( zFull==0 ) return 0; GetFullPathNameA(zRelative, nByte, zFull, &zNotUsed); }#endif return zFull;}/*** The fullSync option is meaningless on windows. This is a no-op.*/static void winSetFullSync(OsFile *id, int v){ return;}/*** Return the underlying file handle for an OsFile*/static int winFileHandle(OsFile *id){ return (int)((winFile*)id)->h;}/*** Return an integer that indices the type of lock currently held** by this handle. (Used for testing and analysis only.)*/static int winLockState(OsFile *id){ return ((winFile*)id)->locktype;}/*** This vector defines all the methods that can operate on an OsFile** for win32.*/static const IoMethod sqlite3WinIoMethod = { winClose, winOpenDirectory, winRead, winWrite, winSeek, winTruncate, winSync, winSetFullSync, winFileHandle, winFileSize, winLock, winUnlock, winLockState, winCheckReservedLock,};/*** Allocate memory for an OsFile. Initialize the new OsFile** to the value given in pInit and return a pointer to the new** OsFile. If we run out of memory, close the file and return NULL.*/static int allocateWinFile(winFile *pInit, OsFile **pId){ winFile *pNew; pNew = sqliteMalloc( sizeof(*pNew) ); if( pNew==0 ){ CloseHandle(pInit->h);#if OS_WINCE sqliteFree(pInit->zDeleteOnClose);#endif *pId = 0; return SQLITE_NOMEM; }else{ *pNew = *pInit; pNew->pMethod = &sqlite3WinIoMethod; pNew->locktype = NO_LOCK; pNew->sharedLockByte = 0; *pId = (OsFile*)pNew; OpenCounter(+1); return SQLITE_OK; }}#endif /* SQLITE_OMIT_DISKIO *//***************************************************************************** Everything above deals with file I/O. Everything that follows deals** with other miscellanous aspects of the operating system interface****************************************************************************//*** Get information to seed the random number generator. The seed** is written into the buffer zBuf[256]. The calling function must** supply a sufficiently large buffer.*/int sqlite3WinRandomSeed(char *zBuf){ /* We have to initialize zBuf to prevent valgrind from reporting ** errors. The reports issued by valgrind are incorrect - we would ** prefer that the randomness be increased by making use of the ** uninitialized space in zBuf - but valgrind errors tend to worry ** some users. Rather than argue, it seems easier just to initialize ** the whole array and silence valgrind, even if that means less randomness ** in the random seed. ** ** When testing, initializing zBuf[] to zero is all we do. That means ** that we always use the same random number sequence.* This makes the ** tests repeatable. */ memset(zBuf, 0, 256); GetSystemTime((LPSYSTEMTIME)zBuf); return SQLITE_OK;}/*** Sleep for a little while. Return the amount of time slept.*/int sqlite3WinSleep(int ms){ Sleep(ms); return ms;}/*** Static variables used for thread synchronization*/static int inMutex = 0;#ifdef SQLITE_W32_THREADS static DWORD mutexOwner; static CRITICAL_SECTION cs;#endif/*** The following pair of routines implement mutual exclusion for** multi-threaded processes. Only a single thread is allowed to** executed code that is surrounded by EnterMutex() and LeaveMutex().**** SQLite uses only a single Mutex. There is not much critical** code and what little there is executes quickly and without blocking.**** Version 3.3.1 and earlier used a simple mutex. Beginning with** version 3.3.2, a recursive mutex is required.*/void sqlite3WinEnterMutex(){#ifdef SQLITE_W32_THREADS static int isInit = 0; while( !isInit ){ static long lock = 0; if( InterlockedIncrement(&lock)==1 ){ InitializeCriticalSection(&cs); isInit = 1; }else{ Sleep(1); } } EnterCriticalSection(&cs); mutexOwner = GetCurrentThreadId();#endif inMutex++;}void sqlite3WinLeaveMutex(){ assert( inMutex ); inMutex--;#ifdef SQLITE_W32_THREADS assert( mutexOwner==GetCurrentThreadId() ); LeaveCriticalSection(&cs);#endif}/*** Return TRUE if the mutex is currently held.**** If the thisThreadOnly parameter is true, return true if and only if the** calling thread holds the mutex. If the parameter is false, return** true if any thread holds the mutex.*/int sqlite3WinInMutex(int thisThreadOnly){#ifdef SQLITE_W32_THREADS return inMutex>0 && (thisThreadOnly==0 || mutexOwner==GetCurrentThreadId());#else return inMutex>0;#endif}/*** The following variable, if set to a non-zero value, becomes the result** returned from sqlite3OsCurrentTime(). This is used for testing.*/#ifdef SQLITE_TESTint sqlite3_current_time = 0;#endif/*** Find the current time (in Universal Coordinated Time). Write the** current time and date as a Julian Day number into *prNow and** return 0. Return 1 if the time and date cannot be found.*/int sqlite3WinCurrentTime(double *prNow){ FILETIME ft; /* FILETIME structure is a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). */ double now;#if OS_WINCE SYSTEMTIME time; GetSystemTime(&time); SystemTimeToFileTime(&time,&ft);#else GetSystemTimeAsFileTime( &ft );#endif now = ((double)ft.dwHighDateTime) * 4294967296.0; *prNow = (now + ft.dwLowDateTime)/864000000000.0 + 2305813.5;#ifdef SQLITE_TEST if( sqlite3_current_time ){ *prNow = sqlite3_current_time/86400.0 + 2440587.5; }#endif return 0;}/*** Remember the number of thread-specific-data blocks allocated.** Use this to verify that we are not leaking thread-specific-data.** Ticket #1601*/#ifdef SQLITE_TESTint sqlite3_tsd_count = 0;# define TSD_COUNTER_INCR InterlockedIncrement(&sqlite3_tsd_count)# define TSD_COUNTER_DECR InterlockedDecrement(&sqlite3_tsd_count)#else# define TSD_COUNTER_INCR /* no-op */# define TSD_COUNTER_DECR /* no-op */#endif/*** If called with allocateFlag>1, then return a pointer to thread** specific data for the current thread. Allocate and zero the** thread-specific data if it does not already exist necessary.**** If called with allocateFlag==0, then check the current thread** specific data. Return it if it exists. If it does not exist,** then return NULL.**** If called with allocateFlag<0, check to see if the thread specific** data is allocated and is all zero. If it is then deallocate it.** Return a pointer to the thread specific data or NULL if it is** unallocated or gets deallocated.*/ThreadData *sqlite3WinThreadSpecificData(int allocateFlag){ static int key; static int keyInit = 0; static const ThreadData zeroData = {0}; ThreadData *pTsd; if( !keyInit ){ sqlite3OsEnterMutex(); if( !keyInit ){ key = TlsAlloc(); if( key==0xffffffff ){ sqlite3OsLeaveMutex(); return 0; } keyInit = 1; } sqlite3OsLeaveMutex(); } pTsd = TlsGetValue(key); if( allocateFlag>0 ){ if( !pTsd ){ pTsd = sqlite3OsMalloc( sizeof(zeroData) ); if( pTsd ){ *pTsd = zeroData; TlsSetValue(key, pTsd); TSD_COUNTER_INCR; } } }else if( pTsd!=0 && allocateFlag<0 && memcmp(pTsd, &zeroData, sizeof(ThreadData))==0 ){ sqlite3OsFree(pTsd); TlsSetValue(key, 0); TSD_COUNTER_DECR; pTsd = 0; } return pTsd;}#endif /* OS_WIN */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -