📄 os_unix.c
字号:
pLock->locktype = NO_LOCK; }else{ rc = SQLITE_IOERR; /* This should never happen */ } } /* Decrement the count of locks against this same file. When the ** count reaches zero, close any other file descriptors whose close ** was deferred because of outstanding locks. */ pOpen = pFile->pOpen; pOpen->nLock--; assert( pOpen->nLock>=0 ); if( pOpen->nLock==0 && pOpen->nPending>0 ){ int i; for(i=0; i<pOpen->nPending; i++){ close(pOpen->aPending[i]); } free(pOpen->aPending); pOpen->nPending = 0; pOpen->aPending = 0; } } sqlite3OsLeaveMutex(); pFile->locktype = locktype; return rc;}/*** Close a file.*/static int unixClose(OsFile **pId){ unixFile *id = (unixFile*)*pId; if( !id ) return SQLITE_OK; unixUnlock(*pId, NO_LOCK); if( id->dirfd>=0 ) close(id->dirfd); id->dirfd = -1; sqlite3OsEnterMutex(); if( id->pOpen->nLock ){ /* If there are outstanding locks, do not actually close the file just ** yet because that would clear those locks. Instead, add the file ** descriptor to pOpen->aPending. It will be automatically closed when ** the last lock is cleared. */ int *aNew; struct openCnt *pOpen = id->pOpen; aNew = realloc( pOpen->aPending, (pOpen->nPending+1)*sizeof(int) ); if( aNew==0 ){ /* If a malloc fails, just leak the file descriptor */ }else{ pOpen->aPending = aNew; pOpen->aPending[pOpen->nPending] = id->h; pOpen->nPending++; } }else{ /* There are no outstanding locks so we can close the file immediately */ close(id->h); } releaseLockInfo(id->pLock); releaseOpenCnt(id->pOpen); sqlite3OsLeaveMutex(); id->isOpen = 0; TRACE2("CLOSE %-3d\n", id->h); OpenCounter(-1); sqlite3ThreadSafeFree(id); *pId = 0; return SQLITE_OK;}/*** 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 *sqlite3UnixFullPathname(const char *zRelative){ char *zFull = 0; if( zRelative[0]=='/' ){ sqlite3SetString(&zFull, zRelative, (char*)0); }else{ char *zBuf = sqliteMalloc(5000); if( zBuf==0 ){ return 0; } zBuf[0] = 0; sqlite3SetString(&zFull, getcwd(zBuf, 5000), "/", zRelative, (char*)0); sqliteFree(zBuf); }#if 0 /* ** Remove "/./" path elements and convert "/A/./" path elements ** to just "/". */ if( zFull ){ int i, j; for(i=j=0; zFull[i]; i++){ if( zFull[i]=='/' ){ if( zFull[i+1]=='/' ) continue; if( zFull[i+1]=='.' && zFull[i+2]=='/' ){ i += 1; continue; } if( zFull[i+1]=='.' && zFull[i+2]=='.' && zFull[i+3]=='/' ){ while( j>0 && zFull[j-1]!='/' ){ j--; } i += 3; continue; } } zFull[j++] = zFull[i]; } zFull[j] = 0; }#endif return zFull;}/*** Change the value of the fullsync flag in the given file descriptor.*/static void unixSetFullSync(OsFile *id, int v){ ((unixFile*)id)->fullSync = v;}/*** Return the underlying file handle for an OsFile*/static int unixFileHandle(OsFile *id){ return ((unixFile*)id)->h;}/*** Return an integer that indices the type of lock currently held** by this handle. (Used for testing and analysis only.)*/static int unixLockState(OsFile *id){ return ((unixFile*)id)->locktype;}/*** This vector defines all the methods that can operate on an OsFile** for unix.*/static const IoMethod sqlite3UnixIoMethod = { unixClose, unixOpenDirectory, unixRead, unixWrite, unixSeek, unixTruncate, unixSync, unixSetFullSync, unixFileHandle, unixFileSize, unixLock, unixUnlock, unixLockState, unixCheckReservedLock,};/*** Allocate memory for a unixFile. Initialize the new unixFile** 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 allocateUnixFile(unixFile *pInit, OsFile **pId){ unixFile *pNew; pInit->dirfd = -1; pInit->fullSync = 0; pInit->locktype = 0; pInit->offset = 0; SET_THREADID(pInit); pNew = sqlite3ThreadSafeMalloc( sizeof(unixFile) ); if( pNew==0 ){ close(pInit->h); sqlite3OsEnterMutex(); releaseLockInfo(pInit->pLock); releaseOpenCnt(pInit->pOpen); sqlite3OsLeaveMutex(); *pId = 0; return SQLITE_NOMEM; }else{ *pNew = *pInit; pNew->pMethod = &sqlite3UnixIoMethod; *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 sqlite3UnixRandomSeed(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);#if !defined(SQLITE_TEST) { int pid, fd; fd = open("/dev/urandom", O_RDONLY); if( fd<0 ){ time_t t; time(&t); memcpy(zBuf, &t, sizeof(t)); pid = getpid(); memcpy(&zBuf[sizeof(time_t)], &pid, sizeof(pid)); }else{ read(fd, zBuf, 256); close(fd); } }#endif return SQLITE_OK;}/*** Sleep for a little while. Return the amount of time slept.** The argument is the number of milliseconds we want to sleep.*/int sqlite3UnixSleep(int ms){#if defined(HAVE_USLEEP) && HAVE_USLEEP usleep(ms*1000); return ms;#else sleep((ms+999)/1000); return 1000*((ms+999)/1000);#endif}/*** Static variables used for thread synchronization.**** inMutex the nesting depth of the recursive mutex. The thread** holding mutexMain can read this variable at any time.** But is must hold mutexAux to change this variable. Other** threads must hold mutexAux to read the variable and can** never write.**** mutexOwner The thread id of the thread holding mutexMain. Same** access rules as for inMutex.**** mutexOwnerValid True if the value in mutexOwner is valid. The same** access rules apply as for inMutex.**** mutexMain The main mutex. Hold this mutex in order to get exclusive** access to SQLite data structures.**** mutexAux An auxiliary mutex needed to access variables defined above.**** Mutexes are always acquired in this order: mutexMain mutexAux. It** is not necessary to acquire mutexMain in order to get mutexAux - just** do not attempt to acquire them in the reverse order: mutexAux mutexMain.** Either get the mutexes with mutexMain first or get mutexAux only.**** When running on a platform where the three variables inMutex, mutexOwner,** and mutexOwnerValid can be set atomically, the mutexAux is not required.** On many systems, all three are 32-bit integers and writing to a 32-bit** integer is atomic. I think. But there are no guarantees. So it seems** safer to protect them using mutexAux.*/static int inMutex = 0;#ifdef SQLITE_UNIX_THREADSstatic pthread_t mutexOwner; /* Thread holding mutexMain */static int mutexOwnerValid = 0; /* True if mutexOwner is valid */static pthread_mutex_t mutexMain = PTHREAD_MUTEX_INITIALIZER; /* The mutex */static pthread_mutex_t mutexAux = PTHREAD_MUTEX_INITIALIZER; /* Aux mutex */#endif/*** The following pair of routine 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.**** As of version 3.3.2, this mutex must be recursive.*/void sqlite3UnixEnterMutex(){#ifdef SQLITE_UNIX_THREADS pthread_mutex_lock(&mutexAux); if( !mutexOwnerValid || !pthread_equal(mutexOwner, pthread_self()) ){ pthread_mutex_unlock(&mutexAux); pthread_mutex_lock(&mutexMain); assert( inMutex==0 ); assert( !mutexOwnerValid ); pthread_mutex_lock(&mutexAux); mutexOwner = pthread_self(); mutexOwnerValid = 1; } inMutex++; pthread_mutex_unlock(&mutexAux);#else inMutex++;#endif}void sqlite3UnixLeaveMutex(){ assert( inMutex>0 );#ifdef SQLITE_UNIX_THREADS pthread_mutex_lock(&mutexAux); inMutex--; assert( pthread_equal(mutexOwner, pthread_self()) ); if( inMutex==0 ){ assert( mutexOwnerValid ); mutexOwnerValid = 0; pthread_mutex_unlock(&mutexMain); } pthread_mutex_unlock(&mutexAux);#else inMutex--;#endif}/*** Return TRUE if the mutex is currently held.**** If the thisThrd parameter is true, return true only if the** calling thread holds the mutex. If the parameter is false, return** true if any thread holds the mutex.*/int sqlite3UnixInMutex(int thisThrd){#ifdef SQLITE_UNIX_THREADS int rc; pthread_mutex_lock(&mutexAux); rc = inMutex>0 && (thisThrd==0 || pthread_equal(mutexOwner,pthread_self())); pthread_mutex_unlock(&mutexAux); return rc;#else return inMutex>0;#endif}/*** 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;# ifdef SQLITE_UNIX_THREADS static pthread_mutex_t tsd_counter_mutex = PTHREAD_MUTEX_INITIALIZER;# define TSD_COUNTER(N) \ pthread_mutex_lock(&tsd_counter_mutex); \ sqlite3_tsd_count += N; \ pthread_mutex_unlock(&tsd_counter_mutex);# else# define TSD_COUNTER(N) sqlite3_tsd_count += N# endif#else# define TSD_COUNTER(N) /* no-op */#endif/*** If called with allocateFlag>0, 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.**** 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 *sqlite3UnixThreadSpecificData(int allocateFlag){ static const ThreadData zeroData = {0}; /* Initializer to silence warnings ** from broken compilers */#ifdef SQLITE_UNIX_THREADS static pthread_key_t key; static int keyInit = 0; ThreadData *pTsd; if( !keyInit ){ sqlite3OsEnterMutex(); if( !keyInit ){ int rc; rc = pthread_key_create(&key, 0); if( rc ){ sqlite3OsLeaveMutex(); return 0; } keyInit = 1; } sqlite3OsLeaveMutex(); } pTsd = pthread_getspecific(key); if( allocateFlag>0 ){ if( pTsd==0 ){ if( !sqlite3TestMallocFail() ){ pTsd = sqlite3OsMalloc(sizeof(zeroData)); }#ifdef SQLITE_MEMDEBUG sqlite3_isFail = 0;#endif if( pTsd ){ *pTsd = zeroData; pthread_setspecific(key, pTsd); TSD_COUNTER(+1); } } }else if( pTsd!=0 && allocateFlag<0 && memcmp(pTsd, &zeroData, sizeof(ThreadData))==0 ){ sqlite3OsFree(pTsd); pthread_setspecific(key, 0); TSD_COUNTER(-1); pTsd = 0; } return pTsd;#else static ThreadData *pTsd = 0; if( allocateFlag>0 ){ if( pTsd==0 ){ if( !sqlite3TestMallocFail() ){ pTsd = sqlite3OsMalloc( sizeof(zeroData) ); }#ifdef SQLITE_MEMDEBUG sqlite3_isFail = 0;#endif if( pTsd ){ *pTsd = zeroData; TSD_COUNTER(+1); } } }else if( pTsd!=0 && allocateFlag<0 && memcmp(pTsd, &zeroData, sizeof(ThreadData))==0 ){ sqlite3OsFree(pTsd); TSD_COUNTER(-1); pTsd = 0; } return pTsd;#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 sqlite3UnixCurrentTime(double *prNow){#ifdef NO_GETTOD time_t t; time(&t); *prNow = t/86400.0 + 2440587.5;#else struct timeval sNow; struct timezone sTz; /* Not used */ gettimeofday(&sNow, &sTz); *prNow = 2440587.5 + sNow.tv_sec/86400.0 + sNow.tv_usec/86400000000.0;#endif#ifdef SQLITE_TEST if( sqlite3_current_time ){ *prNow = sqlite3_current_time/86400.0 + 2440587.5; }#endif return 0;}#endif /* OS_UNIX */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -