new
authorDaniel Barlow <dan@telent.net>
Wed, 2 Apr 2003 14:01:38 +0000 (14:01 +0000)
committerDaniel Barlow <dan@telent.net>
Wed, 2 Apr 2003 14:01:38 +0000 (14:01 +0000)
src/code/target-unithread.lisp [new file with mode: 0644]

diff --git a/src/code/target-unithread.lisp b/src/code/target-unithread.lisp
new file mode 100644 (file)
index 0000000..c79c011
--- /dev/null
@@ -0,0 +1,117 @@
+(in-package "SB!THREAD")
+
+(defun current-thread-id ()
+  (sb!sys:sap-int
+   (sb!vm::current-thread-offset-sap sb!vm::thread-pid-slot)))
+
+;;;; queues, locks 
+
+;; spinlocks use 0 as "free" value: higher-level locks use NIL
+(defun get-spinlock (lock offset new-value) )
+
+(defmacro with-spinlock ((queue) &body body)
+  `(progn ,@body))
+
+;;;; the higher-level locking operations are based on waitqueues
+
+(defstruct waitqueue
+  (name nil :type (or null simple-base-string))
+  (lock 0)
+  (data nil))
+
+(defstruct (mutex (:include waitqueue))
+  (value nil))
+
+#+nil
+(defun wait-on-queue (queue &optional lock)
+  (let ((pid (current-thread-id)))
+    ;; FIXME what should happen if we get interrupted when we've blocked
+    ;; the sigcont?  For that matter, can we get interrupted?
+    (block-sigcont)
+    (when lock (release-mutex lock))
+    (get-spinlock queue 2 pid)
+    (pushnew pid (waitqueue-data queue))
+    (setf (waitqueue-lock queue) 0)
+    (unblock-sigcont-and-sleep)))
+
+#+nil
+(defun dequeue (queue)
+  (let ((pid (current-thread-id)))
+    (get-spinlock queue 2 pid)
+    (setf (waitqueue-data queue)
+         (delete pid (waitqueue-data queue)))
+    (setf (waitqueue-lock queue) 0)))
+
+#+nil
+(defun signal-queue-head (queue)
+  (let ((pid (current-thread-id)))
+    (get-spinlock queue 2 pid)
+    (let ((h (car (waitqueue-data queue))))
+      (setf (waitqueue-lock queue) 0)
+      (when h
+       (sb!unix:unix-kill h :sigcont)))))
+
+;;;; mutex
+
+#+nil
+(defun get-mutex (lock &optional new-value (wait-p t))
+  (declare (type mutex lock))
+  (let ((pid (current-thread-id)))
+    (unless new-value (setf new-value pid))
+    (assert (not (eql new-value (mutex-value lock))))
+    (loop
+     (unless
+        ;; args are object slot-num old-value new-value
+        (sb!vm::%instance-set-conditional lock 4 nil new-value)
+       (dequeue lock)
+       (return t))
+     (unless wait-p (return nil))
+     (wait-on-queue lock nil))))
+
+#+nil
+(defun release-mutex (lock &optional (new-value nil))
+  (declare (type mutex lock))
+  (let ((old-value (mutex-value lock))
+       (t1 nil))
+    (loop
+     (unless
+        ;; args are object slot-num old-value new-value
+        (eql old-value
+             (setf t1
+                   (sb!vm::%instance-set-conditional lock 4 old-value new-value)))       
+       (signal-queue-head lock)
+       (return t))
+     (setf old-value t1))))
+
+(defmacro with-mutex ((mutex &key value (wait-p t))  &body body)
+  (declare (ignore mutex value wait-p))
+  `(progn ,@body))
+
+;;; what's the best thing to do with these on unithread?
+#+NIl
+(defun condition-wait (queue lock)
+  "Atomically release LOCK and enqueue ourselves on QUEUE.  Another
+thread may subsequently notify us using CONDITION-NOTIFY, at which
+time we reacquire LOCK and return to the caller."
+  (unwind-protect
+       (wait-on-queue queue lock)
+    ;; If we are interrupted while waiting, we should do these things
+    ;; before returning.  Ideally, in the case of an unhandled signal,
+    ;; we should do them before entering the debugger, but this is
+    ;; better than nothing.
+    (dequeue queue)
+    (get-mutex lock)))
+
+#+nil
+(defun condition-notify (queue)
+  "Notify one of the processes waiting on QUEUE"
+  (signal-queue-head queue))
+
+
+;;;; multiple independent listeners
+
+(defvar *session-lock* nil)
+
+;;;; job control
+
+(defun debugger-wait-until-foreground-thread (stream) t)