0.8.1.48
authorDaniel Barlow <dan@telent.net>
Fri, 18 Jul 2003 21:40:43 +0000 (21:40 +0000)
committerDaniel Barlow <dan@telent.net>
Fri, 18 Jul 2003 21:40:43 +0000 (21:40 +0000)
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
contrib/sb-posix/README
src/code/target-thread.lisp
src/runtime/linux-os.c

index 2629aef..e487966 100644 (file)
 
 ;;; 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"
index d77b7ed..5448ffe 100644 (file)
@@ -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 ]
 
index ec06a87..c7d40d9 100644 (file)
@@ -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
     (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
 
   (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)
 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)
index 6d82304..c757711 100644 (file)
@@ -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