From 40676067383d8fef9cc1690154011708c7e8e256 Mon Sep 17 00:00:00 2001 From: Mark H Weaver Date: Sun, 17 Nov 2013 02:54:31 -0500 Subject: [PATCH 6/6] Make (ice-9 popen) thread-safe. * module/ice-9/popen.scm: Import (ice-9 threads). (port/pid-table): Mark as deprecated in comment. (port/pid-table-mutex): New variable. (open-pipe*): Stash the pid in the port's alist. Lock 'port/pid-table-mutex' while mutating 'port/pid-table'. (fetch-pid): Fetch the pid from the port's alist. Don't touch 'port/pid-table'. (close-process-quietly): Don't add the port to 'port/pid-table-mutex', since it was never removed. (close-pipe): Improve error message. (reap-pipes): Check to see if the port is already closed. --- module/ice-9/popen.scm | 27 +++++++++++++++++---------- 1 files changed, 17 insertions(+), 10 deletions(-) diff --git a/module/ice-9/popen.scm b/module/ice-9/popen.scm index f8668cd..0e896d7 100644 --- a/module/ice-9/popen.scm +++ b/module/ice-9/popen.scm @@ -18,6 +18,7 @@ ;;;; (define-module (ice-9 popen) + :use-module (ice-9 threads) :export (port/pid-table open-pipe* open-pipe close-pipe open-input-pipe open-output-pipe open-input-output-pipe)) @@ -40,7 +41,10 @@ (define pipe-guardian (make-guardian)) ;; a weak hash-table to store the process ids. +;; XXX use of this table is deprecated. It is no longer used, and is +;; populated only for backward compatibility (since it is exported). (define port/pid-table (make-weak-key-hash-table 31)) +(define port/pid-table-mutex (make-mutex)) (define (open-pipe* mode command . args) "Executes the program @var{command} with optional arguments @@ -57,8 +61,13 @@ port to the process is created: it should be the value of read-port write-port (%make-void-port mode)))) + (%set-port-alist! port (acons 'popen-pid pid (%port-alist port))) (pipe-guardian port) - (hashq-set! port/pid-table port pid) + + ;; XXX populate port/pid-table for backward compatibility. + (with-mutex port/pid-table-mutex + (hashq-set! port/pid-table port pid)) + port)))) (define (open-pipe command mode) @@ -70,9 +79,7 @@ port to the process is created: it should be the value of (open-pipe* mode "/bin/sh" "-c" command)) (define (fetch-pid port) - (let ((pid (hashq-ref port/pid-table port))) - (hashq-remove! port/pid-table port) - pid)) + (assq-ref (%port-alist port) 'popen-pid)) (define (close-process port pid) (close-port port) @@ -92,8 +99,7 @@ port to the process is created: it should be the value of (let ((pid/status (waitpid pid WNOHANG))) (when (zero? (car pid/status)) ;; not ready for collection - (pipe-guardian port) - (hashq-set! port/pid-table port pid)))) + (pipe-guardian port)))) (lambda args #f))) (define (close-pipe p) @@ -101,16 +107,17 @@ port to the process is created: it should be the value of to terminate and returns its status value, @xref{Processes, waitpid}, for information on how to interpret this value." (let ((pid (fetch-pid p))) - (unless pid (error "close-pipe: pipe not in table")) + (unless pid (error "close-pipe: pipe not created by (ice-9 popen)")) (close-process p pid))) (define (reap-pipes) (let loop () (let ((p (pipe-guardian))) (when p - ;; maybe removed already by close-pipe. - (let ((pid (fetch-pid p))) - (when pid (close-process-quietly p pid))) + ;; maybe closed already. + (unless (port-closed? p) + (let ((pid (fetch-pid p))) + (when pid (close-process-quietly p pid)))) (loop))))) (add-hook! after-gc-hook reap-pipes) -- 1.7.5.4