aboutsummaryrefslogtreecommitdiff
path: root/sqlite3_opt_unlock_notify.go
diff options
context:
space:
mode:
authorMura Li <mura_li@example.com>2018-09-30 10:06:56 +0800
committerMura Li <mura_li@example.com>2018-10-20 10:15:13 +0800
commiteb08795f52358ce90e601fe964c564ad27cf73e0 (patch)
tree52f18afd7be0147ef31ba61acd633d40b990ac2c /sqlite3_opt_unlock_notify.go
parentMerge pull request #616 from jung-kurt/patch-1 (diff)
downloadgolite-eb08795f52358ce90e601fe964c564ad27cf73e0.tar.gz
golite-eb08795f52358ce90e601fe964c564ad27cf73e0.tar.xz
Add support for sqlite3_unlock_notify
Diffstat (limited to 'sqlite3_opt_unlock_notify.go')
-rw-r--r--sqlite3_opt_unlock_notify.go92
1 files changed, 92 insertions, 0 deletions
diff --git a/sqlite3_opt_unlock_notify.go b/sqlite3_opt_unlock_notify.go
new file mode 100644
index 0000000..ee29439
--- /dev/null
+++ b/sqlite3_opt_unlock_notify.go
@@ -0,0 +1,92 @@
+// Copyright (C) 2018 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
+//
+// Use of this source code is governed by an MIT-style
+// license that can be found in the LICENSE file.
+
+// +build cgo
+// +build sqlite_unlock_notify
+
+package sqlite3
+
+/*
+#cgo CFLAGS: -DSQLITE_ENABLE_UNLOCK_NOTIFY
+
+#include <stdlib.h>
+#include <sqlite3-binding.h>
+
+extern void unlock_notify_callback(void *arg, int argc);
+*/
+import "C"
+import (
+ "fmt"
+ "sync"
+ "unsafe"
+)
+
+type unlock_notify_table struct {
+ sync.Mutex
+ seqnum uint
+ table map[uint]chan struct{}
+}
+
+var unt unlock_notify_table = unlock_notify_table{table: make(map[uint]chan struct{})}
+
+func (t *unlock_notify_table) add(c chan struct{}) uint {
+ t.Lock()
+ defer t.Unlock()
+ h := t.seqnum
+ t.table[h] = c
+ t.seqnum++
+ return h
+}
+
+func (t *unlock_notify_table) remove(h uint) {
+ t.Lock()
+ defer t.Unlock()
+ delete(t.table, h)
+}
+
+func (t *unlock_notify_table) get(h uint) chan struct{} {
+ t.Lock()
+ defer t.Unlock()
+ c, ok := t.table[h]
+ if !ok {
+ panic(fmt.Sprintf("Non-existent key for unlcok-notify channel: %d", h))
+ }
+ return c
+}
+
+//export unlock_notify_callback
+func unlock_notify_callback(argv unsafe.Pointer, argc C.int) {
+ for i := 0; i < int(argc); i++ {
+ parg := ((*(*[1 << 30]*[1]uint)(argv))[i])
+ arg := *parg
+ h := arg[0]
+ c := unt.get(h)
+ c <- struct{}{}
+ }
+}
+
+//export unlock_notify_wait
+func unlock_notify_wait(db *C.sqlite3) C.int {
+ // It has to be a bufferred channel to not block in sqlite_unlock_notify
+ // as sqlite_unlock_notify could invoke the callback before it returns.
+ c := make(chan struct{}, 1)
+ defer close(c)
+
+ h := unt.add(c)
+ defer unt.remove(h)
+
+ pargv := C.malloc(C.sizeof_uint)
+ defer C.free(pargv)
+
+ argv := (*[1]uint)(pargv)
+ argv[0] = h
+ if rv := C.sqlite3_unlock_notify(db, (*[0]byte)(C.unlock_notify_callback), unsafe.Pointer(pargv)); rv != C.SQLITE_OK {
+ return rv
+ }
+
+ <-c
+
+ return C.SQLITE_OK
+}