github.com/jdgcs/sqlite3@v1.12.1-0.20210908114423-bc5f96e4dd51/lib/mutex.go (about)

     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  	"runtime"
    10  	"sync"
    11  	"sync/atomic"
    12  	"unsafe"
    13  
    14  	"modernc.org/libc"
    15  	"modernc.org/libc/sys/types"
    16  )
    17  
    18  func init() {
    19  	tls := libc.NewTLS()
    20  	if Xsqlite3_threadsafe(tls) == 0 {
    21  		panic(fmt.Errorf("sqlite: thread safety configuration error"))
    22  	}
    23  
    24  	varArgs := libc.Xmalloc(tls, types.Size_t(unsafe.Sizeof(uintptr(0))))
    25  	if varArgs == 0 {
    26  		panic(fmt.Errorf("cannot allocate memory"))
    27  	}
    28  
    29  	// experimental pthreads support currently only on linux/amd64
    30  	if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
    31  		// int sqlite3_config(int, ...);
    32  		if rc := Xsqlite3_config(tls, SQLITE_CONFIG_MUTEX, libc.VaList(varArgs, uintptr(unsafe.Pointer(&mutexMethods)))); rc != SQLITE_OK {
    33  			p := Xsqlite3_errstr(tls, rc)
    34  			str := libc.GoString(p)
    35  			panic(fmt.Errorf("sqlite: failed to configure mutex methods: %v", str))
    36  		}
    37  	}
    38  
    39  	libc.Xfree(tls, varArgs)
    40  	tls.Close()
    41  }
    42  
    43  var (
    44  	mutexMethods = Sqlite3_mutex_methods{
    45  		FxMutexInit: *(*uintptr)(unsafe.Pointer(&struct{ f func(*libc.TLS) int32 }{mutexInit})),
    46  		FxMutexEnd:  *(*uintptr)(unsafe.Pointer(&struct{ f func(*libc.TLS) int32 }{mutexEnd})),
    47  		FxMutexAlloc: *(*uintptr)(unsafe.Pointer(&struct {
    48  			f func(*libc.TLS, int32) uintptr
    49  		}{mutexAlloc})),
    50  		FxMutexFree:  *(*uintptr)(unsafe.Pointer(&struct{ f func(*libc.TLS, uintptr) }{mutexFree})),
    51  		FxMutexEnter: *(*uintptr)(unsafe.Pointer(&struct{ f func(*libc.TLS, uintptr) }{mutexEnter})),
    52  		FxMutexTry: *(*uintptr)(unsafe.Pointer(&struct {
    53  			f func(*libc.TLS, uintptr) int32
    54  		}{mutexTry})),
    55  		FxMutexLeave: *(*uintptr)(unsafe.Pointer(&struct{ f func(*libc.TLS, uintptr) }{mutexLeave})),
    56  		FxMutexHeld: *(*uintptr)(unsafe.Pointer(&struct {
    57  			f func(*libc.TLS, uintptr) int32
    58  		}{mutexHeld})),
    59  		FxMutexNotheld: *(*uintptr)(unsafe.Pointer(&struct {
    60  			f func(*libc.TLS, uintptr) int32
    61  		}{mutexNotheld})),
    62  	}
    63  
    64  	mutexApp1   mutex
    65  	mutexApp2   mutex
    66  	mutexApp3   mutex
    67  	mutexLRU    mutex
    68  	mutexMaster mutex
    69  	mutexMem    mutex
    70  	mutexOpen   mutex
    71  	mutexPMem   mutex
    72  	mutexPRNG   mutex
    73  	mutexVFS1   mutex
    74  	mutexVFS2   mutex
    75  	mutexVFS3   mutex
    76  )
    77  
    78  type mutex struct {
    79  	cnt int32
    80  	id  int32
    81  	sync.Mutex
    82  	wait      sync.Mutex
    83  	recursive bool
    84  }
    85  
    86  func (m *mutex) enter(id int32) {
    87  	if !m.recursive {
    88  		m.Lock()
    89  		m.id = id
    90  		return
    91  	}
    92  
    93  	for {
    94  		m.Lock()
    95  		switch m.id {
    96  		case 0:
    97  			m.cnt = 1
    98  			m.id = id
    99  			m.wait.Lock()
   100  			m.Unlock()
   101  			return
   102  		case id:
   103  			m.cnt++
   104  			m.Unlock()
   105  			return
   106  		}
   107  
   108  		m.Unlock()
   109  		m.wait.Lock()
   110  		//lint:ignore SA2001 TODO report staticcheck issue
   111  		m.wait.Unlock()
   112  	}
   113  }
   114  
   115  func (m *mutex) try(id int32) int32 {
   116  	if !m.recursive {
   117  		return SQLITE_BUSY
   118  	}
   119  
   120  	m.Lock()
   121  	switch m.id {
   122  	case 0:
   123  		m.cnt = 1
   124  		m.id = id
   125  		m.wait.Lock()
   126  		m.Unlock()
   127  		return SQLITE_OK
   128  	case id:
   129  		m.cnt++
   130  		m.Unlock()
   131  		return SQLITE_OK
   132  	}
   133  
   134  	m.Unlock()
   135  	return SQLITE_BUSY
   136  }
   137  
   138  func (m *mutex) leave(id int32) {
   139  	if !m.recursive {
   140  		m.id = 0
   141  		m.Unlock()
   142  		return
   143  	}
   144  
   145  	m.Lock()
   146  	m.cnt--
   147  	if m.cnt == 0 {
   148  		m.id = 0
   149  		m.wait.Unlock()
   150  	}
   151  	m.Unlock()
   152  }
   153  
   154  // int (*xMutexInit)(void);
   155  //
   156  // The xMutexInit method defined by this structure is invoked as part of system
   157  // initialization by the sqlite3_initialize() function. The xMutexInit routine
   158  // is called by SQLite exactly once for each effective call to
   159  // sqlite3_initialize().
   160  //
   161  // The xMutexInit() method must be threadsafe. It must be harmless to invoke
   162  // xMutexInit() multiple times within the same process and without intervening
   163  // calls to xMutexEnd(). Second and subsequent calls to xMutexInit() must be
   164  // no-ops. xMutexInit() must not use SQLite memory allocation (sqlite3_malloc()
   165  // and its associates).
   166  //
   167  // If xMutexInit fails in any way, it is expected to clean up after itself
   168  // prior to returning.
   169  func mutexInit(tls *libc.TLS) int32 { return SQLITE_OK }
   170  
   171  // int (*xMutexEnd)(void);
   172  func mutexEnd(tls *libc.TLS) int32 { return SQLITE_OK }
   173  
   174  // sqlite3_mutex *(*xMutexAlloc)(int);
   175  //
   176  // The sqlite3_mutex_alloc() routine allocates a new mutex and returns a
   177  // pointer to it. The sqlite3_mutex_alloc() routine returns NULL if it is
   178  // unable to allocate the requested mutex. The argument to
   179  // sqlite3_mutex_alloc() must one of these integer constants:
   180  //
   181  //	SQLITE_MUTEX_FAST
   182  //	SQLITE_MUTEX_RECURSIVE
   183  //	SQLITE_MUTEX_STATIC_MASTER
   184  //	SQLITE_MUTEX_STATIC_MEM
   185  //	SQLITE_MUTEX_STATIC_OPEN
   186  //	SQLITE_MUTEX_STATIC_PRNG
   187  //	SQLITE_MUTEX_STATIC_LRU
   188  //	SQLITE_MUTEX_STATIC_PMEM
   189  //	SQLITE_MUTEX_STATIC_APP1
   190  //	SQLITE_MUTEX_STATIC_APP2
   191  //	SQLITE_MUTEX_STATIC_APP3
   192  //	SQLITE_MUTEX_STATIC_VFS1
   193  //	SQLITE_MUTEX_STATIC_VFS2
   194  //	SQLITE_MUTEX_STATIC_VFS3
   195  //
   196  // The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) cause
   197  // sqlite3_mutex_alloc() to create a new mutex. The new mutex is recursive when
   198  // SQLITE_MUTEX_RECURSIVE is used but not necessarily so when SQLITE_MUTEX_FAST
   199  // is used. The mutex implementation does not need to make a distinction
   200  // between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does not want to.
   201  // SQLite will only request a recursive mutex in cases where it really needs
   202  // one. If a faster non-recursive mutex implementation is available on the host
   203  // platform, the mutex subsystem might return such a mutex in response to
   204  // SQLITE_MUTEX_FAST.
   205  //
   206  // The other allowed parameters to sqlite3_mutex_alloc() (anything other than
   207  // SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) each return a pointer to a
   208  // static preexisting mutex. Nine static mutexes are used by the current
   209  // version of SQLite. Future versions of SQLite may add additional static
   210  // mutexes. Static mutexes are for internal use by SQLite only. Applications
   211  // that use SQLite mutexes should use only the dynamic mutexes returned by
   212  // SQLITE_MUTEX_FAST or SQLITE_MUTEX_RECURSIVE.
   213  //
   214  // Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST or
   215  // SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() returns a
   216  // different mutex on every call. For the static mutex types, the same mutex is
   217  // returned on every call that has the same type number.
   218  func mutexAlloc(tls *libc.TLS, typ int32) uintptr {
   219  	defer func() {
   220  	}()
   221  	switch typ {
   222  	case SQLITE_MUTEX_FAST:
   223  		return libc.Xcalloc(tls, 1, types.Size_t(unsafe.Sizeof(mutex{})))
   224  	case SQLITE_MUTEX_RECURSIVE:
   225  		p := libc.Xcalloc(tls, 1, types.Size_t(unsafe.Sizeof(mutex{})))
   226  		(*mutex)(unsafe.Pointer(p)).recursive = true
   227  		return p
   228  	case SQLITE_MUTEX_STATIC_MASTER:
   229  		return uintptr(unsafe.Pointer(&mutexMaster))
   230  	case SQLITE_MUTEX_STATIC_MEM:
   231  		return uintptr(unsafe.Pointer(&mutexMem))
   232  	case SQLITE_MUTEX_STATIC_OPEN:
   233  		return uintptr(unsafe.Pointer(&mutexOpen))
   234  	case SQLITE_MUTEX_STATIC_PRNG:
   235  		return uintptr(unsafe.Pointer(&mutexPRNG))
   236  	case SQLITE_MUTEX_STATIC_LRU:
   237  		return uintptr(unsafe.Pointer(&mutexLRU))
   238  	case SQLITE_MUTEX_STATIC_PMEM:
   239  		return uintptr(unsafe.Pointer(&mutexPMem))
   240  	case SQLITE_MUTEX_STATIC_APP1:
   241  		return uintptr(unsafe.Pointer(&mutexApp1))
   242  	case SQLITE_MUTEX_STATIC_APP2:
   243  		return uintptr(unsafe.Pointer(&mutexApp2))
   244  	case SQLITE_MUTEX_STATIC_APP3:
   245  		return uintptr(unsafe.Pointer(&mutexApp3))
   246  	case SQLITE_MUTEX_STATIC_VFS1:
   247  		return uintptr(unsafe.Pointer(&mutexVFS1))
   248  	case SQLITE_MUTEX_STATIC_VFS2:
   249  		return uintptr(unsafe.Pointer(&mutexVFS2))
   250  	case SQLITE_MUTEX_STATIC_VFS3:
   251  		return uintptr(unsafe.Pointer(&mutexVFS3))
   252  	default:
   253  		return 0
   254  	}
   255  }
   256  
   257  // void (*xMutexFree)(sqlite3_mutex *);
   258  func mutexFree(tls *libc.TLS, m uintptr) { libc.Xfree(tls, m) }
   259  
   260  // The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt to enter
   261  // a mutex. If another thread is already within the mutex,
   262  // sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
   263  // SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK upon
   264  // successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can be
   265  // entered multiple times by the same thread. In such cases, the mutex must be
   266  // exited an equal number of times before another thread can enter. If the same
   267  // thread tries to enter any mutex other than an SQLITE_MUTEX_RECURSIVE more
   268  // than once, the behavior is undefined.
   269  //
   270  // If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or
   271  // sqlite3_mutex_leave() is a NULL pointer, then all three routines behave as
   272  // no-ops.
   273  
   274  // void (*xMutexEnter)(sqlite3_mutex *);
   275  func mutexEnter(tls *libc.TLS, m uintptr) {
   276  	if m == 0 {
   277  		return
   278  	}
   279  
   280  	(*mutex)(unsafe.Pointer(m)).enter(tls.ID)
   281  }
   282  
   283  // int (*xMutexTry)(sqlite3_mutex *);
   284  func mutexTry(tls *libc.TLS, m uintptr) int32 {
   285  	if m == 0 {
   286  		return SQLITE_OK
   287  	}
   288  
   289  	return (*mutex)(unsafe.Pointer(m)).try(tls.ID)
   290  }
   291  
   292  // void (*xMutexLeave)(sqlite3_mutex *);
   293  func mutexLeave(tls *libc.TLS, m uintptr) {
   294  	if m == 0 {
   295  		return
   296  	}
   297  
   298  	(*mutex)(unsafe.Pointer(m)).leave(tls.ID)
   299  }
   300  
   301  // The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines are intended
   302  // for use inside assert() statements. The SQLite core never uses these
   303  // routines except inside an assert() and applications are advised to follow
   304  // the lead of the core. The SQLite core only provides implementations for
   305  // these routines when it is compiled with the SQLITE_DEBUG flag. External
   306  // mutex implementations are only required to provide these routines if
   307  // SQLITE_DEBUG is defined and if NDEBUG is not defined.
   308  //
   309  // These routines should return true if the mutex in their argument is held or
   310  // not held, respectively, by the calling thread.
   311  //
   312  // The implementation is not required to provide versions of these routines
   313  // that actually work. If the implementation does not provide working versions
   314  // of these routines, it should at least provide stubs that always return true
   315  // so that one does not get spurious assertion failures.
   316  //
   317  // If the argument to sqlite3_mutex_held() is a NULL pointer then the routine
   318  // should return 1. This seems counter-intuitive since clearly the mutex cannot
   319  // be held if it does not exist. But the reason the mutex does not exist is
   320  // because the build is not using mutexes. And we do not want the assert()
   321  // containing the call to sqlite3_mutex_held() to fail, so a non-zero return is
   322  // the appropriate thing to do. The sqlite3_mutex_notheld() interface should
   323  // also return 1 when given a NULL pointer.
   324  
   325  // int (*xMutexHeld)(sqlite3_mutex *);
   326  func mutexHeld(tls *libc.TLS, m uintptr) int32 {
   327  	if m == 0 {
   328  		return 1
   329  	}
   330  
   331  	return libc.Bool32(atomic.LoadInt32(&(*mutex)(unsafe.Pointer(m)).id) == tls.ID)
   332  }
   333  
   334  // int (*xMutexNotheld)(sqlite3_mutex *);
   335  func mutexNotheld(tls *libc.TLS, m uintptr) int32 {
   336  	if m == 0 {
   337  		return 1
   338  	}
   339  
   340  	return libc.Bool32(atomic.LoadInt32(&(*mutex)(unsafe.Pointer(m)).id) != tls.ID)
   341  }