Source File
mutex.go
Belonging Package
modernc.org/sqlite/lib
// Copyright 2021 The Sqlite Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package sqlite3import ()func () {:= libc.NewTLS()if Xsqlite3_threadsafe() == 0 {panic(fmt.Errorf("sqlite: thread safety configuration error"))}:= libc.Xmalloc(, types.Size_t(unsafe.Sizeof(uintptr(0))))if == 0 {panic(fmt.Errorf("cannot allocate memory"))}// experimental pthreads support currently only on linux/amd64if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {// int sqlite3_config(int, ...);if := Xsqlite3_config(, SQLITE_CONFIG_MUTEX, libc.VaList(, uintptr(unsafe.Pointer(&mutexMethods)))); != SQLITE_OK {:= Xsqlite3_errstr(, ):= libc.GoString()panic(fmt.Errorf("sqlite: failed to configure mutex methods: %v", ))}}libc.Xfree(, ).Close()}var (mutexMethods = Sqlite3_mutex_methods{FxMutexInit: *(*uintptr)(unsafe.Pointer(&struct{ f func(*libc.TLS) int32 }{mutexInit})),FxMutexEnd: *(*uintptr)(unsafe.Pointer(&struct{ f func(*libc.TLS) int32 }{mutexEnd})),FxMutexAlloc: *(*uintptr)(unsafe.Pointer(&struct {f func(*libc.TLS, int32) uintptr}{mutexAlloc})),FxMutexFree: *(*uintptr)(unsafe.Pointer(&struct{ f func(*libc.TLS, uintptr) }{mutexFree})),FxMutexEnter: *(*uintptr)(unsafe.Pointer(&struct{ f func(*libc.TLS, uintptr) }{mutexEnter})),FxMutexTry: *(*uintptr)(unsafe.Pointer(&struct {f func(*libc.TLS, uintptr) int32}{mutexTry})),FxMutexLeave: *(*uintptr)(unsafe.Pointer(&struct{ f func(*libc.TLS, uintptr) }{mutexLeave})),FxMutexHeld: *(*uintptr)(unsafe.Pointer(&struct {f func(*libc.TLS, uintptr) int32}{mutexHeld})),FxMutexNotheld: *(*uintptr)(unsafe.Pointer(&struct {f func(*libc.TLS, uintptr) int32}{mutexNotheld})),}mutexApp1 mutexmutexApp2 mutexmutexApp3 mutexmutexLRU mutexmutexMaster mutexmutexMem mutexmutexOpen mutexmutexPMem mutexmutexPRNG mutexmutexVFS1 mutexmutexVFS2 mutexmutexVFS3 mutex)type mutex struct {cnt int32id int32sync.Mutexwait sync.Mutexrecursive bool}func ( *mutex) ( int32) {if !.recursive {.Lock().id =return}for {.Lock()switch .id {case 0:.cnt = 1.id =.wait.Lock().Unlock()returncase :.cnt++.Unlock()return}.Unlock().wait.Lock()//lint:ignore SA2001 TODO report staticcheck issue.wait.Unlock()}}func ( *mutex) ( int32) int32 {if !.recursive {return SQLITE_BUSY}.Lock()switch .id {case 0:.cnt = 1.id =.wait.Lock().Unlock()return SQLITE_OKcase :.cnt++.Unlock()return SQLITE_OK}.Unlock()return SQLITE_BUSY}func ( *mutex) ( int32) {if !.recursive {.id = 0.Unlock()return}.Lock().cnt--if .cnt == 0 {.id = 0.wait.Unlock()}.Unlock()}// int (*xMutexInit)(void);//// The xMutexInit method defined by this structure is invoked as part of system// initialization by the sqlite3_initialize() function. The xMutexInit routine// is called by SQLite exactly once for each effective call to// sqlite3_initialize().//// The xMutexInit() method must be threadsafe. It must be harmless to invoke// xMutexInit() multiple times within the same process and without intervening// calls to xMutexEnd(). Second and subsequent calls to xMutexInit() must be// no-ops. xMutexInit() must not use SQLite memory allocation (sqlite3_malloc()// and its associates).//// If xMutexInit fails in any way, it is expected to clean up after itself// prior to returning.func ( *libc.TLS) int32 { return SQLITE_OK }// int (*xMutexEnd)(void);func ( *libc.TLS) int32 { return SQLITE_OK }// sqlite3_mutex *(*xMutexAlloc)(int);//// The sqlite3_mutex_alloc() routine allocates a new mutex and returns a// pointer to it. The sqlite3_mutex_alloc() routine returns NULL if it is// unable to allocate the requested mutex. The argument to// sqlite3_mutex_alloc() must one of these integer constants://// SQLITE_MUTEX_FAST// SQLITE_MUTEX_RECURSIVE// SQLITE_MUTEX_STATIC_MASTER// SQLITE_MUTEX_STATIC_MEM// SQLITE_MUTEX_STATIC_OPEN// SQLITE_MUTEX_STATIC_PRNG// SQLITE_MUTEX_STATIC_LRU// SQLITE_MUTEX_STATIC_PMEM// SQLITE_MUTEX_STATIC_APP1// SQLITE_MUTEX_STATIC_APP2// SQLITE_MUTEX_STATIC_APP3// SQLITE_MUTEX_STATIC_VFS1// SQLITE_MUTEX_STATIC_VFS2// SQLITE_MUTEX_STATIC_VFS3//// The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) cause// sqlite3_mutex_alloc() to create a new mutex. The new mutex is recursive when// SQLITE_MUTEX_RECURSIVE is used but not necessarily so when SQLITE_MUTEX_FAST// is used. The mutex implementation does not need to make a distinction// between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does not want to.// SQLite will only request a recursive mutex in cases where it really needs// one. If a faster non-recursive mutex implementation is available on the host// platform, the mutex subsystem might return such a mutex in response to// SQLITE_MUTEX_FAST.//// The other allowed parameters to sqlite3_mutex_alloc() (anything other than// SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) each return a pointer to a// static preexisting mutex. Nine static mutexes are used by the current// version of SQLite. Future versions of SQLite may add additional static// mutexes. Static mutexes are for internal use by SQLite only. Applications// that use SQLite mutexes should use only the dynamic mutexes returned by// SQLITE_MUTEX_FAST or SQLITE_MUTEX_RECURSIVE.//// Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST or// SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() returns a// different mutex on every call. For the static mutex types, the same mutex is// returned on every call that has the same type number.func ( *libc.TLS, int32) uintptr {defer func() {}()switch {case SQLITE_MUTEX_FAST:return libc.Xcalloc(, 1, types.Size_t(unsafe.Sizeof(mutex{})))case SQLITE_MUTEX_RECURSIVE::= libc.Xcalloc(, 1, types.Size_t(unsafe.Sizeof(mutex{})))(*mutex)(unsafe.Pointer()).recursive = truereturncase SQLITE_MUTEX_STATIC_MASTER:return uintptr(unsafe.Pointer(&mutexMaster))case SQLITE_MUTEX_STATIC_MEM:return uintptr(unsafe.Pointer(&mutexMem))case SQLITE_MUTEX_STATIC_OPEN:return uintptr(unsafe.Pointer(&mutexOpen))case SQLITE_MUTEX_STATIC_PRNG:return uintptr(unsafe.Pointer(&mutexPRNG))case SQLITE_MUTEX_STATIC_LRU:return uintptr(unsafe.Pointer(&mutexLRU))case SQLITE_MUTEX_STATIC_PMEM:return uintptr(unsafe.Pointer(&mutexPMem))case SQLITE_MUTEX_STATIC_APP1:return uintptr(unsafe.Pointer(&mutexApp1))case SQLITE_MUTEX_STATIC_APP2:return uintptr(unsafe.Pointer(&mutexApp2))case SQLITE_MUTEX_STATIC_APP3:return uintptr(unsafe.Pointer(&mutexApp3))case SQLITE_MUTEX_STATIC_VFS1:return uintptr(unsafe.Pointer(&mutexVFS1))case SQLITE_MUTEX_STATIC_VFS2:return uintptr(unsafe.Pointer(&mutexVFS2))case SQLITE_MUTEX_STATIC_VFS3:return uintptr(unsafe.Pointer(&mutexVFS3))default:return 0}}// void (*xMutexFree)(sqlite3_mutex *);func ( *libc.TLS, uintptr) { libc.Xfree(, ) }// The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt to enter// a mutex. If another thread is already within the mutex,// sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return// SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK upon// successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can be// entered multiple times by the same thread. In such cases, the mutex must be// exited an equal number of times before another thread can enter. If the same// thread tries to enter any mutex other than an SQLITE_MUTEX_RECURSIVE more// than once, the behavior is undefined.//// If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or// sqlite3_mutex_leave() is a NULL pointer, then all three routines behave as// no-ops.// void (*xMutexEnter)(sqlite3_mutex *);func ( *libc.TLS, uintptr) {if == 0 {return}(*mutex)(unsafe.Pointer()).enter(.ID)}// int (*xMutexTry)(sqlite3_mutex *);func ( *libc.TLS, uintptr) int32 {if == 0 {return SQLITE_OK}return (*mutex)(unsafe.Pointer()).try(.ID)}// void (*xMutexLeave)(sqlite3_mutex *);func ( *libc.TLS, uintptr) {if == 0 {return}(*mutex)(unsafe.Pointer()).leave(.ID)}// The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines are intended// for use inside assert() statements. The SQLite core never uses these// routines except inside an assert() and applications are advised to follow// the lead of the core. The SQLite core only provides implementations for// these routines when it is compiled with the SQLITE_DEBUG flag. External// mutex implementations are only required to provide these routines if// SQLITE_DEBUG is defined and if NDEBUG is not defined.//// These routines should return true if the mutex in their argument is held or// not held, respectively, by the calling thread.//// The implementation is not required to provide versions of these routines// that actually work. If the implementation does not provide working versions// of these routines, it should at least provide stubs that always return true// so that one does not get spurious assertion failures.//// If the argument to sqlite3_mutex_held() is a NULL pointer then the routine// should return 1. This seems counter-intuitive since clearly the mutex cannot// be held if it does not exist. But the reason the mutex does not exist is// because the build is not using mutexes. And we do not want the assert()// containing the call to sqlite3_mutex_held() to fail, so a non-zero return is// the appropriate thing to do. The sqlite3_mutex_notheld() interface should// also return 1 when given a NULL pointer.// int (*xMutexHeld)(sqlite3_mutex *);func ( *libc.TLS, uintptr) int32 {if == 0 {return 1}return libc.Bool32(atomic.LoadInt32(&(*mutex)(unsafe.Pointer()).id) == .ID)}// int (*xMutexNotheld)(sqlite3_mutex *);func ( *libc.TLS, uintptr) int32 {if == 0 {return 1}return libc.Bool32(atomic.LoadInt32(&(*mutex)(unsafe.Pointer()).id) != .ID)}
![]() |
The pages are generated with Golds v0.3.6. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |