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

📄 os_unix.c

📁 sqlite最新源码
💻 C
📖 第 1 页 / 共 5 页
字号:
#endif#ifdef ENOTSUP  case ENOTSUP:     /* invalid fd, unless during file system support introspection, in which      * it actually means what it says */#endif  case EIO:  case EBADF:  case EINVAL:  case ENOTCONN:  case ENODEV:  case ENXIO:  case ENOENT:  case ESTALE:  case ENOSYS:    /* these should force the client to close the file and reconnect */      default:     return sqliteIOErr;  }}/************************************************************************************************ Begin Unique File ID Utility Used By VxWorks ******************* On most versions of unix, we can get a unique ID for a file by concatenating** the device number and the inode number.  But this does not work on VxWorks.** On VxWorks, a unique file id must be based on the canonical filename.**** A pointer to an instance of the following structure can be used as a** unique file ID in VxWorks.  Each instance of this structure contains** a copy of the canonical filename.  There is also a reference count.  ** The structure is reclaimed when the number of pointers to it drops to** zero.**** There are never very many files open at one time and lookups are not** a performance-critical path, so it is sufficient to put these** structures on a linked list.*/struct vxworksFileId {  struct vxworksFileId *pNext;  /* Next in a list of them all */  int nRef;                     /* Number of references to this one */  int nName;                    /* Length of the zCanonicalName[] string */  char *zCanonicalName;         /* Canonical filename */};#if OS_VXWORKS/* ** All unique filenames are held on a linked list headed by this** variable:*/static struct vxworksFileId *vxworksFileList = 0;/*** Simplify a filename into its canonical form** by making the following changes:****  * removing any trailing and duplicate /**  * convert /./ into just /**  * convert /A/../ where A is any simple name into just /**** Changes are made in-place.  Return the new name length.**** The original filename is in z[0..n-1].  Return the number of** characters in the simplified name.*/static int vxworksSimplifyName(char *z, int n){  int i, j;  while( n>1 && z[n-1]=='/' ){ n--; }  for(i=j=0; i<n; i++){    if( z[i]=='/' ){      if( z[i+1]=='/' ) continue;      if( z[i+1]=='.' && i+2<n && z[i+2]=='/' ){        i += 1;        continue;      }      if( z[i+1]=='.' && i+3<n && z[i+2]=='.' && z[i+3]=='/' ){        while( j>0 && z[j-1]!='/' ){ j--; }        if( j>0 ){ j--; }        i += 2;        continue;      }    }    z[j++] = z[i];  }  z[j] = 0;  return j;}/*** Find a unique file ID for the given absolute pathname.  Return** a pointer to the vxworksFileId object.  This pointer is the unique** file ID.**** The nRef field of the vxworksFileId object is incremented before** the object is returned.  A new vxworksFileId object is created** and added to the global list if necessary.**** If a memory allocation error occurs, return NULL.*/static struct vxworksFileId *vxworksFindFileId(const char *zAbsoluteName){  struct vxworksFileId *pNew;         /* search key and new file ID */  struct vxworksFileId *pCandidate;   /* For looping over existing file IDs */  int n;                              /* Length of zAbsoluteName string */  assert( zAbsoluteName[0]=='/' );  n = (int)strlen(zAbsoluteName);  pNew = sqlite3_malloc( sizeof(*pNew) + (n+1) );  if( pNew==0 ) return 0;  pNew->zCanonicalName = (char*)&pNew[1];  memcpy(pNew->zCanonicalName, zAbsoluteName, n+1);  n = vxworksSimplifyName(pNew->zCanonicalName, n);  /* Search for an existing entry that matching the canonical name.  ** If found, increment the reference count and return a pointer to  ** the existing file ID.  */  unixEnterMutex();  for(pCandidate=vxworksFileList; pCandidate; pCandidate=pCandidate->pNext){    if( pCandidate->nName==n      && memcmp(pCandidate->zCanonicalName, pNew->zCanonicalName, n)==0    ){       sqlite3_free(pNew);       pCandidate->nRef++;       unixLeaveMutex();       return pCandidate;    }  }  /* No match was found.  We will make a new file ID */  pNew->nRef = 1;  pNew->nName = n;  pNew->pNext = vxworksFileList;  vxworksFileList = pNew;  unixLeaveMutex();  return pNew;}/*** Decrement the reference count on a vxworksFileId object.  Free** the object when the reference count reaches zero.*/static void vxworksReleaseFileId(struct vxworksFileId *pId){  unixEnterMutex();  assert( pId->nRef>0 );  pId->nRef--;  if( pId->nRef==0 ){    struct vxworksFileId **pp;    for(pp=&vxworksFileList; *pp && *pp!=pId; pp = &((*pp)->pNext)){}    assert( *pp==pId );    *pp = pId->pNext;    sqlite3_free(pId);  }  unixLeaveMutex();}#endif /* OS_VXWORKS *//*************** End of Unique File ID Utility Used By VxWorks **********************************************************************************************//********************************************************************************************************* Posix Advisory Locking ******************************** POSIX advisory locks are broken by design.  ANSI STD 1003.1 (1996)** section 6.5.2.2 lines 483 through 490 specify that when a process** sets or clears a lock, that operation overrides any prior locks set** by the same process.  It does not explicitly say so, but this implies** that it overrides locks set by the same process using a different** file descriptor.  Consider this test case:****       int fd1 = open("./file1", O_RDWR|O_CREAT, 0644);**       int fd2 = open("./file2", O_RDWR|O_CREAT, 0644);**** Suppose ./file1 and ./file2 are really the same file (because** one is a hard or symbolic link to the other) then if you set** an exclusive lock on fd1, then try to get an exclusive lock** on fd2, it works.  I would have expected the second lock to** fail since there was already a lock on the file due to fd1.** But not so.  Since both locks came from the same process, the** second overrides the first, even though they were on different** file descriptors opened on different file names.**** This means that we cannot use POSIX locks to synchronize file access** among competing threads of the same process.  POSIX locks will work fine** to synchronize access for threads in separate processes, but not** threads within the same process.**** To work around the problem, SQLite has to manage file locks internally** on its own.  Whenever a new database is opened, we have to find the** specific inode of the database file (the inode is determined by the** st_dev and st_ino fields of the stat structure that fstat() fills in)** and check for locks already existing on that inode.  When locks are** created or removed, we have to look at our own internal record of the** locks to see if another thread has previously set a lock on that same** inode.**** (Aside: The use of inode numbers as unique IDs does not work on VxWorks.** For VxWorks, we have to use the alternative unique ID system based on** canonical filename and implemented in the previous division.)**** The sqlite3_file structure for POSIX is no longer just an integer file** descriptor.  It is now a structure that holds the integer file** descriptor and a pointer to a structure that describes the internal** locks on the corresponding inode.  There is one locking structure** per inode, so if the same inode is opened twice, both unixFile structures** point to the same locking structure.  The locking structure keeps** a reference count (so we will know when to delete it) and a "cnt"** field that tells us its internal lock status.  cnt==0 means the** file is unlocked.  cnt==-1 means the file has an exclusive lock.** cnt>0 means there are cnt shared locks on the file.**** Any attempt to lock or unlock a file first checks the locking** structure.  The fcntl() system call is only invoked to set a ** POSIX lock if the internal lock structure transitions between** a locked and an unlocked state.**** But wait:  there are yet more problems with POSIX advisory locks.**** If you close a file descriptor that points to a file that has locks,** all locks on that file that are owned by the current process are** released.  To work around this problem, each unixFile structure contains** a pointer to an unixOpenCnt structure.  There is one unixOpenCnt structure** per open inode, which means that multiple unixFile can point to a single** unixOpenCnt.  When an attempt is made to close an unixFile, if there are** other unixFile open on the same inode that are holding locks, the call** to close() the file descriptor is deferred until all of the locks clear.** The unixOpenCnt structure keeps a list of file descriptors that need to** be closed and that list is walked (and cleared) when the last lock** clears.**** Yet another problem:  LinuxThreads do not play well with posix locks.**** Many older versions of linux use the LinuxThreads library which is** not posix compliant.  Under LinuxThreads, a lock created by thread** A cannot be modified or overridden by a different thread B.** Only thread A can modify the lock.  Locking behavior is correct** if the appliation uses the newer Native Posix Thread Library (NPTL)** on linux - with NPTL a lock created by thread A can override locks** in thread B.  But there is no way to know at compile-time which** threading library is being used.  So there is no way to know at** compile-time whether or not thread A can override locks on thread B.** We have to do a run-time check to discover the behavior of the** current process.**** On systems where thread A is unable to modify locks created by** thread B, we have to keep track of which thread created each** lock.  Hence there is an extra field in the key to the unixLockInfo** structure to record this information.  And on those systems it** is illegal to begin a transaction in one thread and finish it** in another.  For this latter restriction, there is no work-around.** It is a limitation of LinuxThreads.*//*** Set or check the unixFile.tid field.  This field is set when an unixFile** is first opened.  All subsequent uses of the unixFile verify that the** same thread is operating on the unixFile.  Some operating systems do** not allow locks to be overridden by other threads and that restriction** means that sqlite3* database handles cannot be moved from one thread** to another while locks are held.**** Version 3.3.1 (2006-01-15):  unixFile can be moved from one thread to** another as long as we are running on a system that supports threads** overriding each others locks (which is now the most common behavior)** or if no locks are held.  But the unixFile.pLock field needs to be** recomputed because its key includes the thread-id.  See the ** transferOwnership() function below for additional information*/#if SQLITE_THREADSAFE && defined(__linux__)# define SET_THREADID(X)   (X)->tid = pthread_self()# define CHECK_THREADID(X) (threadsOverrideEachOthersLocks==0 && \                            !pthread_equal((X)->tid, pthread_self()))#else# define SET_THREADID(X)# define CHECK_THREADID(X) 0#endif/*** An instance of the following structure serves as the key used** to locate a particular unixOpenCnt structure given its inode.  This** is the same as the unixLockKey except that the thread ID is omitted.*/struct unixFileId {  dev_t dev;                  /* Device number */#if OS_VXWORKS  struct vxworksFileId *pId;  /* Unique file ID for vxworks. */#else  ino_t ino;                  /* Inode number */#endif};/*** An instance of the following structure serves as the key used** to locate a particular unixLockInfo structure given its inode.**** If threads cannot override each others locks (LinuxThreads), then we** set the unixLockKey.tid field to the thread ID.  If threads can override** each others locks (Posix and NPTL) then tid is always set to zero.** tid is omitted if we compile without threading support or on an OS** other than linux.*/struct unixLockKey {  struct unixFileId fid;  /* Unique identifier for the file */#if SQLITE_THREADSAFE && defined(__linux__)  pthread_t tid;  /* Thread ID of lock owner. Zero if not using LinuxThreads */#endif};/*** An instance of the following structure is allocated for each open** inode.  Or, on LinuxThreads, there is one of these structures for** each inode opened by each thread.**** A single inode can have multiple file descriptors, so each unixFile** structure contains a pointer to an instance of this object and this** object keeps a count of the number of unixFile pointing to it.*/struct unixLockInfo {  struct unixLockKey lockKey;     /* The lookup key */  int cnt;                        /* Number of SHARED locks held */  int locktype;                   /* One of SHARED_LOCK, RESERVED_LOCK etc. */  int nRef;                       /* Number of pointers to this structure */  struct unixLockInfo *pNext;     /* List of all unixLockInfo objects */  struct unixLockInfo *pPrev;     /*    .... doubly linked */};/*** An instance of the following structure is allocated for each open** inode.  This structure keeps track of the number of locks on that** inode.  If a close is attempted against an inode that is holding** locks, the close is deferred until all locks clear by adding the** file descriptor to be closed to the pending list.**** TODO:  Consider changing this so that there is only a single file** descriptor for each open file, even when it is opened multiple times.** The close() system call would only occur when the last database** using the file closes.*/struct unixOpenCnt {  struct unixFileId fileId;   /* The lookup key */  int nRef;                   /* Number of pointers to this structure */  int nLock;                  /* Number of outstanding locks */  int nPending;               /* Number of pending close() operations */  int *aPending;            /* Malloced space holding fd's awaiting a close() */#if OS_VXWORKS  sem_t *pSem;                     /* Named POSIX semaphore */  char aSemName[MAX_PATHNAME+1];   /* Name of that semaphore */#endif  struct unixOpenCnt *pNext, *pPrev;   /* List of all unixOpenCnt objects */};/*** Lists of all unixLockInfo and unixOpenCnt objects.  These used to be hash** tables.  But the number of objects is rarely more than a dozen and** never exceeds a few thousand.  And lookup is not on a critical** path so a simple linked list will suffice.*/static struct unixLockInfo *lockList = 0;static struct unixOpenCnt *openList = 0;/*** This variable remembers whether or not threads can override each others** locks.****    0:  No.  Threads cannot override each others locks.  (LinuxThreads)**    1:  Yes.  Threads can override each others locks.  (Posix & NLPT)**   -1:  We don't know yet.**** On some systems, we know at compile-time if threads can override each** others locks.  On those systems, the SQLITE_THREAD_OVERRIDE_LOCK macro** will be set appropriately.  On other systems, we have to check at** runtime.  On these latter systems, SQLTIE_THREAD_OVERRIDE_LOCK is** undefined.**** This variable normally has file scope only.  But during testing, we make** it a global so that the test code can change its value in order to verify** that the right stuff happens in either case.*/#if SQLITE_THREADSAFE && defined(__linux__)#  ifndef SQLITE_THREAD_OVERRIDE_LOCK#    define SQLITE_THREAD_OVERRIDE_LOCK -1#  endif#  ifdef SQLITE_TESTint threadsOverrideEachOthersLocks = SQLITE_THREAD_OVERRIDE_LOCK;#  elsestatic int threadsOverrideEachOthersLocks = SQLITE_THREAD_OVERRIDE_LOCK;#  endif#endif/*** This structure holds information passed into individual test** threads by the testThreadLockingBehavior() routine.*/struct threadTestData {

⌨️ 快捷键说明

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