public GlobalStatics( bool memstat, bool coreMutex, bool fullMutex, bool openUri, int maxStrlen, int lookasideSize, int lookasides, //sqlite3_mem_methods m, //sqlite3_mutex_methods mutex, //array_t<byte[]> heap, //int minReq, int maxReq, byte[][] scratch, int scratchSize, int scratchs, bool sharedCacheEnabled, bool isInit, bool inProgress, bool isMutexInit, bool isMallocInit, MutexEx initMutex, int initMutexRefs, Action <object, int, string> log, object logArg, bool localtimeFault #if ENABLE_SQLLOG , Action <object, TagBase, string, int> Sqllog, object SqllogArg #endif ) { Memstat = memstat; CoreMutex = coreMutex; OpenUri = openUri; FullMutex = fullMutex; MaxStrlen = maxStrlen; LookasideSize = lookasideSize; Lookasides = lookasides; //m = m; //mutex = mutex; //Heap = heap; //MaxReq = minReq; MinReq = maxReq; Scratch = scratch; ScratchSize = scratchSize; Scratchs = scratchs; SharedCacheEnabled = sharedCacheEnabled; IsInit = isInit; InProgress = inProgress; IsMutexInit = isMutexInit; IsMallocInit = isMallocInit; InitMutex = initMutex; InitMutexRefs = initMutexRefs; Log = log; LogArg = logArg; LocaltimeFault = localtimeFault; #if ENABLE_SQLLOG Sqllog = sqllog; SqllogArg = sqllogArg; #endif }
public static void MemReleaseExternal(Mem mem) { Debug.Assert(mem.Ctx == null || MutexEx.Held(mem.Ctx.Mutex)); if ((mem.Flags & MEM.Agg) != 0) { MemFinalize(mem, mem.u.Def); Debug.Assert((mem.Flags & MEM.Agg) == 0); MemRelease(mem); } else if ((mem.Flags & MEM.Dyn) != 0 && mem.Del != null) { Debug.Assert((mem.Flags & MEM.RowSet) == 0); mem.Del(mem.Z); mem.Del = null; } else if ((mem.Flags & MEM.RowSet) != 0) { RowSet_Clear(mem.u.RowSet); } else if ((mem.Flags & MEM.Frame) != 0) { MemSetNull(mem); } mem.N = 0; mem.Z = null; mem.Z_ = null; }
public static RC MemExpandBlob(Mem mem) { if ((mem.Flags & MEM.Zero) != 0) { Debug.Assert((mem.Flags & MEM.Blob) != 0); Debug.Assert((mem.Flags & MEM.RowSet) == 0); Debug.Assert(mem.Ctx == null || MutexEx.Held(mem.Ctx.Mutex)); // Set nByte to the number of bytes required to store the expanded blob. int bytes = mem.N + mem.u.Zeros; if (bytes <= 0) { bytes = 1; } if (MemGrow(mem, bytes, true) != 0) { return(RC.NOMEM); } //: _memset(&mem->Z[mem->N], 0, mem->u.Zeros); mem.Z_ = Encoding.UTF8.GetBytes(mem.Z); mem.Z = null; mem.N += (int)mem.u.Zeros; mem.u.I = 0; mem.Flags &= ~(MEM.Zero | MEM.Static | MEM.Ephem | MEM.Term); mem.Flags |= MEM.Dyn; } return(RC.OK); }
static RC BindText(Vdbe p, int i, string z, int n, Action <string> del, TEXTENCODE encoding) { RC rc = VdbeUnbind(p, i); if (rc == RC.OK) { if (z != null) { Mem var = p.Vars[i - 1]; rc = MemSetStr(var, z, n, encoding, del); if (rc == RC.OK && encoding != 0) { rc = ChangeEncoding(var, E.CTXENCODE(p.Ctx)); } SysEx.Error(p.Ctx, rc, 0); rc = SysEx.ApiExit(p.Ctx, rc); } MutexEx.Leave(p.Ctx.Mutex); } else if (del != null) { del(z); } return(rc); }
public static long IntValue(Mem mem) { Debug.Assert(mem.Ctx == null || MutexEx.Held(mem.Ctx.Mutex)); // assert( EIGHT_BYTE_ALIGNMENT(pMem) ); MEM flags = mem.Flags; if ((flags & MEM.Int) != 0) { return(mem.u.I); } else if ((flags & MEM.Real) != 0) { return(DoubleToInt64(mem.R)); } else if ((flags & (MEM.Str)) != 0) { Debug.Assert(mem.Z != null || mem.N == 0); C.ASSERTCOVERAGE(mem.Z == null); long value; ConvertEx.Atoi64(mem.Z, out value, mem.N, mem.Encode); return(value); } else if ((flags & (MEM.Blob)) != 0) { Debug.Assert(mem.Z_ != null || mem.N == 0); C.ASSERTCOVERAGE(mem.Z_ == null); long value; ConvertEx.Atoi64(Encoding.UTF8.GetString(mem.Z_, 0, mem.N), out value, mem.N, mem.Encode); return(value); } return(0); }
public static RC MemNumerify(Mem mem) { if ((mem.Flags & (MEM.Int | MEM.Real | MEM.Null)) == 0) { Debug.Assert((mem.Flags & (MEM.Blob | MEM.Str)) != 0); Debug.Assert(mem.Ctx == null || MutexEx.Held(mem.Ctx.Mutex)); if ((mem.Flags & MEM.Blob) != 0 && mem.Z == null) { if (ConvertEx.Atoi64(Encoding.UTF8.GetString(mem.Z_, 0, mem.Z_.Length), out mem.u.I, mem.N, mem.Encode) == 0) { E.MemSetTypeFlag(mem, MEM.Int); } else { mem.R = RealValue(mem); E.MemSetTypeFlag(mem, MEM.Real); IntegerAffinity(mem); } } else if (ConvertEx.Atoi64(mem.Z, out mem.u.I, mem.N, mem.Encode) == 0) { E.MemSetTypeFlag(mem, MEM.Int); } else { mem.R = RealValue(mem); E.MemSetTypeFlag(mem, MEM.Real); IntegerAffinity(mem); } } Debug.Assert((mem.Flags & (MEM.Int | MEM.Real | MEM.Null)) != 0); mem.Flags &= ~(MEM.Str | MEM.Blob); return(RC.OK); }
public static double RealValue(Mem mem) { Debug.Assert(mem.Ctx == null || MutexEx.Held(mem.Ctx.Mutex)); //Debug.Assert(C._HASALIGNMENT8(mem)); if ((mem.Flags & MEM.Real) != 0) { return(mem.R); } else if ((mem.Flags & MEM.Int) != 0) { return((double)mem.u.I); } else if ((mem.Flags & (MEM.Str)) != 0) { double val = (double)0; ConvertEx.Atof(mem.Z, ref val, mem.N, mem.Encode); return(val); } else if ((mem.Flags & (MEM.Blob)) != 0) { double val = (double)0; Debug.Assert(mem.Z_ != null || mem.N == 0); ConvertEx.Atof(Encoding.UTF8.GetString(mem.Z_, 0, mem.N), ref val, mem.N, mem.Encode); return(val); } return((double)0); }
public static void Result_ErrorNoMem(FuncContext fctx) { Debug.Assert(MutexEx.Held(fctx.S.Ctx.Mutex)); MemSetNull(fctx.S); fctx.IsError = RC.NOMEM; fctx.S.Ctx.MallocFailed = true; }
public static RC Reprepare(Vdbe p) { Context ctx = p.Ctx; Debug.Assert(MutexEx.Held(ctx.Mutex)); string sql = Vdbe.Sql(p); Debug.Assert(sql != null); // Reprepare only called for prepare_v2() statements Vdbe newVdbe = new Vdbe(); RC rc = LockAndPrepare(ctx, sql, -1, false, p, ref newVdbe, null); if (rc != 0) { if (rc == RC.NOMEM) { ctx.MallocFailed = true; } Debug.Assert(newVdbe == null); return(rc); } else { Debug.Assert(newVdbe != null); } Vdbe.Swap((Vdbe)newVdbe, p); Vdbe.TransferBindings(newVdbe, (Vdbe)p); newVdbe.ResetStepResult(); newVdbe.Finalize(); return(RC.OK); }
public static RC Prepare16(Context ctx, string sql, int bytes, bool isPrepareV2, out Vdbe stmtOut, out string tailOut) { // This function currently works by first transforming the UTF-16 encoded string to UTF-8, then invoking sqlite3_prepare(). The // tricky bit is figuring out the pointer to return in *pzTail. stmtOut = null; if (!sqlite3SafetyCheckOk(ctx)) { return(SysEx.MISUSE_BKPT()); } MutexEx.Enter(ctx.Mutex); RC rc = RC.OK; string tail8 = null; string sql8 = Vdbe.Utf16to8(ctx, sql, bytes, TEXTENCODE.UTF16NATIVE); if (sql8 != null) { rc = LockAndPrepare(ctx, sql8, -1, isPrepareV2, null, ref stmtOut, ref tail8); } if (tail8 != null && tailOut != null) { // If sqlite3_prepare returns a tail pointer, we calculate the equivalent pointer into the UTF-16 string by counting the unicode // characters between zSql8 and zTail8, and then returning a pointer the same number of characters into the UTF-16 string. Debugger.Break(); //: int charsParsed = Vdbe::Utf8CharLen(sql8, (int)(tail8 - sql8)); //: *tailOut = (uint8 *)sql + Vdbe::Utf16ByteLen(sql, charsParsed); } C._tagfree(ctx, ref sql8); rc = SysEx.ApiExit(ctx, rc); MutexEx.Leave(ctx.Mutex); return(rc); }
public static RC Config(Context ctx, VTABLECONFIG op, object arg1) { RC rc = RC.OK; MutexEx.Enter(ctx.Mutex); switch (op) { case VTABLECONFIG.CONSTRAINT: { VTableContext p = ctx.VTableCtx; if (p == null) { rc = SysEx.MISUSE_BKPT(); } else { Debug.Assert(p.Table == null || (p.Table.TabFlags & TF.Virtual) != 0); p.VTable.Constraint = (bool)arg1; } break; } default: rc = SysEx.MISUSE_BKPT(); break; } if (rc != RC.OK) { Main.Error(ctx, rc, null); } MutexEx.Leave(ctx.Mutex); return(rc); }
public static RC DeclareVTable(Context ctx, string createTableName) { MutexEx.Enter(ctx.Mutex); Table table; if (ctx.VTableCtx == null || (table = ctx.VTableCtx.Table) == null) { sqlite3Error(ctx, RC.MISUSE, null); MutexEx.Leave(ctx.Mutex); return(SysEx.MISUSE_BKPT()); } Debug.Assert((table.TabFlags & TF.Virtual) != 0); RC rc = RC.OK; Parse parse = new Parse(); //: _stackalloc(ctx, sizeof(Parse)); if (parse == null) { rc = RC.NOMEM; } else { parse.DeclareVTable = true; parse.Ctx = ctx; parse.QueryLoops = 1; string error = null; if (sqlite3RunParser(parse, createTableName, ref error) == RC.OK && parse.NewTable != null && !ctx.MallocFailed && parse.NewTable.Select == null && (parse.NewTable.TabFlags & TF.Virtual) == 0) { if (table.Cols.data == null) { table.Cols.data = parse.NewTable.Cols.data; table.Cols.length = parse.NewTable.Cols.length; parse.NewTable.Cols.length = 0; parse.NewTable.Cols.data = null; } ctx.VTableCtx.Table = null; } else { sqlite3Error(ctx, RC.ERROR, (error != null ? "%s" : null), error); C._tagfree(ctx, ref error); rc = RC.ERROR; } parse.DeclareVTable = false; if (parse.V != null) { parse.V.Finalize(); } Parse.DeleteTable(ctx, ref parse.NewTable); parse = null; //: C._stackfree(ctx, parse); } Debug.Assert(((int)rc & 0xff) == (int)rc); rc = SysEx.ApiExit(ctx, rc); MutexEx.Leave(ctx.Mutex); return(rc); }
public static RC MemRealify(Mem mem) { Debug.Assert(mem.Ctx == null || MutexEx.Held(mem.Ctx.Mutex)); //Debug.Assert(C._HASALIGNMENT8(mem)); mem.R = RealValue(mem); E.MemSetTypeFlag(mem, MEM.Real); return(RC.OK); }
public static Vdbe Stmt_Next(Context ctx, Vdbe p) { MutexEx.Enter(ctx.Mutex); Vdbe next = (p == null ? ctx.Vdbes[0] : p.Next); MutexEx.Leave(ctx.Mutex); return(next); }
public static RC UnregisterVfs(VSystem vfs) { var mutex = MutexEx.Alloc(MutexEx.MUTEX.STATIC_MASTER); MutexEx.Enter(mutex); UnlinkVfs(vfs); MutexEx.Leave(mutex); return(RC.OK); }
public static void CloseExtensions(Context ctx) { Debug.Assert(MutexEx.Held(ctx.Mutex)); for (int i = 0; i < ctx.Extensions.length; i++) { ctx.Vfs.DlClose((HANDLE)ctx.Extensions[i]); } C._tagfree(ctx, ref ctx.Extensions.data); }
public RC SetAuthorizer(Context ctx, Func <object, int, string, string, string, string, ARC> auth, object arg) { MutexEx.Enter(ctx.Mutex); ctx.Auth = auth; ctx.AuthArg = arg; Vdbe.ExpirePreparedStatements(ctx); MutexEx.Leave(ctx.Mutex); return(RC.OK); }
public static RC LoadExtension(Context ctx, string fileName, string procName, ref string errMsg) { MutexEx.Enter(ctx.Mutex); RC rc = LoadExtension_(ctx, fileName, procName, ref errMsg); rc = ApiExit(ctx, rc); MutexEx.Leave(ctx.Mutex); return(rc); }
public static RC MemIntegerify(Mem mem) { Debug.Assert(mem.Ctx == null || MutexEx.Held(mem.Ctx.Mutex)); Debug.Assert((mem.Flags & MEM.RowSet) == 0); //Debug.Assert(C._HASALIGNMENT8(mem)); mem.u.I = IntValue(mem); E.MemSetTypeFlag(mem, MEM.Int); return(RC.OK); }
static void ColumnMallocFailure(Vdbe p) { // If malloc() failed during an encoding conversion within an sqlite3_column_XXX API, then set the return code of the statement to // RC_NOMEM. The next call to _step() (if any) will return RC_ERROR and _finalize() will return NOMEM. if (p != null) { p.RC_ = SysEx.ApiExit(p.Ctx, p.RC_); MutexEx.Leave(p.Ctx.Mutex); } }
public static RC Bind_Null(Vdbe p, int i) { RC rc = VdbeUnbind(p, i); if (rc == RC.OK) { MutexEx.Leave(p.Ctx.Mutex); } return(rc); }
public static RC MemStringify(Mem mem, TEXTENCODE encode) { MEM f = mem.Flags; Debug.Assert(mem.Ctx == null || MutexEx.Held(mem.Ctx.Mutex)); Debug.Assert((f & MEM.Zero) == 0); Debug.Assert((f & (MEM.Str | MEM.Blob)) == 0); Debug.Assert((f & (MEM.Int | MEM.Real)) != 0); Debug.Assert((mem.Flags & MEM.RowSet) == 0); //: Debug.Assert(C._HASALIGNMENT8(mem)); const int bytes = 32; if (MemGrow(mem, bytes, false) != 0) { return(RC.NOMEM); } // For a Real or Integer, use sqlite3_mprintf() to produce the UTF-8 string representation of the value. Then, if the required encoding // is UTF-16le or UTF-16be do a translation. // FIX ME: It would be better if sqlite3_snprintf() could do UTF-16. if ((f & MEM.Int) != 0) { mem.Z = mem.u.I.ToString(); //: __snprintf(mem->Z, bytes, "%lld", mem->u.I); } else { Debug.Assert((f & MEM.Real) != 0); if (double.IsNegativeInfinity(mem.R)) { mem.Z = "-Inf"; } else if (double.IsInfinity(mem.R)) { mem.Z = "Inf"; } else if (double.IsPositiveInfinity(mem.R)) { mem.Z = "+Inf"; } else if (mem.R.ToString(CultureInfo.InvariantCulture).Contains(".")) { mem.Z = mem.R.ToString(CultureInfo.InvariantCulture).ToLower(); //: __snprintf(mem->Z, bytes, "%!.15g", mem->R); } else { mem.Z = mem.R.ToString(CultureInfo.InvariantCulture) + ".0"; } } mem.N = mem.Z.Length; mem.Encode = TEXTENCODE.UTF8; mem.Flags |= MEM.Str | MEM.Term; ChangeEncoding(mem, encode); return(RC.OK); }
public static RC Bind_Zeroblob(Vdbe p, int i, int n) { RC rc = VdbeUnbind(p, i); if (rc == RC.OK) { MemSetZeroBlob(p.Vars[i - 1], n); MutexEx.Leave(p.Ctx.Mutex); } return(rc); }
public static object get_Auxdata(FuncContext fctx, int arg) { Debug.Assert(MutexEx.Held(fctx.S.Ctx.Mutex)); VdbeFunc vdbeFunc = fctx.VdbeFunc; if (vdbeFunc == null || arg >= vdbeFunc.AuxsLength || arg < 0) { return(null); } return(vdbeFunc.Auxs[arg].Aux); }
public static RC Bind_Double(Vdbe p, int i, double value) { RC rc = VdbeUnbind(p, i); if (rc == RC.OK) { MemSetDouble(p.Vars[i - 1], value); MutexEx.Leave(p.Ctx.Mutex); } return(rc); }
public static RC Bind_Int64(Vdbe p, int i, long value) { RC rc = VdbeUnbind(p, i); if (rc == RC.OK) { MemSetInt64(p.Vars[i - 1], value); MutexEx.Leave(p.Ctx.Mutex); } return(rc); }
public static RC MemSetStr(Mem mem, byte[] z, int offset, int n, TEXTENCODE encode, Action <object> del) { Debug.Assert(mem.Ctx == null || MutexEx.Held(mem.Ctx.Mutex)); Debug.Assert((mem.Flags & MEM.RowSet) == 0); // If z is a NULL pointer, set pMem to contain an SQL NULL. if (z == null || z.Length < offset) { MemSetNull(mem); return(RC.OK); } int limit = (mem.Ctx != null ? mem.Ctx.Limits[(int)LIMIT.LENGTH] : CORE_MAX_LENGTH); // Maximum allowed string or blob size MEM flags = (encode == 0 ? MEM.Blob : MEM.Str); // New value for pMem->flags int bytes = n; // New value for pMem->n if (bytes < 0) { Debug.Assert(encode != 0); if (encode == TEXTENCODE.UTF8) { for (bytes = 0; bytes <= limit && bytes < z.Length - offset && z[offset + bytes] != 0; bytes++) { } } else { for (bytes = 0; bytes <= limit && z[bytes + offset] != 0 || z[offset + bytes + 1] != 0; bytes += 2) { } } } // The following block sets the new values of Mem.z and Mem.xDel. It also sets a flag in local variable "flags" to indicate the memory // management (one of MEM_Dyn or MEM_Static). Debug.Assert(encode == 0); { mem.Z = null; mem.Z_ = C._alloc(n); Buffer.BlockCopy(z, offset, mem.Z_, 0, n); } mem.N = bytes; mem.Flags = MEM.Blob | MEM.Term; mem.Encode = (encode == 0 ? TEXTENCODE.UTF8 : encode); mem.Type = (encode == 0 ? TYPE.BLOB : TYPE.TEXT); #if !OMIT_UTF16 if (mem.Encode != TEXTENCODE.UTF8 && MemHandleBom(mem) != 0) { return(RC.NOMEM); } #endif return(bytes > limit ? RC.TOOBIG : RC.OK); }
public static void MemMove(Mem to, Mem from) { Debug.Assert(from.Ctx == null || MutexEx.Held(from.Ctx.Mutex)); Debug.Assert(to.Ctx == null || MutexEx.Held(to.Ctx.Mutex)); Debug.Assert(from.Ctx == null || to.Ctx == null || from.Ctx == to.Ctx); MemRelease(to); from._memcpy(ref to); from.Flags = MEM.Null; from.Del = null; from.Z = null; from.Z_ = null; }
public static RC TransferBindings(Vdbe from, Vdbe to) { Debug.Assert(to.Ctx == from.Ctx); Debug.Assert(to.Vars.length == from.Vars.length); MutexEx.Enter(to.Ctx.Mutex); for (int i = 0; i < from.Vars.length; i++) { MemMove(to.Vars[i], from.Vars[i]); } MutexEx.Leave(to.Ctx.Mutex); return(RC.OK); }
public static VSystem FindVfs(string name) { VSystem vfs = null; var mutex = MutexEx.Alloc(MutexEx.MUTEX.STATIC_MASTER); MutexEx.Enter(mutex); for (vfs = _vfsList; vfs != null && name != vfs.Name; vfs = vfs.Next) { } MutexEx.Leave(mutex); return(vfs); }
public static void PostInitialize(MutexEx masterMutex) { MutexEx.Leave(_GlobalStatics.InitMutex); // Go back under the static mutex and clean up the recursive mutex to prevent a resource leak. MutexEx.Enter(masterMutex); _GlobalStatics.InitMutexRefs--; if (_GlobalStatics.InitMutexRefs <= 0) { Debug.Assert(_GlobalStatics.InitMutexRefs == 0); MutexEx.Free(_GlobalStatics.InitMutex); _GlobalStatics.InitMutex.Tag = null; } MutexEx.Leave(masterMutex); }
public GlobalStatics( bool memstat, bool coreMutex, bool fullMutex, bool openUri, int maxStrlen, int lookasideSize, int lookasides, //sqlite3_mem_methods m, //sqlite3_mutex_methods mutex, //array_t<byte[]> heap, //int minReq, int maxReq, byte[][] scratch, int scratchSize, int scratchs, bool sharedCacheEnabled, bool isInit, bool inProgress, bool isMutexInit, bool isMallocInit, MutexEx initMutex, int initMutexRefs, Action<object, int, string> log, object logArg, bool localtimeFault #if ENABLE_SQLLOG , Action<object, TagBase, string, int> Sqllog, object SqllogArg #endif ) { Memstat = memstat; CoreMutex = coreMutex; OpenUri = openUri; FullMutex = fullMutex; MaxStrlen = maxStrlen; LookasideSize = lookasideSize; Lookasides = lookasides; //m = m; //mutex = mutex; //Heap = heap; //MaxReq = minReq; MinReq = maxReq; Scratch = scratch; ScratchSize = scratchSize; Scratchs = scratchs; SharedCacheEnabled = sharedCacheEnabled; IsInit = isInit; InProgress = inProgress; IsMutexInit = isMutexInit; IsMallocInit = isMallocInit; InitMutex = initMutex; InitMutexRefs = initMutexRefs; Log = log; LogArg = logArg; LocaltimeFault = localtimeFault; #if ENABLE_SQLLOG Sqllog = sqllog; SqllogArg = sqllogArg; #endif }
public static RC PreInitialize(out MutexEx masterMutex) { masterMutex = default(MutexEx); // If SQLite is already completely initialized, then this call to sqlite3_initialize() should be a no-op. But the initialization // must be complete. So isInit must not be set until the very end of this routine. if (_GlobalStatics.IsInit) return RC.OK; // The following is just a sanity check to make sure SQLite has been compiled correctly. It is important to run this code, but // we don't want to run it too often and soak up CPU cycles for no reason. So we run it once during initialization. #if !NDEBUG && !OMIT_FLOATING_POINT // This section of code's only "output" is via assert() statements. //ulong x = (((ulong)1)<<63)-1; //double y; //Debug.Assert(sizeof(ulong) == 8); //Debug.Assert(sizeof(ulong) == sizeof(double)); //_memcpy<void>(&y, &x, 8); //Debug.Assert(double.IsNaN(y)); #endif RC rc; #if ENABLE_SQLLOG { Init_Sqllog(); } #endif // Make sure the mutex subsystem is initialized. If unable to initialize the mutex subsystem, return early with the error. // If the system is so sick that we are unable to allocate a mutex, there is not much SQLite is going to be able to do. // The mutex subsystem must take care of serializing its own initialization. rc = RC.OK; //MutexEx::Init(); if (rc != 0) return rc; // Initialize the malloc() system and the recursive pInitMutex mutex. This operation is protected by the STATIC_MASTER mutex. Note that // MutexAlloc() is called for a static mutex prior to initializing the malloc subsystem - this implies that the allocation of a static // mutex must not require support from the malloc subsystem. masterMutex = MutexEx.Alloc(MutexEx.MUTEX.STATIC_MASTER); // The main static mutex MutexEx.Enter(masterMutex); _GlobalStatics.IsMutexInit = true; //if (!SysEx_GlobalStatics.IsMallocInit) // rc = sqlite3MallocInit(); if (rc == RC.OK) { _GlobalStatics.IsMallocInit = true; if (_GlobalStatics.InitMutex.Tag == null) { _GlobalStatics.InitMutex = MutexEx.Alloc(MutexEx.MUTEX.RECURSIVE); if (_GlobalStatics.CoreMutex && _GlobalStatics.InitMutex.Tag == null) rc = RC.NOMEM; } } if (rc == RC.OK) _GlobalStatics.InitMutexRefs++; MutexEx.Leave(masterMutex); // If rc is not SQLITE_OK at this point, then either the malloc subsystem could not be initialized or the system failed to allocate // the pInitMutex mutex. Return an error in either case. if (rc != RC.OK) return rc; // Do the rest of the initialization under the recursive mutex so that we will be able to handle recursive calls into // sqlite3_initialize(). The recursive calls normally come through sqlite3_os_init() when it invokes sqlite3_vfs_register(), but other // recursive calls might also be possible. // // IMPLEMENTATION-OF: R-00140-37445 SQLite automatically serializes calls to the xInit method, so the xInit method need not be threadsafe. // // The following mutex is what serializes access to the appdef pcache xInit methods. The sqlite3_pcache_methods.xInit() all is embedded in the // call to sqlite3PcacheInitialize(). MutexEx.Enter(_GlobalStatics.InitMutex); if (!_GlobalStatics.IsInit && !_GlobalStatics.InProgress) { _GlobalStatics.InProgress = true; rc = VSystem.Initialize(); } if (rc != RC.OK) MutexEx.Leave(_GlobalStatics.InitMutex); return rc; }