From 8ee426cacceebd52f18232cd748ba8a1f211e9fd Mon Sep 17 00:00:00 2001 From: Daniel Barlow Date: Fri, 18 Jul 2003 21:40:43 +0000 Subject: [PATCH] 0.8.1.48 Significantly rearrange locking code for thread waitqueues, to eradicate races shown up in McCLIM applications. It's better than it was, and I can't trigger the lockup any longer: I don't claim it's _correct_, just that I can no longer see anything wrong with it Tidy up some constants in sb-bsd-sockets Amend spec in SB-POSIX to deal better with the differences between a CL namestring and a string-representing-a-filename- as-known-to-the-OS --- contrib/sb-bsd-sockets/constants.lisp | 4 +-- contrib/sb-posix/README | 15 ++++++++--- src/code/target-thread.lisp | 45 ++++++++++++++++++--------------- src/runtime/linux-os.c | 2 ++ 4 files changed, 40 insertions(+), 26 deletions(-) diff --git a/contrib/sb-bsd-sockets/constants.lisp b/contrib/sb-bsd-sockets/constants.lisp index 2629aef..e487966 100644 --- a/contrib/sb-bsd-sockets/constants.lisp +++ b/contrib/sb-bsd-sockets/constants.lisp @@ -10,12 +10,12 @@ ;;; then the stuff we're looking for ((:integer af-inet "AF_INET" "IP Protocol family") - (:integer af-unspec "AF_UNSPEC" "Unspecified.") + (:integer af-unspec "AF_UNSPEC" "Unspecified") (:integer af-local #+(or sunos solaris) "AF_UNIX" #-(or sunos solaris) "AF_LOCAL" "Local to host (pipes and file-domain).") - #+linux (:integer af-inet6 "AF_INET6" "IP version 6. ") + #+linux (:integer af-inet6 "AF_INET6" "IP version 6") #+linux (:integer af-route "AF_NETLINK" "Alias to emulate 4.4BSD ") (:integer sock-stream "SOCK_STREAM" diff --git a/contrib/sb-posix/README b/contrib/sb-posix/README index d77b7ed..5448ffe 100644 --- a/contrib/sb-posix/README +++ b/contrib/sb-posix/README @@ -81,13 +81,20 @@ results if the stream is buffered. A filename is a string. A pathname is a designator for a file-descriptor: the filename is -computed as if by NAMESTRING +computed using the same mechanism as the implementation would +use to map pathnames to OS filenames internally. + +In an implementation that supports pathnames to files on other hosts, +using mechanisms not available to the underlying OS (for example, +using an FTP or HTTP client in the Lisp implementation), the effect +of supplying this interface with a pathname to such a file is undefined. + ** buffer -A buffer is an opaque object with accessors BUFFER-START and -BUFFER-LENGTH, which represents an area of memory that system calls -may access. A buffer can be created using ALLOCATE-BUFFER or GET-BUFFER. +A buffer is an opaque object which represents an area of memory that +system calls may access. It has accessors BUFFER-START and +BUFFER-LENGTH, and can be created using ALLOCATE-BUFFER or GET-BUFFER. [ TODO: GET-BUFFER is a silly name. Come up with a better one ] diff --git a/src/code/target-thread.lisp b/src/code/target-thread.lisp index ec06a87..c7d40d9 100644 --- a/src/code/target-thread.lisp +++ b/src/code/target-thread.lisp @@ -83,6 +83,8 @@ (sb!alien:define-alien-routine "block_sigcont" void) (sb!alien:define-alien-routine "unblock_sigcont_and_sleep" void) +;;; this should only be called while holding the queue spinlock. +;;; it releases the spinlock before sleeping (defun wait-on-queue (queue &optional lock) (let ((pid (current-thread-id))) ;; FIXME what should happen if we get interrupted when we've blocked @@ -90,28 +92,23 @@ (block-sigcont) (when lock (release-mutex lock)) (sb!sys:without-interrupts - (get-spinlock queue 2 pid) - (pushnew pid (waitqueue-data queue)) - (setf (waitqueue-lock queue) 0)) + (pushnew pid (waitqueue-data queue))) + (setf (waitqueue-lock queue) 0) (unblock-sigcont-and-sleep))) +;;; this should only be called while holding the queue spinlock. It doesn't +;;; release it (defun dequeue (queue) (let ((pid (current-thread-id))) - (sb!sys:without-interrupts - (get-spinlock queue 2 pid) + (sb!sys:without-interrupts (setf (waitqueue-data queue) - (delete pid (waitqueue-data queue))) - (setf (waitqueue-lock queue) 0)))) + (delete pid (waitqueue-data queue)))))) +;;; this should probably only be called while holding the queue spinlock. +;;; not sure (defun signal-queue-head (queue) - (let ((pid (current-thread-id)) - h) - (sb!sys:without-interrupts - (get-spinlock queue 2 pid) - (setf h (car (waitqueue-data queue))) - (setf (waitqueue-lock queue) 0)) - (when h - (sb!unix:unix-kill h :sigcont)))) + (let ((p (car (waitqueue-data queue)))) + (when p (sb!unix:unix-kill p :sigcont)))) ;;;; mutex @@ -120,20 +117,25 @@ (let ((pid (current-thread-id))) (unless new-value (setf new-value pid)) (assert (not (eql new-value (mutex-value lock)))) + (get-spinlock lock 2 pid) (loop (unless ;; args are object slot-num old-value new-value (sb!vm::%instance-set-conditional lock 4 nil new-value) (dequeue lock) + (setf (waitqueue-lock lock) 0) (return t)) - (unless wait-p (return nil)) + (unless wait-p + (setf (waitqueue-lock lock) 0) + (return nil)) (wait-on-queue lock nil)))) (defun release-mutex (lock &optional (new-value nil)) (declare (type mutex lock)) ;; we assume the lock is ours to release - (setf (mutex-value lock) new-value) - (signal-queue-head lock)) + (with-spinlock (lock) + (setf (mutex-value lock) new-value) + (signal-queue-head lock))) (defmacro with-mutex ((mutex &key value (wait-p t)) &body body) @@ -152,12 +154,15 @@ 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) + (progn + (get-spinlock queue 2 (current-thread-id)) + (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) + (with-spinlock (queue) + (dequeue queue)) (get-mutex lock))) (defun condition-notify (queue) diff --git a/src/runtime/linux-os.c b/src/runtime/linux-os.c index 6d82304..c757711 100644 --- a/src/runtime/linux-os.c +++ b/src/runtime/linux-os.c @@ -251,6 +251,8 @@ void sigcont_handler(int signal, siginfo_t *info, void *void_context) /* we need to have a handler installed for this signal so that * sigwaitinfo() for it actually returns at the appropriate time */ + fprintf(stderr, "Thread %d received stray SIGCONT\n", + arch_os_get_current_thread()->pid); } void -- 1.7.10.4