public sqlite3_mutex(sqlite3_mutex mutex, int id, int nRef, int owner #if DEBUG , int trace #endif ) { this.mutex = mutex; this.id = id; this.nRef = nRef; this.owner = owner; #if DEBUG this.trace = 0; #endif }
static int debugMutexTry( sqlite3_mutex pX ) { sqlite3_debug_mutex p = (sqlite3_debug_mutex)pX; Debug.Assert( p.id == SQLITE_MUTEX_RECURSIVE || debugMutexNotheld( p ) ); p.cnt++; return SQLITE_OK; }
/* ** The sqlite3_mutex_leave() routine exits a mutex that was ** previously entered by the same thread. The behavior ** is undefined if the mutex is not currently entered or ** is not currently allocated. SQLite will never do either. */ static void debugMutexLeave( sqlite3_mutex pX ) { sqlite3_debug_mutex p = (sqlite3_debug_mutex)pX; Debug.Assert( debugMutexHeld( p ) ); p.cnt--; Debug.Assert( p.id == SQLITE_MUTEX_RECURSIVE || debugMutexNotheld( p ) ); }
} //#define sqlite3_mutex_try(X) SQLITE_OK static void sqlite3_mutex_leave(sqlite3_mutex m) { } //#define sqlite3_mutex_leave(X)
static bool sqlite3_mutex_notheld(sqlite3_mutex p) { return(true); }
static void noopMutexEnter(sqlite3_mutex p) { }
/* ** The sqlite3_mutex_leave() routine exits a mutex that was previously ** entered by the same thread. The behavior is undefined if the mutex ** is not currently entered. If a NULL pointer is passed as an argument ** this function is a no-op. */ static void sqlite3_mutex_leave(sqlite3_mutex p){ if( p !=null){ sqlite3GlobalConfig.mutex.xMutexLeave(p); } }
// was:sqlite3BtreeOpen public static RC Open(VirtualFileSystem pVfs, string zFilename, sqlite3 db, ref Btree rTree, OPEN flags, VFSOPEN vfsFlags) { Btree p; // Handle to return var rc = RC.OK; byte nReserve; // Byte of unused space on each page var zDbHeader = new byte[100]; // Database header content // True if opening an ephemeral, temporary database */ bool isTempDb = string.IsNullOrEmpty(zFilename); // Set the variable isMemdb to true for an in-memory database, or false for a file-based database. #if SQLITE_OMIT_MEMORYDB var isMemdb = false; #else var isMemdb = (zFilename == ":memory:" || isTempDb && db.sqlite3TempInMemory()); #endif Debug.Assert(db != null); Debug.Assert(pVfs != null); Debug.Assert(MutexEx.Held(db.Mutex)); Debug.Assert(((uint)flags & 0xff) == (uint)flags); // flags fit in 8 bits // Only a BTREE_SINGLE database can be BTREE_UNORDERED Debug.Assert((flags & OPEN.UNORDERED) == 0 || (flags & OPEN.SINGLE) != 0); // A BTREE_SINGLE database is always a temporary and/or ephemeral Debug.Assert((flags & OPEN.SINGLE) == 0 || isTempDb); if ((db.flags & sqlite3b.SQLITE.NoReadlock) != 0) flags |= OPEN.NO_READLOCK; if (isMemdb) flags |= OPEN.MEMORY; if ((vfsFlags & VFSOPEN.MAIN_DB) != 0 && (isMemdb || isTempDb)) vfsFlags = (vfsFlags & ~VFSOPEN.MAIN_DB) | VFSOPEN.TEMP_DB; p = new Btree(); p.InTransaction = TRANS.NONE; p.DB = db; #if !SQLITE_OMIT_SHARED_CACHE p.Locks.Tree = p; p.Locks.TableID = 1; #endif BtShared shared = null; // Shared part of btree structure sqlite3_mutex mutexOpen = null; // Prevents a race condition. #if !SQLITE_OMIT_SHARED_CACHE && !SQLITE_OMIT_DISKIO // If this Btree is a candidate for shared cache, try to find an existing BtShared object that we can share with if (!isMemdb && !isTempDb) { if ((vfsFlags & VFSOPEN.SHAREDCACHE) != 0) { p.Sharable = true; string zPathname; rc = pVfs.xFullPathname(zFilename, out zPathname); mutexOpen = MutexEx.sqlite3MutexAlloc(MUTEX.STATIC_OPEN); MutexEx.sqlite3_mutex_enter(mutexOpen); var mutexShared = MutexEx.sqlite3MutexAlloc(MUTEX.STATIC_MASTER); MutexEx.sqlite3_mutex_enter(mutexShared); for (shared = SysEx.getGLOBAL<BtShared>(s_sqlite3SharedCacheList); shared != null; shared = shared.Next) { Debug.Assert(shared.nRef > 0); if (string.Equals(zPathname, shared.Pager.sqlite3PagerFilename) && shared.Pager.sqlite3PagerVfs == pVfs) { for (var iDb = db.DBs - 1; iDb >= 0; iDb--) { var existingTree = db.AllocDBs[iDb].Tree; if (existingTree != null && existingTree.Shared == shared) { MutexEx.sqlite3_mutex_leave(mutexShared); MutexEx.sqlite3_mutex_leave(mutexOpen); p = null; return RC.CONSTRAINT; } } p.Shared = shared; shared.nRef++; break; } } MutexEx.sqlite3_mutex_leave(mutexShared); } #if DEBUG else // In debug mode, we mark all persistent databases as sharable even when they are not. This exercises the locking code and // gives more opportunity for asserts(sqlite3_mutex_held()) statements to find locking problems. p.Sharable = true; #endif } #endif if (shared == null) { // The following asserts make sure that structures used by the btree are the right size. This is to guard against size changes that result // when compiling on a different architecture. Debug.Assert(sizeof(long) == 8 || sizeof(long) == 4); Debug.Assert(sizeof(ulong) == 8 || sizeof(ulong) == 4); Debug.Assert(sizeof(uint) == 4); Debug.Assert(sizeof(ushort) == 2); Debug.Assert(sizeof(Pgno) == 4); shared = new BtShared(); rc = Pager.Open(pVfs, out shared.Pager, zFilename, EXTRA_SIZE, (Pager.PAGEROPEN)flags, vfsFlags, pageReinit, () => new MemPage()); if (rc == RC.OK) rc = shared.Pager.ReadFileHeader(zDbHeader.Length, zDbHeader); if (rc != RC.OK) goto btree_open_out; shared.OpenFlags = flags; shared.DB = db; shared.Pager.SetBusyHandler(btreeInvokeBusyHandler, shared); p.Shared = shared; shared.Cursors = null; shared.Page1 = null; shared.ReadOnly = shared.Pager.IsReadonly; #if SQLITE_SECURE_DELETE pBt.secureDelete = true; #endif shared.PageSize = (uint)((zDbHeader[16] << 8) | (zDbHeader[17] << 16)); if (shared.PageSize < 512 || shared.PageSize > Pager.SQLITE_MAX_PAGE_SIZE || ((shared.PageSize - 1) & shared.PageSize) != 0) { shared.PageSize = 0; #if !SQLITE_OMIT_AUTOVACUUM // If the magic name ":memory:" will create an in-memory database, then leave the autoVacuum mode at 0 (do not auto-vacuum), even if // SQLITE_DEFAULT_AUTOVACUUM is true. On the other hand, if SQLITE_OMIT_MEMORYDB has been defined, then ":memory:" is just a // regular file-name. In this case the auto-vacuum applies as per normal. if (zFilename != string.Empty && !isMemdb) { shared.AutoVacuum = (AUTOVACUUM.DEFAULT != AUTOVACUUM.NONE); shared.IncrVacuum = (AUTOVACUUM.DEFAULT == AUTOVACUUM.INCR); } #endif nReserve = 0; } else { nReserve = zDbHeader[20]; shared.PageSizeFixed = true; #if !SQLITE_OMIT_AUTOVACUUM shared.AutoVacuum = ConvertEx.Get4(zDbHeader, 36 + 4 * 4) != 0; shared.IncrVacuum = ConvertEx.Get4(zDbHeader, 36 + 7 * 4) != 0; #endif } rc = shared.Pager.SetPageSize(ref shared.PageSize, nReserve); if (rc != RC.OK) goto btree_open_out; shared.UsableSize = (ushort)(shared.PageSize - nReserve); Debug.Assert((shared.PageSize & 7) == 0); // 8-byte alignment of pageSize #if !SQLITE_OMIT_SHARED_CACHE && !SQLITE_OMIT_DISKIO // Add the new BtShared object to the linked list sharable BtShareds. if (p.Sharable) { sqlite3_mutex mutexShared; shared.nRef = 1; mutexShared = MutexEx.sqlite3MutexAlloc(MUTEX.STATIC_MASTER); if (MutexEx.SQLITE_THREADSAFE && MutexEx.WantsCoreMutex) shared.Mutex = MutexEx.sqlite3MutexAlloc(MUTEX.FAST); MutexEx.sqlite3_mutex_enter(mutexShared); shared.Next = SysEx.getGLOBAL<BtShared>(s_sqlite3SharedCacheList); SysEx.setGLOBAL<BtShared>(s_sqlite3SharedCacheList, shared); MutexEx.sqlite3_mutex_leave(mutexShared); } #endif } #if !SQLITE_OMIT_SHARED_CACHE && !SQLITE_OMIT_DISKIO // If the new Btree uses a sharable pBtShared, then link the new Btree into the list of all sharable Btrees for the same connection. // The list is kept in ascending order by pBt address. Btree existingTree2; if (p.Sharable) for (var i = 0; i < db.DBs; i++) if ((existingTree2 = db.AllocDBs[i].Tree) != null && existingTree2.Sharable) { while (existingTree2.Prev != null) { existingTree2 = existingTree2.Prev; } if (p.Shared.Version < existingTree2.Shared.Version) { p.Next = existingTree2; p.Prev = null; existingTree2.Prev = p; } else { while (existingTree2.Next != null && existingTree2.Next.Shared.Version < p.Shared.Version) existingTree2 = existingTree2.Next; p.Next = existingTree2.Next; p.Prev = existingTree2; if (p.Next != null) p.Next.Prev = p; existingTree2.Next = p; } break; } #endif rTree = p; // btree_open_out: if (rc != RC.OK) { if (shared != null && shared.Pager != null) shared.Pager.Close(); shared = null; p = null; rTree = null; } else { // If the B-Tree was successfully opened, set the pager-cache size to the default value. Except, when opening on an existing shared pager-cache, // do not change the pager-cache size. if (p.GetSchema(0, null, null) == null) p.Shared.Pager.SetCacheSize(SQLITE_DEFAULT_CACHE_SIZE); } if (mutexOpen != null) { Debug.Assert(MutexEx.Held(mutexOpen)); MutexEx.sqlite3_mutex_leave(mutexOpen); } return rc; }
/* ** Free a dynamic mutex. */ static void sqlite3_mutex_free( sqlite3_mutex p){ if( p!=null ){ sqlite3GlobalConfig.mutex.xMutexFree( p); } }
/* ** Obtain the mutex p. If some other thread already has the mutex, block ** until it can be obtained. */ static void sqlite3_mutex_enter(sqlite3_mutex p){ if( p !=null){ sqlite3GlobalConfig.mutex.xMutexEnter(p); } }
public static bool sqlite3_mutex_notheld(sqlite3_mutex sqlite3_mutex) { return true; }
public static void sqlite3_mutex_leave(sqlite3_mutex sqlite3_mutex) { }
public static void sqlite3_mutex_free(sqlite3_mutex mutex) { }
static void noopMutexLeave(sqlite3_mutex p) { }
/* ** Enter a countable mutex. Block until entry is safe. */ static void counterMutexEnter(sqlite3_mutex p) { Debug.Assert(g.isInit); g.aCounter[p.eType]++; g.m.xMutexEnter(p.pReal); }
static int noopMutexTry(sqlite3_mutex p) { return SQLITE_OK; }
/* Leave a mutex */ static void counterMutexLeave(sqlite3_mutex p) { Debug.Assert(g.isInit); g.m.xMutexLeave(p.pReal); }
static int noopMutexNotheld(sqlite3_mutex p) { return(1); }
/* Return true if the countable mutex is not currently held */ static bool counterMutexNotheld(sqlite3_mutex p) { return(g.m.xMutexNotheld(p.pReal)); }
} //#define sqlite3_mutex_alloc(X) ((sqlite3_mutex*)8) private static void sqlite3_mutex_free(ref sqlite3_mutex m) { } //#define sqlite3_mutex_free(X)
}//#define sqlite3_mutex_alloc(X) ((sqlite3_mutex*)8) static void sqlite3_mutex_free(sqlite3_mutex m) { } //#define sqlite3_mutex_free(X)
public static void sqlite3_mutex_enter(sqlite3_mutex sqlite3_mutex) { }
/* ** Obtain the mutex p. If successful, return SQLITE_OK. Otherwise, if another ** thread holds the mutex and it cannot be obtained, return SQLITE_BUSY. */ static int sqlite3_mutex_try(sqlite3_mutex p){ int rc = SQLITE_OK; if( p!=null ){ return sqlite3GlobalConfig.mutex.xMutexTry(p); } return rc; }
static bool debugMutexNotheld( sqlite3_mutex pX ) { sqlite3_debug_mutex p = (sqlite3_debug_mutex)pX; return p == null || p.cnt == 0; }
static void noopMutexFree(sqlite3_mutex p) { }
static bool sqlite3_mutex_notheld(sqlite3_mutex p){ return p == null || sqlite3GlobalConfig.mutex.xMutexNotheld( p ); }
static int noopMutexNotheld(sqlite3_mutex p) { return 1; }
public PgHdr1 pLruHead, pLruTail; /* LRU list of unpinned pages */ // C# public PGroup() { mutex = new sqlite3_mutex(); }
} //#define sqlite3_mutex_leave(X) static bool sqlite3_mutex_held(sqlite3_mutex m) { return(true); }//#define sqlite3_mutex_held(X) ((void)(X),1)
/* ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are ** intended for use inside Debug.Assert() statements. */ static bool sqlite3_mutex_held(sqlite3_mutex p) { return(p == null || sqlite3GlobalConfig.mutex.xMutexHeld(p) != 0); }
static bool debugMutexNotheld(sqlite3_mutex pX) { sqlite3_debug_mutex p = (sqlite3_debug_mutex)pX; return(p == null || p.cnt == 0); }
static int noopMutexTry(sqlite3_mutex p) { return(SQLITE_OK); }
public static bool Held(sqlite3_mutex sqlite3_mutex) { return(true); }
static bool sqlite3_mutex_notheld(sqlite3_mutex p) { return(p == null || sqlite3GlobalConfig.mutex.xMutexNotheld(p)); }
public static bool sqlite3_mutex_notheld(sqlite3_mutex sqlite3_mutex) { return(true); }
} //#define sqlite3_mutex_held(X) 1 static bool sqlite3_mutex_notheld(sqlite3_mutex m) { return(true); } //#define sqlite3_mutex_notheld(X) 1
} //#define sqlite3_mutex_free(X) static void sqlite3_mutex_enter(sqlite3_mutex m) { } //#define sqlite3_mutex_enter(X)
/* ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt ** to enter a mutex. If another thread is already within the mutex, ** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return ** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK ** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can ** be entered multiple times by the same thread. In such cases the, ** mutex must be exited an equal number of times before another thread ** can enter. If the same thread tries to enter any other kind of mutex ** more than once, the behavior is undefined. */ static void debugMutexEnter( sqlite3_mutex pX ) { sqlite3_debug_mutex p = (sqlite3_debug_mutex)pX; Debug.Assert( p.id == SQLITE_MUTEX_RECURSIVE || debugMutexNotheld( p ) ); p.cnt++; }
static void sqlite3_mutex_leave( sqlite3_mutex m ) { } //#define sqlite3_mutex_leave(X) static bool sqlite3_mutex_held( sqlite3_mutex m ) { return true; }//#define sqlite3_mutex_held(X) 1
/* ** This routine deallocates a previously allocated mutex. */ static void debugMutexFree( sqlite3_mutex pX ) { sqlite3_debug_mutex p = (sqlite3_debug_mutex)pX; Debug.Assert( p.cnt == 0 ); Debug.Assert( p.id == SQLITE_MUTEX_FAST || p.id == SQLITE_MUTEX_RECURSIVE ); //sqlite3_free(ref p); }
}//#define sqlite3_mutex_held(X) ((void)(X),1) static bool sqlite3_mutex_notheld(sqlite3_mutex m) { return true; } //#define sqlite3_mutex_notheld(X) ((void)(X),1)
public static bool Held(sqlite3_mutex sqlite3_mutex) { return true; }