diff options
| -rw-r--r-- | .pre-commit-config.yaml | 5 | ||||
| -rw-r--r-- | ocicl.csv | 4 | ||||
| -rwxr-xr-x | run-tests.sh | 12 | ||||
| -rw-r--r-- | src/rw-lock.lisp | 136 | ||||
| -rw-r--r-- | test/all.lisp | 28 | ||||
| -rw-r--r-- | test/rw-lock.lisp | 79 | ||||
| -rw-r--r-- | ukkoclot.asd | 4 |
7 files changed, 267 insertions, 1 deletions
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f30fd61..e2f455c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml | |||
| @@ -9,6 +9,11 @@ repos: | |||
| 9 | entry: ocicl lint | 9 | entry: ocicl lint |
| 10 | pass_filenames: true | 10 | pass_filenames: true |
| 11 | files: \.(lisp|asd)$ | 11 | files: \.(lisp|asd)$ |
| 12 | - id: run-testsuite | ||
| 13 | name: run-testsuite | ||
| 14 | language: system | ||
| 15 | entry: ./run-tests.sh | ||
| 16 | pass_filenames: false | ||
| 12 | - repo: https://github.com/fsfe/reuse-tool | 17 | - repo: https://github.com/fsfe/reuse-tool |
| 13 | rev: v6.1.2 | 18 | rev: v6.1.2 |
| 14 | hooks: | 19 | hooks: |
| @@ -36,6 +36,7 @@ fast-http, ghcr.io/ocicl/fast-http@sha256:44e98b5239c0ded4921dc0b04ae272cff00583 | |||
| 36 | fast-http-test, ghcr.io/ocicl/fast-http@sha256:44e98b5239c0ded4921dc0b04ae272cff00583d93797a657543db782979eb50c, fast-http-20240503-2232fc9/fast-http-test.asd | 36 | fast-http-test, ghcr.io/ocicl/fast-http@sha256:44e98b5239c0ded4921dc0b04ae272cff00583d93797a657543db782979eb50c, fast-http-20240503-2232fc9/fast-http-test.asd |
| 37 | fast-io, ghcr.io/ocicl/fast-io@sha256:7ba35a0eddf00b3c25656b3c5a93e95460f6cb8f807afbc04ef4f50076d95aff, fast-io-20240503-a4c5ad6/fast-io.asd | 37 | fast-io, ghcr.io/ocicl/fast-io@sha256:7ba35a0eddf00b3c25656b3c5a93e95460f6cb8f807afbc04ef4f50076d95aff, fast-io-20240503-a4c5ad6/fast-io.asd |
| 38 | fast-io-test, ghcr.io/ocicl/fast-io@sha256:7ba35a0eddf00b3c25656b3c5a93e95460f6cb8f807afbc04ef4f50076d95aff, fast-io-20240503-a4c5ad6/fast-io-test.asd | 38 | fast-io-test, ghcr.io/ocicl/fast-io@sha256:7ba35a0eddf00b3c25656b3c5a93e95460f6cb8f807afbc04ef4f50076d95aff, fast-io-20240503-a4c5ad6/fast-io-test.asd |
| 39 | fiveam, ghcr.io/ocicl/fiveam@sha256:e283043dc8d31e8df2b214465cf5a06ea07bdbea10e600a40e17aaf9518226ac, fiveam-20240928-e43d6c8/fiveam.asd | ||
| 39 | flexi-streams, ghcr.io/ocicl/flexi-streams@sha256:95005b06a8a95c82780c75ead53810bcb273d07fcf5fe76b527f1856df9923f2, flexi-streams-20240503-4951d57/flexi-streams.asd | 40 | flexi-streams, ghcr.io/ocicl/flexi-streams@sha256:95005b06a8a95c82780c75ead53810bcb273d07fcf5fe76b527f1856df9923f2, flexi-streams-20240503-4951d57/flexi-streams.asd |
| 40 | flexi-streams-test, ghcr.io/ocicl/flexi-streams@sha256:95005b06a8a95c82780c75ead53810bcb273d07fcf5fe76b527f1856df9923f2, flexi-streams-20240503-4951d57/flexi-streams-test.asd | 41 | flexi-streams-test, ghcr.io/ocicl/flexi-streams@sha256:95005b06a8a95c82780c75ead53810bcb273d07fcf5fe76b527f1856df9923f2, flexi-streams-20240503-4951d57/flexi-streams-test.asd |
| 41 | float-features, ghcr.io/ocicl/float-features@sha256:64922efd92a08670cf8292ea56dfff29c577d36d8a7f7576cea0c031805c52d2, float-features-20250813-cd5dab0/float-features.asd | 42 | float-features, ghcr.io/ocicl/float-features@sha256:64922efd92a08670cf8292ea56dfff29c577d36d8a7f7576cea0c031805c52d2, float-features-20250813-cd5dab0/float-features.asd |
| @@ -60,6 +61,7 @@ log4cl-examples, ghcr.io/ocicl/log4cl@sha256:bd33f6e5ad346892e852492e7101bc18d26 | |||
| 60 | log4cl.log4slime, ghcr.io/ocicl/log4cl@sha256:bd33f6e5ad346892e852492e7101bc18d263f9ef2ba6192178568d1b20337112, log4cl-20240503-fe3da51/log4cl.log4slime.asd | 61 | log4cl.log4slime, ghcr.io/ocicl/log4cl@sha256:bd33f6e5ad346892e852492e7101bc18d263f9ef2ba6192178568d1b20337112, log4cl-20240503-fe3da51/log4cl.log4slime.asd |
| 61 | log4cl.log4sly, ghcr.io/ocicl/log4cl@sha256:bd33f6e5ad346892e852492e7101bc18d263f9ef2ba6192178568d1b20337112, log4cl-20240503-fe3da51/log4cl.log4sly.asd | 62 | log4cl.log4sly, ghcr.io/ocicl/log4cl@sha256:bd33f6e5ad346892e852492e7101bc18d263f9ef2ba6192178568d1b20337112, log4cl-20240503-fe3da51/log4cl.log4sly.asd |
| 62 | multilang-documentation-utils, ghcr.io/ocicl/documentation-utils@sha256:b2a1b3f3bcd1a738af85ae2b0168d408c177661eab6d6bbebb254e394d983f54, documentation-utils-20230511-98630dd/multilang-documentation-utils.asd | 63 | multilang-documentation-utils, ghcr.io/ocicl/documentation-utils@sha256:b2a1b3f3bcd1a738af85ae2b0168d408c177661eab6d6bbebb254e394d983f54, documentation-utils-20230511-98630dd/multilang-documentation-utils.asd |
| 64 | net.didierverna.asdf-flv, ghcr.io/ocicl/net.didierverna.asdf-flv@sha256:e5cd087d41cf24302a92d9bac426a925f8868b554be2414c0f012c961e3ddb8c, asdf-flv-20240503-3f1de41/net.didierverna.asdf-flv.asd | ||
| 63 | parse-declarations-1.0, ghcr.io/ocicl/parse-declarations-1.0@sha256:9305fa9624205b16fd1fc51cb1cc4282a18e50eee9ac75b66a14f6f2c5df9518, parse-declarations-20240503-549aebb/parse-declarations-1.0.asd | 65 | parse-declarations-1.0, ghcr.io/ocicl/parse-declarations-1.0@sha256:9305fa9624205b16fd1fc51cb1cc4282a18e50eee9ac75b66a14f6f2c5df9518, parse-declarations-20240503-549aebb/parse-declarations-1.0.asd |
| 64 | parse-number, ghcr.io/ocicl/parse-number@sha256:11f3f9f512871e1f96cea6b8260aa3610e34e8fd7272bbcdb210fd3c5dd8025c, parse-number-20240503-cb9e487/parse-number.asd | 66 | parse-number, ghcr.io/ocicl/parse-number@sha256:11f3f9f512871e1f96cea6b8260aa3610e34e8fd7272bbcdb210fd3c5dd8025c, parse-number-20240503-cb9e487/parse-number.asd |
| 65 | proc-parse, ghcr.io/ocicl/proc-parse@sha256:0880f9acb35eb9efbe1f77a981e36e84e8f29a22b14f680c7686eb381fa87bd6, proc-parse-20240503-3afe2b7/proc-parse.asd | 67 | proc-parse, ghcr.io/ocicl/proc-parse@sha256:0880f9acb35eb9efbe1f77a981e36e84e8f29a22b14f680c7686eb381fa87bd6, proc-parse-20240503-3afe2b7/proc-parse.asd |
| @@ -89,6 +91,8 @@ trivia.ppcre, ghcr.io/ocicl/trivia@sha256:51db74757bc31ceaf3a643914a8ffa87825799 | |||
| 89 | trivia.quasiquote, ghcr.io/ocicl/trivia@sha256:51db74757bc31ceaf3a643914a8ffa87825799097dea4912650e6ac62bed5209, trivia-20240904-4383dd8/trivia.quasiquote.asd | 91 | trivia.quasiquote, ghcr.io/ocicl/trivia@sha256:51db74757bc31ceaf3a643914a8ffa87825799097dea4912650e6ac62bed5209, trivia-20240904-4383dd8/trivia.quasiquote.asd |
| 90 | trivia.test, ghcr.io/ocicl/trivia@sha256:51db74757bc31ceaf3a643914a8ffa87825799097dea4912650e6ac62bed5209, trivia-20240904-4383dd8/trivia.test.asd | 92 | trivia.test, ghcr.io/ocicl/trivia@sha256:51db74757bc31ceaf3a643914a8ffa87825799097dea4912650e6ac62bed5209, trivia-20240904-4383dd8/trivia.test.asd |
| 91 | trivia.trivial, ghcr.io/ocicl/trivia@sha256:51db74757bc31ceaf3a643914a8ffa87825799097dea4912650e6ac62bed5209, trivia-20240904-4383dd8/trivia.trivial.asd | 93 | trivia.trivial, ghcr.io/ocicl/trivia@sha256:51db74757bc31ceaf3a643914a8ffa87825799097dea4912650e6ac62bed5209, trivia-20240904-4383dd8/trivia.trivial.asd |
| 94 | trivial-backtrace, ghcr.io/ocicl/trivial-backtrace@sha256:89a3138695bb767c50001402fad60dacfc1e867e4e3d3579cc6f636d3e29a51c, trivial-backtrace-20240503-7f90b4a/trivial-backtrace.asd | ||
| 95 | trivial-backtrace-test, ghcr.io/ocicl/trivial-backtrace@sha256:89a3138695bb767c50001402fad60dacfc1e867e4e3d3579cc6f636d3e29a51c, trivial-backtrace-20240503-7f90b4a/trivial-backtrace-test.asd | ||
| 92 | trivial-cltl2, ghcr.io/ocicl/trivial-cltl2@sha256:69470b4f6469314799074b9d944050dc4bcb67d5cbb2ba32c7a8899bb492f04e, trivial-cltl2-20230809-2ada872/trivial-cltl2.asd | 96 | trivial-cltl2, ghcr.io/ocicl/trivial-cltl2@sha256:69470b4f6469314799074b9d944050dc4bcb67d5cbb2ba32c7a8899bb492f04e, trivial-cltl2-20230809-2ada872/trivial-cltl2.asd |
| 93 | trivial-features, ghcr.io/ocicl/trivial-features@sha256:e278e24d39060fc7d3715531b16ddd9ab7f93f22ade53e436c0b86dbae3aa065, trivial-features-1.0/trivial-features.asd | 97 | trivial-features, ghcr.io/ocicl/trivial-features@sha256:e278e24d39060fc7d3715531b16ddd9ab7f93f22ade53e436c0b86dbae3aa065, trivial-features-1.0/trivial-features.asd |
| 94 | trivial-features-tests, ghcr.io/ocicl/trivial-features@sha256:e278e24d39060fc7d3715531b16ddd9ab7f93f22ade53e436c0b86dbae3aa065, trivial-features-1.0/trivial-features-tests.asd | 98 | trivial-features-tests, ghcr.io/ocicl/trivial-features@sha256:e278e24d39060fc7d3715531b16ddd9ab7f93f22ade53e436c0b86dbae3aa065, trivial-features-1.0/trivial-features-tests.asd |
diff --git a/run-tests.sh b/run-tests.sh new file mode 100755 index 0000000..f8338b3 --- /dev/null +++ b/run-tests.sh | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | # SPDX-License-Identifier: EUPL-1.2 | ||
| 3 | # SPDX-FileCopyrightText: 2025 Uko Kokņevičs <perkontevs@gmail.com> | ||
| 4 | |||
| 5 | set -eu | ||
| 6 | |||
| 7 | exec sbcl \ | ||
| 8 | --disable-ldb --lose-on-corruption \ | ||
| 9 | --noinform --noprint --non-interactive \ | ||
| 10 | --eval '(asdf:load-system :ukkoclot/test/all)' \ | ||
| 11 | --eval '(setf ukkoclot/test/all:*should-quit* t)' \ | ||
| 12 | --eval '(asdf:test-system :ukkoclot)' | ||
diff --git a/src/rw-lock.lisp b/src/rw-lock.lisp new file mode 100644 index 0000000..b32d3d0 --- /dev/null +++ b/src/rw-lock.lisp | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | ;; SPDX-License-Identifier: EUPL-1.2 | ||
| 2 | ;; SPDX-FileCopyrightText: 2025 Uko Kokņevičs <perkontevs@gmail.com> | ||
| 3 | (defpackage :ukkoclot/src/rw-lock | ||
| 4 | (:documentation "Implementation of a shared/read-write lock.") | ||
| 5 | (:use :c2cl :bt2 :iterate) | ||
| 6 | (:import-from :alexandria :with-gensyms) | ||
| 7 | (:import-from :com.dieggsy.f-string :enable-f-strings) | ||
| 8 | (:import-from :sb-sys | ||
| 9 | :allow-with-interrupts :with-local-interrupts :without-interrupts) | ||
| 10 | (:export | ||
| 11 | #:rw-lock | ||
| 12 | #:rw-lock-p | ||
| 13 | #:make-rw-lock | ||
| 14 | #:acquire-read-lock | ||
| 15 | #:release-read-lock | ||
| 16 | #:with-read-lock | ||
| 17 | #:acquire-write-lock | ||
| 18 | #:release-write-lock | ||
| 19 | #:with-write-lock)) | ||
| 20 | (in-package :ukkoclot/src/rw-lock) | ||
| 21 | |||
| 22 | (eval-when (:compile-toplevel :load-toplevel :execute) | ||
| 23 | (enable-f-strings)) | ||
| 24 | |||
| 25 | ;; TODO: Get rid of broadcasting for writers, instead have separate condvars | ||
| 26 | ;; TODO: Make it a bit more fair, 50% chance of waking up writers or readers | ||
| 27 | ;; TODO: Use atomic-integer in best-case for read locks to decrease contention | ||
| 28 | (defstruct (rw-lock (:constructor make-rw-lock%)) | ||
| 29 | (lock nil :type lock :read-only t) | ||
| 30 | (unlocked nil :type condition-variable :read-only t) | ||
| 31 | (readers 0 :type integer) | ||
| 32 | (has-writer nil :type boolean)) | ||
| 33 | |||
| 34 | (defvar *counter-lock* (make-lock :name "rw-lock::*counter-lock*")) | ||
| 35 | |||
| 36 | (defvar *counter* 0) | ||
| 37 | |||
| 38 | (defun gen-name () | ||
| 39 | (format nil "Read-Write Lock ~A" | ||
| 40 | (with-lock-held (*counter-lock*) | ||
| 41 | (incf *counter*)))) | ||
| 42 | |||
| 43 | (defun make-rw-lock (&key (name (gen-name))) | ||
| 44 | (check-type name string) | ||
| 45 | (make-rw-lock% | ||
| 46 | :lock (make-lock :name #f"{name}'s internal lock") | ||
| 47 | :unlocked (make-condition-variable :name #f"{name}'s internal unlocked"))) | ||
| 48 | |||
| 49 | (defun acquire-read-lock (rw-lock &key (wait t)) | ||
| 50 | ;; TODO: timeout | ||
| 51 | (check-type rw-lock rw-lock) | ||
| 52 | (with-slots (lock unlocked readers has-writer) rw-lock | ||
| 53 | (let ((lock-acquired)) | ||
| 54 | (without-interrupts | ||
| 55 | (unwind-protect | ||
| 56 | (when (setf lock-acquired | ||
| 57 | (allow-with-interrupts | ||
| 58 | (acquire-lock lock :wait wait))) | ||
| 59 | (with-local-interrupts | ||
| 60 | (when (if wait | ||
| 61 | (iter | ||
| 62 | (unless has-writer | ||
| 63 | (return t)) | ||
| 64 | (condition-wait unlocked lock)) | ||
| 65 | (not has-writer)) | ||
| 66 | (incf readers) | ||
| 67 | t))) | ||
| 68 | (when lock-acquired | ||
| 69 | (release-lock lock))))))) | ||
| 70 | |||
| 71 | (defun release-read-lock (rw-lock) | ||
| 72 | (check-type rw-lock rw-lock) | ||
| 73 | (with-slots (lock unlocked readers has-writer) rw-lock | ||
| 74 | (with-lock-held (lock) | ||
| 75 | (decf readers) | ||
| 76 | (when (zerop readers) | ||
| 77 | (condition-broadcast unlocked)))) | ||
| 78 | rw-lock) | ||
| 79 | |||
| 80 | (defmacro with-read-lock ((rw-lock) &body body) | ||
| 81 | ;; TODO: timeout | ||
| 82 | (with-gensyms (lock-acquired lock-value) | ||
| 83 | `(let ((,lock-acquired) | ||
| 84 | (,lock-value ,rw-lock)) | ||
| 85 | (without-interrupts | ||
| 86 | (unwind-protect | ||
| 87 | (when (setf ,lock-acquired | ||
| 88 | (allow-with-interrupts | ||
| 89 | (acquire-read-lock ,lock-value))) | ||
| 90 | (with-local-interrupts ,@body)) | ||
| 91 | (when ,lock-acquired | ||
| 92 | (release-read-lock ,lock-value))))))) | ||
| 93 | |||
| 94 | (defun acquire-write-lock (rw-lock &key (wait t)) | ||
| 95 | ;; TODO: timeout | ||
| 96 | (check-type rw-lock rw-lock) | ||
| 97 | (with-slots (lock unlocked readers has-writer) rw-lock | ||
| 98 | (let ((lock-acquired)) | ||
| 99 | (without-interrupts | ||
| 100 | (unwind-protect | ||
| 101 | (when (setf lock-acquired | ||
| 102 | (allow-with-interrupts | ||
| 103 | (acquire-lock lock :wait wait))) | ||
| 104 | (with-local-interrupts | ||
| 105 | (when (if wait | ||
| 106 | (iter | ||
| 107 | (unless (or (> readers 0) has-writer) | ||
| 108 | (return t)) | ||
| 109 | (condition-wait unlocked lock)) | ||
| 110 | (and (zerop readers) (not has-writer))) | ||
| 111 | (setf has-writer t) | ||
| 112 | t))) | ||
| 113 | (when lock-acquired | ||
| 114 | (release-lock lock))))))) | ||
| 115 | |||
| 116 | (defun release-write-lock (rw-lock) | ||
| 117 | (check-type rw-lock rw-lock) | ||
| 118 | (with-slots (lock unlocked readers has-writer) rw-lock | ||
| 119 | (with-lock-held (lock) | ||
| 120 | (setf has-writer nil) | ||
| 121 | (condition-broadcast unlocked))) | ||
| 122 | rw-lock) | ||
| 123 | |||
| 124 | (defmacro with-write-lock ((rw-lock) &body body) | ||
| 125 | ;; TODO: timeout | ||
| 126 | (with-gensyms (lock-acquired lock-value) | ||
| 127 | `(let ((,lock-acquired) | ||
| 128 | (,lock-value ,rw-lock)) | ||
| 129 | (without-interrupts | ||
| 130 | (unwind-protect | ||
| 131 | (when (setf ,lock-acquired | ||
| 132 | (allow-with-interrupts | ||
| 133 | (acquire-write-lock ,lock-value))) | ||
| 134 | (with-local-interrupts ,@body)) | ||
| 135 | (when ,lock-acquired | ||
| 136 | (release-write-lock ,lock-value))))))) | ||
diff --git a/test/all.lisp b/test/all.lisp new file mode 100644 index 0000000..b0a731b --- /dev/null +++ b/test/all.lisp | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | ;; SPDX-License-Identifier: EUPL-1.2 | ||
| 2 | ;; SPDX-FileCopyrightText: 2025 Uko Kokņevičs <perkontevs@gmail.com> | ||
| 3 | (defpackage :ukkoclot/test/all | ||
| 4 | (:documentation "Main test runner package.") | ||
| 5 | (:use :c2cl :fiveam | ||
| 6 | :ukkoclot/test/rw-lock) | ||
| 7 | (:import-from :bt2 :with-timeout) | ||
| 8 | (:import-from :uiop) | ||
| 9 | (:export #:*should-quit* #:run-tests)) | ||
| 10 | (in-package :ukkoclot/test/all) | ||
| 11 | |||
| 12 | (defvar *should-quit* nil | ||
| 13 | "Bind as true if `run-tests' should exit the process with 0 or 1. | ||
| 14 | |||
| 15 | Useful for CI.") | ||
| 16 | |||
| 17 | ;; TODO: Maybe I should signal on failure instead :thinking: | ||
| 18 | (defun run-tests () | ||
| 19 | "Run all tests" | ||
| 20 | (with-timeout (100) | ||
| 21 | (let ((status (run-all-tests))) | ||
| 22 | (when *should-quit* | ||
| 23 | (format t "~2&BTW Ignore the fatal ERROR condition below") | ||
| 24 | (cond | ||
| 25 | (status (format t "~&!GREAT SUCCESS!~2%") | ||
| 26 | (uiop:quit 0)) | ||
| 27 | (t (format t "~&!!! TESTS R FUCKED MATE !!!~2%") | ||
| 28 | (uiop:quit 1))))))) | ||
diff --git a/test/rw-lock.lisp b/test/rw-lock.lisp new file mode 100644 index 0000000..4460398 --- /dev/null +++ b/test/rw-lock.lisp | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | ;; SPDX-License-Identifier: EUPL-1.2 | ||
| 2 | ;; SPDX-FileCopyrightText: 2025 Uko Kokņevičs <perkontevs@gmail.com> | ||
| 3 | (defpackage :ukkoclot/test/rw-lock | ||
| 4 | (:documentation "Test-suite for :ukkoclot/src/rw-lock.") | ||
| 5 | (:use :c2cl :fiveam :ukkoclot/src/rw-lock) | ||
| 6 | (:import-from :bt2 :with-timeout)) | ||
| 7 | (in-package :ukkoclot/test/rw-lock) | ||
| 8 | |||
| 9 | (def-suite :ukkoclot/rw-lock) | ||
| 10 | (in-suite :ukkoclot/rw-lock) | ||
| 11 | |||
| 12 | (test rw-lock.typep | ||
| 13 | (is (typep (make-rw-lock) 'rw-lock))) | ||
| 14 | |||
| 15 | (test rw-lock-p | ||
| 16 | (is (rw-lock-p (make-rw-lock)))) | ||
| 17 | |||
| 18 | (test acquire-read-lock.no-contention | ||
| 19 | (with-timeout (5) | ||
| 20 | (let ((lock (make-rw-lock))) | ||
| 21 | (is-true (acquire-read-lock lock :wait t)) | ||
| 22 | (is (rw-lock-p (release-read-lock lock))) | ||
| 23 | (is-true (acquire-read-lock lock :wait nil)) | ||
| 24 | (is (rw-lock-p (release-read-lock lock)))))) | ||
| 25 | |||
| 26 | (test acquire-read-lock.multiple | ||
| 27 | (with-timeout (5) | ||
| 28 | (let ((lock (make-rw-lock))) | ||
| 29 | (is-true (acquire-read-lock lock :wait t)) | ||
| 30 | (is-true (acquire-read-lock lock :wait nil)) | ||
| 31 | (is-true (acquire-read-lock lock :wait t)) | ||
| 32 | (is (rw-lock-p (release-read-lock lock))) | ||
| 33 | (is (rw-lock-p (release-read-lock lock))) | ||
| 34 | (is (rw-lock-p (release-read-lock lock)))))) | ||
| 35 | |||
| 36 | (test acquire-write-lock.no-contention | ||
| 37 | (let ((lock (make-rw-lock))) | ||
| 38 | (is-true (acquire-write-lock lock :wait nil)) | ||
| 39 | (is (rw-lock-p (release-write-lock lock))) | ||
| 40 | (is-true (acquire-write-lock lock :wait nil)) | ||
| 41 | (is (rw-lock-p (release-write-lock lock))))) | ||
| 42 | |||
| 43 | (test acquire-write-lock.contention | ||
| 44 | (let ((lock (make-rw-lock))) | ||
| 45 | (is-true (acquire-write-lock lock :wait nil)) | ||
| 46 | (is-false (acquire-write-lock lock :wait nil)) | ||
| 47 | (is (rw-lock-p (release-write-lock lock))))) | ||
| 48 | |||
| 49 | (test acquire-read&write-lock.contention | ||
| 50 | (let ((lock (make-rw-lock))) | ||
| 51 | (is-true (acquire-read-lock lock :wait nil)) | ||
| 52 | (is-true (acquire-read-lock lock :wait nil)) | ||
| 53 | (is-false (acquire-write-lock lock :wait nil)) | ||
| 54 | (is (rw-lock-p (release-read-lock lock))) | ||
| 55 | (is (rw-lock-p (release-read-lock lock))) | ||
| 56 | (is-true (acquire-write-lock lock :wait nil)) | ||
| 57 | (is-false (acquire-read-lock lock :wait nil)) | ||
| 58 | (is (rw-lock-p (release-write-lock lock))))) | ||
| 59 | |||
| 60 | (test with-read-lock.simple | ||
| 61 | (let ((lock (make-rw-lock))) | ||
| 62 | (with-read-lock (lock) | ||
| 63 | (is-true (acquire-read-lock lock :wait nil)) | ||
| 64 | (is (rw-lock-p (release-read-lock lock))) | ||
| 65 | (is-false (acquire-write-lock lock :wait nil))) | ||
| 66 | (is-true (acquire-read-lock lock :wait nil)) | ||
| 67 | (is (rw-lock-p (release-read-lock lock))) | ||
| 68 | (is-true (acquire-write-lock lock :wait nil)) | ||
| 69 | (is (rw-lock-p (release-write-lock lock))))) | ||
| 70 | |||
| 71 | (test with-write-lock.simple | ||
| 72 | (let ((lock (make-rw-lock))) | ||
| 73 | (with-write-lock (lock) | ||
| 74 | (is-false (acquire-read-lock lock :wait nil)) | ||
| 75 | (is-false (acquire-write-lock lock :wait nil))) | ||
| 76 | (is-true (acquire-read-lock lock :wait nil)) | ||
| 77 | (is (rw-lock-p (release-read-lock lock))) | ||
| 78 | (is-true (acquire-write-lock lock :wait nil)) | ||
| 79 | (is (rw-lock-p (release-write-lock lock))))) | ||
diff --git a/ukkoclot.asd b/ukkoclot.asd index fd7f14e..339a208 100644 --- a/ukkoclot.asd +++ b/ukkoclot.asd | |||
| @@ -11,11 +11,13 @@ | |||
| 11 | :description "ukkoclot: Ukko's shitty telegram bot" | 11 | :description "ukkoclot: Ukko's shitty telegram bot" |
| 12 | :long-description #.(uiop:read-file-string (uiop:subpathname *load-pathname* "README.md")) | 12 | :long-description #.(uiop:read-file-string (uiop:subpathname *load-pathname* "README.md")) |
| 13 | :depends-on (:ukkoclot/src/main) | 13 | :depends-on (:ukkoclot/src/main) |
| 14 | ;; TODO: :in-order-to ((test-op (test-op ukkoclot-test))) | 14 | :in-order-to ((test-op (load-op :ukkoclot/test/all))) |
| 15 | :perform (test-op (o c) (symbol-call :ukkoclot/test/all :run-tests))) | ||
| 15 | 16 | ||
| 16 | (register-system-packages :ukkoclot/src/config '(:conf)) | 17 | (register-system-packages :ukkoclot/src/config '(:conf)) |
| 17 | (register-system-packages :ukkoclot/src/main '(:ukkoclot)) | 18 | (register-system-packages :ukkoclot/src/main '(:ukkoclot)) |
| 18 | 19 | ||
| 20 | (register-system-packages :bordeaux-threads '(:bt2)) | ||
| 19 | (register-system-packages :closer-mop '(:c2cl)) | 21 | (register-system-packages :closer-mop '(:c2cl)) |
| 20 | (register-system-packages :dexador '(:dex)) | 22 | (register-system-packages :dexador '(:dex)) |
| 21 | (register-system-packages :log4cl '(:log)) | 23 | (register-system-packages :log4cl '(:log)) |