source: code/trunk/vendor/modernc.org/sqlite/lib/mutex.go@ 822

Last change on this file since 822 was 822, checked in by yakumo.izuru, 22 months ago

Prefer immortal.run over runit and rc.d, use vendored modules
for convenience.

Signed-off-by: Izuru Yakumo <yakumo.izuru@…>

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