-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathentity-impl-lock.lisp
68 lines (57 loc) · 2.76 KB
/
entity-impl-lock.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
;;;; entity-impl-lock.lisp
;;
;;;; Copyright (c) 2019 Ivan Podmazov
;;; https://en.wikipedia.org/wiki/Readers-writers_problem
(in-package #:cl-multiagent-system)
(eval-when (:compile-toplevel :load-toplevel :execute)
(defun make-read-write-lock-vars ()
(list (gensym "READ-COUNT") (gensym "COUNT-ACCESS")
(gensym "RESOURCE-ACCESS") (gensym "SERVICE-QUEUE")))
(defun rw-lock-read-count (lock-vars)
(first lock-vars))
(defun rw-lock-read-count-access (lock-vars)
(second lock-vars))
(defun rw-lock-resource-access (lock-vars)
(third lock-vars))
(defun rw-lock-service-queue (lock-vars)
(fourth lock-vars))
(defun read-write-lock-bindings (lock-vars)
`((,(rw-lock-read-count lock-vars) 0)
(,(rw-lock-read-count-access lock-vars)
#1=(bt:make-semaphore :count 1))
(,(rw-lock-resource-access lock-vars) #1#)
(,(rw-lock-service-queue lock-vars) #1#)))
(defun read-write-lock-declarations (lock-vars)
`((ignorable ,(rw-lock-read-count lock-vars)
,(rw-lock-read-count-access lock-vars)))))
(defmacro with-read-write-lock-held ((write-locks read-locks) &body body)
(flet ((writer-entry (lock-vars)
`((bt:wait-on-semaphore ,(rw-lock-service-queue lock-vars))
(bt:wait-on-semaphore ,(rw-lock-resource-access lock-vars))
(bt:signal-semaphore ,(rw-lock-service-queue lock-vars))))
(writer-exit (lock-vars)
`((bt:signal-semaphore ,(rw-lock-resource-access lock-vars))))
(reader-entry (lock-vars)
`((bt:wait-on-semaphore ,(rw-lock-service-queue lock-vars))
(bt:wait-on-semaphore ,(rw-lock-read-count-access lock-vars))
(when (zerop ,(rw-lock-read-count lock-vars))
(bt:wait-on-semaphore ,(rw-lock-resource-access lock-vars)))
(incf ,(rw-lock-read-count lock-vars))
(bt:signal-semaphore ,(rw-lock-service-queue lock-vars))
(bt:signal-semaphore ,(rw-lock-read-count-access lock-vars))))
(reader-exit (lock-vars)
`((bt:wait-on-semaphore ,(rw-lock-read-count-access lock-vars))
(decf ,(rw-lock-read-count lock-vars))
(when (zerop ,(rw-lock-read-count lock-vars))
(bt:signal-semaphore ,(rw-lock-resource-access lock-vars)))
(bt:signal-semaphore ,(rw-lock-read-count-access lock-vars)))))
`(progn
,@(loop :for write-lock :in write-locks
:append (writer-entry write-lock))
,@(loop :for read-lock :in read-locks
:append (reader-entry read-lock))
,@body
,@(loop :for write-lock :in write-locks
:append (writer-exit write-lock))
,@(loop :for read-lock :in read-locks
:append (reader-exit read-lock)))))