diff options
| author | Peter Bex <peter@more-magic.net> | 2017-11-18 13:58:13 +0100 | 
|---|---|---|
| committer | Peter Bex <peter@more-magic.net> | 2017-11-18 13:58:13 +0100 | 
| commit | 1adc1af6d9b52ad33f0b773cfdcd64573a2b7b9e (patch) | |
| tree | 87af9bb2ce76dbd998da736eeaaff5fdf61aed0b | |
| parent | dac7e59c6ccd22d36ba4de9c9c6c171c143eb9cc (diff) | |
| download | scsh-process-1adc1af6d9b52ad33f0b773cfdcd64573a2b7b9e.tar.gz | |
Run signal handler in a separate thread
This seems to be necessary so that condition-variable-broadcast! works
when the signal handler is running in the same thread as the waiting
thread.
| -rw-r--r-- | scsh-process.scm | 35 | ||||
| -rw-r--r-- | tests/run.scm | 9 | 
2 files changed, 26 insertions, 18 deletions
| diff --git a/scsh-process.scm b/scsh-process.scm index 1a6c22b..fd7ff3f 100644 --- a/scsh-process.scm +++ b/scsh-process.scm @@ -177,21 +177,26 @@                    (else (syntax-rules () ((_ val) val))))))       (let ((old-handler (workaround (signal-handler signal/chld))))         (lambda (signal) -         (for-each (lambda (pid) -                     (handle-exceptions exn -                       ;; User might have waited manually -                         (begin (remove-scsh-pending-process! pid) (void)) -                       (receive (pid ok? status) -                         (posix-process-wait pid #t) -                         (unless (zero? pid) -                           (let ((p (hash-table-ref *scsh-pending-processes* pid))) -                             (scsh-process-exit-status-set! p status) -                             (scsh-process-ok?-set! p ok?) -			     (condition-variable-broadcast! -                              (scsh-process-child-condition p)) -                             ;; The GC can clean it up -                             (remove-scsh-pending-process! pid)))))) -                   (hash-table-keys *scsh-pending-processes*)) +         ;; Run the signal handler in another thread. This is needed +         ;; because the current thread may be waiting on a condition +         ;; variable, and we can't wake ourselves up. +         (thread-start! +          (lambda () +            (for-each (lambda (pid) +                        (handle-exceptions exn +                            ;; User might have waited manually +                            (begin (remove-scsh-pending-process! pid) (void)) +                          (receive (pid ok? status) +                              (posix-process-wait pid #t) +                            (unless (zero? pid) +                              (let ((p (hash-table-ref *scsh-pending-processes* pid))) +                                (scsh-process-exit-status-set! p status) +                                (scsh-process-ok?-set! p ok?) +                                (condition-variable-broadcast! +                                 (scsh-process-child-condition p)) +                                ;; The GC can clean it up +                                (remove-scsh-pending-process! pid)))))) +                      (hash-table-keys *scsh-pending-processes*))))           (when old-handler (old-handler signal)))))))  (define (signal-process proc sig) diff --git a/tests/run.scm b/tests/run.scm index f05d643..7690752 100644 --- a/tests/run.scm +++ b/tests/run.scm @@ -18,9 +18,12 @@          "This is a test"          (run/string* (lambda () (display "This is a test")))) -  ;; We must mask sigchld, because otherwise our (wait #f) will fail -  ;; due to scsh-process' signal handler possibly reaping the child -  ;; before our wait is able to do so. +  ;; Ensure all processes up to here have been reaped +  (handle-exceptions exn (void) (let lp () (when (wait #f) (lp)))) + +  ;; We must mask sigchld, because otherwise our next (wait #f) will +  ;; fail due to scsh-process' signal handler possibly reaping the +  ;; child before our wait is able to do so.    (signal-mask! signal/chld)    (test "wait for next process to exit" | 
