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

📄 os.c

📁 sqlite-source-2_8_16.zip 轻量级嵌入式数据库源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/*** 2001 September 16**** The author disclaims copyright to this source code.  In place of** a legal notice, here is a blessing:****    May you do good and not evil.**    May you find forgiveness for yourself and forgive others.**    May you share freely, never taking more than you give.************************************************************************************ This file contains code that is specific to particular operating** systems.  The purpose of this file is to provide a uniform abstraction** on which the rest of SQLite can operate.*/#include "os.h"          /* Must be first to enable large file support */#include "sqliteInt.h"#if OS_UNIX# include <time.h># include <errno.h># include <unistd.h># ifndef O_LARGEFILE#  define O_LARGEFILE 0# endif# ifdef SQLITE_DISABLE_LFS#  undef O_LARGEFILE#  define O_LARGEFILE 0# endif# ifndef O_NOFOLLOW#  define O_NOFOLLOW 0# endif# ifndef O_BINARY#  define O_BINARY 0# endif#endif#if OS_WIN# include <winbase.h>#endif#if OS_MAC# include <extras.h># include <path2fss.h># include <TextUtils.h># include <FinderRegistry.h># include <Folders.h># include <Timer.h># include <OSUtils.h>#endif/*** The DJGPP compiler environment looks mostly like Unix, but it** lacks the fcntl() system call.  So redefine fcntl() to be something** that always succeeds.  This means that locking does not occur under** DJGPP.  But its DOS - what did you expect?*/#ifdef __DJGPP__# define fcntl(A,B,C) 0#endif/*** Macros used to determine whether or not to use threads.  The** SQLITE_UNIX_THREADS macro is defined if we are synchronizing for** Posix threads and SQLITE_W32_THREADS is defined if we are** synchronizing using Win32 threads.*/#if OS_UNIX && defined(THREADSAFE) && THREADSAFE# include <pthread.h># define SQLITE_UNIX_THREADS 1#endif#if OS_WIN && defined(THREADSAFE) && THREADSAFE# define SQLITE_W32_THREADS 1#endif#if OS_MAC && defined(THREADSAFE) && THREADSAFE# include <Multiprocessing.h># define SQLITE_MACOS_MULTITASKING 1#endif/*** Macros for performance tracing.  Normally turned off*/#if 0static int last_page = 0;__inline__ unsigned long long int hwtime(void){  unsigned long long int x;  __asm__("rdtsc\n\t"          "mov %%edx, %%ecx\n\t"          :"=A" (x));  return x;}static unsigned long long int g_start;static unsigned int elapse;#define TIMER_START       g_start=hwtime()#define TIMER_END         elapse=hwtime()-g_start#define SEEK(X)           last_page=(X)#define TRACE1(X)         fprintf(stderr,X)#define TRACE2(X,Y)       fprintf(stderr,X,Y)#define TRACE3(X,Y,Z)     fprintf(stderr,X,Y,Z)#define TRACE4(X,Y,Z,A)   fprintf(stderr,X,Y,Z,A)#define TRACE5(X,Y,Z,A,B) fprintf(stderr,X,Y,Z,A,B)#else#define TIMER_START#define TIMER_END#define SEEK(X)#define TRACE1(X)#define TRACE2(X,Y)#define TRACE3(X,Y,Z)#define TRACE4(X,Y,Z,A)#define TRACE5(X,Y,Z,A,B)#endif#if OS_UNIX/*** Here is the dirt on POSIX advisory locks:  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.**** Bummer.  If you ask me, this is broken.  Badly broken.  It 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.**** The OsFile 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 OsFile 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.**** 2004-Jan-11:** More recent discoveries about POSIX advisory locks.  (The more** I discover, the more I realize the a POSIX advisory locks are** an abomination.)**** 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 OsFile structure contains** a pointer to an openCnt structure.  There is one openCnt structure** per open inode, which means that multiple OsFiles can point to a single** openCnt.  When an attempt is made to close an OsFile, if there are** other OsFiles 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 openCnt structure keeps a list of file descriptors that need to** be closed and that list is walked (and cleared) when the last lock** clears.**** First, under Linux threads, because each thread has a separate** process ID, lock operations in one thread do not override locks** to the same file in other threads.  Linux threads behave like** separate processes in this respect.  But, if you close a file** descriptor in linux threads, all locks are cleared, even locks** on other threads and even though the other threads have different** process IDs.  Linux threads is inconsistent in this respect.** (I'm beginning to think that linux threads is an abomination too.)** The consequence of this all is that the hash table for the lockInfo** structure has to include the process id as part of its key because** locks in different threads are treated as distinct.  But the ** openCnt structure should not include the process id in its** key because close() clears lock on all threads, not just the current** thread.  Were it not for this goofiness in linux threads, we could** combine the lockInfo and openCnt structures into a single structure.*//*** An instance of the following structure serves as the key used** to locate a particular lockInfo structure given its inode.  Note** that we have to include the process ID as part of the key.  On some** threading implementations (ex: linux), each thread has a separate** process ID.*/struct lockKey {  dev_t dev;   /* Device number */  ino_t ino;   /* Inode number */  pid_t pid;   /* Process ID */};/*** An instance of the following structure is allocated for each open** inode on each thread with a different process ID.  (Threads have** different process IDs on linux, but not on most other unixes.)**** A single inode can have multiple file descriptors, so each OsFile** structure contains a pointer to an instance of this object and this** object keeps a count of the number of OsFiles pointing to it.*/struct lockInfo {  struct lockKey key;  /* The lookup key */  int cnt;             /* 0: unlocked.  -1: write lock.  1...: read lock. */  int nRef;            /* Number of pointers to this structure */};/*** An instance of the following structure serves as the key used** to locate a particular openCnt structure given its inode.  This** is the same as the lockKey except that the process ID is omitted.*/struct openKey {  dev_t dev;   /* Device number */  ino_t ino;   /* Inode number */};/*** 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.*/struct openCnt {  struct openKey key;   /* 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() */};/* ** These hash table maps inodes and process IDs into lockInfo and openCnt** structures.  Access to these hash tables must be protected by a mutex.*/static Hash lockHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };static Hash openHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };/*** Release a lockInfo structure previously allocated by findLockInfo().*/static void releaseLockInfo(struct lockInfo *pLock){  pLock->nRef--;  if( pLock->nRef==0 ){    sqliteHashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0);    sqliteFree(pLock);  }}/*** Release a openCnt structure previously allocated by findLockInfo().*/static void releaseOpenCnt(struct openCnt *pOpen){  pOpen->nRef--;  if( pOpen->nRef==0 ){    sqliteHashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0);    sqliteFree(pOpen->aPending);    sqliteFree(pOpen);  }}/*** Given a file descriptor, locate lockInfo and openCnt structures that** describes that file descriptor.  Create a new ones if necessary.  The** return values might be unset if an error occurs.**** Return the number of errors.*/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;  key1.pid = getpid();  memset(&key2, 0, sizeof(key2));  key2.dev = statbuf.st_dev;  key2.ino = statbuf.st_ino;  pLock = (struct lockInfo*)sqliteHashFind(&lockHash, &key1, sizeof(key1));  if( pLock==0 ){    struct lockInfo *pOld;    pLock = sqliteMallocRaw( sizeof(*pLock) );    if( pLock==0 ) return 1;    pLock->key = key1;    pLock->nRef = 1;    pLock->cnt = 0;    pOld = sqliteHashInsert(&lockHash, &pLock->key, sizeof(key1), pLock);    if( pOld!=0 ){      assert( pOld==pLock );      sqliteFree(pLock);      return 1;    }  }else{    pLock->nRef++;  }  *ppLock = pLock;  pOpen = (struct openCnt*)sqliteHashFind(&openHash, &key2, sizeof(key2));  if( pOpen==0 ){    struct openCnt *pOld;    pOpen = sqliteMallocRaw( sizeof(*pOpen) );    if( pOpen==0 ){      releaseLockInfo(pLock);      return 1;    }    pOpen->key = key2;    pOpen->nRef = 1;    pOpen->nLock = 0;    pOpen->nPending = 0;    pOpen->aPending = 0;    pOld = sqliteHashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen);    if( pOld!=0 ){      assert( pOld==pOpen );      sqliteFree(pOpen);      releaseLockInfo(pLock);      return 1;    }  }else{    pOpen->nRef++;  }  *ppOpen = pOpen;  return 0;}#endif  /** POSIX advisory lock work-around **//*** If we compile with the SQLITE_TEST macro set, then the following block** of code will give us the ability to simulate a disk I/O error.  This** is used for testing the I/O recovery logic.*/#ifdef SQLITE_TESTint sqlite_io_error_pending = 0;#define SimulateIOError(A)  \   if( sqlite_io_error_pending ) \     if( sqlite_io_error_pending-- == 1 ){ local_ioerr(); return A; }static void local_ioerr(){  sqlite_io_error_pending = 0;  /* Really just a place to set a breakpoint */}#else#define SimulateIOError(A)#endif/*** When testing, keep a count of the number of open files.*/#ifdef SQLITE_TESTint sqlite_open_file_count = 0;#define OpenCounter(X)  sqlite_open_file_count+=(X)#else#define OpenCounter(X)#endif/*** Delete the named file*/int sqliteOsDelete(const char *zFilename){#if OS_UNIX  unlink(zFilename);#endif#if OS_WIN  DeleteFile(zFilename);#endif#if OS_MAC  unlink(zFilename);#endif  return SQLITE_OK;}/*** Return TRUE if the named file exists.*/int sqliteOsFileExists(const char *zFilename){#if OS_UNIX  return access(zFilename, 0)==0;#endif#if OS_WIN  return GetFileAttributes(zFilename) != 0xffffffff;#endif#if OS_MAC  return access(zFilename, 0)==0;#endif}#if 0 /* NOT USED *//*** Change the name of an existing file.*/int sqliteOsFileRename(const char *zOldName, const char *zNewName){#if OS_UNIX  if( link(zOldName, zNewName) ){    return SQLITE_ERROR;  }  unlink(zOldName);  return SQLITE_OK;#endif#if OS_WIN  if( !MoveFile(zOldName, zNewName) ){    return SQLITE_ERROR;  }  return SQLITE_OK;#endif#if OS_MAC  /**** FIX ME ***/  return SQLITE_ERROR;#endif}#endif /* NOT USED *//*** 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 sqliteOsOpenReadWrite(  const char *zFilename,  OsFile *id,  int *pReadonly){#if OS_UNIX  int rc;

⌨️ 快捷键说明

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