github.com/jdgcs/sqlite3@v1.12.1-0.20210908114423-bc5f96e4dd51/lib/mutex.go (about) 1 // Copyright 2021 The Sqlite Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package sqlite3 6 7 import ( 8 "fmt" 9 "runtime" 10 "sync" 11 "sync/atomic" 12 "unsafe" 13 14 "modernc.org/libc" 15 "modernc.org/libc/sys/types" 16 ) 17 18 func init() { 19 tls := libc.NewTLS() 20 if Xsqlite3_threadsafe(tls) == 0 { 21 panic(fmt.Errorf("sqlite: thread safety configuration error")) 22 } 23 24 varArgs := libc.Xmalloc(tls, types.Size_t(unsafe.Sizeof(uintptr(0)))) 25 if varArgs == 0 { 26 panic(fmt.Errorf("cannot allocate memory")) 27 } 28 29 // experimental pthreads support currently only on linux/amd64 30 if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" { 31 // int sqlite3_config(int, ...); 32 if rc := Xsqlite3_config(tls, SQLITE_CONFIG_MUTEX, libc.VaList(varArgs, uintptr(unsafe.Pointer(&mutexMethods)))); rc != SQLITE_OK { 33 p := Xsqlite3_errstr(tls, rc) 34 str := libc.GoString(p) 35 panic(fmt.Errorf("sqlite: failed to configure mutex methods: %v", str)) 36 } 37 } 38 39 libc.Xfree(tls, varArgs) 40 tls.Close() 41 } 42 43 var ( 44 mutexMethods = Sqlite3_mutex_methods{ 45 FxMutexInit: *(*uintptr)(unsafe.Pointer(&struct{ f func(*libc.TLS) int32 }{mutexInit})), 46 FxMutexEnd: *(*uintptr)(unsafe.Pointer(&struct{ f func(*libc.TLS) int32 }{mutexEnd})), 47 FxMutexAlloc: *(*uintptr)(unsafe.Pointer(&struct { 48 f func(*libc.TLS, int32) uintptr 49 }{mutexAlloc})), 50 FxMutexFree: *(*uintptr)(unsafe.Pointer(&struct{ f func(*libc.TLS, uintptr) }{mutexFree})), 51 FxMutexEnter: *(*uintptr)(unsafe.Pointer(&struct{ f func(*libc.TLS, uintptr) }{mutexEnter})), 52 FxMutexTry: *(*uintptr)(unsafe.Pointer(&struct { 53 f func(*libc.TLS, uintptr) int32 54 }{mutexTry})), 55 FxMutexLeave: *(*uintptr)(unsafe.Pointer(&struct{ f func(*libc.TLS, uintptr) }{mutexLeave})), 56 FxMutexHeld: *(*uintptr)(unsafe.Pointer(&struct { 57 f func(*libc.TLS, uintptr) int32 58 }{mutexHeld})), 59 FxMutexNotheld: *(*uintptr)(unsafe.Pointer(&struct { 60 f func(*libc.TLS, uintptr) int32 61 }{mutexNotheld})), 62 } 63 64 mutexApp1 mutex 65 mutexApp2 mutex 66 mutexApp3 mutex 67 mutexLRU mutex 68 mutexMaster mutex 69 mutexMem mutex 70 mutexOpen mutex 71 mutexPMem mutex 72 mutexPRNG mutex 73 mutexVFS1 mutex 74 mutexVFS2 mutex 75 mutexVFS3 mutex 76 ) 77 78 type mutex struct { 79 cnt int32 80 id int32 81 sync.Mutex 82 wait sync.Mutex 83 recursive bool 84 } 85 86 func (m *mutex) enter(id int32) { 87 if !m.recursive { 88 m.Lock() 89 m.id = id 90 return 91 } 92 93 for { 94 m.Lock() 95 switch m.id { 96 case 0: 97 m.cnt = 1 98 m.id = id 99 m.wait.Lock() 100 m.Unlock() 101 return 102 case id: 103 m.cnt++ 104 m.Unlock() 105 return 106 } 107 108 m.Unlock() 109 m.wait.Lock() 110 //lint:ignore SA2001 TODO report staticcheck issue 111 m.wait.Unlock() 112 } 113 } 114 115 func (m *mutex) try(id int32) int32 { 116 if !m.recursive { 117 return SQLITE_BUSY 118 } 119 120 m.Lock() 121 switch m.id { 122 case 0: 123 m.cnt = 1 124 m.id = id 125 m.wait.Lock() 126 m.Unlock() 127 return SQLITE_OK 128 case id: 129 m.cnt++ 130 m.Unlock() 131 return SQLITE_OK 132 } 133 134 m.Unlock() 135 return SQLITE_BUSY 136 } 137 138 func (m *mutex) leave(id int32) { 139 if !m.recursive { 140 m.id = 0 141 m.Unlock() 142 return 143 } 144 145 m.Lock() 146 m.cnt-- 147 if m.cnt == 0 { 148 m.id = 0 149 m.wait.Unlock() 150 } 151 m.Unlock() 152 } 153 154 // int (*xMutexInit)(void); 155 // 156 // The xMutexInit method defined by this structure is invoked as part of system 157 // initialization by the sqlite3_initialize() function. The xMutexInit routine 158 // is called by SQLite exactly once for each effective call to 159 // sqlite3_initialize(). 160 // 161 // The xMutexInit() method must be threadsafe. It must be harmless to invoke 162 // xMutexInit() multiple times within the same process and without intervening 163 // calls to xMutexEnd(). Second and subsequent calls to xMutexInit() must be 164 // no-ops. xMutexInit() must not use SQLite memory allocation (sqlite3_malloc() 165 // and its associates). 166 // 167 // If xMutexInit fails in any way, it is expected to clean up after itself 168 // prior to returning. 169 func mutexInit(tls *libc.TLS) int32 { return SQLITE_OK } 170 171 // int (*xMutexEnd)(void); 172 func mutexEnd(tls *libc.TLS) int32 { return SQLITE_OK } 173 174 // sqlite3_mutex *(*xMutexAlloc)(int); 175 // 176 // The sqlite3_mutex_alloc() routine allocates a new mutex and returns a 177 // pointer to it. The sqlite3_mutex_alloc() routine returns NULL if it is 178 // unable to allocate the requested mutex. The argument to 179 // sqlite3_mutex_alloc() must one of these integer constants: 180 // 181 // SQLITE_MUTEX_FAST 182 // SQLITE_MUTEX_RECURSIVE 183 // SQLITE_MUTEX_STATIC_MASTER 184 // SQLITE_MUTEX_STATIC_MEM 185 // SQLITE_MUTEX_STATIC_OPEN 186 // SQLITE_MUTEX_STATIC_PRNG 187 // SQLITE_MUTEX_STATIC_LRU 188 // SQLITE_MUTEX_STATIC_PMEM 189 // SQLITE_MUTEX_STATIC_APP1 190 // SQLITE_MUTEX_STATIC_APP2 191 // SQLITE_MUTEX_STATIC_APP3 192 // SQLITE_MUTEX_STATIC_VFS1 193 // SQLITE_MUTEX_STATIC_VFS2 194 // SQLITE_MUTEX_STATIC_VFS3 195 // 196 // The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) cause 197 // sqlite3_mutex_alloc() to create a new mutex. The new mutex is recursive when 198 // SQLITE_MUTEX_RECURSIVE is used but not necessarily so when SQLITE_MUTEX_FAST 199 // is used. The mutex implementation does not need to make a distinction 200 // between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does not want to. 201 // SQLite will only request a recursive mutex in cases where it really needs 202 // one. If a faster non-recursive mutex implementation is available on the host 203 // platform, the mutex subsystem might return such a mutex in response to 204 // SQLITE_MUTEX_FAST. 205 // 206 // The other allowed parameters to sqlite3_mutex_alloc() (anything other than 207 // SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) each return a pointer to a 208 // static preexisting mutex. Nine static mutexes are used by the current 209 // version of SQLite. Future versions of SQLite may add additional static 210 // mutexes. Static mutexes are for internal use by SQLite only. Applications 211 // that use SQLite mutexes should use only the dynamic mutexes returned by 212 // SQLITE_MUTEX_FAST or SQLITE_MUTEX_RECURSIVE. 213 // 214 // Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST or 215 // SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() returns a 216 // different mutex on every call. For the static mutex types, the same mutex is 217 // returned on every call that has the same type number. 218 func mutexAlloc(tls *libc.TLS, typ int32) uintptr { 219 defer func() { 220 }() 221 switch typ { 222 case SQLITE_MUTEX_FAST: 223 return libc.Xcalloc(tls, 1, types.Size_t(unsafe.Sizeof(mutex{}))) 224 case SQLITE_MUTEX_RECURSIVE: 225 p := libc.Xcalloc(tls, 1, types.Size_t(unsafe.Sizeof(mutex{}))) 226 (*mutex)(unsafe.Pointer(p)).recursive = true 227 return p 228 case SQLITE_MUTEX_STATIC_MASTER: 229 return uintptr(unsafe.Pointer(&mutexMaster)) 230 case SQLITE_MUTEX_STATIC_MEM: 231 return uintptr(unsafe.Pointer(&mutexMem)) 232 case SQLITE_MUTEX_STATIC_OPEN: 233 return uintptr(unsafe.Pointer(&mutexOpen)) 234 case SQLITE_MUTEX_STATIC_PRNG: 235 return uintptr(unsafe.Pointer(&mutexPRNG)) 236 case SQLITE_MUTEX_STATIC_LRU: 237 return uintptr(unsafe.Pointer(&mutexLRU)) 238 case SQLITE_MUTEX_STATIC_PMEM: 239 return uintptr(unsafe.Pointer(&mutexPMem)) 240 case SQLITE_MUTEX_STATIC_APP1: 241 return uintptr(unsafe.Pointer(&mutexApp1)) 242 case SQLITE_MUTEX_STATIC_APP2: 243 return uintptr(unsafe.Pointer(&mutexApp2)) 244 case SQLITE_MUTEX_STATIC_APP3: 245 return uintptr(unsafe.Pointer(&mutexApp3)) 246 case SQLITE_MUTEX_STATIC_VFS1: 247 return uintptr(unsafe.Pointer(&mutexVFS1)) 248 case SQLITE_MUTEX_STATIC_VFS2: 249 return uintptr(unsafe.Pointer(&mutexVFS2)) 250 case SQLITE_MUTEX_STATIC_VFS3: 251 return uintptr(unsafe.Pointer(&mutexVFS3)) 252 default: 253 return 0 254 } 255 } 256 257 // void (*xMutexFree)(sqlite3_mutex *); 258 func mutexFree(tls *libc.TLS, m uintptr) { libc.Xfree(tls, m) } 259 260 // The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt to enter 261 // a mutex. If another thread is already within the mutex, 262 // sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return 263 // SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK upon 264 // successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can be 265 // entered multiple times by the same thread. In such cases, the mutex must be 266 // exited an equal number of times before another thread can enter. If the same 267 // thread tries to enter any mutex other than an SQLITE_MUTEX_RECURSIVE more 268 // than once, the behavior is undefined. 269 // 270 // If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or 271 // sqlite3_mutex_leave() is a NULL pointer, then all three routines behave as 272 // no-ops. 273 274 // void (*xMutexEnter)(sqlite3_mutex *); 275 func mutexEnter(tls *libc.TLS, m uintptr) { 276 if m == 0 { 277 return 278 } 279 280 (*mutex)(unsafe.Pointer(m)).enter(tls.ID) 281 } 282 283 // int (*xMutexTry)(sqlite3_mutex *); 284 func mutexTry(tls *libc.TLS, m uintptr) int32 { 285 if m == 0 { 286 return SQLITE_OK 287 } 288 289 return (*mutex)(unsafe.Pointer(m)).try(tls.ID) 290 } 291 292 // void (*xMutexLeave)(sqlite3_mutex *); 293 func mutexLeave(tls *libc.TLS, m uintptr) { 294 if m == 0 { 295 return 296 } 297 298 (*mutex)(unsafe.Pointer(m)).leave(tls.ID) 299 } 300 301 // The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines are intended 302 // for use inside assert() statements. The SQLite core never uses these 303 // routines except inside an assert() and applications are advised to follow 304 // the lead of the core. The SQLite core only provides implementations for 305 // these routines when it is compiled with the SQLITE_DEBUG flag. External 306 // mutex implementations are only required to provide these routines if 307 // SQLITE_DEBUG is defined and if NDEBUG is not defined. 308 // 309 // These routines should return true if the mutex in their argument is held or 310 // not held, respectively, by the calling thread. 311 // 312 // The implementation is not required to provide versions of these routines 313 // that actually work. If the implementation does not provide working versions 314 // of these routines, it should at least provide stubs that always return true 315 // so that one does not get spurious assertion failures. 316 // 317 // If the argument to sqlite3_mutex_held() is a NULL pointer then the routine 318 // should return 1. This seems counter-intuitive since clearly the mutex cannot 319 // be held if it does not exist. But the reason the mutex does not exist is 320 // because the build is not using mutexes. And we do not want the assert() 321 // containing the call to sqlite3_mutex_held() to fail, so a non-zero return is 322 // the appropriate thing to do. The sqlite3_mutex_notheld() interface should 323 // also return 1 when given a NULL pointer. 324 325 // int (*xMutexHeld)(sqlite3_mutex *); 326 func mutexHeld(tls *libc.TLS, m uintptr) int32 { 327 if m == 0 { 328 return 1 329 } 330 331 return libc.Bool32(atomic.LoadInt32(&(*mutex)(unsafe.Pointer(m)).id) == tls.ID) 332 } 333 334 // int (*xMutexNotheld)(sqlite3_mutex *); 335 func mutexNotheld(tls *libc.TLS, m uintptr) int32 { 336 if m == 0 { 337 return 1 338 } 339 340 return libc.Bool32(atomic.LoadInt32(&(*mutex)(unsafe.Pointer(m)).id) != tls.ID) 341 }