From 47bc44daa0ae321942884693b7c2268caa486feb Mon Sep 17 00:00:00 2001 From: Juanjo Garcia-Ripoll Date: Thu, 26 Apr 2012 16:16:05 +0200 Subject: [PATCH] In EXT:RUN-PROGRAM, synchronize the child so that it waits until the parent has set up the process structure. --- src/CHANGELOG | 4 ++++ src/c/unixsys.d | 31 ++++++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/CHANGELOG b/src/CHANGELOG index f68fad7e8..1b4777c0c 100755 --- a/src/CHANGELOG +++ b/src/CHANGELOG @@ -31,6 +31,10 @@ ECL 12.2.2: - ENSURE-DIRECTORIES-EXIST accepts the keyword argument :MODE which is passed to MKDIR. + - In EXT:RUN-PROGRAM the child process is delayed until the parent has created + the process structure and stored the process id in it. Formerly we had race + conditions due to the child exiting before the parent was able to call sigwait(). + * Metaobject protocol: - Implemented CLOS:COMPUTE-APPLICABLE-METHODS-USING-CLASSES. diff --git a/src/c/unixsys.d b/src/c/unixsys.d index 272dc12e5..c240a2440 100755 --- a/src/c/unixsys.d +++ b/src/c/unixsys.d @@ -623,6 +623,7 @@ make_windows_handle(HANDLE h) #else /* mingw */ { int child_stdin, child_stdout, child_stderr; + int pipe_fd[2]; argv = CONS(command, ecl_nconc(argv, ecl_list1(Cnil))); argv = cl_funcall(3, @'coerce', argv, @'vector'); AGAIN_INPUT: @@ -701,14 +702,22 @@ make_windows_handle(HANDLE h) error); } add_external_process(the_env, process); - /* We have to protect this, to avoid the signal being delivered or handled - * before we set the process pid */ - ecl_bds_bind(the_env, @'ext::*interrupts-enabled*', Cnil); + pipe(pipe_fd); child_pid = fork(); if (child_pid == 0) { /* Child */ int j; void **argv_ptr = (void **)argv->vector.self.t; + { + /* Wait for the parent to set up its process structure */ + char sync[1]; + close(pipe_fd[1]); + while (read(pipe_fd[0], sync, 1) < 1) { + printf("\nError reading child pipe %d", errno); + fflush(stdout); + } + close(pipe_fd[0]); + } dup2(child_stdin, STDIN_FILENO); if (parent_write) close(parent_write); dup2(child_stdout, STDOUT_FILENO); @@ -740,8 +749,20 @@ make_windows_handle(HANDLE h) pid = MAKE_FIXNUM(child_pid); } set_external_process_pid(process, pid); - ecl_bds_unwind1(the_env); - ecl_check_pending_interrupts(the_env); + { + /* This guarantees that the child process does not exit + * before we have created the process structure. If we do not + * do this, the SIGPIPE signal may arrive before + * set_external_process_pid() and our call to external-process-wait + * down there may block indefinitely. */ + char sync[1]; + close(pipe_fd[0]); + while (write(pipe_fd[1], sync, 1) < 1) { + printf("\nError writing child pipe %d", errno); + fflush(stdout); + } + close(pipe_fd[1]); + } close(child_stdin); close(child_stdout); close(child_stderr);