summaryrefslogtreecommitdiff
path: root/execute_cmd.c
diff options
context:
space:
mode:
authorChet Ramey <chet.ramey@case.edu>2011-12-07 09:25:28 -0500
committerChet Ramey <chet.ramey@case.edu>2011-12-07 09:25:28 -0500
commit09767ff09d0d1c3202881d3a09325f5ddbfceb1b (patch)
treeb16d7697c61c9689a7b63ba2e2239844d3e4c230 /execute_cmd.c
parentfdf670eaa19e905943e34b770824faa76e94032c (diff)
downloadbash-09767ff09d0d1c3202881d3a09325f5ddbfceb1b.tar.gz
commit bash-20080703 snapshot
Diffstat (limited to 'execute_cmd.c')
-rw-r--r--execute_cmd.c330
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;
}