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 | ix := p - 1
|
---|
96 | return &mutexes.a[ix>>8][ix&255]
|
---|
97 | }
|
---|
98 |
|
---|
99 | func (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 |
|
---|
123 | func (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 |
|
---|
134 | type 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 |
|
---|
146 | func (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 |
|
---|
179 | func (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 |
|
---|
204 | func (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.
|
---|
235 | func mutexInit(tls *libc.TLS) int32 { return SQLITE_OK }
|
---|
236 |
|
---|
237 | // int (*xMutexEnd)(void);
|
---|
238 | func 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.
|
---|
284 | func 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 *);
|
---|
322 | func 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 *);
|
---|
339 | func 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 *);
|
---|
347 | func 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 *);
|
---|
356 | func 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 *);
|
---|
389 | func 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 *);
|
---|
398 | func 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 | }
|
---|