📄 os_unix.c
字号:
s = fcntl(fd, op, p); sqlite3DebugPrintf("fcntl unknown %d %d %d\n", fd, op, s); return s; } if( p->l_type==F_RDLCK ){ zType = "RDLCK"; }else if( p->l_type==F_WRLCK ){ zType = "WRLCK"; }else if( p->l_type==F_UNLCK ){ zType = "UNLCK"; }else{ assert( 0 ); } assert( p->l_whence==SEEK_SET ); s = fcntl(fd, op, p); savedErrno = errno; sqlite3DebugPrintf("fcntl %d %d %s %s %d %d %d %d\n", threadid, fd, zOpName, zType, (int)p->l_start, (int)p->l_len, (int)p->l_pid, s); if( s==(-1) && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){ struct flock l2; l2 = *p; fcntl(fd, F_GETLK, &l2); if( l2.l_type==F_RDLCK ){ zType = "RDLCK"; }else if( l2.l_type==F_WRLCK ){ zType = "WRLCK"; }else if( l2.l_type==F_UNLCK ){ zType = "UNLCK"; }else{ assert( 0 ); } sqlite3DebugPrintf("fcntl-failure-reason: %s %d %d %d\n", zType, (int)l2.l_start, (int)l2.l_len, (int)l2.l_pid); } errno = savedErrno; return s;}#define fcntl lockTrace#endif /* SQLITE_LOCK_TRACE *//*** The testThreadLockingBehavior() routine launches two separate** threads on this routine. This routine attempts to lock a file** descriptor then returns. The success or failure of that attempt** allows the testThreadLockingBehavior() procedure to determine** whether or not threads can override each others locks.*/static void *threadLockingTest(void *pArg){ struct threadTestData *pData = (struct threadTestData*)pArg; pData->result = fcntl(pData->fd, F_SETLK, &pData->lock); return pArg;}/*** This procedure attempts to determine whether or not threads** can override each others locks then sets the ** threadsOverrideEachOthersLocks variable appropriately.*/static void testThreadLockingBehavior(int fd_orig){ int fd; struct threadTestData d[2]; pthread_t t[2]; fd = dup(fd_orig); if( fd<0 ) return; memset(d, 0, sizeof(d)); d[0].fd = fd; d[0].lock.l_type = F_RDLCK; d[0].lock.l_len = 1; d[0].lock.l_start = 0; d[0].lock.l_whence = SEEK_SET; d[1] = d[0]; d[1].lock.l_type = F_WRLCK; pthread_create(&t[0], 0, threadLockingTest, &d[0]); pthread_create(&t[1], 0, threadLockingTest, &d[1]); pthread_join(t[0], 0); pthread_join(t[1], 0); close(fd); threadsOverrideEachOthersLocks = d[0].result==0 && d[1].result==0;}#endif /* SQLITE_THREADSAFE *//*** Release a lockInfo structure previously allocated by findLockInfo().*/static void releaseLockInfo(struct lockInfo *pLock){ if (pLock == NULL) return; pLock->nRef--; if( pLock->nRef==0 ){ sqlite3HashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0); sqlite3_free(pLock); }}/*** Release a openCnt structure previously allocated by findLockInfo().*/static void releaseOpenCnt(struct openCnt *pOpen){ if (pOpen == NULL) return; pOpen->nRef--; if( pOpen->nRef==0 ){ sqlite3HashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0); free(pOpen->aPending); sqlite3_free(pOpen); }}#ifdef SQLITE_ENABLE_LOCKING_STYLE/*** Tests a byte-range locking query to see if byte range locks are ** supported, if not we fall back to dotlockLockingStyle.*/static sqlite3LockingStyle sqlite3TestLockingStyle( const char *filePath, int fd){ /* test byte-range lock using fcntl */ struct flock lockInfo; lockInfo.l_len = 1; lockInfo.l_start = 0; lockInfo.l_whence = SEEK_SET; lockInfo.l_type = F_RDLCK; if( fcntl(fd, F_GETLK, &lockInfo)!=-1 ) { return posixLockingStyle; } /* testing for flock can give false positives. So if if the above test ** fails, then we fall back to using dot-lock style locking. */ return dotlockLockingStyle;}/* ** Examines the f_fstypename entry in the statfs structure as returned by ** stat() for the file system hosting the database file, assigns the ** appropriate locking style based on it's value. These values and ** assignments are based on Darwin/OSX behavior and have not been tested on ** other systems.*/static sqlite3LockingStyle sqlite3DetectLockingStyle( const char *filePath, int fd){#ifdef SQLITE_FIXED_LOCKING_STYLE return (sqlite3LockingStyle)SQLITE_FIXED_LOCKING_STYLE;#else struct statfs fsInfo; if (statfs(filePath, &fsInfo) == -1) return sqlite3TestLockingStyle(filePath, fd); if (fsInfo.f_flags & MNT_RDONLY) return noLockingStyle; if( (!strcmp(fsInfo.f_fstypename, "hfs")) || (!strcmp(fsInfo.f_fstypename, "ufs")) ) return posixLockingStyle; if(!strcmp(fsInfo.f_fstypename, "afpfs")) return afpLockingStyle; if(!strcmp(fsInfo.f_fstypename, "nfs")) return sqlite3TestLockingStyle(filePath, fd); if(!strcmp(fsInfo.f_fstypename, "smbfs")) return flockLockingStyle; if(!strcmp(fsInfo.f_fstypename, "msdos")) return dotlockLockingStyle; if(!strcmp(fsInfo.f_fstypename, "webdav")) return unsupportedLockingStyle; return sqlite3TestLockingStyle(filePath, fd); #endif /* SQLITE_FIXED_LOCKING_STYLE */}#endif /* SQLITE_ENABLE_LOCKING_STYLE *//*** Given a file descriptor, locate lockInfo and openCnt structures that** describes that file descriptor. Create new ones if necessary. The** return values might be uninitialized if an error occurs.**** Return the number of errors.*/static int findLockInfo( int fd, /* The file descriptor used in the key */ struct lockInfo **ppLock, /* Return the lockInfo structure here */ struct openCnt **ppOpen /* Return the openCnt structure here */){ int rc; struct lockKey key1; struct openKey key2; struct stat statbuf; struct lockInfo *pLock; struct openCnt *pOpen; rc = fstat(fd, &statbuf); if( rc!=0 ) return 1; memset(&key1, 0, sizeof(key1)); key1.dev = statbuf.st_dev; key1.ino = statbuf.st_ino;#if SQLITE_THREADSAFE if( threadsOverrideEachOthersLocks<0 ){ testThreadLockingBehavior(fd); } key1.tid = threadsOverrideEachOthersLocks ? 0 : pthread_self();#endif memset(&key2, 0, sizeof(key2)); key2.dev = statbuf.st_dev; key2.ino = statbuf.st_ino; pLock = (struct lockInfo*)sqlite3HashFind(&lockHash, &key1, sizeof(key1)); if( pLock==0 ){ struct lockInfo *pOld; pLock = sqlite3_malloc( sizeof(*pLock) ); if( pLock==0 ){ rc = 1; goto exit_findlockinfo; } pLock->key = key1; pLock->nRef = 1; pLock->cnt = 0; pLock->locktype = 0; pOld = sqlite3HashInsert(&lockHash, &pLock->key, sizeof(key1), pLock); if( pOld!=0 ){ assert( pOld==pLock ); sqlite3_free(pLock); rc = 1; goto exit_findlockinfo; } }else{ pLock->nRef++; } *ppLock = pLock; if( ppOpen!=0 ){ pOpen = (struct openCnt*)sqlite3HashFind(&openHash, &key2, sizeof(key2)); if( pOpen==0 ){ struct openCnt *pOld; pOpen = sqlite3_malloc( sizeof(*pOpen) ); if( pOpen==0 ){ releaseLockInfo(pLock); rc = 1; goto exit_findlockinfo; } pOpen->key = key2; pOpen->nRef = 1; pOpen->nLock = 0; pOpen->nPending = 0; pOpen->aPending = 0; pOld = sqlite3HashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen); if( pOld!=0 ){ assert( pOld==pOpen ); sqlite3_free(pOpen); releaseLockInfo(pLock); rc = 1; goto exit_findlockinfo; } }else{ pOpen->nRef++; } *ppOpen = pOpen; }exit_findlockinfo: return rc;}#ifdef SQLITE_DEBUG/*** Helper function for printing out trace information from debugging** binaries. This returns the string represetation of the supplied** integer lock-type.*/static const char *locktypeName(int locktype){ switch( locktype ){ case NO_LOCK: return "NONE"; case SHARED_LOCK: return "SHARED"; case RESERVED_LOCK: return "RESERVED"; case PENDING_LOCK: return "PENDING"; case EXCLUSIVE_LOCK: return "EXCLUSIVE"; } return "ERROR";}#endif/*** If we are currently in a different thread than the thread that the** unixFile argument belongs to, then transfer ownership of the unixFile** over to the current thread.**** A unixFile is only owned by a thread on systems where one thread is** unable to override locks created by a different thread. RedHat9 is** an example of such a system.**** Ownership transfer is only allowed if the unixFile is currently unlocked.** If the unixFile is locked and an ownership is wrong, then return** SQLITE_MISUSE. SQLITE_OK is returned if everything works.*/#if SQLITE_THREADSAFEstatic int transferOwnership(unixFile *pFile){ int rc; pthread_t hSelf; if( threadsOverrideEachOthersLocks ){ /* Ownership transfers not needed on this system */ return SQLITE_OK; } hSelf = pthread_self(); if( pthread_equal(pFile->tid, hSelf) ){ /* We are still in the same thread */ OSTRACE1("No-transfer, same thread\n"); return SQLITE_OK; } if( pFile->locktype!=NO_LOCK ){ /* We cannot change ownership while we are holding a lock! */ return SQLITE_MISUSE; } OSTRACE4("Transfer ownership of %d from %d to %d\n", pFile->h, pFile->tid, hSelf); pFile->tid = hSelf; if (pFile->pLock != NULL) { releaseLockInfo(pFile->pLock); rc = findLockInfo(pFile->h, &pFile->pLock, 0); OSTRACE5("LOCK %d is now %s(%s,%d)\n", pFile->h, locktypeName(pFile->locktype), locktypeName(pFile->pLock->locktype), pFile->pLock->cnt); return rc; } else { return SQLITE_OK; }}#else /* On single-threaded builds, ownership transfer is a no-op */# define transferOwnership(X) SQLITE_OK#endif/*** Seek to the offset passed as the second argument, then read cnt ** bytes into pBuf. Return the number of bytes actually read.*/static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){ int got; i64 newOffset; TIMER_START;#if defined(USE_PREAD) got = pread(id->h, pBuf, cnt, offset); SimulateIOError( got = -1 );#elif defined(USE_PREAD64) got = pread64(id->h, pBuf, cnt, offset); SimulateIOError( got = -1 );#else newOffset = lseek(id->h, offset, SEEK_SET); SimulateIOError( newOffset-- ); if( newOffset!=offset ){ return -1; } got = read(id->h, pBuf, cnt);#endif TIMER_END; OSTRACE5("READ %-3d %5d %7lld %d\n", id->h, got, offset, TIMER_ELAPSED); return got;}/*** Read data from a file into a buffer. Return SQLITE_OK if all** bytes were read successfully and SQLITE_IOERR if anything goes** wrong.*/static int unixRead( sqlite3_file *id, void *pBuf, int amt, sqlite3_int64 offset){ int got; assert( id ); got = seekAndRead((unixFile*)id, offset, pBuf, amt); if( got==amt ){ return SQLITE_OK; }else if( got<0 ){ return SQLITE_IOERR_READ; }else{ memset(&((char*)pBuf)[got], 0, amt-got); return SQLITE_IOERR_SHORT_READ; }}/*** Seek to the offset in id->offset then read cnt bytes into pBuf.** Return the number of bytes actually read. Update the offset.*/static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){ int got; i64 newOffset; TIMER_START;#if defined(USE_PREAD) got = pwrite(id->h, pBuf, cnt, offset);#elif defined(USE_PREAD64) got = pwrite64(id->h, pBuf, cnt, offset);#else newOffset = lseek(id->h, offset, SEEK_SET); if( newOffset!=offset ){ return -1; } got = write(id->h, pBuf, cnt);#endif TIMER_END; OSTRACE5("WRITE %-3d %5d %7lld %d\n", id->h, got, offset, TIMER_ELAPSED); return got;}/*** Write data from a buffer into a file. Return SQLITE_OK on success** or some other error code on failure.*/static int unixWrite( sqlite3_file *id, const void *pBuf, int amt, sqlite3_int64 offset ){ int wrote = 0; assert( id );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -