📄 os_unix.c
字号:
*/struct threadTestData { int fd; /* File to be locked */ struct flock lock; /* The locking operation */ int result; /* Result of the locking operation */};#ifdef SQLITE_LOCK_TRACE/*** Print out information about all locking operations.**** This routine is used for troubleshooting locks on multithreaded** platforms. Enable by compiling with the -DSQLITE_LOCK_TRACE** command-line option on the compiler. This code is normally** turned off.*/static int lockTrace(int fd, int op, struct flock *p){ char *zOpName, *zType; int s; int savedErrno; if( op==F_GETLK ){ zOpName = "GETLK"; }else if( op==F_SETLK ){ zOpName = "SETLK"; }else{ 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_UNIX_THREADS *//*** Release a lockInfo structure previously allocated by findLockInfo().*/static void releaseLockInfo(struct lockInfo *pLock){ assert( sqlite3OsInMutex(1) ); if (pLock == NULL) return; pLock->nRef--; if( pLock->nRef==0 ){ sqlite3HashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0); sqlite3ThreadSafeFree(pLock); }}/*** Release a openCnt structure previously allocated by findLockInfo().*/static void releaseOpenCnt(struct openCnt *pOpen){ assert( sqlite3OsInMutex(1) ); if (pOpen == NULL) return; pOpen->nRef--; if( pOpen->nRef==0 ){ sqlite3HashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0); free(pOpen->aPending); sqlite3ThreadSafeFree(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; assert( sqlite3OsInMutex(1) ); memset(&key1, 0, sizeof(key1)); key1.dev = statbuf.st_dev; key1.ino = statbuf.st_ino;#ifdef SQLITE_UNIX_THREADS 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 = sqlite3ThreadSafeMalloc( 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 ); sqlite3ThreadSafeFree(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 = sqlite3ThreadSafeMalloc( 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 ); sqlite3ThreadSafeFree(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.*/#ifdef SQLITE_UNIX_THREADSstatic 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/*** Delete the named file*/int sqlite3UnixDelete(const char *zFilename){ SimulateIOError(return SQLITE_IOERR_DELETE); unlink(zFilename); return SQLITE_OK;}/*** Return TRUE if the named file exists.*/int sqlite3UnixFileExists(const char *zFilename){ return access(zFilename, 0)==0;}/* Forward declaration */static int allocateUnixFile( int h, /* File descriptor of the open file */ OsFile **pId, /* Write the real file descriptor here */ const char *zFilename, /* Name of the file being opened */ int delFlag /* If true, make sure the file deletes on close */);/*** Attempt to open a file for both reading and writing. If that** fails, try opening it read-only. If the file does not exist,** try to create it.**** On success, a handle for the open file is written to *id** and *pReadonly is set to 0 if the file was opened for reading and** writing or 1 if the file was opened read-only. The function returns** SQLITE_OK.**** On failure, the function returns SQLITE_CANTOPEN and leaves** *id and *pReadonly unchanged.*/int sqlite3UnixOpenReadWrite( const char *zFilename, OsFile **pId, int *pReadonly){ int h; CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadWrite, zFilename, pId, pReadonly); assert( 0==*pId ); h = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, SQLITE_DEFAULT_FILE_PERMISSIONS); if( h<0 ){#ifdef EISDIR if( errno==EISDIR ){ return SQLITE_CANTOPEN;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -