1// Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>. 2// 3// Use of this source code is governed by an MIT-style 4// license that can be found in the LICENSE file. 5 6// +build cgo 7// +build sqlite_unlock_notify 8 9package sqlite3 10 11/* 12#cgo CFLAGS: -DSQLITE_ENABLE_UNLOCK_NOTIFY 13 14#include <stdlib.h> 15#include <sqlite3-binding.h> 16 17extern void unlock_notify_callback(void *arg, int argc); 18*/ 19import "C" 20import ( 21 "fmt" 22 "math" 23 "sync" 24 "unsafe" 25) 26 27type unlock_notify_table struct { 28 sync.Mutex 29 seqnum uint 30 table map[uint]chan struct{} 31} 32 33var unt unlock_notify_table = unlock_notify_table{table: make(map[uint]chan struct{})} 34 35func (t *unlock_notify_table) add(c chan struct{}) uint { 36 t.Lock() 37 defer t.Unlock() 38 h := t.seqnum 39 t.table[h] = c 40 t.seqnum++ 41 return h 42} 43 44func (t *unlock_notify_table) remove(h uint) { 45 t.Lock() 46 defer t.Unlock() 47 delete(t.table, h) 48} 49 50func (t *unlock_notify_table) get(h uint) chan struct{} { 51 t.Lock() 52 defer t.Unlock() 53 c, ok := t.table[h] 54 if !ok { 55 panic(fmt.Sprintf("Non-existent key for unlcok-notify channel: %d", h)) 56 } 57 return c 58} 59 60//export unlock_notify_callback 61func unlock_notify_callback(argv unsafe.Pointer, argc C.int) { 62 for i := 0; i < int(argc); i++ { 63 parg := ((*(*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.uint)(nil))]*[1]uint)(argv))[i]) 64 arg := *parg 65 h := arg[0] 66 c := unt.get(h) 67 c <- struct{}{} 68 } 69} 70 71//export unlock_notify_wait 72func unlock_notify_wait(db *C.sqlite3) C.int { 73 // It has to be a bufferred channel to not block in sqlite_unlock_notify 74 // as sqlite_unlock_notify could invoke the callback before it returns. 75 c := make(chan struct{}, 1) 76 defer close(c) 77 78 h := unt.add(c) 79 defer unt.remove(h) 80 81 pargv := C.malloc(C.sizeof_uint) 82 defer C.free(pargv) 83 84 argv := (*[1]uint)(pargv) 85 argv[0] = h 86 if rv := C.sqlite3_unlock_notify(db, (*[0]byte)(C.unlock_notify_callback), unsafe.Pointer(pargv)); rv != C.SQLITE_OK { 87 return rv 88 } 89 90 <-c 91 92 return C.SQLITE_OK 93} 94