drh | 90f6a5b | 2007-08-15 13:04:54 +0000 | [diff] [blame] | 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 | ************************************************************************* |
drh | 437b901 | 2007-08-28 16:34:42 +0000 | [diff] [blame] | 12 | ** This file contains the C functions that implement mutexes. |
drh | 90f6a5b | 2007-08-15 13:04:54 +0000 | [diff] [blame] | 13 | ** |
drh | 18472fa | 2008-10-07 15:25:48 +0000 | [diff] [blame] | 14 | ** This file contains code that is common across all mutex implementations. |
drh | 90f6a5b | 2007-08-15 13:04:54 +0000 | [diff] [blame] | 15 | */ |
| 16 | #include "sqliteInt.h" |
| 17 | |
drh | d0bc5d2 | 2009-09-10 22:30:53 +0000 | [diff] [blame] | 18 | #if defined(SQLITE_DEBUG) && !defined(SQLITE_MUTEX_OMIT) |
drh | fe5bdb3 | 2009-09-10 17:45:00 +0000 | [diff] [blame] | 19 | /* |
| 20 | ** For debugging purposes, record when the mutex subsystem is initialized |
| 21 | ** and uninitialized so that we can assert() if there is an attempt to |
| 22 | ** allocate a mutex while the system is uninitialized. |
| 23 | */ |
| 24 | static SQLITE_WSD int mutexIsInit = 0; |
mistachkin | 8bdc914 | 2015-09-11 05:06:15 +0000 | [diff] [blame] | 25 | #endif /* SQLITE_DEBUG && !defined(SQLITE_MUTEX_OMIT) */ |
drh | fe5bdb3 | 2009-09-10 17:45:00 +0000 | [diff] [blame] | 26 | |
| 27 | |
drh | 18472fa | 2008-10-07 15:25:48 +0000 | [diff] [blame] | 28 | #ifndef SQLITE_MUTEX_OMIT |
danielk1977 | 6d2ab0e | 2008-06-17 17:21:18 +0000 | [diff] [blame] | 29 | /* |
mistachkin | 8bdc914 | 2015-09-11 05:06:15 +0000 | [diff] [blame] | 30 | ** Copies a mutex implementation. Both arguments must point to valid |
| 31 | ** memory. |
| 32 | */ |
mistachkin | ffce11a | 2015-09-23 16:24:19 +0000 | [diff] [blame] | 33 | void sqlite3MutexCopy( |
mistachkin | 8bdc914 | 2015-09-11 05:06:15 +0000 | [diff] [blame] | 34 | sqlite3_mutex_methods *pTo, |
| 35 | sqlite3_mutex_methods const *pFrom |
| 36 | ){ |
| 37 | pTo->xMutexInit = pFrom->xMutexInit; |
| 38 | pTo->xMutexEnd = pFrom->xMutexEnd; |
| 39 | pTo->xMutexFree = pFrom->xMutexFree; |
| 40 | pTo->xMutexEnter = pFrom->xMutexEnter; |
| 41 | pTo->xMutexTry = pFrom->xMutexTry; |
| 42 | pTo->xMutexLeave = pFrom->xMutexLeave; |
| 43 | pTo->xMutexHeld = pFrom->xMutexHeld; |
| 44 | pTo->xMutexNotheld = pFrom->xMutexNotheld; |
| 45 | pTo->xMutexAlloc = pFrom->xMutexAlloc; |
| 46 | } |
| 47 | |
| 48 | /* |
danielk1977 | 6d2ab0e | 2008-06-17 17:21:18 +0000 | [diff] [blame] | 49 | ** Initialize the mutex system. |
| 50 | */ |
danielk1977 | d025174 | 2008-06-18 18:57:42 +0000 | [diff] [blame] | 51 | int sqlite3MutexInit(void){ |
mistachkin | 8bdc914 | 2015-09-11 05:06:15 +0000 | [diff] [blame] | 52 | int rc; |
mistachkin | ffce11a | 2015-09-23 16:24:19 +0000 | [diff] [blame] | 53 | |
| 54 | sqlite3MemoryBarrier(); |
| 55 | if( sqlite3CompareAndSwap( |
| 56 | (void * volatile *)&sqlite3GlobalConfig.mutex.xMutexAlloc, |
| 57 | 0, sqlite3GlobalConfig.mutex.xMutexAlloc)==0 ){ |
| 58 | /* If the xMutexAlloc method has not been set, then the user did not |
| 59 | ** install a mutex implementation via sqlite3_config() prior to |
| 60 | ** sqlite3_initialize() being called. This block copies pointers to |
| 61 | ** the default implementation into the sqlite3GlobalConfig structure. |
drh | 92d7652 | 2010-05-05 00:05:24 +0000 | [diff] [blame] | 62 | */ |
dan | 558814f | 2010-06-02 05:53:53 +0000 | [diff] [blame] | 63 | sqlite3_mutex_methods const *pFrom; |
mistachkin | 24271dc | 2015-09-23 16:33:44 +0000 | [diff] [blame] | 64 | |
drh | 92d7652 | 2010-05-05 00:05:24 +0000 | [diff] [blame] | 65 | if( sqlite3GlobalConfig.bCoreMutex ){ |
| 66 | pFrom = sqlite3DefaultMutex(); |
| 67 | }else{ |
| 68 | pFrom = sqlite3NoopMutex(); |
danielk1977 | 6d2ab0e | 2008-06-17 17:21:18 +0000 | [diff] [blame] | 69 | } |
mistachkin | ffce11a | 2015-09-23 16:24:19 +0000 | [diff] [blame] | 70 | sqlite3MutexCopy(&sqlite3GlobalConfig.mutex, pFrom); |
drh | 6081c1d | 2015-09-06 02:51:04 +0000 | [diff] [blame] | 71 | sqlite3MemoryBarrier(); |
danielk1977 | 6d2ab0e | 2008-06-17 17:21:18 +0000 | [diff] [blame] | 72 | } |
mistachkin | ffce11a | 2015-09-23 16:24:19 +0000 | [diff] [blame] | 73 | assert( sqlite3GlobalConfig.mutex.xMutexInit ); |
| 74 | rc = sqlite3GlobalConfig.mutex.xMutexInit(); |
danielk1977 | 6d2ab0e | 2008-06-17 17:21:18 +0000 | [diff] [blame] | 75 | |
drh | fe5bdb3 | 2009-09-10 17:45:00 +0000 | [diff] [blame] | 76 | #ifdef SQLITE_DEBUG |
| 77 | GLOBAL(int, mutexIsInit) = 1; |
| 78 | #endif |
| 79 | |
danielk1977 | 6d2ab0e | 2008-06-17 17:21:18 +0000 | [diff] [blame] | 80 | return rc; |
| 81 | } |
| 82 | |
| 83 | /* |
| 84 | ** Shutdown the mutex system. This call frees resources allocated by |
danielk1977 | d025174 | 2008-06-18 18:57:42 +0000 | [diff] [blame] | 85 | ** sqlite3MutexInit(). |
danielk1977 | 6d2ab0e | 2008-06-17 17:21:18 +0000 | [diff] [blame] | 86 | */ |
danielk1977 | d025174 | 2008-06-18 18:57:42 +0000 | [diff] [blame] | 87 | int sqlite3MutexEnd(void){ |
danielk1977 | 6d2ab0e | 2008-06-17 17:21:18 +0000 | [diff] [blame] | 88 | int rc = SQLITE_OK; |
danielk1977 | 0a54907 | 2009-02-17 16:29:10 +0000 | [diff] [blame] | 89 | if( sqlite3GlobalConfig.mutex.xMutexEnd ){ |
| 90 | rc = sqlite3GlobalConfig.mutex.xMutexEnd(); |
| 91 | } |
drh | fe5bdb3 | 2009-09-10 17:45:00 +0000 | [diff] [blame] | 92 | |
| 93 | #ifdef SQLITE_DEBUG |
| 94 | GLOBAL(int, mutexIsInit) = 0; |
| 95 | #endif |
| 96 | |
danielk1977 | 6d2ab0e | 2008-06-17 17:21:18 +0000 | [diff] [blame] | 97 | return rc; |
| 98 | } |
| 99 | |
| 100 | /* |
| 101 | ** Retrieve a pointer to a static mutex or allocate a new dynamic one. |
| 102 | */ |
| 103 | sqlite3_mutex *sqlite3_mutex_alloc(int id){ |
danielk1977 | bc10d77 | 2008-06-18 18:08:39 +0000 | [diff] [blame] | 104 | #ifndef SQLITE_OMIT_AUTOINIT |
drh | d42d0be | 2014-07-30 21:10:12 +0000 | [diff] [blame] | 105 | if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0; |
mistachkin | 2d8ad51 | 2014-10-27 22:06:21 +0000 | [diff] [blame] | 106 | if( id>SQLITE_MUTEX_RECURSIVE && sqlite3MutexInit() ) return 0; |
danielk1977 | bc10d77 | 2008-06-18 18:08:39 +0000 | [diff] [blame] | 107 | #endif |
mistachkin | 89e57dd | 2015-09-12 03:35:55 +0000 | [diff] [blame] | 108 | assert( sqlite3GlobalConfig.mutex.xMutexAlloc ); |
danielk1977 | 075c23a | 2008-09-01 18:34:20 +0000 | [diff] [blame] | 109 | return sqlite3GlobalConfig.mutex.xMutexAlloc(id); |
danielk1977 | 6d2ab0e | 2008-06-17 17:21:18 +0000 | [diff] [blame] | 110 | } |
| 111 | |
danielk1977 | 59f8c08 | 2008-06-18 17:09:10 +0000 | [diff] [blame] | 112 | sqlite3_mutex *sqlite3MutexAlloc(int id){ |
danielk1977 | 075c23a | 2008-09-01 18:34:20 +0000 | [diff] [blame] | 113 | if( !sqlite3GlobalConfig.bCoreMutex ){ |
danielk1977 | 59f8c08 | 2008-06-18 17:09:10 +0000 | [diff] [blame] | 114 | return 0; |
| 115 | } |
drh | fe5bdb3 | 2009-09-10 17:45:00 +0000 | [diff] [blame] | 116 | assert( GLOBAL(int, mutexIsInit) ); |
mistachkin | 89e57dd | 2015-09-12 03:35:55 +0000 | [diff] [blame] | 117 | assert( sqlite3GlobalConfig.mutex.xMutexAlloc ); |
danielk1977 | 075c23a | 2008-09-01 18:34:20 +0000 | [diff] [blame] | 118 | return sqlite3GlobalConfig.mutex.xMutexAlloc(id); |
danielk1977 | 59f8c08 | 2008-06-18 17:09:10 +0000 | [diff] [blame] | 119 | } |
| 120 | |
danielk1977 | 6d2ab0e | 2008-06-17 17:21:18 +0000 | [diff] [blame] | 121 | /* |
| 122 | ** Free a dynamic mutex. |
| 123 | */ |
| 124 | void sqlite3_mutex_free(sqlite3_mutex *p){ |
| 125 | if( p ){ |
mistachkin | 89e57dd | 2015-09-12 03:35:55 +0000 | [diff] [blame] | 126 | assert( sqlite3GlobalConfig.mutex.xMutexFree ); |
danielk1977 | 075c23a | 2008-09-01 18:34:20 +0000 | [diff] [blame] | 127 | sqlite3GlobalConfig.mutex.xMutexFree(p); |
danielk1977 | 6d2ab0e | 2008-06-17 17:21:18 +0000 | [diff] [blame] | 128 | } |
| 129 | } |
| 130 | |
| 131 | /* |
| 132 | ** Obtain the mutex p. If some other thread already has the mutex, block |
| 133 | ** until it can be obtained. |
| 134 | */ |
| 135 | void sqlite3_mutex_enter(sqlite3_mutex *p){ |
| 136 | if( p ){ |
mistachkin | 89e57dd | 2015-09-12 03:35:55 +0000 | [diff] [blame] | 137 | assert( sqlite3GlobalConfig.mutex.xMutexEnter ); |
danielk1977 | 075c23a | 2008-09-01 18:34:20 +0000 | [diff] [blame] | 138 | sqlite3GlobalConfig.mutex.xMutexEnter(p); |
danielk1977 | 6d2ab0e | 2008-06-17 17:21:18 +0000 | [diff] [blame] | 139 | } |
| 140 | } |
| 141 | |
| 142 | /* |
| 143 | ** Obtain the mutex p. If successful, return SQLITE_OK. Otherwise, if another |
| 144 | ** thread holds the mutex and it cannot be obtained, return SQLITE_BUSY. |
| 145 | */ |
| 146 | int sqlite3_mutex_try(sqlite3_mutex *p){ |
| 147 | int rc = SQLITE_OK; |
| 148 | if( p ){ |
mistachkin | 89e57dd | 2015-09-12 03:35:55 +0000 | [diff] [blame] | 149 | assert( sqlite3GlobalConfig.mutex.xMutexTry ); |
danielk1977 | 075c23a | 2008-09-01 18:34:20 +0000 | [diff] [blame] | 150 | return sqlite3GlobalConfig.mutex.xMutexTry(p); |
danielk1977 | 6d2ab0e | 2008-06-17 17:21:18 +0000 | [diff] [blame] | 151 | } |
| 152 | return rc; |
| 153 | } |
| 154 | |
| 155 | /* |
| 156 | ** The sqlite3_mutex_leave() routine exits a mutex that was previously |
| 157 | ** entered by the same thread. The behavior is undefined if the mutex |
| 158 | ** is not currently entered. If a NULL pointer is passed as an argument |
| 159 | ** this function is a no-op. |
| 160 | */ |
| 161 | void sqlite3_mutex_leave(sqlite3_mutex *p){ |
| 162 | if( p ){ |
mistachkin | 89e57dd | 2015-09-12 03:35:55 +0000 | [diff] [blame] | 163 | assert( sqlite3GlobalConfig.mutex.xMutexLeave ); |
danielk1977 | 075c23a | 2008-09-01 18:34:20 +0000 | [diff] [blame] | 164 | sqlite3GlobalConfig.mutex.xMutexLeave(p); |
danielk1977 | 6d2ab0e | 2008-06-17 17:21:18 +0000 | [diff] [blame] | 165 | } |
| 166 | } |
| 167 | |
| 168 | #ifndef NDEBUG |
| 169 | /* |
| 170 | ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are |
| 171 | ** intended for use inside assert() statements. |
| 172 | */ |
| 173 | int sqlite3_mutex_held(sqlite3_mutex *p){ |
mistachkin | 89e57dd | 2015-09-12 03:35:55 +0000 | [diff] [blame] | 174 | assert( p==0 || sqlite3GlobalConfig.mutex.xMutexHeld ); |
danielk1977 | 075c23a | 2008-09-01 18:34:20 +0000 | [diff] [blame] | 175 | return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p); |
danielk1977 | 6d2ab0e | 2008-06-17 17:21:18 +0000 | [diff] [blame] | 176 | } |
| 177 | int sqlite3_mutex_notheld(sqlite3_mutex *p){ |
mistachkin | 89e57dd | 2015-09-12 03:35:55 +0000 | [diff] [blame] | 178 | assert( p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld ); |
danielk1977 | 075c23a | 2008-09-01 18:34:20 +0000 | [diff] [blame] | 179 | return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p); |
danielk1977 | 6d2ab0e | 2008-06-17 17:21:18 +0000 | [diff] [blame] | 180 | } |
| 181 | #endif |
| 182 | |
drh | e4c88c0 | 2012-01-04 12:57:45 +0000 | [diff] [blame] | 183 | #endif /* !defined(SQLITE_MUTEX_OMIT) */ |