-
Notifications
You must be signed in to change notification settings - Fork 5
/
monitor-macros.lisp
146 lines (121 loc) · 5.13 KB
/
monitor-macros.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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
(in-package :useful-macros)
;; --------------------------------------------
(defun separate-declares-and-documentation (body-list &optional decls doc)
"Used to help define macros that define declarations that can have a
documentation string and any number of declares. Those items must be placed
in the correct spot after the opening of the declaring form (e.g., DEFUN, DEFMETHOD).
And so these elements must be stripped off the incoming macro argument representing
the &body of the defining form. See the example of DEFINE-MONITOR which follows."
(if (null body-list)
(if decls
(values doc (nreverse decls) nil)
(if doc
(values nil nil (list doc))
(values nil nil nil)))
(if (and (null doc)
(stringp (first body-list)))
(separate-declares-and-documentation (rest body-list) decls (first body-list))
(if (and (consp (first body-list))
(eq 'declare (first (first body-list))))
(separate-declares-and-documentation (rest body-list)
(push (first body-list) decls)
doc)
(values doc (nreverse decls) body-list))
)))
;; ----------------------------------------------
;; A MONITOR is a group of functions whose entry is controlled
;; by a lock, and which may affect globally held values that are
;; shared between processes.
;;
;; Guarded functions can only be entered by one process at a time.
(defmacro with-monitor (name bindings clauses &key pre-lock)
(labels ((gen-body (def-hdr body)
(um:bind*
((:values (doc decls body-list) (separate-declares-and-documentation body)))
`(,@def-hdr
,@(if doc `(,doc))
,@decls
,@(if pre-lock `(,pre-lock))
(#+:LISPWORKS mp:with-lock
#+:ALLEGRO mp:with-process-lock
#+:CLOZURE mp:with-lock-grabbed
#+:SBCL sb-thread:with-recursive-lock
(,name)
,@body-list))
)))
`(let ,bindings
,@(mapcar (lambda (clause)
(match clause
((deftype name meth-comb args &rest body) :when (and meth-comb
(symbolp meth-comb))
(gen-body `(,deftype ,name ,meth-comb ,args) body))
((deftype name args &rest body)
(gen-body `(,deftype ,name ,args) body))
))
clauses))
))
(defmacro define-monitor (name bindings clauses &key pre-lock)
`(#+:LISPWORKS dspec:def
#+:LISPWORKS (define-monitor ,name)
#+:ALLEGRO progn
#+:CLOZURE progn
#+:SBCL progn
(progn
(defvar ,name
#+:LISPWORKS (mp:make-lock)
#+:ALLEGRO (mp:make-process-lock)
#+:CLOZURE (mp:make-lock)
#+:SBCL (sb-thread:make-mutex))
(with-monitor ,name ,bindings ,clauses :pre-lock ,pre-lock))))
(defmacro let-monitor (bindings clauses &key pre-lock)
(let ((glock (gensym)))
`(let ((,glock #+:LISPWORKS (mp:make-lock)
#+:ALLEGRO (mp:make-process-lock)
#+:CLOZURE (mp:make-lock)
#+:SBCL (sb-thread:make-mutex)
))
(with-monitor ,glock ,bindings ,clauses :pre-lock ,pre-lock))
))
;; ----------------------------------------------
#|
(defclass lock-mixin ()
((lock-mixin-lock :reader lock-mixin-lock
:initform
#+:LISWORKS (mp:make-lock)
#+:ALLEGRO (mp:make-process-lock)
#+:CLOZURE (mp:make-lock)
#+:SBCL (sb-thread:make-mutex)
)))
(defmacro let-locking (clauses &key pre-lock)
(labels ((gen-body (def-hdr lockable-arg body)
(multiple-value-bind (doc decls body-list)
(separate-declares-and-documentation body)
`(,@def-hdr
,@(if doc `(,doc))
,@decls
,@(if pre-lock `(,pre-lock))
(#+:LISPWORKS mp:with-lock
#+:ALLEGRO mp:with-process-lock
#+:CLOZURE mp:with-lock-grabbed
#+:SBCL sb-thread:with-recursive-lock
((lock-mixin-lock ,(if (consp lockable-arg) ;; as from a qualified method arg
(first lockable-arg)
lockable-arg)))
,@body-list))
)))
`(progn
,@(mapcar (lambda (clause)
(match clause
((deftype name meth-comb args . body) :when (keywordp meth-comb)
(gen-body `(,deftype ,name ,meth-comb ,args) (first args) body))
((deftype name args . body)
(gen-body `(,deftype ,name ,args) (first args) body))
))
clauses))
))
|#
;; ----------------------------------------------
#+:LISPWORKS
(progn
(editor:setup-indent "define-monitor" 2 2 4)
(editor:setup-indent "let-monitor" 2 2 4))