persistentstorage/sqlite3api/SQLite/mutex.c
changeset 0 08ec8eefde2f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 /*
       
     2 ** 2007 August 14
       
     3 **
       
     4 ** The author disclaims copyright to this source code.  In place of
       
     5 ** 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 ** The implementation in this file does not provide any mutual
       
    15 ** exclusion and is thus suitable for use only in applications
       
    16 ** that use SQLite in a single thread.  But this implementation
       
    17 ** does do a lot of error checking on mutexes to make sure they
       
    18 ** are called correctly and at appropriate times.  Hence, this
       
    19 ** implementation is suitable for testing.
       
    20 ** debugging purposes
       
    21 **
       
    22 ** $Id: mutex.c,v 1.28 2008/09/01 18:34:20 danielk1977 Exp $
       
    23 */
       
    24 #include "sqliteInt.h"
       
    25 
       
    26 #ifndef SQLITE_MUTEX_NOOP
       
    27 /*
       
    28 ** Initialize the mutex system.
       
    29 */
       
    30 int sqlite3MutexInit(void){ 
       
    31   int rc = SQLITE_OK;
       
    32   if( sqlite3GlobalConfig.bCoreMutex ){
       
    33     if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){
       
    34       /* If the xMutexAlloc method has not been set, then the user did not
       
    35       ** install a mutex implementation via sqlite3_config() prior to 
       
    36       ** sqlite3_initialize() being called. This block copies pointers to
       
    37       ** the default implementation into the sqlite3GlobalConfig structure.
       
    38       **
       
    39       ** The danger is that although sqlite3_config() is not a threadsafe
       
    40       ** API, sqlite3_initialize() is, and so multiple threads may be
       
    41       ** attempting to run this function simultaneously. To guard write
       
    42       ** access to the sqlite3GlobalConfig structure, the 'MASTER' static mutex
       
    43       ** is obtained before modifying it.
       
    44       */
       
    45       sqlite3_mutex_methods *p = sqlite3DefaultMutex();
       
    46       sqlite3_mutex *pMaster = 0;
       
    47   
       
    48       rc = p->xMutexInit();
       
    49       if( rc==SQLITE_OK ){
       
    50         pMaster = p->xMutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
       
    51         assert(pMaster);
       
    52         p->xMutexEnter(pMaster);
       
    53         assert( sqlite3GlobalConfig.mutex.xMutexAlloc==0 
       
    54              || sqlite3GlobalConfig.mutex.xMutexAlloc==p->xMutexAlloc
       
    55         );
       
    56         if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){
       
    57           sqlite3GlobalConfig.mutex = *p;
       
    58         }
       
    59         p->xMutexLeave(pMaster);
       
    60       }
       
    61     }else{
       
    62       rc = sqlite3GlobalConfig.mutex.xMutexInit();
       
    63     }
       
    64   }
       
    65 
       
    66   return rc;
       
    67 }
       
    68 
       
    69 /*
       
    70 ** Shutdown the mutex system. This call frees resources allocated by
       
    71 ** sqlite3MutexInit().
       
    72 */
       
    73 int sqlite3MutexEnd(void){
       
    74   int rc = SQLITE_OK;
       
    75   rc = sqlite3GlobalConfig.mutex.xMutexEnd();
       
    76   return rc;
       
    77 }
       
    78 
       
    79 /*
       
    80 ** Retrieve a pointer to a static mutex or allocate a new dynamic one.
       
    81 */
       
    82 SQLITE_EXPORT sqlite3_mutex *sqlite3_mutex_alloc(int id){
       
    83 #ifndef SQLITE_OMIT_AUTOINIT
       
    84   if( sqlite3_initialize() ) return 0;
       
    85 #endif
       
    86   return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
       
    87 }
       
    88 
       
    89 sqlite3_mutex *sqlite3MutexAlloc(int id){
       
    90   if( !sqlite3GlobalConfig.bCoreMutex ){
       
    91     return 0;
       
    92   }
       
    93   return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
       
    94 }
       
    95 
       
    96 /*
       
    97 ** Free a dynamic mutex.
       
    98 */
       
    99 SQLITE_EXPORT void sqlite3_mutex_free(sqlite3_mutex *p){
       
   100   if( p ){
       
   101     sqlite3GlobalConfig.mutex.xMutexFree(p);
       
   102   }
       
   103 }
       
   104 
       
   105 /*
       
   106 ** Obtain the mutex p. If some other thread already has the mutex, block
       
   107 ** until it can be obtained.
       
   108 */
       
   109 SQLITE_EXPORT void sqlite3_mutex_enter(sqlite3_mutex *p){
       
   110   if( p ){
       
   111     sqlite3GlobalConfig.mutex.xMutexEnter(p);
       
   112   }
       
   113 }
       
   114 
       
   115 /*
       
   116 ** Obtain the mutex p. If successful, return SQLITE_OK. Otherwise, if another
       
   117 ** thread holds the mutex and it cannot be obtained, return SQLITE_BUSY.
       
   118 */
       
   119 SQLITE_EXPORT int sqlite3_mutex_try(sqlite3_mutex *p){
       
   120   int rc = SQLITE_OK;
       
   121   if( p ){
       
   122     return sqlite3GlobalConfig.mutex.xMutexTry(p);
       
   123   }
       
   124   return rc;
       
   125 }
       
   126 
       
   127 /*
       
   128 ** The sqlite3_mutex_leave() routine exits a mutex that was previously
       
   129 ** entered by the same thread.  The behavior is undefined if the mutex 
       
   130 ** is not currently entered. If a NULL pointer is passed as an argument
       
   131 ** this function is a no-op.
       
   132 */
       
   133 SQLITE_EXPORT void sqlite3_mutex_leave(sqlite3_mutex *p){
       
   134   if( p ){
       
   135     sqlite3GlobalConfig.mutex.xMutexLeave(p);
       
   136   }
       
   137 }
       
   138 
       
   139 #ifndef NDEBUG
       
   140 /*
       
   141 ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
       
   142 ** intended for use inside assert() statements.
       
   143 */
       
   144 SQLITE_EXPORT int sqlite3_mutex_held(sqlite3_mutex *p){
       
   145   return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p);
       
   146 }
       
   147 SQLITE_EXPORT int sqlite3_mutex_notheld(sqlite3_mutex *p){
       
   148   return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p);
       
   149 }
       
   150 #else
       
   151 
       
   152 SQLITE_EXPORT int sqlite3_mutex_held(sqlite3_mutex *p){return 1;}
       
   153 SQLITE_EXPORT int sqlite3_mutex_notheld(sqlite3_mutex *p){return 1;}
       
   154 
       
   155 #endif
       
   156 #endif
       
   157 
       
   158 #ifdef SQLITE_MUTEX_NOOP_DEBUG
       
   159 /*
       
   160 ** In this implementation, mutexes do not provide any mutual exclusion.
       
   161 ** But the error checking is provided.  This implementation is useful
       
   162 ** for test purposes.
       
   163 */
       
   164 
       
   165 /*
       
   166 ** The mutex object
       
   167 */
       
   168 struct sqlite3_mutex {
       
   169   int id;     /* The mutex type */
       
   170   int cnt;    /* Number of entries without a matching leave */
       
   171 };
       
   172 
       
   173 /*
       
   174 ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
       
   175 ** intended for use inside assert() statements.
       
   176 */
       
   177 static int noopMutexHeld(sqlite3_mutex *p){
       
   178   return p==0 || p->cnt>0;
       
   179 }
       
   180 static int noopMutexNotheld(sqlite3_mutex *p){
       
   181   return p==0 || p->cnt==0;
       
   182 }
       
   183 
       
   184 /*
       
   185 ** Initialize and deinitialize the mutex subsystem.
       
   186 */
       
   187 static int noopMutexInit(void){ return SQLITE_OK; }
       
   188 static int noopMutexEnd(void){ return SQLITE_OK; }
       
   189 
       
   190 /*
       
   191 ** The sqlite3_mutex_alloc() routine allocates a new
       
   192 ** mutex and returns a pointer to it.  If it returns NULL
       
   193 ** that means that a mutex could not be allocated. 
       
   194 */
       
   195 static sqlite3_mutex *noopMutexAlloc(int id){
       
   196   static sqlite3_mutex aStatic[6];
       
   197   sqlite3_mutex *pNew = 0;
       
   198   switch( id ){
       
   199     case SQLITE_MUTEX_FAST:
       
   200     case SQLITE_MUTEX_RECURSIVE: {
       
   201       pNew = sqlite3Malloc(sizeof(*pNew));
       
   202       if( pNew ){
       
   203         pNew->id = id;
       
   204         pNew->cnt = 0;
       
   205       }
       
   206       break;
       
   207     }
       
   208     default: {
       
   209       assert( id-2 >= 0 );
       
   210       assert( id-2 < sizeof(aStatic)/sizeof(aStatic[0]) );
       
   211       pNew = &aStatic[id-2];
       
   212       pNew->id = id;
       
   213       break;
       
   214     }
       
   215   }
       
   216   return pNew;
       
   217 }
       
   218 
       
   219 /*
       
   220 ** This routine deallocates a previously allocated mutex.
       
   221 */
       
   222 static void noopMutexFree(sqlite3_mutex *p){
       
   223   assert( p->cnt==0 );
       
   224   assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
       
   225   sqlite3_free(p);
       
   226 }
       
   227 
       
   228 /*
       
   229 ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
       
   230 ** to enter a mutex.  If another thread is already within the mutex,
       
   231 ** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
       
   232 ** SQLITE_BUSY.  The sqlite3_mutex_try() interface returns SQLITE_OK
       
   233 ** upon successful entry.  Mutexes created using SQLITE_MUTEX_RECURSIVE can
       
   234 ** be entered multiple times by the same thread.  In such cases the,
       
   235 ** mutex must be exited an equal number of times before another thread
       
   236 ** can enter.  If the same thread tries to enter any other kind of mutex
       
   237 ** more than once, the behavior is undefined.
       
   238 */
       
   239 static void noopMutexEnter(sqlite3_mutex *p){
       
   240   assert( p->id==SQLITE_MUTEX_RECURSIVE || noopMutexNotheld(p) );
       
   241   p->cnt++;
       
   242 }
       
   243 static int noopMutexTry(sqlite3_mutex *p){
       
   244   assert( p->id==SQLITE_MUTEX_RECURSIVE || noopMutexNotheld(p) );
       
   245   p->cnt++;
       
   246   return SQLITE_OK;
       
   247 }
       
   248 
       
   249 /*
       
   250 ** The sqlite3_mutex_leave() routine exits a mutex that was
       
   251 ** previously entered by the same thread.  The behavior
       
   252 ** is undefined if the mutex is not currently entered or
       
   253 ** is not currently allocated.  SQLite will never do either.
       
   254 */
       
   255 static void noopMutexLeave(sqlite3_mutex *p){
       
   256   assert( noopMutexHeld(p) );
       
   257   p->cnt--;
       
   258   assert( p->id==SQLITE_MUTEX_RECURSIVE || noopMutexNotheld(p) );
       
   259 }
       
   260 
       
   261 sqlite3_mutex_methods *sqlite3DefaultMutex(void){
       
   262   static sqlite3_mutex_methods sMutex = {
       
   263     noopMutexInit,
       
   264     noopMutexEnd,
       
   265     noopMutexAlloc,
       
   266     noopMutexFree,
       
   267     noopMutexEnter,
       
   268     noopMutexTry,
       
   269     noopMutexLeave,
       
   270 
       
   271     noopMutexHeld,
       
   272     noopMutexNotheld
       
   273   };
       
   274 
       
   275   return &sMutex;
       
   276 }
       
   277 #endif /* SQLITE_MUTEX_NOOP_DEBUG */