Suppose I want an operation (SUBPROCESS-WAIT* <subprocess>) that behaves as it seems that this definition should behave:
(define (subprocess-wait* subprocess) (let* ((status (subprocess-wait subprocess)) (exit-reason (subprocess-exit-reason subprocess))) (cons status exit-reason))) More precisely, SUBPROCESS-WAIT* (1) waits until the subprocess's status is not RUNNING, and then (2) returns both the status and the exit reason associated with that status. This idiom doesn't work as written, though. Consider a process that stops, is continued, and then exits normally. But before it exits, another Scheme thread reads its status, thereby updating its exit reason. Then although we may see its status as STOPPED when calling SUBPROCESS-WAIT*, SUBPROCESS-EXIT-REASON may yield its return value -- not the signal by which it was stopped. (let ((subprocess (start-pipe-subprocess "/bin/sh" '#("/bin/sh" "-c" "kill -STOP $$; exit 1") '#()))) (sleep-current-thread 1000) (let ((status (subprocess-wait subprocess))) (pp (subprocess-id subprocess)) ;; *** (create-thread #f (lambda () (sleep-current-thread 5000) (subprocess-status subprocess))) (sleep-current-thread 10000) (cons status (subprocess-exit-reason subprocess)))) If, at the line marked `;; ***', I open up a shell and `kill -CONT' the subprocess (within the five second window), this reliably yields (STOPPED . 1), but in this case, SUBPROCESS-WAIT* should return only either (EXITED . 1) or (STOPPED . n), where n is the value of SIGSTOP on your favourite Unix system (usually not 1). The closest I can get with the built-in operations is the following, but it has the problem described in the comment marked `;; ***'. (define (subprocess-wait* subprocess) (let wait-loop () (subprocess-wait subprocess) (let tick-loop ((tick (subprocess-status-tick subprocess))) (let ((status (subprocess-status subprocess))) (case status ((RUNNING) ;; *** We know we have lost information: SUBPROCESS-WAIT ;; told us, by returning, that the process had a status ;; other than RUNNING, together with an exit reason which we ;; can no longer know. (wait-loop)) ((EXITED SIGNALLED) ;; No race condition for these cases: the process's exit ;; reason will never change. (cons status (subprocess-exit-reason subprocess))) ((STOPPED) (let ((exit-reason (subprocess-exit-reason subprocess))) (let ((tick* (subprocess-status-tick subprocess))) (if (eq? tick* tick) (cons 'STOPPED exit-reason) (tick-loop tick*))))) (else (error "Invalid subprocess status:" status))))))) One straightforward answer is `don't operate on subprocesses in another thread', but I don't think that's a very good answer, particularly in the context surrounding this problem. However, that context would require another mail as long as this one. Perhaps SUBPROCESS-WAIT* should be built-in to runtime/process.scm, and hooked into the logic inside %SUBPROCESS-STATUS. I'd also like it if SIGNAL-IO-THREAD-EVENTS delivered all I/O thread events registered for process status changes, rather than delivering only the first one -- especially since one cannot register an I/O thread event for a particular process's status changes. But maybe it would be better just to rewrite the I/O thread event registry altogether. _______________________________________________ MIT-Scheme-devel mailing list MIT-Scheme-devel@gnu.org http://lists.gnu.org/mailman/listinfo/mit-scheme-devel