⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 os_unix.c

📁 sqlite最新源码
💻 C
📖 第 1 页 / 共 5 页
字号:
  int fd;                /* File to be locked */  struct flock lock;     /* The locking operation */  int result;            /* Result of the locking operation */};#if SQLITE_THREADSAFE && defined(__linux__)/*** This function is used as the main routine for a thread launched by** testThreadLockingBehavior(). It tests whether the shared-lock obtained** by the main thread in testThreadLockingBehavior() conflicts with a** hypothetical write-lock obtained by this thread on the same file.**** The write-lock is not actually acquired, as this is not possible if ** the file is open in read-only mode (see ticket #3472).*/ static void *threadLockingTest(void *pArg){  struct threadTestData *pData = (struct threadTestData*)pArg;  pData->result = fcntl(pData->fd, F_GETLK, &pData->lock);  return pArg;}#endif /* SQLITE_THREADSAFE && defined(__linux__) */#if SQLITE_THREADSAFE && defined(__linux__)/*** 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;  int rc;  struct threadTestData d;  struct flock l;  pthread_t t;  fd = dup(fd_orig);  if( fd<0 ) return;  memset(&l, 0, sizeof(l));  l.l_type = F_RDLCK;  l.l_len = 1;  l.l_start = 0;  l.l_whence = SEEK_SET;  rc = fcntl(fd_orig, F_SETLK, &l);  if( rc!=0 ) return;  memset(&d, 0, sizeof(d));  d.fd = fd;  d.lock = l;  d.lock.l_type = F_WRLCK;  pthread_create(&t, 0, threadLockingTest, &d);  pthread_join(t, 0);  close(fd);  if( d.result!=0 ) return;  threadsOverrideEachOthersLocks = (d.lock.l_type==F_UNLCK);}#endif /* SQLITE_THERADSAFE && defined(__linux__) *//*** Release a unixLockInfo structure previously allocated by findLockInfo().*/static void releaseLockInfo(struct unixLockInfo *pLock){  if( pLock ){    pLock->nRef--;    if( pLock->nRef==0 ){      if( pLock->pPrev ){        assert( pLock->pPrev->pNext==pLock );        pLock->pPrev->pNext = pLock->pNext;      }else{        assert( lockList==pLock );        lockList = pLock->pNext;      }      if( pLock->pNext ){        assert( pLock->pNext->pPrev==pLock );        pLock->pNext->pPrev = pLock->pPrev;      }      sqlite3_free(pLock);    }  }}/*** Release a unixOpenCnt structure previously allocated by findLockInfo().*/static void releaseOpenCnt(struct unixOpenCnt *pOpen){  if( pOpen ){    pOpen->nRef--;    if( pOpen->nRef==0 ){      if( pOpen->pPrev ){        assert( pOpen->pPrev->pNext==pOpen );        pOpen->pPrev->pNext = pOpen->pNext;      }else{        assert( openList==pOpen );        openList = pOpen->pNext;      }      if( pOpen->pNext ){        assert( pOpen->pNext->pPrev==pOpen );        pOpen->pNext->pPrev = pOpen->pPrev;      }      sqlite3_free(pOpen->aPending);      sqlite3_free(pOpen);    }  }}/*** Given a file descriptor, locate unixLockInfo and unixOpenCnt structures that** describes that file descriptor.  Create new ones if necessary.  The** return values might be uninitialized if an error occurs.**** Return an appropriate error code.*/static int findLockInfo(  unixFile *pFile,               /* Unix file with file desc used in the key */  struct unixLockInfo **ppLock,  /* Return the unixLockInfo structure here */  struct unixOpenCnt **ppOpen    /* Return the unixOpenCnt structure here */){  int rc;                        /* System call return code */  int fd;                        /* The file descriptor for pFile */  struct unixLockKey lockKey;    /* Lookup key for the unixLockInfo structure */  struct unixFileId fileId;      /* Lookup key for the unixOpenCnt struct */  struct stat statbuf;           /* Low-level file information */  struct unixLockInfo *pLock;    /* Candidate unixLockInfo object */  struct unixOpenCnt *pOpen;     /* Candidate unixOpenCnt object */  /* Get low-level information about the file that we can used to  ** create a unique name for the file.  */  fd = pFile->h;  rc = fstat(fd, &statbuf);  if( rc!=0 ){    pFile->lastErrno = errno;#ifdef EOVERFLOW    if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS;#endif    return SQLITE_IOERR;  }#ifdef __APPLE__  /* On OS X on an msdos filesystem, the inode number is reported  ** incorrectly for zero-size files.  See ticket #3260.  To work  ** around this problem (we consider it a bug in OS X, not SQLite)  ** we always increase the file size to 1 by writing a single byte  ** prior to accessing the inode number.  The one byte written is  ** an ASCII 'S' character which also happens to be the first byte  ** in the header of every SQLite database.  In this way, if there  ** is a race condition such that another thread has already populated  ** the first page of the database, no damage is done.  */  if( statbuf.st_size==0 ){    rc = write(fd, "S", 1);    if( rc!=1 ){      return SQLITE_IOERR;    }    rc = fstat(fd, &statbuf);    if( rc!=0 ){      pFile->lastErrno = errno;      return SQLITE_IOERR;    }  }#endif  memset(&lockKey, 0, sizeof(lockKey));  lockKey.fid.dev = statbuf.st_dev;#if OS_VXWORKS  lockKey.fid.pId = pFile->pId;#else  lockKey.fid.ino = statbuf.st_ino;#endif#if SQLITE_THREADSAFE && defined(__linux__)  if( threadsOverrideEachOthersLocks<0 ){    testThreadLockingBehavior(fd);  }  lockKey.tid = threadsOverrideEachOthersLocks ? 0 : pthread_self();#endif  fileId = lockKey.fid;  if( ppLock!=0 ){    pLock = lockList;    while( pLock && memcmp(&lockKey, &pLock->lockKey, sizeof(lockKey)) ){      pLock = pLock->pNext;    }    if( pLock==0 ){      pLock = sqlite3_malloc( sizeof(*pLock) );      if( pLock==0 ){        rc = SQLITE_NOMEM;        goto exit_findlockinfo;      }      pLock->lockKey = lockKey;      pLock->nRef = 1;      pLock->cnt = 0;      pLock->locktype = 0;      pLock->pNext = lockList;      pLock->pPrev = 0;      if( lockList ) lockList->pPrev = pLock;      lockList = pLock;    }else{      pLock->nRef++;    }    *ppLock = pLock;  }  if( ppOpen!=0 ){    pOpen = openList;    while( pOpen && memcmp(&fileId, &pOpen->fileId, sizeof(fileId)) ){      pOpen = pOpen->pNext;    }    if( pOpen==0 ){      pOpen = sqlite3_malloc( sizeof(*pOpen) );      if( pOpen==0 ){        releaseLockInfo(pLock);        rc = SQLITE_NOMEM;        goto exit_findlockinfo;      }      pOpen->fileId = fileId;      pOpen->nRef = 1;      pOpen->nLock = 0;      pOpen->nPending = 0;      pOpen->aPending = 0;      pOpen->pNext = openList;      pOpen->pPrev = 0;      if( openList ) openList->pPrev = pOpen;      openList = pOpen;#if OS_VXWORKS      pOpen->pSem = NULL;      pOpen->aSemName[0] = '\0';#endif    }else{      pOpen->nRef++;    }    *ppOpen = pOpen;  }exit_findlockinfo:  return rc;}/*** 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 that use LinuxThreads.**** 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_THREADSAFE && defined(__linux__)static 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, &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  /* if not SQLITE_THREADSAFE */  /* On single-threaded builds, ownership transfer is a no-op */# define transferOwnership(X) SQLITE_OK#endif /* SQLITE_THREADSAFE *//*** 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, set *pResOut** to a non-zero value otherwise *pResOut is set to zero.  The return value** is set to SQLITE_OK unless an I/O error occurs during lock checking.*/static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){  int rc = SQLITE_OK;  int reserved = 0;  unixFile *pFile = (unixFile*)id;  SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );  assert( pFile );  unixEnterMutex(); /* Because pFile->pLock is shared across threads */  /* Check if a thread in this process holds such a lock */  if( pFile->pLock->locktype>SHARED_LOCK ){    reserved = 1;  }  /* Otherwise see if some other process holds it.  */#ifndef __DJGPP__  if( !reserved ){    struct flock lock;    lock.l_whence = SEEK_SET;    lock.l_start = RESERVED_BYTE;    lock.l_len = 1;    lock.l_type = F_WRLCK;    if (-1 == fcntl(pFile->h, F_GETLK, &lock)) {      int tErrno = errno;      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK);      pFile->lastErrno = tErrno;    } else if( lock.l_type!=F_UNLCK ){      reserved = 1;    }  }#endif    unixLeaveMutex();  OSTRACE4("TEST WR-LOCK %d %d %d\n", pFile->h, rc, reserved);  *pResOut = reserved;  return rc;}/*** 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.  Use the sqlite3OsUnlock()** routine to lower a locking level.*/static int unixLock(sqlite3_file *id, int locktype){  /* The following describes the implementation of the various locks and  ** lock transitions in terms of the POSIX advisory shared and exclusive  ** lock primitives (called read-locks and write-locks below, to avoid  ** confusion with SQLite lock names). The algorithms are complicated  ** slightly in order to be compatible with windows systems simultaneously  ** accessing the same database file, in case that is ever required.  **  ** Symbols defined in os.h indentify the 'pending byte' and the 'reserved  ** byte', each single bytes at well known offsets, and the 'shared byte  ** range', a range of 510 bytes at a well known offset.  **  ** To obtain a SHARED lock, a read-lock is obtained on the 'pending  ** byte'.  If this is successful, a random byte from the 'shared byte  ** range' is read-locked and the lock on the 'pending byte' released.  **  ** A process may only obtain a RESERVED lock after it has a SHARED lock.  ** A RESERVED lock is implemented by grabbing a write-lock on the  ** 'reserved byte'.   **  ** A process may only obtain a PENDING lock after it has obtained a  ** SHARED lock. A PENDING lock is implemented by obtaining a write-lock  ** on the 'pending byte'. This ensures that no new SHARED locks can be  ** obtained, but existing SHARED locks are allowed to persist. A process  ** does not have to obtain a RESERVED lock on the way to a PENDING lock.  ** This property is used by the algorithm for rolling back a journal file  ** after a crash.  **  ** An EXCLUSIVE lock, obtained after a PENDING lock is held, is  ** implemented by obtaining a write-lock on the entire 'shared byte  ** range'. Since all other locks require a read-lock on one of the bytes  ** within this range, this ensures that no other locks are held on the  ** database.   **  ** The reason a single byte cannot be used instead of the 'shared byte  ** range' is that some versions of windows do not support read-locks. By  ** locking a random byte from a range, concurrent SHARED locks may exist  ** even if the locking primitive used is always a write-lock.  */  int rc = SQLITE_OK;  unixFile *pFile = (unixFile*)id;  struct unixLockInfo *pLock = pFile->pLock;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -