~ chicken-core (chicken-5) fc6045225f052f04960799db8712a31b646bde02


commit fc6045225f052f04960799db8712a31b646bde02
Author:     Evan Hanson <evhan@foldling.org>
AuthorDate: Fri Sep 25 20:29:09 2015 +0200
Commit:     Evan Hanson <evhan@foldling.org>
CommitDate: Fri Sep 25 21:34:21 2015 +0200

    Avoid adding duplicate file descriptors when populating C_fdset_set
    
    Previously, when populating the C_fdset_set with pollfd entries before
    unblocking threads for i/o, an entry was added for each thread waiting
    on a given file descriptor, meaning multiple entries might be created
    for the same fd. Later code assumes that the C_fdset_set is a true set
    of fds, causing an assertion to fail. This patch changes `create-fdset`
    to ensure that each file descriptor appears once in the C_fdset_set,
    with the union of its input and output flags.

diff --git a/scheduler.scm b/scheduler.scm
index 68437d52..9758ccb4 100644
--- a/scheduler.scm
+++ b/scheduler.scm
@@ -395,26 +395,30 @@ EOF
   ((foreign-lambda void "C_prepare_fdset" int) (##sys#length ##sys#fd-list))
   (let loop ((lst ##sys#fd-list))
     (unless (null? lst)
-      (let ((fd (caar lst)))
+      (let ((fd (caar lst))
+	    (input #f)
+	    (output #f))
 	(for-each
 	 (lambda (t)
 	   (let ((p (##sys#slot t 11)))
-             (when (pair? p) ; (FD . RWFLAGS)? (can also be mutex or thread)
-               (fdset-set fd (cdr p)))))
+	     (when (pair? p) ; (FD . RWFLAGS)? (can also be mutex or thread)
+	       (let ((i/o (cdr p)))
+		 (case i/o
+		   ((#t #:input)
+		    (set! input #t))
+		   ((#f #:output)
+		    (set! output #t))
+		   ((#:all)
+		    (set! input #t)
+		    (set! output #t))
+		   (else
+		    (panic
+		     (sprintf "create-fdset: invalid i/o direction: ~S (fd = ~S)" i/o fd))))))))
 	 (cdar lst))
+	(when (or input output)
+	  ((foreign-lambda void "C_fdset_add" int bool bool) fd input output))
 	(loop (cdr lst))))))
 
-(define (fdset-set fd i/o)
-  (let ((fdset-add! (foreign-lambda void "C_fdset_add" int bool bool)))
-    (dbg "setting fdset for " fd " to " i/o)
-    (case i/o
-      ((#t #:input) (fdset-add! fd #t #f))
-      ((#f #:output) (fdset-add! fd #f #t))
-      ((#:all) (fdset-add! fd #t #t))
-      (else
-       (panic
-        (sprintf "fdset-set: invalid i/o direction: ~S (fd = ~S)" i/o fd))))))
-
 (define (fdset-test inf outf i/o)
   (case i/o
     ((#t #:input) inf)
Trap