Commit 58026126 authored by cznic's avatar cznic

support SQLite's multi-thread model

parent 179c16d7
......@@ -7,10 +7,10 @@
//
// Changelog
//
// 2019-12-18 v1.1.0 Pre-alpha release using the new cc/v3, gocc, qbe
// 2019-12-18 v1.1.0 First alpha release using the new cc/v3, gocc, qbe
// toolchain. Some primitive tests pass on linux_{amd64,386}. Not yet safe for
// concurrent access by multiple goroutines. Alpha release is planed to arrive
// before the end of this year.
// concurrent access by multiple goroutines. Next alpha release is planed to
// arrive before the end of this year.
//
// 2017-06-10 Windows/Intel no more uses the VM (thanks Steffen Butzer).
//
......
......@@ -29,11 +29,13 @@ var (
"-DSQLITE_LIKE_DOESNT_MATCH_BLOBS",
"-DSQLITE_MAX_EXPR_DEPTH=0",
"-DSQLITE_MEMDEBUG", //TODO-
"-DSQLITE_MUTEX_APPDEF=1",
"-DSQLITE_MUTEX_NOOP",
"-DSQLITE_OMIT_DECLTYPE",
"-DSQLITE_OMIT_DEPRECATED",
"-DSQLITE_OMIT_PROGRESS_CALLBACK",
"-DSQLITE_OMIT_SHARED_CACHE",
"-DSQLITE_THREADSAFE=0",
"-DSQLITE_THREADSAFE=2", // Multi-thread
"-DSQLITE_USE_ALLOCA",
}
......
......@@ -2,4 +2,4 @@ module modernc.org/sqlite
go 1.13
require modernc.org/crt/v2 v2.0.0-alpha.1
require modernc.org/crt/v2 v2.0.0-20191219143825-5728f219e36a
// Code generated by `gocc /tmp/go-generate-780942695/x.c -o internal/bin/h_linux_amd64.go -Itestdata/sqlite-amalgamation-3300100 -qbec-defines -qbec-enumconsts -qbec-import <none> -qbec-pkgname bin -qbec-structs -DLONGDOUBLE_TYPE=double -DSQLITE_DEBUG -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_DQS=0 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_MEMDEBUG -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_THREADSAFE=0 -DSQLITE_USE_ALLOCA`, DO NOT EDIT.
// Code generated by `gocc /tmp/go-generate-795667064/x.c -o internal/bin/h_linux_amd64.go -Itestdata/sqlite-amalgamation-3300100 -qbec-defines -qbec-enumconsts -qbec-import <none> -qbec-pkgname bin -qbec-structs -DLONGDOUBLE_TYPE=double -DSQLITE_DEBUG -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_DQS=0 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_MEMDEBUG -DSQLITE_MUTEX_APPDEF=1 -DSQLITE_MUTEX_NOOP -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_THREADSAFE=2 -DSQLITE_USE_ALLOCA`, DO NOT EDIT.
package bin
......@@ -289,7 +289,9 @@ const (
DSQLITE_MEMDEBUG = 1
DSQLITE_MISMATCH = 20
DSQLITE_MISUSE = 21
DSQLITE_MUTEX_APPDEF = 1
DSQLITE_MUTEX_FAST = 0
DSQLITE_MUTEX_NOOP = 1
DSQLITE_MUTEX_RECURSIVE = 1
DSQLITE_MUTEX_STATIC_APP1 = 8
DSQLITE_MUTEX_STATIC_APP2 = 9
......@@ -428,7 +430,7 @@ const (
DSQLITE_TESTCTRL_SORTER_MMAP = 24
DSQLITE_TESTCTRL_VDBE_COVERAGE = 21
DSQLITE_TEXT = 3
DSQLITE_THREADSAFE = 0
DSQLITE_THREADSAFE = 2
DSQLITE_TOOBIG = 18
DSQLITE_TRACE_CLOSE = 8
DSQLITE_TRACE_PROFILE = 2
......
This diff is collapsed.
// Copyright 2019 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 sqlite // import "modernc.org/sqlite"
import (
"sync"
"sync/atomic"
"unsafe"
"modernc.org/crt/v2"
"modernc.org/sqlite/internal/bin"
)
var (
mutexMethods = bin.Ssqlite3_mutex_methods{
FxMutexInit: *(*uintptr)(unsafe.Pointer(&struct{ f func(*crt.TLS) int32 }{mutexInit})),
FxMutexEnd: *(*uintptr)(unsafe.Pointer(&struct{ f func(*crt.TLS) int32 }{mutexEnd})),
FxMutexAlloc: *(*uintptr)(unsafe.Pointer(&struct {
f func(*crt.TLS, int32) crt.Intptr
}{mutexAlloc})),
FxMutexFree: *(*uintptr)(unsafe.Pointer(&struct{ f func(*crt.TLS, crt.Intptr) }{mutexFree})),
FxMutexEnter: *(*uintptr)(unsafe.Pointer(&struct{ f func(*crt.TLS, crt.Intptr) }{mutexEnter})),
FxMutexTry: *(*uintptr)(unsafe.Pointer(&struct {
f func(*crt.TLS, crt.Intptr) int32
}{mutexTry})),
FxMutexLeave: *(*uintptr)(unsafe.Pointer(&struct{ f func(*crt.TLS, crt.Intptr) }{mutexLeave})),
FxMutexHeld: *(*uintptr)(unsafe.Pointer(&struct {
f func(*crt.TLS, crt.Intptr) int32
}{mutexHeld})),
FxMutexNotheld: *(*uintptr)(unsafe.Pointer(&struct {
f func(*crt.TLS, crt.Intptr) 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
}
func (m *mutex) enter(id int32) {
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()
m.wait.Unlock()
}
}
func (m *mutex) leave() {
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 *crt.TLS) int32 { return bin.DSQLITE_OK }
// int (*xMutexEnd)(void);
func mutexEnd(tls *crt.TLS) int32 { return bin.DSQLITE_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 *crt.TLS, typ int32) (r crt.Intptr) {
defer func() {
}()
switch typ {
case
bin.DSQLITE_MUTEX_FAST,
bin.DSQLITE_MUTEX_RECURSIVE:
return crt.Xcalloc(tls, 1, crt.Intptr(unsafe.Sizeof(mutex{})))
case bin.DSQLITE_MUTEX_STATIC_MASTER:
return crt.Intptr(uintptr(unsafe.Pointer(&mutexMaster)))
case bin.DSQLITE_MUTEX_STATIC_MEM:
return crt.Intptr(uintptr(unsafe.Pointer(&mutexMem)))
case bin.DSQLITE_MUTEX_STATIC_OPEN:
return crt.Intptr(uintptr(unsafe.Pointer(&mutexOpen)))
case bin.DSQLITE_MUTEX_STATIC_PRNG:
return crt.Intptr(uintptr(unsafe.Pointer(&mutexPRNG)))
case bin.DSQLITE_MUTEX_STATIC_LRU:
return crt.Intptr(uintptr(unsafe.Pointer(&mutexLRU)))
case bin.DSQLITE_MUTEX_STATIC_PMEM:
return crt.Intptr(uintptr(unsafe.Pointer(&mutexPMem)))
case bin.DSQLITE_MUTEX_STATIC_APP1:
return crt.Intptr(uintptr(unsafe.Pointer(&mutexApp1)))
case bin.DSQLITE_MUTEX_STATIC_APP2:
return crt.Intptr(uintptr(unsafe.Pointer(&mutexApp2)))
case bin.DSQLITE_MUTEX_STATIC_APP3:
return crt.Intptr(uintptr(unsafe.Pointer(&mutexApp3)))
case bin.DSQLITE_MUTEX_STATIC_VFS1:
return crt.Intptr(uintptr(unsafe.Pointer(&mutexVFS1)))
case bin.DSQLITE_MUTEX_STATIC_VFS2:
return crt.Intptr(uintptr(unsafe.Pointer(&mutexVFS2)))
case bin.DSQLITE_MUTEX_STATIC_VFS3:
return crt.Intptr(uintptr(unsafe.Pointer(&mutexVFS3)))
default:
return 0
}
}
// void (*xMutexFree)(sqlite3_mutex *);
func mutexFree(tls *crt.TLS, m crt.Intptr) { crt.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 *crt.TLS, m crt.Intptr) {
if m == 0 {
return
}
(*mutex)(unsafe.Pointer(uintptr(m))).enter(tls.ID)
}
// int (*xMutexTry)(sqlite3_mutex *);
func mutexTry(tls *crt.TLS, m crt.Intptr) int32 { return bin.DSQLITE_BUSY }
// void (*xMutexLeave)(sqlite3_mutex *);
func mutexLeave(tls *crt.TLS, m crt.Intptr) {
if m == 0 {
return
}
(*mutex)(unsafe.Pointer(uintptr(m))).leave()
}
// 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 *crt.TLS, m crt.Intptr) int32 {
if m == 0 {
return 1
}
return crt.Bool32(atomic.LoadInt32(&(*mutex)(unsafe.Pointer(uintptr(m))).id) == tls.ID)
}
// int (*xMutexNotheld)(sqlite3_mutex *);
func mutexNotheld(tls *crt.TLS, m crt.Intptr) int32 {
if m == 0 {
return 1
}
return crt.Bool32(atomic.LoadInt32(&(*mutex)(unsafe.Pointer(uintptr(m))).id) != tls.ID)
}
......@@ -40,10 +40,24 @@ const (
func init() {
tls := crt.NewTLS()
if bin.Xsqlite3_threadsafe(tls) != 0 { //TODO implement mutexes
if bin.Xsqlite3_threadsafe(tls) == 0 {
panic(fmt.Errorf("sqlite: thread safety configuration error"))
}
varArgs := crt.Xmalloc(tls, crt.Intptr(ptrSize))
if varArgs == 0 {
panic(fmt.Errorf("cannot allocate memory"))
}
*(*uintptr)(unsafe.Pointer(uintptr(varArgs))) = uintptr(unsafe.Pointer(&mutexMethods))
// int sqlite3_config(int, ...);
if rc := bin.Xsqlite3_config(tls, bin.DSQLITE_CONFIG_MUTEX, uintptr(varArgs)); rc != bin.DSQLITE_OK {
p := bin.Xsqlite3_errstr(tls, rc)
str := crt.GoString(p)
panic(fmt.Errorf("sqlite: failed to configure mutex methods: %v", str))
}
crt.Xfree(tls, varArgs)
sql.Register(driverName, newDrv())
}
......@@ -726,10 +740,6 @@ func newConn(s *Driver, name string) (_ *conn, err error) {
}
}()
c.Lock()
defer c.Unlock()
c.tls = crt.NewTLS()
if err = c.openV2(
name,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment