2021-04-21 20:56:00 -07:00
|
|
|
// 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"
|
|
|
|
"sync"
|
|
|
|
"sync/atomic"
|
|
|
|
"unsafe"
|
|
|
|
|
2024-09-04 11:57:58 +02:00
|
|
|
"modernc.org/sqlite/internal/libc"
|
|
|
|
"modernc.org/sqlite/internal/libc/sys/types"
|
2021-04-21 20:56:00 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
tls := libc.NewTLS()
|
|
|
|
if Xsqlite3_threadsafe(tls) == 0 {
|
|
|
|
panic(fmt.Errorf("sqlite: thread safety configuration error"))
|
|
|
|
}
|
|
|
|
|
2021-11-25 16:13:25 +01:00
|
|
|
varArgs := libc.Xmalloc(tls, types.Size_t(unsafe.Sizeof(uintptr(0))))
|
|
|
|
if varArgs == 0 {
|
|
|
|
panic(fmt.Errorf("cannot allocate memory"))
|
2021-04-21 20:56:00 -07:00
|
|
|
}
|
|
|
|
|
2021-11-25 16:13:25 +01:00
|
|
|
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)
|
2021-04-21 20:56:00 -07:00
|
|
|
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})),
|
|
|
|
}
|
|
|
|
|
2022-12-28 23:26:14 +01:00
|
|
|
MutexCounters = libc.NewPerfCounter([]string{
|
|
|
|
"enter-fast",
|
|
|
|
"enter-recursive",
|
|
|
|
"enter-recursive-loop",
|
|
|
|
"try-fast",
|
|
|
|
"try-recursive",
|
|
|
|
})
|
|
|
|
MutexEnterCallers = libc.NewStackCapture(4)
|
|
|
|
|
|
|
|
mutexes mutexPool
|
2023-01-04 18:30:44 -08:00
|
|
|
|
|
|
|
mutexApp1 = mutexes.alloc(false)
|
|
|
|
mutexApp2 = mutexes.alloc(false)
|
|
|
|
mutexApp3 = mutexes.alloc(false)
|
|
|
|
mutexLRU = mutexes.alloc(false)
|
|
|
|
mutexMaster = mutexes.alloc(false)
|
|
|
|
mutexMem = mutexes.alloc(false)
|
|
|
|
mutexOpen = mutexes.alloc(false)
|
|
|
|
mutexPMem = mutexes.alloc(false)
|
|
|
|
mutexPRNG = mutexes.alloc(false)
|
|
|
|
mutexVFS1 = mutexes.alloc(false)
|
|
|
|
mutexVFS2 = mutexes.alloc(false)
|
|
|
|
mutexVFS3 = mutexes.alloc(false)
|
2021-04-21 20:56:00 -07:00
|
|
|
)
|
|
|
|
|
2022-12-28 23:26:14 +01:00
|
|
|
type mutexPool struct {
|
|
|
|
sync.Mutex
|
|
|
|
a []*[256]mutex
|
|
|
|
freeList []int
|
|
|
|
}
|
|
|
|
|
2023-01-04 18:26:21 -08:00
|
|
|
func mutexFromPtr(p uintptr) *mutex {
|
|
|
|
if p == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
2023-06-02 14:29:30 +04:00
|
|
|
|
2023-01-04 18:30:44 -08:00
|
|
|
ix := p - 1
|
2023-06-02 14:29:30 +04:00
|
|
|
|
|
|
|
mutexes.Lock()
|
|
|
|
defer mutexes.Unlock()
|
|
|
|
|
2023-01-04 18:26:21 -08:00
|
|
|
return &mutexes.a[ix>>8][ix&255]
|
|
|
|
}
|
|
|
|
|
2022-12-28 23:26:14 +01:00
|
|
|
func (m *mutexPool) alloc(recursive bool) uintptr {
|
|
|
|
m.Lock()
|
|
|
|
defer m.Unlock()
|
|
|
|
|
|
|
|
n := len(m.freeList)
|
|
|
|
if n == 0 {
|
|
|
|
outer := len(m.a) << 8
|
|
|
|
m.a = append(m.a, &[256]mutex{})
|
|
|
|
for i := 0; i < 256; i++ {
|
|
|
|
m.freeList = append(m.freeList, outer+i)
|
|
|
|
}
|
|
|
|
n = len(m.freeList)
|
|
|
|
}
|
|
|
|
ix := m.freeList[n-1]
|
|
|
|
outer := ix >> 8
|
|
|
|
inner := ix & 255
|
|
|
|
m.freeList = m.freeList[:n-1]
|
|
|
|
p := &m.a[outer][inner]
|
|
|
|
p.poolIndex = ix
|
|
|
|
p.recursive = recursive
|
2023-01-04 18:30:44 -08:00
|
|
|
return uintptr(ix) + 1
|
2022-12-28 23:26:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *mutexPool) free(p uintptr) {
|
2023-01-04 18:26:21 -08:00
|
|
|
ptr := mutexFromPtr(p)
|
|
|
|
ix := ptr.poolIndex
|
|
|
|
*ptr = mutex{}
|
2022-12-28 23:26:14 +01:00
|
|
|
|
2023-06-02 14:29:30 +04:00
|
|
|
m.Lock()
|
2022-12-28 23:26:14 +01:00
|
|
|
defer m.Unlock()
|
|
|
|
|
|
|
|
m.freeList = append(m.freeList, ix)
|
|
|
|
}
|
|
|
|
|
2021-04-21 20:56:00 -07:00
|
|
|
type mutex struct {
|
2022-12-28 23:26:14 +01:00
|
|
|
sync.Mutex
|
|
|
|
wait sync.Mutex
|
|
|
|
|
|
|
|
poolIndex int
|
|
|
|
|
2021-04-21 20:56:00 -07:00
|
|
|
cnt int32
|
|
|
|
id int32
|
2022-12-28 23:26:14 +01:00
|
|
|
|
2021-04-21 20:56:00 -07:00
|
|
|
recursive bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *mutex) enter(id int32) {
|
|
|
|
if !m.recursive {
|
|
|
|
m.Lock()
|
2023-07-01 16:17:25 +02:00
|
|
|
m.id = id
|
2021-04-21 20:56:00 -07:00
|
|
|
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()
|
2024-09-03 18:26:18 +02:00
|
|
|
|
2021-04-21 20:56:00 -07:00
|
|
|
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 {
|
2023-07-01 16:17:25 +02:00
|
|
|
m.id = 0
|
2021-04-21 20:56:00 -07:00
|
|
|
m.Unlock()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
m.Lock()
|
|
|
|
m.cnt--
|
|
|
|
if m.cnt == 0 {
|
|
|
|
m.id = 0
|
|
|
|
m.wait.Unlock()
|
|
|
|
}
|
|
|
|
m.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
func mutexInit(tls *libc.TLS) int32 { return SQLITE_OK }
|
|
|
|
|
|
|
|
func mutexEnd(tls *libc.TLS) int32 { return SQLITE_OK }
|
|
|
|
|
|
|
|
func mutexAlloc(tls *libc.TLS, typ int32) uintptr {
|
|
|
|
defer func() {
|
|
|
|
}()
|
|
|
|
switch typ {
|
|
|
|
case SQLITE_MUTEX_FAST:
|
2022-12-28 23:26:14 +01:00
|
|
|
return mutexes.alloc(false)
|
2021-04-21 20:56:00 -07:00
|
|
|
case SQLITE_MUTEX_RECURSIVE:
|
2022-12-28 23:26:14 +01:00
|
|
|
return mutexes.alloc(true)
|
2021-04-21 20:56:00 -07:00
|
|
|
case SQLITE_MUTEX_STATIC_MASTER:
|
2023-01-04 18:30:44 -08:00
|
|
|
return mutexMaster
|
2021-04-21 20:56:00 -07:00
|
|
|
case SQLITE_MUTEX_STATIC_MEM:
|
2023-01-04 18:30:44 -08:00
|
|
|
return mutexMem
|
2021-04-21 20:56:00 -07:00
|
|
|
case SQLITE_MUTEX_STATIC_OPEN:
|
2023-01-04 18:30:44 -08:00
|
|
|
return mutexOpen
|
2021-04-21 20:56:00 -07:00
|
|
|
case SQLITE_MUTEX_STATIC_PRNG:
|
2023-01-04 18:30:44 -08:00
|
|
|
return mutexPRNG
|
2021-04-21 20:56:00 -07:00
|
|
|
case SQLITE_MUTEX_STATIC_LRU:
|
2023-01-04 18:30:44 -08:00
|
|
|
return mutexLRU
|
2021-04-21 20:56:00 -07:00
|
|
|
case SQLITE_MUTEX_STATIC_PMEM:
|
2023-01-04 18:30:44 -08:00
|
|
|
return mutexPMem
|
2021-04-21 20:56:00 -07:00
|
|
|
case SQLITE_MUTEX_STATIC_APP1:
|
2023-01-04 18:30:44 -08:00
|
|
|
return mutexApp1
|
2021-04-21 20:56:00 -07:00
|
|
|
case SQLITE_MUTEX_STATIC_APP2:
|
2023-01-04 18:30:44 -08:00
|
|
|
return mutexApp2
|
2021-04-21 20:56:00 -07:00
|
|
|
case SQLITE_MUTEX_STATIC_APP3:
|
2023-01-04 18:30:44 -08:00
|
|
|
return mutexApp3
|
2021-04-21 20:56:00 -07:00
|
|
|
case SQLITE_MUTEX_STATIC_VFS1:
|
2023-01-04 18:30:44 -08:00
|
|
|
return mutexVFS1
|
2021-04-21 20:56:00 -07:00
|
|
|
case SQLITE_MUTEX_STATIC_VFS2:
|
2023-01-04 18:30:44 -08:00
|
|
|
return mutexVFS2
|
2021-04-21 20:56:00 -07:00
|
|
|
case SQLITE_MUTEX_STATIC_VFS3:
|
2023-01-04 18:30:44 -08:00
|
|
|
return mutexVFS3
|
2021-04-21 20:56:00 -07:00
|
|
|
default:
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-28 23:26:14 +01:00
|
|
|
func mutexFree(tls *libc.TLS, m uintptr) { mutexes.free(m) }
|
2021-04-21 20:56:00 -07:00
|
|
|
|
|
|
|
func mutexEnter(tls *libc.TLS, m uintptr) {
|
|
|
|
if m == 0 {
|
|
|
|
return
|
|
|
|
}
|
2023-01-04 18:26:21 -08:00
|
|
|
mutexFromPtr(m).enter(tls.ID)
|
2021-04-21 20:56:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func mutexTry(tls *libc.TLS, m uintptr) int32 {
|
|
|
|
if m == 0 {
|
|
|
|
return SQLITE_OK
|
|
|
|
}
|
|
|
|
|
2023-01-04 18:26:21 -08:00
|
|
|
return mutexFromPtr(m).try(tls.ID)
|
2021-04-21 20:56:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func mutexLeave(tls *libc.TLS, m uintptr) {
|
|
|
|
if m == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-01-04 18:26:21 -08:00
|
|
|
mutexFromPtr(m).leave(tls.ID)
|
2021-04-21 20:56:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func mutexHeld(tls *libc.TLS, m uintptr) int32 {
|
|
|
|
if m == 0 {
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2023-01-04 18:26:21 -08:00
|
|
|
return libc.Bool32(atomic.LoadInt32(&mutexFromPtr(m).id) == tls.ID)
|
2021-04-21 20:56:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func mutexNotheld(tls *libc.TLS, m uintptr) int32 {
|
|
|
|
if m == 0 {
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2023-01-04 18:26:21 -08:00
|
|
|
return libc.Bool32(atomic.LoadInt32(&mutexFromPtr(m).id) != tls.ID)
|
2021-04-21 20:56:00 -07:00
|
|
|
}
|