1.0.10.28: export semaphore interface
authorNikodemus Siivola <nikodemus@random-state.net>
Fri, 5 Oct 2007 14:00:08 +0000 (14:00 +0000)
committerNikodemus Siivola <nikodemus@random-state.net>
Fri, 5 Oct 2007 14:00:08 +0000 (14:00 +0000)
 * Semaphores are a fundamental threading construct -- export them.
   Clean up the interface slightly: not (SETF SEMAPHORE-COUNT), note
   that being a subclass of STRUCTURE-OBJECT is not guaranteed, etc.

NEWS
doc/manual/threading.texinfo
package-data-list.lisp-expr
src/code/target-thread.lisp
version.lisp-expr

diff --git a/NEWS b/NEWS
index daa94e7..7ec96bc 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,7 @@ changes in sbcl-1.0.11 relative to sbcl-1.0.10:
     locking at the correct granularity. In the current implementation it is
     still safe to have multiple readers access the same table, but it's not
     guaranteed that this property will be maintained in future releases.
+  * enhancement: SB-THREAD package now exports a semaphore interface.
   * enhancement: CONS can now stack-allocate on x86 and
     x86-64. (Earlier LIST and LIST* supported stack-allocation, but
     CONS did not.)
index 759ab0f..7e84de5 100644 (file)
@@ -5,7 +5,7 @@
 SBCL supports a fairly low-level threading interface that maps onto
 the host operating system's concept of threads or lightweight
 processes.  This means that threads may take advantage of hardware
-multiprocessing on machines that have more than one CPU, but it does 
+multiprocessing on machines that have more than one CPU, but it does
 not allow Lisp control of the scheduler.  This is found in the
 SB-THREAD package.
 
@@ -14,12 +14,13 @@ x86 or x86-64 architecture, or SunOS (Solaris) on the x86.  Support for
 threading on Darwin (Mac OS X) and FreeBSD on the x86 is experimental.
 
 @menu
-* Threading basics::            
-* Special Variables::           
-* Mutex Support::               
-* Waitqueue/condition variables::  
-* Sessions/Debugging::          
-* Implementation (Linux x86)::  
+* Threading basics::
+* Special Variables::
+* Mutex Support::
+* Semaphores::
+* Waitqueue/condition variables::
+* Sessions/Debugging::
+* Implementation (Linux x86)::
 @end menu
 
 @node Threading basics
@@ -110,6 +111,20 @@ if you want a bounded wait.
 @include macro-sb-thread-with-mutex.texinfo
 @include macro-sb-thread-with-recursive-lock.texinfo
 
+@node Semaphores
+@comment  node-name,  next,  previous,  up
+@section Semaphores
+
+escribed here should be considered
+experimental, subject to API changes without notice.
+
+@include struct-sb-thread-semaphore.texinfo
+@include fun-sb-thread-make-semaphore.texinfo
+@include fun-sb-thread-semaphore-count.texinfo
+@include fun-sb-thread-semaphore-name.texinfo
+@include fun-sb-thread-signal-semaphore.texinfo
+@include fun-sb-thread-wait-on-semaphore.texinfo
+
 @node Waitqueue/condition variables
 @comment  node-name,  next,  previous,  up
 @section Waitqueue/condition variables
@@ -125,29 +140,29 @@ when you weren't expecting it to.
 There are three components:
 
 @itemize
-@item 
+@item
 the condition itself (not represented in code)
 
-@item 
+@item
 the condition variable (a.k.a waitqueue) which proxies for it
 
-@item 
-a lock to hold while testing the condition 
+@item
+a lock to hold while testing the condition
 @end itemize
 
 Important stuff to be aware of:
 
 @itemize
-@item 
+@item
 when calling condition-wait, you must hold the mutex. condition-wait
 will drop the mutex while it waits, and obtain it again before
 returning for whatever reason;
 
-@item 
+@item
 likewise, you must be holding the mutex around calls to
 condition-notify;
 
-@item 
+@item
 a process may return from condition-wait in several circumstances: it
 is not guaranteed that the underlying condition has become true. You
 must check that the resource is ready for whatever you want to do to
@@ -169,7 +184,7 @@ it.
       (unless *buffer* (return))
       (let ((head (car *buffer*)))
         (setf *buffer* (cdr *buffer*))
-        (format t "reader ~A woke, read ~A~%" 
+        (format t "reader ~A woke, read ~A~%"
                 *current-thread* head))))))
 
 (defun writer ()
@@ -177,14 +192,14 @@ it.
    (sleep (random 5))
    (with-mutex (*buffer-lock*)
      (let ((el (intern
-                (string (code-char 
+                (string (code-char
                          (+ (char-code #\A) (random 26)))))))
        (setf *buffer* (cons el *buffer*)))
      (condition-notify *buffer-queue*))))
 
 (make-thread #'writer)
 (make-thread #'reader)
-(make-thread #'reader)       
+(make-thread #'reader)
 @end lisp
 
 @include struct-sb-thread-waitqueue.texinfo
@@ -205,7 +220,7 @@ view has its own collection of foreground/background/stopped threads.
 A thread which wishes to create a new session can use
 @code{sb-thread:with-new-session} to remove itself from the current
 session (which it shares with its parent and siblings) and create a
-fresh one.  
+fresh one.
 # See also @code{sb-thread:make-listener-thread}.
 
 Within a single session, threads arbitrate between themselves for the
index 1db6a6f..cfe08ac 100644 (file)
@@ -1696,7 +1696,15 @@ is a good idea, but see SB-SYS re. blurring of boundaries."
                "WAITQUEUE" "MAKE-WAITQUEUE" "WAITQUEUE-NAME"
                "CONDITION-WAIT" "CONDITION-NOTIFY" "CONDITION-BROADCAST"
                "MAKE-LISTENER-THREAD"
-               "RELEASE-FOREGROUND" "WITH-NEW-SESSION"))
+               "RELEASE-FOREGROUND"
+               "WITH-NEW-SESSION"
+               ;; Semaphores
+               "MAKE-SEMAPHORE"
+               "SEMAPHORE"
+               "SEMAPHORE-NAME"
+               "SEMAPHORE-COUNT"
+               "SIGNAL-SEMAPHORE"
+               "WAIT-ON-SEMAPHORE"))
 
    #s(sb-cold:package-data
       :name "SB!LOOP"
index 19f2747..1509e01 100644 (file)
@@ -398,41 +398,48 @@ time we reacquire MUTEX and return to the caller."
 
 ;;;; semaphores
 
-(defstruct (semaphore (:constructor %make-semaphore))
+(defstruct (semaphore (:constructor %make-semaphore (name %count)))
   #!+sb-doc
-  "Semaphore type."
+  "Semaphore type. The fact that a SEMAPHORE is a STRUCTURE-OBJECT
+should be considered an implementation detail, and may change in the
+future."
   (name nil :type (or null simple-string))
-  (count 0 :type (integer 0))
+  (%count 0 :type (integer 0))
   (mutex (make-mutex))
   (queue (make-waitqueue)))
 
+(setf (fdocumentation 'semaphore-name 'function)
+      "The name of the semaphore INSTANCE. Setfable.")
+
+(declaim (inline semaphore-count))
+(defun semaphore-count (instance)
+  "Returns the current count of the semaphore INSTANCE."
+  (semaphore-%count instance))
+
 (defun make-semaphore (&key name (count 0))
   #!+sb-doc
-  "Create a semaphore with the supplied COUNT."
-  (%make-semaphore :name name :count count))
+  "Create a semaphore with the supplied COUNT and NAME."
+  (%make-semaphore name count))
 
-(setf (fdocumentation 'semaphore-name 'function)
-      "The name of the semaphore. Setfable.")
-
-(defun wait-on-semaphore (sem)
+(defun wait-on-semaphore (semaphore)
   #!+sb-doc
-  "Decrement the count of SEM if the count would not be negative. Else
-block until the semaphore can be decremented."
+  "Decrement the count of SEMAPHORE if the count would not be
+negative. Else blocks until the semaphore can be decremented."
   ;; a more direct implementation based directly on futexes should be
   ;; possible
-  (with-mutex ((semaphore-mutex sem))
-    (loop until (> (semaphore-count sem) 0)
-          do (condition-wait (semaphore-queue sem) (semaphore-mutex sem))
-          finally (decf (semaphore-count sem)))))
+  (with-mutex ((semaphore-mutex semaphore))
+    (loop until (> (semaphore-%count semaphore) 0)
+          do (condition-wait (semaphore-queue semaphore) (semaphore-mutex semaphore))
+          finally (decf (semaphore-%count semaphore)))))
 
-(defun signal-semaphore (sem &optional (n 1))
+(defun signal-semaphore (semaphore &optional (n 1))
   #!+sb-doc
-  "Increment the count of SEM by N. If there are threads waiting on
-this semaphore, then N of them is woken up."
-  (declare (type (and fixnum (integer 1)) n))
-  (with-mutex ((semaphore-mutex sem))
-    (when (= n (incf (semaphore-count sem) n))
-      (condition-notify (semaphore-queue sem) n))))
+  "Increment the count of SEMAPHORE by N. If there are threads waiting
+on this semaphore, then N of them is woken up."
+  (declare (type (integer 1) n))
+  (with-mutex ((semaphore-mutex semaphore))
+    (when (= n (incf (semaphore-%count semaphore) n))
+      (condition-notify (semaphore-queue semaphore) n))))
 
 ;;;; job control, independent listeners
 
index 693df37..8f1c3d1 100644 (file)
@@ -17,4 +17,4 @@
 ;;; checkins which aren't released. (And occasionally for internal
 ;;; versions, especially for internal versions off the main CVS
 ;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"1.0.10.27"
+"1.0.10.28"