1 ;;;; -*- indent-tabs-mode: nil -*-
3 (in-package :bordeaux-threads-2
)
9 (deftype native-thread
()
12 (defun %make-thread
(function name
)
13 (threads:make-thread function
:name name
))
15 (defun %current-thread
()
16 (threads:current-thread
))
18 (defun %thread-name
(thread)
19 (threads:thread-name thread
))
21 (defun %join-thread
(thread)
22 (threads:thread-join thread
))
24 (defun %thread-yield
()
25 (java:jstatic
"yield" "java.lang.Thread"))
28 ;;; Introspection/debugging
31 (defun %all-threads
()
33 (threads:mapcar-threads
(lambda (thread)
34 (push thread threads
)))
37 (defun %interrupt-thread
(thread function
)
38 (threads:interrupt-thread thread function
))
40 (defun %destroy-thread
(thread)
41 (threads:destroy-thread thread
))
43 (defun %thread-alive-p
(thread)
44 (threads:thread-alive-p thread
))
48 ;;; Non-recursive locks.
51 (defstruct mutex name lock
)
53 (deftype native-lock
() 'mutex
)
55 (defun %make-lock
(name)
58 :lock
(jnew "java.util.concurrent.locks.ReentrantLock")))
60 ;; Making methods constants in this manner avoids the runtime expense of
61 ;; introspection involved in JCALL with string arguments.
63 (jmethod "java.util.concurrent.locks.ReentrantLock" "lock"))
64 (defconstant +try-lock
+
65 (jmethod "java.util.concurrent.locks.ReentrantLock" "tryLock"))
66 (defconstant +try-lock-timeout
+
67 (jmethod "java.util.concurrent.locks.ReentrantLock" "tryLock"
68 (jclass "long") (jclass "java.util.concurrent.TimeUnit")))
69 (defconstant +is-held-by-current-thread
+
70 (jmethod "java.util.concurrent.locks.ReentrantLock" "isHeldByCurrentThread"))
72 (jmethod "java.util.concurrent.locks.ReentrantLock" "unlock"))
73 (defconstant +get-hold-count
+
74 (jmethod "java.util.concurrent.locks.ReentrantLock" "getHoldCount"))
75 (defconstant +microseconds
+
76 (java:jfield
"java.util.concurrent.TimeUnit" "MICROSECONDS"))
78 (defun timeout-to-microseconds (timeout)
79 (truncate (* timeout
1000000)))
81 (defun %acquire-lock
(lock waitp timeout
)
82 (check-type lock mutex
)
83 (when (jcall +is-held-by-current-thread
+ (mutex-lock lock
))
84 (bt-error "Non-recursive lock being reacquired by owner."))
88 (jcall +try-lock-timeout
+
90 (timeout-to-microseconds timeout
)
92 (progn (jcall +lock
+ (mutex-lock lock
)) t
)))
93 (t (jcall +try-lock
+ (mutex-lock lock
)))))
95 (defun %release-lock
(lock)
96 (check-type lock mutex
)
97 (unless (jcall +is-held-by-current-thread
+ (mutex-lock lock
))
98 (bt-error "Attempt to release lock not held by calling thread."))
99 (jcall +unlock
+ (mutex-lock lock
)))
105 (defstruct (mutex-recursive (:include mutex
)))
107 (deftype native-recursive-lock
() 'mutex-recursive
)
109 (defun %make-recursive-lock
(name)
110 (make-mutex-recursive
112 :lock
(jnew "java.util.concurrent.locks.ReentrantLock")))
114 (defun %acquire-recursive-lock
(lock waitp timeout
)
115 (check-type lock mutex-recursive
)
119 (jcall +try-lock-timeout
+
120 (mutex-recursive-lock lock
)
121 (timeout-to-microseconds timeout
)
123 (progn (jcall +lock
+ (mutex-recursive-lock lock
)) t
)))
124 (t (jcall +try-lock
+ (mutex-recursive-lock lock
)))))
126 (defun %release-recursive-lock
(lock)
127 (check-type lock mutex-recursive
)
128 (unless (jcall +is-held-by-current-thread
+ (mutex-lock lock
))
129 (error 'bordeaux-threads-error
130 :message
"Attempt to release lock not held by calling thread."))
131 (jcall +unlock
+ (mutex-lock lock
)))
138 (defstruct (semaphore
139 (:constructor %%make-semaphore
(name cell
)))
140 "Wrapper for java.util.concurrent.Semaphore."
143 (defconstant +semaphore-count
+
144 (jmethod "java.util.concurrent.Semaphore" "availablePermits"))
146 (defun %semaphore-count
(semaphore)
147 (jcall +semaphore-count
+ (semaphore-cell semaphore
)))
149 (defmethod print-object ((sem semaphore
) stream
)
150 (print-unreadable-object (sem stream
:type t
:identity t
)
151 (format stream
"~S count: ~S" (semaphore-name sem
)
152 (%semaphore-count sem
))))
154 (defun %make-semaphore
(name count
)
155 (check-type count unsigned-byte
)
158 (jnew "java.util.concurrent.Semaphore" count t
)))
160 (defconstant +semaphore-release
+
161 (jmethod "java.util.concurrent.Semaphore" "release"
164 (defun %signal-semaphore
(semaphore count
)
165 (jcall +semaphore-release
+ (semaphore-cell semaphore
) count
))
167 (defconstant +semaphore-acquire
+
168 (jmethod "java.util.concurrent.Semaphore" "acquire"))
170 (defconstant +semaphore-try-acquire
+
171 (jmethod "java.util.concurrent.Semaphore" "tryAcquire"
172 (jclass "long") (jclass "java.util.concurrent.TimeUnit")))
174 (defun %wait-on-semaphore
(semaphore timeout
)
175 ;; TODO: handle thread interruption.
178 (jcall +semaphore-acquire
+ (semaphore-cell semaphore
))
181 (jcall +semaphore-try-acquire
+
182 (semaphore-cell semaphore
)
183 (timeout-to-microseconds timeout
)
188 ;;; Condition variables
191 (defstruct (condition-variable
192 (:constructor %make-condition-variable
(name)))
195 (defun %condition-wait
(cv lock timeout
)
196 (threads:synchronized-on cv
199 ;; Since giving a zero time value to threads:object-wait means
200 ;; an indefinite wait, use some arbitrary small number.
201 (threads:object-wait cv
203 least-positive-single-float
205 (threads:object-wait cv
)))
206 (%acquire-lock lock t nil
)
209 (defun %condition-notify
(cv)
210 (threads:synchronized-on cv
211 (threads:object-notify cv
)))
213 (defun %condition-broadcast
(cv)
214 (threads:synchronized-on cv
215 (threads:object-notify-all cv
)))