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