yet another instance of left over entries: threads unblocked by i/o
should not be any longer on the timeout list, otherwise the next timeout
*could* be quite short.  ;-)

Am Sonntag, den 21.09.2008, 13:31 +0200 schrieb Jörg F. Wittenberger:
> Am Freitag, den 19.09.2008, 23:30 +0200 schrieb Jörg F. Wittenberger:
> > > The attached patch fixes ##sys#thread-kill! wrt. to join timeouts.
> 
> The attached fix adds code to mutex-lock! and mutex-unlock! to remove
> the thread from the timeout-list when a timeout was supplied and the
> thread was not unblocked by timeout.

BTW: sorry for the fix still containing the bad-fd handling code and -
too - the extended ##sys#all-threads.  It's getting messy with the diffs
here around.  Please cherry-pick.

Index: scheduler.scm
===================================================================
--- scheduler.scm	(Revision 11974)
+++ scheduler.scm	(Arbeitskopie)
@@ -46,6 +46,8 @@
 # define C_signal_interrupted_p     C_SCHEME_FALSE
 #endif
 
+# include <sys/stat.h>
+
 #ifdef _WIN32
 # if _MSC_VER > 1300
 # include <winsock2.h>
@@ -145,9 +147,8 @@
       ;; Unblock threads blocked by I/O:
       (if eintr
 	  (##sys#force-primordial)
-	  (begin
-	    (unless (null? ##sys#fd-list)
-	      (##sys#unblock-threads-for-i/o) ) ) )
+	  (unless (null? ##sys#fd-list)
+ 	   (##sys#unblock-threads-for-i/o) ) )
       ;; Fetch and activate next ready thread:
       (let loop2 ()
 	(let ([nt (##sys#remove-from-ready-queue)])
@@ -212,6 +213,16 @@
 
 (define ##sys#timeout-list '())
 
+(define (##sys#remove-from-timeout-list! t)
+  (set! ##sys#timeout-list
+	(let loop ((l ##sys#timeout-list))
+	  (if (null? l) 
+	      l
+	      (let ((h (##sys#slot l 0)))
+		(if (eq? (##sys#slot h 1) t)
+		    (##sys#slot l 1)
+		    (cons h (loop (##sys#slot l 1)))))))))
+
 (define (##sys#thread-block-for-timeout! t tm)
   (dbg t " blocks for " tm)
   ;; This should really use a balanced tree:
@@ -341,6 +352,30 @@
   (##sys#setislot t 13 #f)
   (##sys#setslot t 11 (cons fd i/o)) )
 
+(define-foreign-variable error-bad-file int "(errno == EBADF)")
+
+(define (##sys#handle-bad-fd! e)
+  (dbg "check bad" e)
+  (let ((bad ((foreign-lambda*
+	       bool ((integer fd))
+	       "struct stat buf;"
+	       "int i = ( (fstat(fd, &buf) == -1 && errno == EBADF) ? 1 : 0);"
+	       "return(i);")
+	      (car e))))
+    (if bad
+	(for-each
+	 (lambda (thread)
+	   (thread-signal!
+	    thread
+	    (##sys#make-structure
+	     'condition
+	     '(exn i/o) ;; better? '(exn i/o net)
+	     (list '(exn . message) "bad file descriptor"
+		   '(exn . arguments) (list (car e))
+		   '(exn . location) thread) )))
+	 (cdr e)))
+    bad))
+
 (define (##sys#unblock-threads-for-i/o)
   (dbg "fd-list: " ##sys#fd-list)
   (let* ([to? (pair? ##sys#timeout-list)]
@@ -353,8 +388,23 @@
 		   (fxmax 0 (- tmo1 now)) )
 		 0) ) ] )		; otherwise immediate timeout.
     (dbg n " fds ready")
-    (cond [(eq? -1 n) 
-	   (##sys#force-primordial)]
+    (cond [(eq? -1 n)
+	   (cond
+	    (error-bad-file
+	     (set! ##sys#fd-list
+		   (let loop ((l ##sys#fd-list))
+		     (cond
+		      ((null? l) l)
+		      ((##sys#handle-bad-fd! (car l))
+		       (##sys#fdset-clear (caar l))
+		       ;; This is supposed to be a rare case, catch
+		       ;; them one by one.
+		       ;; (loop (cdr l))
+		       (cdr l))
+		      (else (cons (car l) (loop (cdr l)))))))
+	     (##sys#fdset-restore)
+	     (##sys#unblock-threads-for-i/o))
+	    (else (##sys#force-primordial))) ]
 	  [(fx> n 0)
 	   (set! ##sys#fd-list
 	     (let loop ([n n] [lst ##sys#fd-list])
@@ -376,6 +426,7 @@
 				 (when (and (pair? p)
 					    (eq? fd (car p))
 					    (not (##sys#slot t 13) ) ) ; not unblocked by timeout
+				   (##sys#remove-from-timeout-list! t)
 				   (##sys#thread-basic-unblock! t) )
 				 (loop2 (cdr threads)) ) ) )
 			 (cons a (loop n (cdr lst))) ) ) ) ) ) ] )
@@ -408,12 +459,28 @@
 
 ;;; Get list of all threads that are ready or waiting for timeout or waiting for I/O:
 
-(define (##sys#all-threads)
-  (append ##sys#ready-queue-head
-          (apply append (map cdr ##sys#fd-list))
-          (map cdr ##sys#timeout-list)))
+(define (##sys#all-threads . cons+init)
+  (let ((cons (if (null? cons+init)
+		  (lambda (queue arg val init)
+		    (cons val init))
+		  (car cons+init)))
+	(init (if (and (pair? cons+init) (pair? (cdr cons+init)))
+		  (cadr cons+init) '())))
+    (let loop ((l ##sys#ready-queue-head) (i init))
+      (if (pair? l)
+	  (loop (cdr l) (cons 'ready #f (car l) i))
+	  (let loop ((l ##sys#fd-list) (i i))
+	    (if (pair? l)
+		(loop (cdr l)
+		      (let ((fd (caar l)))
+			(let loop ((l (cdar l)))
+			  (if (null? l) i
+			      (cons 'i/o fd (car l) (loop (cdr l)))))))
+		(let loop ((l ##sys#timeout-list) (i i))
+		  (if (pair? l)
+		      (loop (cdr l) (cons 'timeout (caar l) (cdar l) i))
+		      i))))))))
 
-
 ;;; Remove all waiting threads from the relevant queues with the exception of the current thread:
 
 (define (##sys#fetch-and-clear-threads)
@@ -438,14 +505,7 @@
 
 (define (##sys#thread-unblock! t)
   (when (eq? 'blocked (##sys#slot t 3))
-    (set! ##sys#timeout-list
-      (let loop ((l ##sys#timeout-list))
-	(if (null? l) 
-	    l
-	    (let ((h (##sys#slot l 0)))
-	      (if (eq? (##sys#slot h 1) t)
-		  (##sys#slot l 1)
-		  (cons h (loop (##sys#slot l 1))))))))
+    (##sys#remove-from-timeout-list! t)
     (set! ##sys#fd-list 
       (let loop ([fdl ##sys#fd-list])
 	(if (null? fdl)
_______________________________________________
Chicken-users mailing list
[email protected]
http://lists.nongnu.org/mailman/listinfo/chicken-users

Reply via email to