-
Notifications
You must be signed in to change notification settings - Fork 47
/
Copy pathapi-semaphores.lisp
73 lines (62 loc) · 3.06 KB
/
api-semaphores.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
;;;; -*- Mode: LISP; Syntax: ANSI-Common-lisp; Base: 10; Package: BORDEAUX-THREADS-2 -*-
;;;; The above modeline is required for Genera. Do not change.
(in-package :bordeaux-threads-2)
#-(or abcl allegro ccl ecl lispworks mezzano sbcl)
(defstruct (%semaphore
(:constructor %make-semaphore (name counter)))
name counter
(lock (make-lock))
(condition-variable (%make-condition-variable nil)))
#-(or abcl allegro ccl ecl lispworks mezzano sbcl)
(deftype semaphore () '%semaphore)
(defun make-semaphore (&key name (count 0))
"Create a semaphore with the supplied NAME and initial counter value COUNT."
(check-type name (or null string))
(%make-semaphore name count))
#-(or abcl allegro ccl ecl lispworks mezzano sbcl)
(defun %signal-semaphore (semaphore count)
(with-lock-held ((%semaphore-lock semaphore))
(incf (%semaphore-counter semaphore) count)
(dotimes (v count)
(%condition-notify (%semaphore-condition-variable semaphore)))))
(defun signal-semaphore (semaphore &key (count 1))
"Increment SEMAPHORE by COUNT. If there are threads waiting on this
semaphore, then COUNT of them are woken up."
(%signal-semaphore semaphore count)
t)
#-(or abcl allegro ccl ecl lispworks mezzano sbcl)
(defun %wait-on-semaphore (semaphore timeout)
(with-lock-held ((%semaphore-lock semaphore))
(if (plusp (%semaphore-counter semaphore))
(decf (%semaphore-counter semaphore))
(let ((deadline (when timeout
(+ (get-internal-real-time)
(* timeout internal-time-units-per-second)))))
;; we need this loop because of a spurious wakeup possibility
(loop until (plusp (%semaphore-counter semaphore))
do (cond
((null (%condition-wait
(%semaphore-condition-variable semaphore)
(lock-native-lock (%semaphore-lock semaphore))
timeout))
(return-from %wait-on-semaphore))
;; unfortunately cv-wait may return T on timeout too
((and deadline (>= (get-internal-real-time) deadline))
(return-from %wait-on-semaphore))
(timeout
(setf timeout (/ (- deadline (get-internal-real-time))
internal-time-units-per-second)))))
(decf (%semaphore-counter semaphore))))
;; Semaphore acquired.
t))
#+cmu (mark-not-implemented 'wait-on-semaphore :timeout)
(defun wait-on-semaphore (semaphore &key timeout)
"Decrement the count of SEMAPHORE by 1 if the count is larger than zero.
If count is zero, blocks until the semaphore can be decremented.
Returns generalized boolean T on success.
If TIMEOUT is given, it is the maximum number of seconds to wait. If the count
cannot be decremented in that time, returns NIL without decrementing the count."
(%wait-on-semaphore semaphore timeout))
(defun semaphorep (object)
"Returns T if OBJECT is a semaphore, otherwise NIL."
(typep object 'semaphore))