Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
mutex_w32.c392 linesDownload Raw Back to src
1/*2** 2007 August 143**4** The author disclaims copyright to this source code.  In place of5** a legal notice, here is a blessing:6**7**    May you do good and not evil.8**    May you find forgiveness for yourself and forgive others.9**    May you share freely, never taking more than you give.10**11*************************************************************************12** This file contains the C functions that implement mutexes for Win32.13*/14#include "sqliteInt.h"15 16#if SQLITE_OS_WIN17/*18** Include code that is common to all os_*.c files19*/20#include "os_common.h"21 22/*23** Include the header file for the Windows VFS.24*/25#include "os_win.h"26#endif27 28/*29** The code in this file is only used if we are compiling multithreaded30** on a Win32 system.31*/32#ifdef SQLITE_MUTEX_W3233 34/*35** Each recursive mutex is an instance of the following structure.36*/37struct sqlite3_mutex {38  CRITICAL_SECTION mutex;    /* Mutex controlling the lock */39  int id;                    /* Mutex type */40#ifdef SQLITE_DEBUG41  volatile int nRef;         /* Number of entrances */42  volatile DWORD owner;      /* Thread holding this mutex */43  volatile LONG trace;       /* True to trace changes */44#endif45};46 47/*48** These are the initializer values used when declaring a "static" mutex49** on Win32.  It should be noted that all mutexes require initialization50** on the Win32 platform.51*/52#define SQLITE_W32_MUTEX_INITIALIZER { 0 }53 54#ifdef SQLITE_DEBUG55#define SQLITE3_MUTEX_INITIALIZER(id) { SQLITE_W32_MUTEX_INITIALIZER, id, \56                                    0L, (DWORD)0, 0 }57#else58#define SQLITE3_MUTEX_INITIALIZER(id) { SQLITE_W32_MUTEX_INITIALIZER, id }59#endif60 61#ifdef SQLITE_DEBUG62/*63** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are64** intended for use only inside assert() statements.65*/66static int winMutexHeld(sqlite3_mutex *p){67  return p->nRef!=0 && p->owner==GetCurrentThreadId();68}69 70static int winMutexNotheld2(sqlite3_mutex *p, DWORD tid){71  return p->nRef==0 || p->owner!=tid;72}73 74static int winMutexNotheld(sqlite3_mutex *p){75  DWORD tid = GetCurrentThreadId();76  return winMutexNotheld2(p, tid);77}78#endif79 80/*81** Try to provide a memory barrier operation, needed for initialization82** and also for the xShmBarrier method of the VFS in cases when SQLite is83** compiled without mutexes (SQLITE_THREADSAFE=0).84*/85void sqlite3MemoryBarrier(void){86#if defined(SQLITE_MEMORY_BARRIER)87  SQLITE_MEMORY_BARRIER;88#elif defined(__GNUC__)89  __sync_synchronize();90#elif MSVC_VERSION>=140091  _ReadWriteBarrier();92#elif defined(MemoryBarrier)93  MemoryBarrier();94#endif95}96 97/*98** Initialize and deinitialize the mutex subsystem.99*/100static sqlite3_mutex winMutex_staticMutexes[] = {101  SQLITE3_MUTEX_INITIALIZER(2),102  SQLITE3_MUTEX_INITIALIZER(3),103  SQLITE3_MUTEX_INITIALIZER(4),104  SQLITE3_MUTEX_INITIALIZER(5),105  SQLITE3_MUTEX_INITIALIZER(6),106  SQLITE3_MUTEX_INITIALIZER(7),107  SQLITE3_MUTEX_INITIALIZER(8),108  SQLITE3_MUTEX_INITIALIZER(9),109  SQLITE3_MUTEX_INITIALIZER(10),110  SQLITE3_MUTEX_INITIALIZER(11),111  SQLITE3_MUTEX_INITIALIZER(12),112  SQLITE3_MUTEX_INITIALIZER(13)113};114 115static int winMutex_isInit = 0;116static int winMutex_isNt = -1; /* <0 means "need to query" */117 118/* As the winMutexInit() and winMutexEnd() functions are called as part119** of the sqlite3_initialize() and sqlite3_shutdown() processing, the120** "interlocked" magic used here is probably not strictly necessary.121*/122static LONG SQLITE_WIN32_VOLATILE winMutex_lock = 0;123 124int sqlite3_win32_is_nt(void); /* os_win.c */125void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */126 127static int winMutexInit(void){128  /* The first to increment to 1 does actual initialization */129  if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){130    int i;131    for(i=0; i<ArraySize(winMutex_staticMutexes); i++){132      InitializeCriticalSection(&winMutex_staticMutexes[i].mutex);133    }134    winMutex_isInit = 1;135  }else{136    /* Another thread is (in the process of) initializing the static137    ** mutexes */138    while( !winMutex_isInit ){139      sqlite3_win32_sleep(1);140    }141  }142  return SQLITE_OK;143}144 145static int winMutexEnd(void){146  /* The first to decrement to 0 does actual shutdown147  ** (which should be the last to shutdown.) */148  if( InterlockedCompareExchange(&winMutex_lock, 0, 1)==1 ){149    if( winMutex_isInit==1 ){150      int i;151      for(i=0; i<ArraySize(winMutex_staticMutexes); i++){152        DeleteCriticalSection(&winMutex_staticMutexes[i].mutex);153      }154      winMutex_isInit = 0;155    }156  }157  return SQLITE_OK;158}159 160/*161** The sqlite3_mutex_alloc() routine allocates a new162** mutex and returns a pointer to it.  If it returns NULL163** that means that a mutex could not be allocated.  SQLite164** will unwind its stack and return an error.  The argument165** to sqlite3_mutex_alloc() is one of these integer constants:166**167** <ul>168** <li>  SQLITE_MUTEX_FAST169** <li>  SQLITE_MUTEX_RECURSIVE170** <li>  SQLITE_MUTEX_STATIC_MAIN171** <li>  SQLITE_MUTEX_STATIC_MEM172** <li>  SQLITE_MUTEX_STATIC_OPEN173** <li>  SQLITE_MUTEX_STATIC_PRNG174** <li>  SQLITE_MUTEX_STATIC_LRU175** <li>  SQLITE_MUTEX_STATIC_PMEM176** <li>  SQLITE_MUTEX_STATIC_APP1177** <li>  SQLITE_MUTEX_STATIC_APP2178** <li>  SQLITE_MUTEX_STATIC_APP3179** <li>  SQLITE_MUTEX_STATIC_VFS1180** <li>  SQLITE_MUTEX_STATIC_VFS2181** <li>  SQLITE_MUTEX_STATIC_VFS3182** </ul>183**184** The first two constants cause sqlite3_mutex_alloc() to create185** a new mutex.  The new mutex is recursive when SQLITE_MUTEX_RECURSIVE186** is used but not necessarily so when SQLITE_MUTEX_FAST is used.187** The mutex implementation does not need to make a distinction188** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does189** not want to.  But SQLite will only request a recursive mutex in190** cases where it really needs one.  If a faster non-recursive mutex191** implementation is available on the host platform, the mutex subsystem192** might return such a mutex in response to SQLITE_MUTEX_FAST.193**194** The other allowed parameters to sqlite3_mutex_alloc() each return195** a pointer to a static preexisting mutex.  Six static mutexes are196** used by the current version of SQLite.  Future versions of SQLite197** may add additional static mutexes.  Static mutexes are for internal198** use by SQLite only.  Applications that use SQLite mutexes should199** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or200** SQLITE_MUTEX_RECURSIVE.201**202** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST203** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()204** returns a different mutex on every call.  But for the static205** mutex types, the same mutex is returned on every call that has206** the same type number.207*/208static sqlite3_mutex *winMutexAlloc(int iType){209  sqlite3_mutex *p;210 211  switch( iType ){212    case SQLITE_MUTEX_FAST:213    case SQLITE_MUTEX_RECURSIVE: {214      p = sqlite3MallocZero( sizeof(*p) );215      if( p ){216        p->id = iType;217#ifdef SQLITE_DEBUG218#ifdef SQLITE_WIN32_MUTEX_TRACE_DYNAMIC219        p->trace = 1;220#endif221#endif222        InitializeCriticalSection(&p->mutex);223      }224      break;225    }226    default: {227#ifdef SQLITE_ENABLE_API_ARMOR228      if( iType-2<0 || iType-2>=ArraySize(winMutex_staticMutexes) ){229        (void)SQLITE_MISUSE_BKPT;230        return 0;231      }232#endif233      p = &winMutex_staticMutexes[iType-2];234#ifdef SQLITE_DEBUG235#ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC236      InterlockedCompareExchange(&p->trace, 1, 0);237#endif238#endif239      break;240    }241  }242  assert( p==0 || p->id==iType );243  return p;244}245 246 247/*248** This routine deallocates a previously249** allocated mutex.  SQLite is careful to deallocate every250** mutex that it allocates.251*/252static void winMutexFree(sqlite3_mutex *p){253  assert( p );254  assert( p->nRef==0 && p->owner==0 );255  if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ){256    DeleteCriticalSection(&p->mutex);257    sqlite3_free(p);258  }else{259#ifdef SQLITE_ENABLE_API_ARMOR260    (void)SQLITE_MISUSE_BKPT;261#endif262  }263}264 265/*266** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt267** to enter a mutex.  If another thread is already within the mutex,268** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return269** SQLITE_BUSY.  The sqlite3_mutex_try() interface returns SQLITE_OK270** upon successful entry.  Mutexes created using SQLITE_MUTEX_RECURSIVE can271** be entered multiple times by the same thread.  In such cases the,272** mutex must be exited an equal number of times before another thread273** can enter.  If the same thread tries to enter any other kind of mutex274** more than once, the behavior is undefined.275*/276static void winMutexEnter(sqlite3_mutex *p){277#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)278  DWORD tid = GetCurrentThreadId();279#endif280#ifdef SQLITE_DEBUG281  assert( p );282  assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );283#else284  assert( p );285#endif286  assert( winMutex_isInit==1 );287  EnterCriticalSection(&p->mutex);288#ifdef SQLITE_DEBUG289  assert( p->nRef>0 || p->owner==0 );290  p->owner = tid;291  p->nRef++;292  if( p->trace ){293    OSTRACE(("ENTER-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n",294             tid, p->id, p, p->trace, p->nRef));295  }296#endif297}298 299static int winMutexTry(sqlite3_mutex *p){300#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)301  DWORD tid = GetCurrentThreadId();302#endif303  int rc = SQLITE_BUSY;304  assert( p );305  assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );306  /*307  ** The sqlite3_mutex_try() routine is very rarely used, and when it308  ** is used it is merely an optimization.  So it is OK for it to always309  ** fail.310  **311  ** The TryEnterCriticalSection() interface is only available on WinNT.312  ** And some windows compilers complain if you try to use it without313  ** first doing some #defines that prevent SQLite from building on Win98.314  ** For that reason, we will omit this optimization for now.  See315  ** ticket #2685.316  */317#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0400318  assert( winMutex_isInit==1 );319  assert( winMutex_isNt>=-1 && winMutex_isNt<=1 );320  if( winMutex_isNt<0 ){321    winMutex_isNt = sqlite3_win32_is_nt();322  }323  assert( winMutex_isNt==0 || winMutex_isNt==1 );324  if( winMutex_isNt && TryEnterCriticalSection(&p->mutex) ){325#ifdef SQLITE_DEBUG326    p->owner = tid;327    p->nRef++;328#endif329    rc = SQLITE_OK;330  }331#else332  UNUSED_PARAMETER(p);333#endif334#ifdef SQLITE_DEBUG335  if( p->trace ){336    OSTRACE(("TRY-MUTEX tid=%lu, mutex(%d)=%p (%d), owner=%lu, nRef=%d, rc=%s\n",337             tid, p->id, p, p->trace, p->owner, p->nRef, sqlite3ErrName(rc)));338  }339#endif340  return rc;341}342 343/*344** The sqlite3_mutex_leave() routine exits a mutex that was345** previously entered by the same thread.  The behavior346** is undefined if the mutex is not currently entered or347** is not currently allocated.  SQLite will never do either.348*/349static void winMutexLeave(sqlite3_mutex *p){350#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)351  DWORD tid = GetCurrentThreadId();352#endif353  assert( p );354#ifdef SQLITE_DEBUG355  assert( p->nRef>0 );356  assert( p->owner==tid );357  p->nRef--;358  if( p->nRef==0 ) p->owner = 0;359  assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );360#endif361  assert( winMutex_isInit==1 );362  LeaveCriticalSection(&p->mutex);363#ifdef SQLITE_DEBUG364  if( p->trace ){365    OSTRACE(("LEAVE-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n",366             tid, p->id, p, p->trace, p->nRef));367  }368#endif369}370 371sqlite3_mutex_methods const *sqlite3DefaultMutex(void){372  static const sqlite3_mutex_methods sMutex = {373    winMutexInit,374    winMutexEnd,375    winMutexAlloc,376    winMutexFree,377    winMutexEnter,378    winMutexTry,379    winMutexLeave,380#ifdef SQLITE_DEBUG381    winMutexHeld,382    winMutexNotheld383#else384    0,385    0386#endif387  };388  return &sMutex;389}390 391#endif /* SQLITE_MUTEX_W32 */392