/ Artifact Content
Login

Artifact b0fbea2cda9f8e81444f5f1b4b9f07c1a904269e:


/*
** 2007 August 14
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains the C functions that implement mutexes.
**
** This file contains code that is common across all mutex implementations.
*/
#include "sqliteInt.h"

#if defined(SQLITE_DEBUG) && !defined(SQLITE_MUTEX_OMIT)
/*
** For debugging purposes, record when the mutex subsystem is initialized
** and uninitialized so that we can assert() if there is an attempt to
** allocate a mutex while the system is uninitialized.
*/
static SQLITE_WSD int mutexIsInit = 0;
#endif /* SQLITE_DEBUG && !defined(SQLITE_MUTEX_OMIT) */


#ifndef SQLITE_MUTEX_OMIT
/*
** This structure is for use by mutexIsInvalid() only.  It represents an
** invalid mutex implementation (i.e. one where all the function pointers
** are null).
*/
static const sqlite3_mutex_methods mutexNullMethods = {
  0, /* xMutexInit */
  0, /* xMutexEnd */
  0, /* xMutexAlloc */
  0, /* xMutexFree */
  0, /* xMutexEnter */
  0, /* xMutexTry */
  0, /* xMutexLeave */
  0, /* xMutexHeld */
  0  /* xMutexNotheld */
};

/*
** Returns non-zero if the currently configured mutex implemention is
** invalid (i.e. all of its function pointers are null).
*/
static int mutexIsInvalid(void){
  return memcmp(&sqlite3GlobalConfig.mutex, &mutexNullMethods,
                sizeof(sqlite3_mutex_methods))==0;
}

/*
** Copies a mutex implementation.  Both arguments must point to valid
** memory.
*/
static void mutexCopy(
  sqlite3_mutex_methods *pTo,
  sqlite3_mutex_methods const *pFrom
){
  pTo->xMutexInit = pFrom->xMutexInit;
  pTo->xMutexEnd = pFrom->xMutexEnd;
  pTo->xMutexFree = pFrom->xMutexFree;
  pTo->xMutexEnter = pFrom->xMutexEnter;
  pTo->xMutexTry = pFrom->xMutexTry;
  pTo->xMutexLeave = pFrom->xMutexLeave;
  pTo->xMutexHeld = pFrom->xMutexHeld;
  pTo->xMutexNotheld = pFrom->xMutexNotheld;
  pTo->xMutexAlloc = pFrom->xMutexAlloc;
}

/*
** Initialize the mutex system.
*/
int sqlite3MutexInit(void){ 
  static int initPending = 0;
  int rc;
  if( sqlite3CompareAndSwap((void * volatile *)&sqlite3GlobalConfig.pMutex,
                   0, &sqlite3GlobalConfig.mutex)==0 || mutexIsInvalid() ){
    /* If the mutex implementation pointer has not been set, then the user
    ** did not install a mutex implementation via sqlite3_config() prior to
    ** sqlite3_initialize() being called.  This block copies the pointers
    ** for the default implementation into the sqlite3GlobalConfig structure.
    */
    sqlite3_mutex_methods const *pFrom;

    if( sqlite3GlobalConfig.bCoreMutex ){
      pFrom = sqlite3DefaultMutex();
    }else{
      pFrom = sqlite3NoopMutex();
    }
    mutexCopy(&sqlite3GlobalConfig.mutex, pFrom);
    sqlite3MemoryBarrier();
  }
  if( !initPending ){
    assert( sqlite3GlobalConfig.mutex.xMutexInit );
    initPending = 1;
    rc = sqlite3GlobalConfig.mutex.xMutexInit();
    initPending = 0;
  }

#ifdef SQLITE_DEBUG
  GLOBAL(int, mutexIsInit) = 1;
#endif

  return rc;
}

/*
** Shutdown the mutex system. This call frees resources allocated by
** sqlite3MutexInit().
*/
int sqlite3MutexEnd(void){
  int rc = SQLITE_OK;
  if( sqlite3GlobalConfig.mutex.xMutexEnd ){
    rc = sqlite3GlobalConfig.mutex.xMutexEnd();
  }

#ifdef SQLITE_DEBUG
  GLOBAL(int, mutexIsInit) = 0;
#endif

  return rc;
}

/*
** Retrieve a pointer to a static mutex or allocate a new dynamic one.
*/
sqlite3_mutex *sqlite3_mutex_alloc(int id){
#ifndef SQLITE_OMIT_AUTOINIT
  if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0;
  if( id>SQLITE_MUTEX_RECURSIVE && sqlite3MutexInit() ) return 0;
#endif
  assert( sqlite3GlobalConfig.mutex.xMutexAlloc );
  return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
}

sqlite3_mutex *sqlite3MutexAlloc(int id){
  if( !sqlite3GlobalConfig.bCoreMutex ){
    return 0;
  }
  assert( GLOBAL(int, mutexIsInit) );
  assert( sqlite3GlobalConfig.mutex.xMutexAlloc );
  return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
}

/*
** Free a dynamic mutex.
*/
void sqlite3_mutex_free(sqlite3_mutex *p){
  if( p ){
    assert( sqlite3GlobalConfig.mutex.xMutexFree );
    sqlite3GlobalConfig.mutex.xMutexFree(p);
  }
}

/*
** Obtain the mutex p. If some other thread already has the mutex, block
** until it can be obtained.
*/
void sqlite3_mutex_enter(sqlite3_mutex *p){
  if( p ){
    assert( sqlite3GlobalConfig.mutex.xMutexEnter );
    sqlite3GlobalConfig.mutex.xMutexEnter(p);
  }
}

/*
** Obtain the mutex p. If successful, return SQLITE_OK. Otherwise, if another
** thread holds the mutex and it cannot be obtained, return SQLITE_BUSY.
*/
int sqlite3_mutex_try(sqlite3_mutex *p){
  int rc = SQLITE_OK;
  if( p ){
    assert( sqlite3GlobalConfig.mutex.xMutexTry );
    return sqlite3GlobalConfig.mutex.xMutexTry(p);
  }
  return rc;
}

/*
** 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.
*/
void sqlite3_mutex_leave(sqlite3_mutex *p){
  if( p ){
    assert( sqlite3GlobalConfig.mutex.xMutexLeave );
    sqlite3GlobalConfig.mutex.xMutexLeave(p);
  }
}

#ifndef NDEBUG
/*
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
** intended for use inside assert() statements.
*/
int sqlite3_mutex_held(sqlite3_mutex *p){
  assert( p==0 || sqlite3GlobalConfig.mutex.xMutexHeld );
  return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p);
}
int sqlite3_mutex_notheld(sqlite3_mutex *p){
  assert( p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld );
  return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p);
}
#endif

#endif /* !defined(SQLITE_MUTEX_OMIT) */