~ chicken-core (chicken-5) c87b7eb2d4fe286149bb417eea7f1b9e0a209002
commit c87b7eb2d4fe286149bb417eea7f1b9e0a209002 Author: felix <felix@call-with-current-continuation.org> AuthorDate: Fri Aug 27 21:00:04 2010 +0200 Commit: felix <felix@call-with-current-continuation.org> CommitDate: Fri Aug 27 21:00:04 2010 +0200 insane debugging and dump mistakes diff --git a/posixunix.scm b/posixunix.scm index 2260c671..c484bc86 100644 --- a/posixunix.scm +++ b/posixunix.scm @@ -1398,7 +1398,7 @@ EOF (cond [(fx= cnt -1) (if (fx= _errno _ewouldblock) (begin - (##sys#thread-block-for-i/o! ##sys#current-thread fd #t) + (##sys#thread-block-for-i/o! ##sys#current-thread fd #:input) (##sys#thread-yield!) (loop) ) (posix-error #:file-error loc "cannot read" fd nam) )] diff --git a/scheduler.scm b/scheduler.scm index e085d9e2..0df90b81 100644 --- a/scheduler.scm +++ b/scheduler.scm @@ -28,12 +28,12 @@ (declare (unit scheduler) (disable-interrupts) - (hide ##sys#ready-queue-head ##sys#ready-queue-tail ##sys#timeout-list + (hide ready-queue-head ready-queue-tail ##sys#timeout-list ##sys#update-thread-state-buffer ##sys#restore-thread-state-buffer - ##sys#remove-from-ready-queue ##sys#unblock-threads-for-i/o ##sys#force-primordial - ##sys#fdset-input-set ##sys#fdset-output-set ##sys#fdset-clear - ##sys#fdset-select-timeout ##sys#fdset-set - ##sys#create-fdset + remove-from-ready-queue ##sys#unblock-threads-for-i/o ##sys#force-primordial + fdset-input-set fdset-output-set fdset-clear + fdset-select-timeout fdset-set fdset-test + create-fdset ##sys#clear-i/o-state-for-thread! ##sys#abandon-mutexes) (not inline ##sys#interrupt-hook) (unsafe) @@ -82,10 +82,21 @@ EOF (include "common-declarations.scm") -(define-syntax dbg +(define (dbg . args) + (for-each + (lambda (x) + (display x ##sys#standard-error)) + args) + (newline ##sys#standard-error)) + +#;(define-syntax dbg (syntax-rules () ((_ . _) #f))) +(define-syntax panic + (syntax-rules () + ((_ msg) (##core#inline "C_halt" msg)))) + (define (##sys#schedule) (define (switch thread) (dbg "switching to " thread) @@ -97,7 +108,7 @@ EOF (let* ([ct ##sys#current-thread] [eintr #f] [cts (##sys#slot ct 3)] ) - (dbg "scheduling, current: " ct ", ready: " ##sys#ready-queue-head) + (dbg "==================== scheduling, current: " ct ", ready: " ready-queue-head) (##sys#update-thread-state-buffer ct) ;; Put current thread on ready-queue: (when (or (eq? cts 'running) (eq? cts 'ready)) ; should ct really be 'ready? - normally not. @@ -107,14 +118,13 @@ EOF ;; Unblock threads waiting for timeout: (unless (null? ##sys#timeout-list) (let ((now (##core#inline_allocate ("C_a_i_current_milliseconds" 4) #f))) - (dbg "timeout (" now ") list: " ##sys#timeout-list) (let loop ((lst ##sys#timeout-list)) (if (null? lst) (set! ##sys#timeout-list '()) (let* ([tmo1 (caar lst)] ; timeout of thread on list [tto (cdar lst)] ; thread on list [tmo2 (##sys#slot tto 4)] ) ; timeout value stored in thread - (dbg " " tto " -> " tmo2) + (dbg "timeout: " tto " -> " tmo2 " (now: " now ")") (if (equal? tmo1 tmo2) ;XXX why do we check this? (if (fp>= now tmo1) ; timeout reached? (begin @@ -127,7 +137,7 @@ EOF ;; If there are no threads blocking on a select call (fd-list) ;; but there are threads in the timeout list then sleep for ;; the number of milliseconds of next thread to wake up. - (when (and (null? ##sys#ready-queue-head) + (when (and (null? ready-queue-head) (null? ##sys#fd-list) (pair? ##sys#timeout-list)) (let ((tmo1 (caar ##sys#timeout-list))) @@ -148,7 +158,7 @@ EOF (##sys#unblock-threads-for-i/o) ) ) ) ;; Fetch and activate next ready thread: (let loop2 () - (let ([nt (##sys#remove-from-ready-queue)]) + (let ([nt (remove-from-ready-queue)]) (cond [(not nt) (if (and (null? ##sys#timeout-list) (null? ##sys#fd-list)) (##sys#signal-hook #:runtime-error "deadlock") @@ -160,25 +170,25 @@ EOF (dbg "primordial thread forced due to interrupt") (##sys#thread-unblock! ##sys#primordial-thread) ) -(define ##sys#ready-queue-head '()) -(define ##sys#ready-queue-tail '()) +(define ready-queue-head '()) +(define ready-queue-tail '()) -(define (##sys#ready-queue) ##sys#ready-queue-head) +(define (##sys#ready-queue) ready-queue-head) (define (##sys#add-to-ready-queue thread) (##sys#setslot thread 3 'ready) (let ((new-pair (cons thread '()))) - (cond ((eq? '() ##sys#ready-queue-head) - (set! ##sys#ready-queue-head new-pair)) - (else (set-cdr! ##sys#ready-queue-tail new-pair)) ) - (set! ##sys#ready-queue-tail new-pair) ) ) + (cond ((eq? '() ready-queue-head) + (set! ready-queue-head new-pair)) + (else (set-cdr! ready-queue-tail new-pair)) ) + (set! ready-queue-tail new-pair) ) ) -(define (##sys#remove-from-ready-queue) - (let ((first-pair ##sys#ready-queue-head)) +(define (remove-from-ready-queue) + (let ((first-pair ready-queue-head)) (and (not (null? first-pair)) (let ((first-cdr (cdr first-pair))) - (set! ##sys#ready-queue-head first-cdr) - (when (eq? '() first-cdr) (set! ##sys#ready-queue-tail '())) + (set! ready-queue-head first-cdr) + (when (eq? '() first-cdr) (set! ready-queue-tail '())) (car first-pair) ) ) ) ) (define (##sys#update-thread-state-buffer thread) @@ -223,7 +233,9 @@ EOF (loop r l)))))) (define (##sys#thread-block-for-timeout! t tm) - (dbg t " blocks for " tm) + (dbg t " blocks for timeout " tm) + (unless (flonum? tm) + (panic "##sys#thread-block-for-timeout!: invalid timeout")) ;; This should really use a balanced tree: (let loop ([tl ##sys#timeout-list] [prev #f]) (if (or (null? tl) (fp< tm (caar tl))) @@ -289,7 +301,7 @@ EOF (define (##sys#thread-basic-unblock! t) (dbg "unblocking: " t) - (##sys#setislot t 11 #f) + (##sys#setislot t 11 #f) ; (FD . RWFLAGS) (##sys#setislot t 4 #f) (##sys#add-to-ready-queue t) ) @@ -328,48 +340,59 @@ EOF (define ##sys#fd-list '()) ; ((FD1 THREAD1 ...) ...) -(define (##sys#create-fdset) - (##sys#fdset-clear) +(define (create-fdset) + (fdset-clear) (let loop ((lst ##sys#fd-list)) (unless (null? lst) (let ((fd (caar lst))) (for-each (lambda (t) (let ((p (##sys#slot t 11))) - (##sys#fdset-set fd (cdr p)))) + (fdset-set fd (cdr p)))) (cdar lst)) (loop (cdr lst)))))) -(define ##sys#fdset-select-timeout +(define fdset-select-timeout (foreign-lambda* int ([bool to] [double tm]) "struct timeval timeout;" "timeout.tv_sec = tm / 1000;" "timeout.tv_usec = fmod(tm, 1000) * 1000;" "C_return(select(FD_SETSIZE, &C_fdset_input, &C_fdset_output, NULL, to ? &timeout : NULL));") ) -(define (##sys#fdset-clear) +(define fdset-clear (foreign-lambda* void () "FD_ZERO(&C_fdset_input);" "FD_ZERO(&C_fdset_output);") ) -(define ##sys#fdset-input-set +(define fdset-input-set (foreign-lambda* void ([int fd]) "FD_SET(fd, &C_fdset_input);" ) ) -(define ##sys#fdset-output-set +(define fdset-output-set (foreign-lambda* void ([int fd]) "FD_SET(fd, &C_fdset_output);" ) ) -(define (##sys#fdset-set fd i/o) +(define (fdset-set fd i/o) + (dbg "setting fdset for " fd " to " i/o) (case i/o - ((#t #:input) (##sys#fdset-input-set fd)) - ((#f #:output) (##sys#fdset-output-set fd)) + ((#:input) (fdset-input-set fd)) + ((#:output) (fdset-output-set fd)) ((#:all) - (##sys#fdset-input-set fd) - (##sys#fdset-output-set fd) ) )) + (fdset-input-set fd) + (fdset-output-set fd) ) + (else (panic "fdset-set: invalid i/o direction")))) + +(define (fdset-test inf outf i/o) + (case i/o + ((#:input) inf) + ((#:output) outf) + ((#:all) (or inf outf)) + (else (panic "fdset-test: invalid i/o direction")))) (define (##sys#thread-block-for-i/o! t fd i/o) - (dbg t " blocks for I/O " fd) + (dbg t " blocks for I/O " fd " in mode " i/o) + (unless (memq i/o '(#:all #:input #:output)) + (panic "##sys#thread-block-for-i/o!: invalid i/o mode")) (let loop ([lst ##sys#fd-list]) (if (null? lst) (set! ##sys#fd-list (cons (list fd t) ##sys#fd-list)) @@ -383,41 +406,54 @@ EOF (define (##sys#unblock-threads-for-i/o) (dbg "fd-list: " ##sys#fd-list) - (##sys#create-fdset) - (let* ([to? (pair? ##sys#timeout-list)] - [rq? (pair? ##sys#ready-queue-head)] - [n (##sys#fdset-select-timeout ; we use FD_SETSIZE, but really should use max fd - (or rq? to?) - (if (and to? (not rq?)) ; no thread was unblocked by timeout, so wait - (let* ((tmo1 (caar ##sys#timeout-list)) - (now (##core#inline_allocate ("C_a_i_current_milliseconds" 4) #f))) - (fpmax 0.0 (fp- tmo1 now)) ) - 0.0) ) ] ) ; otherwise immediate timeout. - (dbg n " fds ready") - (cond [(eq? -1 n) - (##sys#force-primordial)] - [(fx> n 0) - (set! ##sys#fd-list - (let loop ([n n] [lst ##sys#fd-list]) - (if (or (zero? n) (null? lst)) - lst - (let* ([a (car lst)] - [fd (car a)] - [inf (##core#inline "C_fd_test_input" fd)] - [outf (##core#inline "C_fd_test_output" fd)] ) - (dbg "fd " fd " ready: input=" inf ", output=" outf) - (if (or inf outf) - (let loop2 ([threads (cdr a)]) - (if (null? threads) - (loop (sub1 n) (cdr lst)) - (let* ([t (car threads)] - [p (##sys#slot t 11)] ) - (when (and (pair? p) - (eq? fd (car p)) - (not (##sys#slot t 13) ) ) ; not unblocked by timeout - (##sys#thread-basic-unblock! t) ) - (loop2 (cdr threads)) ) ) ) - (cons a (loop n (cdr lst))) ) ) ) ) ) ] ))) + (create-fdset) + (let* ((to? (pair? ##sys#timeout-list)) + (rq? (pair? ready-queue-head)) + (tmo (if (and to? (not rq?)) ; no thread was unblocked by timeout, so wait + (let* ((tmo1 (caar ##sys#timeout-list)) + (now (##core#inline_allocate ("C_a_i_current_milliseconds" 4) #f))) + (fpmax 0.0 (fp- tmo1 now)) ) + 0.0) ) ) ; otherwise immediate timeout. + (dbg "waiting for I/O with timeout " tmo) + (let ((n (fdset-select-timeout ; we use FD_SETSIZE, but really should use max fd + (or rq? to?) + tmo))) + (dbg n " fds ready") + (cond [(eq? -1 n) + (##sys#force-primordial)] + [(fx> n 0) + (set! ##sys#fd-list + (let loop ([n n] [lst ##sys#fd-list]) + (if (or (zero? n) (null? lst)) + lst + (let* ([a (car lst)] + [fd (car a)] + [inf (##core#inline "C_fd_test_input" fd)] + [outf (##core#inline "C_fd_test_output" fd)] ) + (dbg "fd " fd " ready: input=" inf ", output=" outf) + (if (or inf outf) + (let loop2 ((threads (cdr a)) (keep '())) + (if (null? threads) + (if (null? keep) + (loop (sub1 n) (cdr lst)) + (cons (cons fd keep) (loop (sub1 n) (cdr lst)))) + (let* ((t (car threads)) + (p (##sys#slot t 11)) ) + (dbg "checking " t " " p) + (cond ((##sys#slot t 13) ; unblocked by timeout? + (dbg t " unblocked by timeout") + (loop2 (cdr threads) keep)) + ((not (pair? p)) ; not blocked for I/O? + (panic + "##sys#unblock-threads-for-i/o: thread on fd-list is not blocked for I/O")) + ((not (eq? fd (car p))) + (panic + "##sys#unblock-threads-for-i/o: thread on fd-list has wrong FD")) + ((fdset-test inf outf (cdr p)) + (##sys#thread-basic-unblock! t) + (loop2 (cdr threads) keep)) + (else (loop2 (cdr threads) (cons t keep))))))) + (cons a (loop n (cdr lst))) ) ) ) ) ) ] ))) ) ;;; Clear I/O state for unblocked thread @@ -448,7 +484,7 @@ EOF (cns (lambda (queue arg val init) (cons val init))) (init '())) - (let loop ((l ##sys#ready-queue-head) (i init)) + (let loop ((l ready-queue-head) (i init)) (if (pair? l) (loop (cdr l) (cns 'ready #f (car l) i)) (let loop ((l ##sys#fd-list) (i i)) @@ -467,9 +503,9 @@ EOF ;;; Remove all waiting threads from the relevant queues with the exception of the current thread: (define (##sys#fetch-and-clear-threads) - (let ([all (vector ##sys#ready-queue-head ##sys#ready-queue-tail ##sys#fd-list ##sys#timeout-list)]) - (set! ##sys#ready-queue-head '()) - (set! ##sys#ready-queue-tail '()) + (let ([all (vector ready-queue-head ready-queue-tail ##sys#fd-list ##sys#timeout-list)]) + (set! ready-queue-head '()) + (set! ready-queue-tail '()) (set! ##sys#fd-list '()) (set! ##sys#timeout-list '()) all) ) @@ -478,8 +514,8 @@ EOF ;;; Restore list of waiting threads: (define (##sys#restore-threads vec) - (set! ##sys#ready-queue-head (##sys#slot vec 0)) - (set! ##sys#ready-queue-tail (##sys#slot vec 1)) + (set! ready-queue-head (##sys#slot vec 0)) + (set! ready-queue-tail (##sys#slot vec 1)) (set! ##sys#fd-list (##sys#slot vec 2)) (set! ##sys#timeout-list (##sys#slot vec 3)) ) diff --git a/srfi-18.scm b/srfi-18.scm index d9ad0bf0..36c48fbf 100644 --- a/srfi-18.scm +++ b/srfi-18.scm @@ -29,7 +29,7 @@ (unit srfi-18) (uses scheduler) (disable-interrupts) - (hide ##sys#compute-time-limit) ) + (hide compute-time-limit) ) (include "common-declarations.scm") @@ -45,7 +45,7 @@ ;;; Helper routines: -(define (##sys#compute-time-limit tm loc) +(define (compute-time-limit tm loc) (cond ((not tm) #f) ((##sys#structure? tm 'time) (##sys#slot tm 1)) ((number? tm) (+ (current-milliseconds) (* tm 1000))) @@ -170,7 +170,7 @@ (lambda (thread . timeout) (##sys#check-structure thread 'thread 'thread-join!) (let* ((limit (and (pair? timeout) - (##sys#compute-time-limit (##sys#slot timeout 0) 'thread-join!))) + (compute-time-limit (##sys#slot timeout 0) 'thread-join!))) (rest (and (pair? timeout) (##sys#slot timeout 1))) (tosupplied (and rest (pair? rest))) (toval (and tosupplied (##sys#slot rest 0))) ) @@ -234,7 +234,7 @@ (##sys#thread-block-for-timeout! ct limit) (##sys#schedule) ) ) ) ) (unless tm (##sys#signal-hook #:type-error 'thread-sleep! "invalid timeout argument" tm)) - (sleep (##sys#compute-time-limit tm 'thread-sleep!)) ) + (sleep (compute-time-limit tm 'thread-sleep!)) ) ;;; Mutexes: @@ -269,7 +269,7 @@ (lambda (mutex . ms-and-t) (##sys#check-structure mutex 'mutex 'mutex-lock!) (let* ([limitsup (pair? ms-and-t)] - [limit (and limitsup (##sys#compute-time-limit (car ms-and-t) 'mutex-lock!))] + [limit (and limitsup (compute-time-limit (car ms-and-t) 'mutex-lock!))] [threadsup (fx> (length ms-and-t) 1)] [thread (and threadsup (cadr ms-and-t))] ) (when thread (##sys#check-structure thread 'thread 'mutex-lock!)) @@ -334,7 +334,7 @@ (##sys#call-with-current-continuation (lambda (return) (let ([waiting (##sys#slot mutex 3)] - [limit (and timeout (##sys#compute-time-limit timeout 'mutex-unlock!))] ) + [limit (and timeout (compute-time-limit timeout 'mutex-unlock!))] ) (##sys#setislot mutex 4 #f) (##sys#setislot mutex 5 #f) (let ((t (##sys#slot mutex 2))) @@ -455,7 +455,7 @@ (lambda () (when (or (##sys#fudge 12) (##sys#tty-port? ##sys#standard-input)) (old) - (##sys#thread-block-for-i/o! ##sys#current-thread 0 #t) + (##sys#thread-block-for-i/o! ##sys#current-thread 0 #:input) (thread-yield!)))) ) ) diff --git a/support.scm b/support.scm index a60c7ab8..43bd2444 100644 --- a/support.scm +++ b/support.scm @@ -762,7 +762,9 @@ [(##core#variable quote ##core#undefined ##core#proc ##core#global-ref) #f] [(##core#lambda) (let ([id (first (node-parameters n))]) - (find (lambda (fs) (eq? id (foreign-callback-stub-id fs))) foreign-callback-stubs) ) ] + (find (lambda (fs) + (eq? id (foreign-callback-stub-id fs))) + foreign-callback-stubs) ) ] [(if let) (any walk subs)] [else #t] ) ) ) ) diff --git a/tcp.scm b/tcp.scm index 96299349..1365c249 100644 --- a/tcp.scm +++ b/tcp.scm @@ -349,7 +349,7 @@ EOF (##sys#thread-block-for-timeout! ##sys#current-thread (+ (current-milliseconds) tmr) ) ) - (##sys#thread-block-for-i/o! ##sys#current-thread fd #t) + (##sys#thread-block-for-i/o! ##sys#current-thread fd #:input) (yield) (when (##sys#slot ##sys#current-thread 13) (##sys#signal-hook @@ -457,7 +457,7 @@ EOF (##sys#thread-block-for-timeout! ##sys#current-thread (+ (current-milliseconds) tmw) ) ) - (##sys#thread-block-for-i/o! ##sys#current-thread fd #f) + (##sys#thread-block-for-i/o! ##sys#current-thread fd #:output) (yield) (when (##sys#slot ##sys#current-thread 13) (##sys#signal-hook @@ -525,7 +525,7 @@ EOF (##sys#thread-block-for-timeout! ##sys#current-thread (+ (current-milliseconds) tma) ) ) - (##sys#thread-block-for-i/o! ##sys#current-thread fd #t) + (##sys#thread-block-for-i/o! ##sys#current-thread fd #:input) (yield) (when (##sys#slot ##sys#current-thread 13) (##sys#signal-hookTrap