diff options
| author | 2025-10-24 09:05:12 +0300 | |
|---|---|---|
| committer | 2025-10-24 09:05:12 +0300 | |
| commit | cf975709968ee26110514c779737bc80a5266e83 (patch) | |
| tree | 7bce3f120e011ea0eb53c444b69df9038dfec5f1 /src | |
| parent | Configure a custom readtable explicitly (diff) | |
| download | ukkoclot-main.tar.gz ukkoclot-main.tar.xz ukkoclot-main.zip | |
Diffstat (limited to '')
| -rw-r--r-- | src/db.lisp | 19 | ||||
| -rw-r--r-- | src/rw-lock.lisp | 58 |
2 files changed, 49 insertions, 28 deletions
diff --git a/src/db.lisp b/src/db.lisp index ea18d16..db8f7c1 100644 --- a/src/db.lisp +++ b/src/db.lisp | |||
| @@ -3,8 +3,8 @@ | |||
| 3 | (defpackage :ukkoclot/src/db | 3 | (defpackage :ukkoclot/src/db |
| 4 | (:use :c2cl :sqlite) | 4 | (:use :c2cl :sqlite) |
| 5 | (:import-from :log) | 5 | (:import-from :log) |
| 6 | (:import-from :serapeum :-> :defunion) | 6 | (:import-from :serapeum :-> :defunion :with-thunk) |
| 7 | (:export :inline-bot-type :blacklisted :whitelisted :get-inline-bot-type :set-inline-bot-type :with-db)) | 7 | (:export :inline-bot-type :blacklisted :whitelisted :get-inline-bot-type :set-inline-bot-type :call-with-db :with-db)) |
| 8 | (in-package :ukkoclot/src/db) | 8 | (in-package :ukkoclot/src/db) |
| 9 | 9 | ||
| 10 | (defconstant +target-version+ 1 | 10 | (defconstant +target-version+ 1 |
| @@ -13,10 +13,19 @@ | |||
| 13 | (deftype db () | 13 | (deftype db () |
| 14 | 'sqlite-handle) | 14 | 'sqlite-handle) |
| 15 | 15 | ||
| 16 | (-> call-with-db (pathname (function (db) t)) t) | ||
| 17 | (defun call-with-db (path fn) | ||
| 18 | "Similar to `with-db', but instead of binding the database in a macro body, | ||
| 19 | calls the function `fn' with it as an argument." | ||
| 20 | (let ((db (connect path))) | ||
| 21 | (unwind-protect (progn (upgrade db) | ||
| 22 | (funcall fn db)) | ||
| 23 | (disconnect db)))) | ||
| 24 | |||
| 16 | (defmacro with-db ((name path) &body body) | 25 | (defmacro with-db ((name path) &body body) |
| 17 | `(let ((,name (connect ,path))) | 26 | "Open database specified by `path' and bind it to `name' for the duration of the `body'." |
| 18 | (unwind-protect (progn (upgrade ,name) ,@body) | 27 | (with-thunk (body name) |
| 19 | (disconnect ,name)))) | 28 | `(call-with-db ,path ,body))) |
| 20 | 29 | ||
| 21 | (defunion inline-bot-type | 30 | (defunion inline-bot-type |
| 22 | blacklisted | 31 | blacklisted |
diff --git a/src/rw-lock.lisp b/src/rw-lock.lisp index 2a5e2c3..c0c545b 100644 --- a/src/rw-lock.lisp +++ b/src/rw-lock.lisp | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | ;; These imports make this SBCL-dependent, but technically speaking we could live without them. | 8 | ;; These imports make this SBCL-dependent, but technically speaking we could live without them. |
| 9 | (:import-from :sb-sys | 9 | (:import-from :sb-sys |
| 10 | :allow-with-interrupts :with-local-interrupts :without-interrupts) | 10 | :allow-with-interrupts :with-local-interrupts :without-interrupts) |
| 11 | (:import-from :serapeum :->) | 11 | (:import-from :serapeum :-> :with-thunk) |
| 12 | (:import-from :ukkoclot/src/readtable :readtable) | 12 | (:import-from :ukkoclot/src/readtable :readtable) |
| 13 | (:export | 13 | (:export |
| 14 | #:rw-lock | 14 | #:rw-lock |
| @@ -16,9 +16,11 @@ | |||
| 16 | #:make-rw-lock | 16 | #:make-rw-lock |
| 17 | #:acquire-read-lock | 17 | #:acquire-read-lock |
| 18 | #:release-read-lock | 18 | #:release-read-lock |
| 19 | #:call-with-read-lock | ||
| 19 | #:with-read-lock | 20 | #:with-read-lock |
| 20 | #:acquire-write-lock | 21 | #:acquire-write-lock |
| 21 | #:release-write-lock | 22 | #:release-write-lock |
| 23 | #:call-with-write-lock | ||
| 22 | #:with-write-lock)) | 24 | #:with-write-lock)) |
| 23 | (in-package :ukkoclot/src/rw-lock) | 25 | (in-package :ukkoclot/src/rw-lock) |
| 24 | (in-readtable readtable) | 26 | (in-readtable readtable) |
| @@ -100,19 +102,24 @@ | |||
| 100 | (wakeup-waiters rw-lock)))) | 102 | (wakeup-waiters rw-lock)))) |
| 101 | rw-lock) | 103 | rw-lock) |
| 102 | 104 | ||
| 105 | (-> call-with-read-lock (rw-lock (function () t)) t) | ||
| 106 | (defun call-with-read-lock (rw-lock fn) | ||
| 107 | ;; TODO: timeout | ||
| 108 | "Similar to `with-read-lock', but instead of being a macro, it calls the function `fn'." | ||
| 109 | (let (lock-acquired) | ||
| 110 | (without-interrupts | ||
| 111 | (unwind-protect | ||
| 112 | (when (setf lock-acquired | ||
| 113 | (allow-with-interrupts (acquire-read-lock rw-lock))) | ||
| 114 | (with-local-interrupts (funcall fn))) | ||
| 115 | (when lock-acquired | ||
| 116 | (release-read-lock rw-lock)))))) | ||
| 117 | |||
| 103 | (defmacro with-read-lock ((rw-lock) &body body) | 118 | (defmacro with-read-lock ((rw-lock) &body body) |
| 104 | ;; TODO: timeout | 119 | ;; TODO: timeout |
| 105 | (with-gensyms (lock-acquired lock-value) | 120 | "Hold the read lock for the duration of the `body'." |
| 106 | `(let ((,lock-acquired) | 121 | (with-thunk (body) |
| 107 | (,lock-value ,rw-lock)) | 122 | `(call-with-read-lock ,rw-lock ,body))) |
| 108 | (without-interrupts | ||
| 109 | (unwind-protect | ||
| 110 | (when (setf ,lock-acquired | ||
| 111 | (allow-with-interrupts | ||
| 112 | (acquire-read-lock ,lock-value))) | ||
| 113 | (with-local-interrupts ,@body)) | ||
| 114 | (when ,lock-acquired | ||
| 115 | (release-read-lock ,lock-value))))))) | ||
| 116 | 123 | ||
| 117 | (-> acquire-write-lock (rw-lock &key (:wait boolean)) boolean) | 124 | (-> acquire-write-lock (rw-lock &key (:wait boolean)) boolean) |
| 118 | (defun acquire-write-lock (rw-lock &key (wait t)) | 125 | (defun acquire-write-lock (rw-lock &key (wait t)) |
| @@ -149,16 +156,21 @@ | |||
| 149 | (wakeup-waiters rw-lock))) | 156 | (wakeup-waiters rw-lock))) |
| 150 | rw-lock) | 157 | rw-lock) |
| 151 | 158 | ||
| 159 | (-> call-with-write-lock (rw-lock (function () t)) t) | ||
| 160 | (defun call-with-write-lock (rw-lock fn) | ||
| 161 | ;; TODO: timeout | ||
| 162 | "Similar to `with-write-lock', but instead of being a macro, it calls the function `fn'." | ||
| 163 | (let (lock-acquired) | ||
| 164 | (without-interrupts | ||
| 165 | (unwind-protect | ||
| 166 | (when (setf lock-acquired | ||
| 167 | (allow-with-interrupts (acquire-write-lock rw-lock))) | ||
| 168 | (with-local-interrupts (funcall fn))) | ||
| 169 | (when lock-acquired | ||
| 170 | (release-write-lock rw-lock)))))) | ||
| 171 | |||
| 152 | (defmacro with-write-lock ((rw-lock) &body body) | 172 | (defmacro with-write-lock ((rw-lock) &body body) |
| 153 | ;; TODO: timeout | 173 | ;; TODO: timeout |
| 154 | (with-gensyms (lock-acquired lock-value) | 174 | "Hold the write lock for the duration of the `body'." |
| 155 | `(let ((,lock-acquired) | 175 | (with-thunk (body) |
| 156 | (,lock-value ,rw-lock)) | 176 | `(call-with-write-lock ,rw-lock ,body))) |
| 157 | (without-interrupts | ||
| 158 | (unwind-protect | ||
| 159 | (when (setf ,lock-acquired | ||
| 160 | (allow-with-interrupts | ||
| 161 | (acquire-write-lock ,lock-value))) | ||
| 162 | (with-local-interrupts ,@body)) | ||
| 163 | (when ,lock-acquired | ||
| 164 | (release-write-lock ,lock-value))))))) | ||