gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

mutex.go (11463B)


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