diff options
author | Chet Ramey <chet.ramey@case.edu> | 2011-12-07 09:25:28 -0500 |
---|---|---|
committer | Chet Ramey <chet.ramey@case.edu> | 2011-12-07 09:25:28 -0500 |
commit | 09767ff09d0d1c3202881d3a09325f5ddbfceb1b (patch) | |
tree | b16d7697c61c9689a7b63ba2e2239844d3e4c230 /execute_cmd.c | |
parent | fdf670eaa19e905943e34b770824faa76e94032c (diff) | |
download | bash-09767ff09d0d1c3202881d3a09325f5ddbfceb1b.tar.gz |
commit bash-20080703 snapshot
Diffstat (limited to 'execute_cmd.c')
-rw-r--r-- | execute_cmd.c | 330 |
1 files changed, 327 insertions, 3 deletions
diff --git a/execute_cmd.c b/execute_cmd.c index f8a4ea09..27f7047c 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -181,6 +181,9 @@ static void execute_disk_command __P((WORD_LIST *, REDIRECT *, char *, static char *getinterp __P((char *, int, int *)); static void initialize_subshell __P((void)); static int execute_in_subshell __P((COMMAND *, int, int, int, struct fd_bitmap *)); +#if defined (COPROCESS_SUPPORT) +static int execute_coproc __P((COMMAND *, int, int, struct fd_bitmap *)); +#endif static int execute_pipeline __P((COMMAND *, int, int, int, struct fd_bitmap *)); @@ -540,6 +543,11 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, if (command->type == cm_subshell && (command->flags & CMD_NO_FORK)) return (execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close)); +#if defined (COPROCESS_SUPPORT) + if (command->type == cm_coproc) + return (execute_coproc (command, pipe_in, pipe_out, fds_to_close)); +#endif + if (command->type == cm_subshell || (command->flags & (CMD_WANT_SUBSHELL|CMD_FORCE_SUBSHELL)) || (shell_control_structure (command->type) && @@ -1199,10 +1207,11 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close) struct fd_bitmap *fds_to_close; { int user_subshell, return_code, function_value, should_redir_stdin, invert; - int ois; + int ois, user_coproc; COMMAND *tcom; USE_VAR(user_subshell); + USE_VAR(user_coproc); USE_VAR(invert); USE_VAR(tcom); USE_VAR(asynchronous); @@ -1214,6 +1223,7 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close) invert = (command->flags & CMD_INVERT_RETURN) != 0; user_subshell = command->type == cm_subshell || ((command->flags & CMD_WANT_SUBSHELL) != 0); + user_coproc = command->type == cm_coproc; command->flags &= ~(CMD_FORCE_SUBSHELL | CMD_WANT_SUBSHELL | CMD_INVERT_RETURN); @@ -1266,6 +1276,8 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close) subshell_environment |= SUBSHELL_ASYNC; if (pipe_in != NO_PIPE || pipe_out != NO_PIPE) subshell_environment |= SUBSHELL_PIPE; + if (user_coproc) + subshell_environment |= SUBSHELL_COPROC; } reset_terminating_signals (); /* in sig.c */ @@ -1299,6 +1311,10 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close) do_piping (pipe_in, pipe_out); +#if defined (COPROCESS_SUPPORT) + coproc_close (&sh_coproc); +#endif + /* If this is a user subshell, set a flag if stdin was redirected. This is used later to decide whether to redirect fd 0 to /dev/null for async commands in the subshell. This adds more @@ -1325,7 +1341,12 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close) command->redirects = (REDIRECT *)NULL; } - tcom = (command->type == cm_subshell) ? command->value.Subshell->command : command; + if (command->type == cm_subshell) + tcom = command->value.Subshell->command; + else if (user_coproc) + tcom = command->value.Coproc->command; + else + tcom = command; if (command->flags & CMD_TIME_PIPELINE) tcom->flags |= CMD_TIME_PIPELINE; @@ -1341,7 +1362,7 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close) This means things like ( sleep 10 ) will only cause one fork. If we're timing the command or inverting its return value, however, we cannot do this optimization. */ - if (user_subshell && (tcom->type == cm_simple || tcom->type == cm_subshell) && + if ((user_subshell || user_coproc) && (tcom->type == cm_simple || tcom->type == cm_subshell) && ((tcom->flags & CMD_TIME_PIPELINE) == 0) && ((tcom->flags & CMD_INVERT_RETURN) == 0)) { @@ -1382,6 +1403,302 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close) /* NOTREACHED */ } +#if defined (COPROCESS_SUPPORT) +Coproc sh_coproc = { 0, NO_PID, -1, -1, 0, 0 }; + +/* These currently use a single global "shell coproc" but are written in a + way to not preclude additional coprocs later */ + +struct coproc * +getcoprocbypid (pid) + pid_t pid; +{ + return (pid == sh_coproc.c_pid ? &sh_coproc : 0); +} + +struct coproc * +getcoprocbyname (name) + const char *name; +{ + return ((sh_coproc.c_name && STREQ (sh_coproc.c_name, name)) ? &sh_coproc : 0); +} + +void +coproc_init (cp) + struct coproc *cp; +{ + cp->c_name = 0; + cp->c_pid = NO_PID; + cp->c_rfd = cp->c_wfd = -1; + cp->c_rsave = cp->c_wsave = -1; + cp->c_flags = cp->c_status = 0; +} + +struct coproc * +coproc_alloc (name, pid) + char *name; + pid_t pid; +{ + struct coproc *cp; + + cp = &sh_coproc; + coproc_init (cp); + + cp->c_name = savestring (name); + cp->c_pid = pid; + + return (cp); +} + +void +coproc_dispose (cp) + struct coproc *cp; +{ + if (cp == 0) + return; + + coproc_unsetvars (cp); + FREE (cp->c_name); + coproc_close (cp); + coproc_init (cp); +} + +void +coproc_close (cp) + struct coproc *cp; +{ + if (cp->c_rfd >= 0) + { + close (cp->c_rfd); + cp->c_rfd = -1; + } + if (cp->c_wfd >= 0) + { + close (cp->c_wfd); + cp->c_wfd = -1; + } + cp->c_rsave = cp->c_wsave = -1; +} + +void +coproc_rclose (cp, fd) + struct coproc *cp; + int fd; +{ + if (cp->c_rfd >= 0 && cp->c_rfd == fd) + { + close (cp->c_rfd); + cp->c_rfd = -1; + } +} + +void +coproc_wclose (cp, fd) + struct coproc *cp; + int fd; +{ + if (cp->c_wfd >= 0 && cp->c_wfd == fd) + { + close (cp->c_wfd); + cp->c_wfd = -1; + } +} + +void +coproc_fdchk (cp, fd) + struct coproc *cp; + int fd; +{ + int update; + + update = 0; + if (cp->c_rfd >= 0 && cp->c_rfd == fd) + update = cp->c_rfd = -1; + if (cp->c_wfd >= 0 && cp->c_wfd == fd) + update = cp->c_wfd = -1; + if (update) + coproc_setvars (cp); +} + +void +coproc_fdclose (cp, fd) + struct coproc *cp; + int fd; +{ + coproc_rclose (cp, fd); + coproc_wclose (cp, fd); + coproc_setvars (cp); +} + + +void +coproc_fdsave (cp) + struct coproc *cp; +{ + cp->c_rsave = cp->c_rfd; + cp->c_wsave = cp->c_wfd; +} + +void +coproc_fdrestore (cp) + struct coproc *cp; +{ + cp->c_rfd = cp->c_rsave; + cp->c_wfd = cp->c_wsave; +} + +void +coproc_pidchk (pid) + pid_t pid; +{ + struct coproc *cp; + + cp = getcoprocbypid (pid); + if (cp) + coproc_dispose (cp); +} + +void +coproc_setvars (cp) + struct coproc *cp; +{ + SHELL_VAR *v; + char *namevar, *t; + int l; +#if defined (ARRAY_VARS) + arrayind_t ind; +#endif + + if (cp->c_name == 0) + return; + + l = strlen (cp->c_name); + namevar = xmalloc (l + 16); + +#if defined (ARRAY_VARS) + v = find_variable (cp->c_name); + if (v == 0) + v = make_new_array_variable (cp->c_name); + if (array_p (v) == 0) + v = convert_var_to_array (v); + + t = itos (cp->c_rfd); + ind = 0; + v = bind_array_variable (cp->c_name, ind, t, 0); + free (t); + + t = itos (cp->c_wfd); + ind = 1; + bind_array_variable (cp->c_name, ind, t, 0); + free (t); +#else + sprintf (namevar, "%s_READ", cp->c_name); + t = itos (cp->c_rfd); + bind_variable (namevar, t, 0); + free (t); + sprintf (namevar, "%s_WRITE", cp->c_name); + t = itos (cp->c_wfd); + bind_variable (namevar, t, 0); + free (t); +#endif + + sprintf (namevar, "%s_PID", cp->c_name); + t = itos (cp->c_pid); + bind_variable (namevar, t, 0); + free (t); + + free (namevar); +} + +void +coproc_unsetvars (cp) + struct coproc *cp; +{ + int l; + char *namevar; + + if (cp->c_name == 0) + return; + + l = strlen (cp->c_name); + namevar = xmalloc (l + 16); + + sprintf (namevar, "%s_PID", cp->c_name); + unbind_variable (namevar); + +#if defined (ARRAY_VARS) + unbind_variable (cp->c_name); +#else + sprintf (namevar, "%s_READ", cp->c_name); + unbind_variable (namevar); + sprintf (namevar, "%s_WRITE", cp->c_name); + unbind_variable (namevar); +#endif + + free (namevar); +} + +static int +execute_coproc (command, pipe_in, pipe_out, fds_to_close) + COMMAND *command; + int pipe_in, pipe_out; + struct fd_bitmap *fds_to_close; +{ + int rpipe[2], wpipe[2]; + pid_t coproc_pid; + Coproc *cp; + char *tcmd; + + if (sh_coproc.c_pid != -1) + { + internal_error ("execute_coproc: coproc [%d:%s] already exists", sh_coproc.c_pid, sh_coproc.c_name); + return (last_command_exit_value = EXECUTION_FAILURE); + } + coproc_init (&sh_coproc); + + command_string_index = 0; + tcmd = make_command_string (command); + + sh_openpipe ((int *)&rpipe); /* 0 = parent read, 1 = child write */ + sh_openpipe ((int *)&wpipe); /* 0 = child read, 1 = parent write */ + + coproc_pid = make_child (savestring (tcmd), 1); + if (coproc_pid == 0) + { + close (rpipe[0]); + close (wpipe[1]); + + exit (execute_in_subshell (command, 1, wpipe[0], rpipe[1], fds_to_close)); + } + + close (rpipe[1]); + close (wpipe[0]); + + cp = coproc_alloc (command->value.Coproc->name, coproc_pid); + cp->c_rfd = rpipe[0]; + cp->c_wfd = wpipe[1]; + + SET_CLOSE_ON_EXEC (cp->c_rfd); + SET_CLOSE_ON_EXEC (cp->c_wfd); + + coproc_setvars (cp); + +#if defined (DEBUG) + itrace ("execute_coproc: [%d] %s", coproc_pid, the_printed_command); +#endif + + close_pipes (pipe_in, pipe_out); +#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) + unlink_fifo_list (); +#endif + stop_pipeline (1, (COMMAND *)NULL); + DESCRIBE_PID (coproc_pid); + run_pending_traps (); + + return (EXECUTION_SUCCESS); +} +#endif + static int execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close) COMMAND *command; @@ -2692,6 +3009,10 @@ execute_null_command (redirects, pipe_in, pipe_out, async) do_piping (pipe_in, pipe_out); +#if defined (COPROCESS_SUPPORT) + coproc_close (&sh_coproc); +#endif + subshell_environment = 0; if (async) subshell_environment |= SUBSHELL_ASYNC; @@ -2894,6 +3215,9 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) do_piping (pipe_in, pipe_out); pipe_in = pipe_out = NO_PIPE; +#if defined (COPROCESS_SUPPORT) + coproc_close (&sh_coproc); +#endif last_asynchronous_pid = old_last_async_pid; } |