X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcode%2Fthread.lisp;h=54092dedee2cebadc2ba5d53d8818e06c1c5b13b;hb=496071a75429677a2c064e4995c379d3ba6ec458;hp=50be15f2bee91cf962df3a12491a7eac6deefdf6;hpb=5a2b6553fbbbb62fa789350facd0d56bb136045f;p=sbcl.git diff --git a/src/code/thread.lisp b/src/code/thread.lisp index 50be15f..54092de 100644 --- a/src/code/thread.lisp +++ b/src/code/thread.lisp @@ -1,46 +1,262 @@ +;;;; support for threads needed at cross-compile time + +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; This software is derived from the CMU CL system, which was +;;;; written at Carnegie Mellon University and released into the +;;;; public domain. The software is in the public domain and is +;;;; provided with absolutely no warranty. See the COPYING and CREDITS +;;;; files for more information. + (in-package "SB!THREAD") -(defvar *session-lock*) +(def!struct mutex + #!+sb-doc + "Mutex type." + (name nil :type (or null simple-string)) + (%owner nil :type (or null thread)) + #!+(and (not sb-lutex) sb-thread) + (state 0 :type fixnum) + #!+(and sb-lutex sb-thread) + (lutex (make-lutex))) + +;;; FIXME: We probably want to rename the accessor MUTEX-OWNER. +(defun mutex-value (mutex) + "Current owner of the mutex, NIL if the mutex is free." + (mutex-%owner mutex)) + +(defsetf mutex-value set-mutex-value) + +(declaim (inline set-mutex-value)) +(defun set-mutex-value (mutex value) + (declare (ignore mutex value)) + (error "~S is no longer supported." '(setf mutex-value))) + +(define-compiler-macro set-mutex-value (&whole form mutex value) + (declare (ignore mutex value)) + (warn "~S is no longer supported, and will signal an error at runtime." + '(setf mutex-value)) + form) + +(def!struct spinlock + #!+sb-doc + "Spinlock type." + (name nil :type (or null simple-string)) + (value nil)) + +(sb!xc:defmacro with-mutex ((mutex &key (value '*current-thread*) (wait-p t)) + &body body) + #!+sb-doc + "Acquire MUTEX for the dynamic scope of BODY, setting it to +NEW-VALUE or some suitable default value if NIL. If WAIT-P is non-NIL +and the mutex is in use, sleep until it is available" + `(dx-flet ((with-mutex-thunk () ,@body)) + (call-with-mutex + #'with-mutex-thunk + ,mutex + ,value + ,wait-p))) + +(sb!xc:defmacro with-system-mutex ((mutex &key without-gcing allow-with-interrupts) &body body) + `(dx-flet ((with-system-mutex-thunk () ,@body)) + (,(cond (without-gcing + 'call-with-system-mutex/without-gcing) + (allow-with-interrupts + 'call-with-system-mutex/allow-with-interrupts) + (t + 'call-with-system-mutex)) + #'with-system-mutex-thunk + ,mutex))) + +(sb!xc:defmacro with-system-spinlock ((spinlock &key) &body body) + `(dx-flet ((with-system-spinlock-thunk () ,@body)) + (call-with-system-spinlock + #'with-system-spinlock-thunk + ,spinlock))) (sb!xc:defmacro with-recursive-lock ((mutex) &body body) - #!+sb-thread - (with-unique-names (cfp) - `(let ((,cfp (sb!kernel:current-fp))) - (unless (and (mutex-value ,mutex) - (sb!vm:control-stack-pointer-valid-p - (sb!sys:int-sap - (sb!kernel:get-lisp-obj-address (mutex-value ,mutex))))) - ;; this punning with MAKE-LISP-OBJ depends for its safety on - ;; the frame pointer being a lispobj-aligned integer. While - ;; it is, then MAKE-LISP-OBJ will always return a FIXNUM, so - ;; we're safe to do that. Should this ever change, this - ;; MAKE-LISP-OBJ could return something that looks like a - ;; pointer, but pointing into neverneverland, which will - ;; confuse GC completely. -- CSR, 2003-06-03 - (get-mutex ,mutex (sb!kernel:make-lisp-obj (sb!sys:sap-int ,cfp)))) - (unwind-protect - (progn ,@body) - (when (sb!sys:sap= (sb!sys:int-sap - (sb!kernel:get-lisp-obj-address - (mutex-value ,mutex))) - ,cfp) - (release-mutex ,mutex))))) - #!-sb-thread - `(progn ,@body)) + #!+sb-doc + "Acquires MUTEX for the dynamic scope of BODY. Within that scope +further recursive lock attempts for the same mutex succeed. It is +allowed to mix WITH-MUTEX and WITH-RECURSIVE-LOCK for the same mutex +provided the default value is used for the mutex." + `(dx-flet ((with-recursive-lock-thunk () ,@body)) + (call-with-recursive-lock + #'with-recursive-lock-thunk + ,mutex))) -#!+sb-thread -(defun get-foreground () - (when (not (eql (mutex-value *session-lock*) (current-thread-id))) - (get-mutex *session-lock*)) - (sb!sys:enable-interrupt sb!unix:sigint #'sb!unix::sigint-handler) - t) +(sb!xc:defmacro with-recursive-spinlock ((spinlock) &body body) + `(dx-flet ((with-recursive-spinlock-thunk () ,@body)) + (call-with-recursive-spinlock + #'with-recursive-spinlock-thunk + ,spinlock))) + +(sb!xc:defmacro with-recursive-system-spinlock ((spinlock + &key without-gcing) + &body body) + `(dx-flet ((with-recursive-system-spinlock-thunk () ,@body)) + (,(cond (without-gcing + 'call-with-recursive-system-spinlock/without-gcing) + (t + 'call-with-recursive-system-spinlock)) + #'with-recursive-system-spinlock-thunk + ,spinlock))) + +(sb!xc:defmacro with-spinlock ((spinlock) &body body) + `(dx-flet ((with-spinlock-thunk () ,@body)) + (call-with-spinlock + #'with-spinlock-thunk + ,spinlock))) + +;;; KLUDGE: this separate implementation for (NOT SB-THREAD) is not +;;; strictly necessary; GET-MUTEX and RELEASE-MUTEX are implemented. +;;; However, there would be a (possibly slight) performance hit in +;;; using them. #!-sb-thread -(defun get-foreground () t) +(progn + (macrolet ((def (name &optional variant) + `(defun ,(if variant (symbolicate name "/" variant) name) (function lock) + (declare (ignore lock) (function function)) + ,(ecase variant + (:without-gcing + `(without-gcing (funcall function))) + (:allow-with-interrupts + `(without-interrupts (allow-with-interrupts (funcall function)))) + ((nil) + `(without-interrupts (funcall function))))))) + (def call-with-system-mutex) + (def call-with-system-mutex :without-gcing) + (def call-with-system-mutex :allow-with-interrupts) + (def call-with-system-spinlock) + (def call-with-recursive-system-spinlock) + (def call-with-recursive-system-spinlock :without-gcing)) + + (defun call-with-mutex (function mutex value waitp) + (declare (ignore mutex value waitp) + (function function)) + (funcall function)) + + (defun call-with-recursive-lock (function mutex) + (declare (ignore mutex) (function function)) + (funcall function)) + + (defun call-with-spinlock (function spinlock) + (declare (ignore spinlock) (function function)) + (funcall function)) + + (defun call-with-recursive-spinlock (function spinlock) + (declare (ignore spinlock) (function function)) + (funcall function))) #!+sb-thread -(defun release-foreground () - (sb!sys:enable-interrupt sb!unix:sigint :ignore) - (release-mutex *session-lock*) - t) -#!-sb-thread -(defun release-foreground () t) +;;; KLUDGE: These need to use DX-LET, because the cleanup form that +;;; closes over GOT-IT causes a value-cell to be allocated for it -- +;;; and we prefer that to go on the stack since it can. +(progn + (macrolet ((def (name &optional variant) + `(defun ,(if variant (symbolicate name "/" variant) name) (function mutex) + (declare (function function)) + (flet ((%call-with-system-mutex () + (dx-let (got-it) + #-sb-xc-host (declare (optimize sb!c::stack-allocate-value-cells)) + (unwind-protect + (when (setf got-it (get-mutex mutex)) + (funcall function)) + (when got-it + (release-mutex mutex)))))) + (declare (inline %call-with-system-mutex)) + ,(ecase variant + (:without-gcing + `(without-gcing (%call-with-system-mutex))) + (:allow-with-interrupts + `(without-interrupts (allow-with-interrupts (%call-with-system-mutex)))) + ((nil) + `(without-interrupts (%call-with-system-mutex)))))))) + (def call-with-system-mutex) + (def call-with-system-mutex :without-gcing) + (def call-with-system-mutex :allow-with-interrupts)) + + (defun call-with-system-spinlock (function spinlock) + (declare (function function)) + (without-interrupts + (dx-let (got-it) + #-sb-xc-host (declare (optimize sb!c::stack-allocate-value-cells)) + (unwind-protect + (when (setf got-it (get-spinlock spinlock)) + (funcall function)) + (when got-it + (release-spinlock spinlock)))))) + + (macrolet ((def (name &optional variant) + `(defun ,(if variant (symbolicate name "/" variant) name) (function spinlock) + (declare (function function)) + (flet ((%call-with-system-spinlock () + (dx-let ((inner-lock-p (eq *current-thread* (spinlock-value spinlock))) + (got-it nil)) + #-sb-xc-host (declare (optimize sb!c::stack-allocate-value-cells)) + (unwind-protect + (when (or inner-lock-p (setf got-it (get-spinlock spinlock))) + (funcall function)) + (when got-it + (release-spinlock spinlock)))))) + (declare (inline %call-with-system-spinlock)) + ,(ecase variant + (:without-gcing + `(without-gcing (%call-with-system-spinlock))) + ((nil) + `(without-interrupts (%call-with-system-spinlock)))))))) + (def call-with-recursive-system-spinlock) + (def call-with-recursive-system-spinlock :without-gcing)) + + (defun call-with-spinlock (function spinlock) + (declare (function function)) + (dx-let ((got-it nil)) + #-sb-xc-host (declare (optimize sb!c::stack-allocate-value-cells)) + (without-interrupts + (unwind-protect + (when (setf got-it (allow-with-interrupts + (get-spinlock spinlock))) + (with-local-interrupts (funcall function))) + (when got-it + (release-spinlock spinlock)))))) + + (defun call-with-mutex (function mutex value waitp) + (declare (function function)) + (dx-let ((got-it nil)) + #-sb-xc-host (declare (optimize sb!c::stack-allocate-value-cells)) + (without-interrupts + (unwind-protect + (when (setq got-it (allow-with-interrupts + (get-mutex mutex value waitp))) + (with-local-interrupts (funcall function))) + (when got-it + (release-mutex mutex)))))) + + (defun call-with-recursive-lock (function mutex) + (declare (function function)) + (dx-let ((inner-lock-p (eq (mutex-%owner mutex) *current-thread*)) + (got-it nil)) + #-sb-xc-host (declare (optimize sb!c::stack-allocate-value-cells)) + (without-interrupts + (unwind-protect + (when (or inner-lock-p (setf got-it (allow-with-interrupts + (get-mutex mutex)))) + (with-local-interrupts (funcall function))) + (when got-it + (release-mutex mutex)))))) + + + + (defun call-with-recursive-spinlock (function spinlock) + (declare (function function)) + (dx-let ((inner-lock-p (eq (spinlock-value spinlock) *current-thread*)) + (got-it nil)) + #-sb-xc-host (declare (optimize sb!c::stack-allocate-value-cells)) + (without-interrupts + (unwind-protect + (when (or inner-lock-p (setf got-it (allow-with-interrupts + (get-spinlock spinlock)))) + (with-local-interrupts (funcall function))) + (when got-it + (release-spinlock spinlock)))))))