.github
alerting
client
config
controller
core
docs
examples
jsonpath
k8s
k8stest
metric
pattern
security
storage
util
vendor
cloud.google.com
github.com
go.etcd.io
golang.org
google.golang.org
gopkg.in
k8s.io
lukechampine.com
modernc.org
cc
ccgo
libc
mathutil
memory
opt
sqlite
lib
capi_darwin_amd64.go
capi_darwin_arm64.go
capi_linux_386.go
capi_linux_amd64.go
capi_linux_arm.go
capi_linux_arm64.go
capi_linux_s390x.go
capi_windows_386.go
capi_windows_amd64.go
hooks.go
mutex.go
sqlite_darwin_amd64.go
sqlite_darwin_arm64.go
sqlite_linux_386.go
sqlite_linux_amd64.go
sqlite_linux_arm.go
sqlite_linux_arm64.go
sqlite_linux_s390x.go
sqlite_windows_386.go
sqlite_windows_amd64.go
AUTHORS
CONTRIBUTORS
LICENSE
Makefile
README.md
SQLITE-LICENSE
doc.go
generator.go
go.mod
go.sum
mutex.go
sqlite.go
sqlite_go18.go
unconvert.sh
strutil
token
sigs.k8s.io
modules.txt
watchdog
web
.dockerignore
.gitattributes
.gitignore
Dockerfile
LICENSE.md
Makefile
README.md
config.yaml
go.mod
go.sum
main.go
342 lines
10 KiB
Go
342 lines
10 KiB
Go
// 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 sqlite3
|
|
|
|
import (
|
|
"fmt"
|
|
"runtime"
|
|
"sync"
|
|
"sync/atomic"
|
|
"unsafe"
|
|
|
|
"modernc.org/libc"
|
|
"modernc.org/libc/sys/types"
|
|
)
|
|
|
|
func init() {
|
|
tls := libc.NewTLS()
|
|
if Xsqlite3_threadsafe(tls) == 0 {
|
|
panic(fmt.Errorf("sqlite: thread safety configuration error"))
|
|
}
|
|
|
|
varArgs := libc.Xmalloc(tls, types.Size_t(unsafe.Sizeof(uintptr(0))))
|
|
if varArgs == 0 {
|
|
panic(fmt.Errorf("cannot allocate memory"))
|
|
}
|
|
|
|
// experimental pthreads support currently only on linux/amd64
|
|
if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
|
|
// int sqlite3_config(int, ...);
|
|
if rc := Xsqlite3_config(tls, SQLITE_CONFIG_MUTEX, libc.VaList(varArgs, uintptr(unsafe.Pointer(&mutexMethods)))); rc != SQLITE_OK {
|
|
p := Xsqlite3_errstr(tls, rc)
|
|
str := libc.GoString(p)
|
|
panic(fmt.Errorf("sqlite: failed to configure mutex methods: %v", str))
|
|
}
|
|
}
|
|
|
|
libc.Xfree(tls, varArgs)
|
|
tls.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 mutex
|
|
mutexApp2 mutex
|
|
mutexApp3 mutex
|
|
mutexLRU mutex
|
|
mutexMaster mutex
|
|
mutexMem mutex
|
|
mutexOpen mutex
|
|
mutexPMem mutex
|
|
mutexPRNG mutex
|
|
mutexVFS1 mutex
|
|
mutexVFS2 mutex
|
|
mutexVFS3 mutex
|
|
)
|
|
|
|
type mutex struct {
|
|
cnt int32
|
|
id int32
|
|
sync.Mutex
|
|
wait sync.Mutex
|
|
recursive bool
|
|
}
|
|
|
|
func (m *mutex) enter(id int32) {
|
|
if !m.recursive {
|
|
m.Lock()
|
|
m.id = id
|
|
return
|
|
}
|
|
|
|
for {
|
|
m.Lock()
|
|
switch m.id {
|
|
case 0:
|
|
m.cnt = 1
|
|
m.id = id
|
|
m.wait.Lock()
|
|
m.Unlock()
|
|
return
|
|
case id:
|
|
m.cnt++
|
|
m.Unlock()
|
|
return
|
|
}
|
|
|
|
m.Unlock()
|
|
m.wait.Lock()
|
|
//lint:ignore SA2001 TODO report staticcheck issue
|
|
m.wait.Unlock()
|
|
}
|
|
}
|
|
|
|
func (m *mutex) try(id int32) int32 {
|
|
if !m.recursive {
|
|
return SQLITE_BUSY
|
|
}
|
|
|
|
m.Lock()
|
|
switch m.id {
|
|
case 0:
|
|
m.cnt = 1
|
|
m.id = id
|
|
m.wait.Lock()
|
|
m.Unlock()
|
|
return SQLITE_OK
|
|
case id:
|
|
m.cnt++
|
|
m.Unlock()
|
|
return SQLITE_OK
|
|
}
|
|
|
|
m.Unlock()
|
|
return SQLITE_BUSY
|
|
}
|
|
|
|
func (m *mutex) leave(id int32) {
|
|
if !m.recursive {
|
|
m.id = 0
|
|
m.Unlock()
|
|
return
|
|
}
|
|
|
|
m.Lock()
|
|
m.cnt--
|
|
if m.cnt == 0 {
|
|
m.id = 0
|
|
m.wait.Unlock()
|
|
}
|
|
m.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 mutexInit(tls *libc.TLS) int32 { return SQLITE_OK }
|
|
|
|
// int (*xMutexEnd)(void);
|
|
func mutexEnd(tls *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 mutexAlloc(tls *libc.TLS, typ int32) uintptr {
|
|
defer func() {
|
|
}()
|
|
switch typ {
|
|
case SQLITE_MUTEX_FAST:
|
|
return libc.Xcalloc(tls, 1, types.Size_t(unsafe.Sizeof(mutex{})))
|
|
case SQLITE_MUTEX_RECURSIVE:
|
|
p := libc.Xcalloc(tls, 1, types.Size_t(unsafe.Sizeof(mutex{})))
|
|
(*mutex)(unsafe.Pointer(p)).recursive = true
|
|
return p
|
|
case 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 mutexFree(tls *libc.TLS, m uintptr) { libc.Xfree(tls, m) }
|
|
|
|
// 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 mutexEnter(tls *libc.TLS, m uintptr) {
|
|
if m == 0 {
|
|
return
|
|
}
|
|
|
|
(*mutex)(unsafe.Pointer(m)).enter(tls.ID)
|
|
}
|
|
|
|
// int (*xMutexTry)(sqlite3_mutex *);
|
|
func mutexTry(tls *libc.TLS, m uintptr) int32 {
|
|
if m == 0 {
|
|
return SQLITE_OK
|
|
}
|
|
|
|
return (*mutex)(unsafe.Pointer(m)).try(tls.ID)
|
|
}
|
|
|
|
// void (*xMutexLeave)(sqlite3_mutex *);
|
|
func mutexLeave(tls *libc.TLS, m uintptr) {
|
|
if m == 0 {
|
|
return
|
|
}
|
|
|
|
(*mutex)(unsafe.Pointer(m)).leave(tls.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 mutexHeld(tls *libc.TLS, m uintptr) int32 {
|
|
if m == 0 {
|
|
return 1
|
|
}
|
|
|
|
return libc.Bool32(atomic.LoadInt32(&(*mutex)(unsafe.Pointer(m)).id) == tls.ID)
|
|
}
|
|
|
|
// int (*xMutexNotheld)(sqlite3_mutex *);
|
|
func mutexNotheld(tls *libc.TLS, m uintptr) int32 {
|
|
if m == 0 {
|
|
return 1
|
|
}
|
|
|
|
return libc.Bool32(atomic.LoadInt32(&(*mutex)(unsafe.Pointer(m)).id) != tls.ID)
|
|
}
|