Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
mutex.c375 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.13**14** This file contains code that is common across all mutex implementations.15*/16#include "sqliteInt.h"17 18#if defined(SQLITE_DEBUG) && !defined(SQLITE_MUTEX_OMIT)19/*20** For debugging purposes, record when the mutex subsystem is initialized21** and uninitialized so that we can assert() if there is an attempt to22** allocate a mutex while the system is uninitialized.23*/24static SQLITE_WSD int mutexIsInit = 0;25#endif /* SQLITE_DEBUG && !defined(SQLITE_MUTEX_OMIT) */26 27 28#ifndef SQLITE_MUTEX_OMIT29 30#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS31/*32** This block (enclosed by SQLITE_ENABLE_MULTITHREADED_CHECKS) contains33** the implementation of a wrapper around the system default mutex34** implementation (sqlite3DefaultMutex()). 35**36** Most calls are passed directly through to the underlying default37** mutex implementation. Except, if a mutex is configured by calling38** sqlite3MutexWarnOnContention() on it, then if contention is ever39** encountered within xMutexEnter() a warning is emitted via sqlite3_log().40**41** This type of mutex is used as the database handle mutex when testing42** apps that usually use SQLITE_CONFIG_MULTITHREAD mode.43*/44 45/* 46** Type for all mutexes used when SQLITE_ENABLE_MULTITHREADED_CHECKS47** is defined. Variable CheckMutex.mutex is a pointer to the real mutex48** allocated by the system mutex implementation. Variable iType is usually set49** to the type of mutex requested - SQLITE_MUTEX_RECURSIVE, SQLITE_MUTEX_FAST50** or one of the static mutex identifiers. Or, if this is a recursive mutex51** that has been configured using sqlite3MutexWarnOnContention(), it is52** set to SQLITE_MUTEX_WARNONCONTENTION.53*/54typedef struct CheckMutex CheckMutex;55struct CheckMutex {56  int iType;57  sqlite3_mutex *mutex;58};59 60#define SQLITE_MUTEX_WARNONCONTENTION  (-1)61 62/* 63** Pointer to real mutex methods object used by the CheckMutex64** implementation. Set by checkMutexInit(). 65*/66static SQLITE_WSD const sqlite3_mutex_methods *pGlobalMutexMethods;67 68#ifdef SQLITE_DEBUG69static int checkMutexHeld(sqlite3_mutex *p){70  return pGlobalMutexMethods->xMutexHeld(((CheckMutex*)p)->mutex);71}72static int checkMutexNotheld(sqlite3_mutex *p){73  return pGlobalMutexMethods->xMutexNotheld(((CheckMutex*)p)->mutex);74}75#endif76 77/*78** Initialize and deinitialize the mutex subsystem.79*/80static int checkMutexInit(void){ 81  pGlobalMutexMethods = sqlite3DefaultMutex();82  return SQLITE_OK; 83}84static int checkMutexEnd(void){ 85  pGlobalMutexMethods = 0;86  return SQLITE_OK; 87}88 89/*90** Allocate a mutex.91*/92static sqlite3_mutex *checkMutexAlloc(int iType){93  static CheckMutex staticMutexes[] = {94    {2, 0}, {3, 0}, {4, 0}, {5, 0},95    {6, 0}, {7, 0}, {8, 0}, {9, 0},96    {10, 0}, {11, 0}, {12, 0}, {13, 0}97  };98  CheckMutex *p = 0;99 100  assert( SQLITE_MUTEX_RECURSIVE==1 && SQLITE_MUTEX_FAST==0 );101  if( iType<2 ){102    p = sqlite3MallocZero(sizeof(CheckMutex));103    if( p==0 ) return 0;104    p->iType = iType;105  }else{106#ifdef SQLITE_ENABLE_API_ARMOR107    if( iType-2>=ArraySize(staticMutexes) ){108      (void)SQLITE_MISUSE_BKPT;109      return 0;110    }111#endif112    p = &staticMutexes[iType-2];113  }114 115  if( p->mutex==0 ){116    p->mutex = pGlobalMutexMethods->xMutexAlloc(iType);117    if( p->mutex==0 ){118      if( iType<2 ){119        sqlite3_free(p);120      }121      p = 0;122    }123  }124 125  return (sqlite3_mutex*)p;126}127 128/*129** Free a mutex.130*/131static void checkMutexFree(sqlite3_mutex *p){132  assert( SQLITE_MUTEX_RECURSIVE<2 );133  assert( SQLITE_MUTEX_FAST<2 );134  assert( SQLITE_MUTEX_WARNONCONTENTION<2 );135 136#ifdef SQLITE_ENABLE_API_ARMOR137  if( ((CheckMutex*)p)->iType<2 )138#endif139  {140    CheckMutex *pCheck = (CheckMutex*)p;141    pGlobalMutexMethods->xMutexFree(pCheck->mutex);142    sqlite3_free(pCheck);143  }144#ifdef SQLITE_ENABLE_API_ARMOR145  else{146    (void)SQLITE_MISUSE_BKPT;147  }148#endif149}150 151/*152** Enter the mutex.153*/154static void checkMutexEnter(sqlite3_mutex *p){155  CheckMutex *pCheck = (CheckMutex*)p;156  if( pCheck->iType==SQLITE_MUTEX_WARNONCONTENTION ){157    if( SQLITE_OK==pGlobalMutexMethods->xMutexTry(pCheck->mutex) ){158      return;159    }160    sqlite3_log(SQLITE_MISUSE, 161        "illegal multi-threaded access to database connection"162    );163  }164  pGlobalMutexMethods->xMutexEnter(pCheck->mutex);165}166 167/*168** Enter the mutex (do not block).169*/170static int checkMutexTry(sqlite3_mutex *p){171  CheckMutex *pCheck = (CheckMutex*)p;172  return pGlobalMutexMethods->xMutexTry(pCheck->mutex);173}174 175/*176** Leave the mutex.177*/178static void checkMutexLeave(sqlite3_mutex *p){179  CheckMutex *pCheck = (CheckMutex*)p;180  pGlobalMutexMethods->xMutexLeave(pCheck->mutex);181}182 183sqlite3_mutex_methods const *multiThreadedCheckMutex(void){184  static const sqlite3_mutex_methods sMutex = {185    checkMutexInit,186    checkMutexEnd,187    checkMutexAlloc,188    checkMutexFree,189    checkMutexEnter,190    checkMutexTry,191    checkMutexLeave,192#ifdef SQLITE_DEBUG193    checkMutexHeld,194    checkMutexNotheld195#else196    0,197    0198#endif199  };200  return &sMutex;201}202 203/*204** Mark the SQLITE_MUTEX_RECURSIVE mutex passed as the only argument as205** one on which there should be no contention.206*/207void sqlite3MutexWarnOnContention(sqlite3_mutex *p){208  if( sqlite3GlobalConfig.mutex.xMutexAlloc==checkMutexAlloc ){209    CheckMutex *pCheck = (CheckMutex*)p;210    assert( pCheck->iType==SQLITE_MUTEX_RECURSIVE );211    pCheck->iType = SQLITE_MUTEX_WARNONCONTENTION;212  }213}214#endif   /* ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS */215 216/*217** Initialize the mutex system.218*/219int sqlite3MutexInit(void){ 220  int rc = SQLITE_OK;221  if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){222    /* If the xMutexAlloc method has not been set, then the user did not223    ** install a mutex implementation via sqlite3_config() prior to 224    ** sqlite3_initialize() being called. This block copies pointers to225    ** the default implementation into the sqlite3GlobalConfig structure.226    */227    sqlite3_mutex_methods const *pFrom;228    sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;229 230    if( sqlite3GlobalConfig.bCoreMutex ){231#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS232      pFrom = multiThreadedCheckMutex();233#else234      pFrom = sqlite3DefaultMutex();235#endif236    }else{237      pFrom = sqlite3NoopMutex();238    }239    pTo->xMutexInit = pFrom->xMutexInit;240    pTo->xMutexEnd = pFrom->xMutexEnd;241    pTo->xMutexFree = pFrom->xMutexFree;242    pTo->xMutexEnter = pFrom->xMutexEnter;243    pTo->xMutexTry = pFrom->xMutexTry;244    pTo->xMutexLeave = pFrom->xMutexLeave;245    pTo->xMutexHeld = pFrom->xMutexHeld;246    pTo->xMutexNotheld = pFrom->xMutexNotheld;247    sqlite3MemoryBarrier();248    pTo->xMutexAlloc = pFrom->xMutexAlloc;249  }250  assert( sqlite3GlobalConfig.mutex.xMutexInit );251  rc = sqlite3GlobalConfig.mutex.xMutexInit();252 253#ifdef SQLITE_DEBUG254  GLOBAL(int, mutexIsInit) = 1;255#endif256 257  sqlite3MemoryBarrier();258  return rc;259}260 261/*262** Shutdown the mutex system. This call frees resources allocated by263** sqlite3MutexInit().264*/265int sqlite3MutexEnd(void){266  int rc = SQLITE_OK;267  if( sqlite3GlobalConfig.mutex.xMutexEnd ){268    rc = sqlite3GlobalConfig.mutex.xMutexEnd();269  }270 271#ifdef SQLITE_DEBUG272  GLOBAL(int, mutexIsInit) = 0;273#endif274 275  return rc;276}277 278/*279** Retrieve a pointer to a static mutex or allocate a new dynamic one.280*/281sqlite3_mutex *sqlite3_mutex_alloc(int id){282#ifndef SQLITE_OMIT_AUTOINIT283  if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0;284  if( id>SQLITE_MUTEX_RECURSIVE && sqlite3MutexInit() ) return 0;285#endif286  assert( sqlite3GlobalConfig.mutex.xMutexAlloc );287  return sqlite3GlobalConfig.mutex.xMutexAlloc(id);288}289 290sqlite3_mutex *sqlite3MutexAlloc(int id){291  if( !sqlite3GlobalConfig.bCoreMutex ){292    return 0;293  }294  assert( GLOBAL(int, mutexIsInit) );295  assert( sqlite3GlobalConfig.mutex.xMutexAlloc );296  return sqlite3GlobalConfig.mutex.xMutexAlloc(id);297}298 299/*300** Free a dynamic mutex.301*/302void sqlite3_mutex_free(sqlite3_mutex *p){303  if( p ){304    assert( sqlite3GlobalConfig.mutex.xMutexFree );305    sqlite3GlobalConfig.mutex.xMutexFree(p);306  }307}308 309/*310** Obtain the mutex p. If some other thread already has the mutex, block311** until it can be obtained.312*/313void sqlite3_mutex_enter(sqlite3_mutex *p){314  if( p ){315    assert( sqlite3GlobalConfig.mutex.xMutexEnter );316    sqlite3GlobalConfig.mutex.xMutexEnter(p);317  }318}319 320/*321** Obtain the mutex p. If successful, return SQLITE_OK. Otherwise, if another322** thread holds the mutex and it cannot be obtained, return SQLITE_BUSY.323*/324int sqlite3_mutex_try(sqlite3_mutex *p){325  int rc = SQLITE_OK;326  if( p ){327    assert( sqlite3GlobalConfig.mutex.xMutexTry );328    return sqlite3GlobalConfig.mutex.xMutexTry(p);329  }330  return rc;331}332 333/*334** The sqlite3_mutex_leave() routine exits a mutex that was previously335** entered by the same thread.  The behavior is undefined if the mutex 336** is not currently entered. If a NULL pointer is passed as an argument337** this function is a no-op.338*/339void sqlite3_mutex_leave(sqlite3_mutex *p){340  if( p ){341    assert( sqlite3GlobalConfig.mutex.xMutexLeave );342    sqlite3GlobalConfig.mutex.xMutexLeave(p);343  }344}345 346#ifndef NDEBUG347/*348** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are349** intended for use inside assert() statements.350**351** Because these routines raise false-positive alerts in TSAN, disable352** them (make them always return 1) when compiling with TSAN.353*/354int sqlite3_mutex_held(sqlite3_mutex *p){355# if defined(__has_feature)356#   if __has_feature(thread_sanitizer)357      p = 0;358#   endif359# endif360  assert( p==0 || sqlite3GlobalConfig.mutex.xMutexHeld );361  return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p);362}363int sqlite3_mutex_notheld(sqlite3_mutex *p){364# if defined(__has_feature)365#   if __has_feature(thread_sanitizer)366      p = 0;367#   endif368# endif369  assert( p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld );370  return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p);371}372#endif /* NDEBUG */373 374#endif /* !defined(SQLITE_MUTEX_OMIT) */375