]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gdb/ChangeLog:
authorJim Blandy <jimb@codesourcery.com>
Fri, 17 Mar 2006 20:36:14 +0000 (20:36 +0000)
committerJim Blandy <jimb@codesourcery.com>
Fri, 17 Mar 2006 20:36:14 +0000 (20:36 +0000)
2006-03-17  Jim Blandy  <jimb@codesourcery.com>

Add support for 'target remote |' on MinGW.
* ser-mingw.c (struct pipe_state): New structure.
(make_pipe_state, free_pipe_state, cleanup_pipe_state)
(pipe_windows_open, pipe_windows_close, pipe_windows_read)
(pipe_windows_write, pipe_wait_handle): New functions.
(_initialize_ser_windows): Register a "pipe" interface based on
them.

include/ChangeLog:
2006-03-15  Jim Blandy  <jimb@codesourcery.com>

* libiberty.h (pex_write_input): New declaration.

libiberty/ChangeLog:
2006-03-15  Jim Blandy  <jimb@codesourcery.com>

* pex-common.c (pex_write_input): New function.
* pexecute.txh (pex_write_input): Document it.
* pex-common.h (struct pex_funcs): New function ptr fdopenw.
* pex-unix.c (pex_unix_fdopenw): New function.
(funcs): List it as our fdopenw function.
* pex-win32.c (pex_win32_fdopenw): New function.
(funcs): List it as our fdopenw function.
* pex-djgpp.c (funcs): Leave fdopenw null.
* pex-msdos (funcs): Same.
* functions.texi: Regenerated.

2006-03-12  Jim Blandy  <jimb@red-bean.com>

* pex-common.h (struct pex_obj): Doc fixes.

2006-03-11  Jim Blandy  <jimb@red-bean.com>

* functions.texi: Regenerate.

13 files changed:
gdb/ChangeLog
gdb/ser-mingw.c
include/ChangeLog
include/libiberty.h
libiberty/ChangeLog
libiberty/functions.texi
libiberty/pex-common.c
libiberty/pex-common.h
libiberty/pex-djgpp.c
libiberty/pex-msdos.c
libiberty/pex-unix.c
libiberty/pex-win32.c
libiberty/pexecute.txh

index 34b1c6cf046bbcdbde280185b9c409605174b24f..0cbace82b4489f1bfe2fe236fbdb62c211882e1c 100644 (file)
@@ -1,3 +1,13 @@
+2006-03-17  Jim Blandy  <jimb@codesourcery.com>
+
+       Add support for 'target remote |' on MinGW.
+       * ser-mingw.c (struct pipe_state): New structure.
+       (make_pipe_state, free_pipe_state, cleanup_pipe_state)
+       (pipe_windows_open, pipe_windows_close, pipe_windows_read)
+       (pipe_windows_write, pipe_wait_handle): New functions.
+       (_initialize_ser_windows): Register a "pipe" interface based on
+       them.
+
 2006-02-26  Mark Kettenis  <kettenis@gnu.org>
 
        * i386obsd-tdep.c (i386obsd_trapframe_sniffer): Also recognize
index 7a6f232379ec78a6894c405a7892a2230a0295b8..5d0c0733b5766f27fe15f1b3f1f8bd124aedc6d3 100644 (file)
@@ -571,6 +571,214 @@ ser_console_get_tty_state (struct serial *scb)
     return NULL;
 }
 
+struct pipe_state
+{
+  /* Since we use the pipe_select_thread for our select emulation,
+     we need to place the state structure it requires at the front
+     of our state.  */
+  struct ser_console_state wait;
+
+  /* The pex obj for our (one-stage) pipeline.  */
+  struct pex_obj *pex;
+
+  /* Streams for the pipeline's input and output.  */
+  FILE *input, *output;
+};
+
+static struct pipe_state *
+make_pipe_state (void)
+{
+  struct pipe_state *ps = XMALLOC (struct pipe_state);
+
+  memset (ps, 0, sizeof (*ps));
+  ps->wait.read_event = INVALID_HANDLE_VALUE;
+  ps->wait.except_event = INVALID_HANDLE_VALUE;
+  ps->wait.start_select = INVALID_HANDLE_VALUE;
+  ps->wait.stop_select = INVALID_HANDLE_VALUE;
+
+  return ps;
+}
+
+static void
+free_pipe_state (struct pipe_state *ps)
+{
+  int saved_errno = errno;
+
+  if (ps->wait.read_event != INVALID_HANDLE_VALUE)
+    CloseHandle (ps->wait.read_event);
+  if (ps->wait.except_event != INVALID_HANDLE_VALUE)
+    CloseHandle (ps->wait.except_event);
+  if (ps->wait.start_select != INVALID_HANDLE_VALUE)
+    CloseHandle (ps->wait.start_select);
+
+  /* If we have a select thread running, let the select thread free
+     the stop event.  */
+  if (ps->wait.stop_select != INVALID_HANDLE_VALUE)
+    SetEvent (ps->wait.stop_select);
+
+  if (ps->pex)
+    pex_free (ps->pex);
+  if (ps->input)
+    fclose (ps->input);
+  /* pex_free closes ps->output.  */
+
+  xfree (ps);
+
+  errno = saved_errno;
+}
+
+static void
+cleanup_pipe_state (void *untyped)
+{
+  struct pipe_state *ps = untyped;
+
+  free_pipe_state (ps);
+}
+
+static int
+pipe_windows_open (struct serial *scb, const char *name)
+{
+  char **argv = buildargv (name);
+  struct cleanup *back_to = make_cleanup_freeargv (argv);
+  if (! argv[0] || argv[0][0] == '\0')
+    error ("missing child command");
+
+  struct pipe_state *ps = make_pipe_state ();
+  make_cleanup (cleanup_pipe_state, ps);
+
+  ps->pex = pex_init (PEX_USE_PIPES, "target remote pipe", NULL);
+  if (! ps->pex)
+    goto fail;
+  ps->input = pex_write_input (ps->pex, 1);
+  if (! ps->input)
+    goto fail;
+
+  {
+    int err;
+    const char *err_msg
+      = pex_run (ps->pex, PEX_SEARCH | PEX_BINARY_INPUT | PEX_BINARY_OUTPUT,
+                 argv[0], argv, NULL, NULL,
+                 &err);
+
+    if (err_msg)
+      {
+        /* Our caller expects us to return -1, but all they'll do with
+           it generally is print the message based on errno.  We have
+           all the same information here, plus err_msg provided by
+           pex_run, so we just raise the error here.  */
+        if (err)
+          error ("error starting child process '%s': %s: %s",
+                 name, err_msg, safe_strerror (err));
+        else
+          error ("error starting child process '%s': %s",
+                 name, err_msg);
+      }
+  }
+
+  ps->output = pex_read_output (ps->pex, 1);
+  if (! ps->output)
+    goto fail;
+
+  scb->fd = fileno (ps->output);
+  scb->state = (void *) ps;
+
+  discard_cleanups (back_to);
+  return 0;
+
+ fail:
+  do_cleanups (back_to);
+  return -1;
+}
+
+
+static void
+pipe_windows_close (struct serial *scb)
+{
+  struct pipe_state *ps = scb->state;
+
+  /* In theory, we should try to kill the subprocess here, but the pex
+     interface doesn't give us enough information to do that.  Usually
+     closing the input pipe will get the message across.  */
+
+  free_pipe_state (ps);
+}
+
+
+static int
+pipe_windows_read (struct serial *scb, size_t count)
+{
+  HANDLE pipeline_out = (HANDLE) _get_osfhandle (scb->fd);
+  if (pipeline_out == INVALID_HANDLE_VALUE)
+    return -1;
+
+  DWORD available;
+  if (! PeekNamedPipe (pipeline_out, NULL, 0, NULL, &available, NULL))
+    return -1;
+
+  if (count > available)
+    count = available;
+
+  DWORD bytes_read;
+  if (! ReadFile (pipeline_out, scb->buf, count, &bytes_read, NULL))
+    return -1;
+
+  return bytes_read;
+}
+
+
+static int
+pipe_windows_write (struct serial *scb, const void *buf, size_t count)
+{
+  struct pipe_state *ps = scb->state;
+  int pipeline_in_fd = fileno (ps->input);
+  if (pipeline_in_fd < 0)
+    return -1;
+
+  HANDLE pipeline_in = (HANDLE) _get_osfhandle (pipeline_in_fd);
+  if (pipeline_in == INVALID_HANDLE_VALUE)
+    return -1;
+
+  DWORD written;
+  if (! WriteFile (pipeline_in, buf, count, &written, NULL))
+    return -1;
+
+  return written;
+}
+
+
+static void
+pipe_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except)
+{
+  struct pipe_state *ps = scb->state;
+
+  /* Have we allocated our events yet?  */
+  if (ps->wait.read_event == INVALID_HANDLE_VALUE)
+    {
+      DWORD threadId;
+
+      /* Create auto reset events to wake and terminate the select thread.  */
+      ps->wait.start_select = CreateEvent (0, FALSE, FALSE, 0);
+      ps->wait.stop_select = CreateEvent (0, FALSE, FALSE, 0);
+
+      /* Create our own events to report read and exceptions separately.
+        The exception event is currently never used.  */
+      ps->wait.read_event = CreateEvent (0, FALSE, FALSE, 0);
+      ps->wait.except_event = CreateEvent (0, FALSE, FALSE, 0);
+
+      /* Start the select thread.  */
+      CreateThread (NULL, 0, pipe_select_thread, scb, 0, &threadId);
+    }
+
+  ResetEvent (ps->wait.read_event);
+  ResetEvent (ps->wait.except_event);
+
+  SetEvent (ps->wait.start_select);
+
+  *read = ps->wait.read_event;
+  *except = ps->wait.except_event;
+}
+
+
 struct net_windows_state
 {
   HANDLE read_event;
@@ -763,6 +971,34 @@ _initialize_ser_windows (void)
 
   serial_add_interface (ops);
 
+  /* The pipe interface.  */
+
+  ops = XMALLOC (struct serial_ops);
+  memset (ops, 0, sizeof (struct serial_ops));
+  ops->name = "pipe";
+  ops->next = 0;
+  ops->open = pipe_windows_open;
+  ops->close = pipe_windows_close;
+  ops->readchar = ser_base_readchar;
+  ops->write = ser_base_write;
+  ops->flush_output = ser_base_flush_output;
+  ops->flush_input = ser_base_flush_input;
+  ops->send_break = ser_base_send_break;
+  ops->go_raw = ser_base_raw;
+  ops->get_tty_state = ser_base_get_tty_state;
+  ops->set_tty_state = ser_base_set_tty_state;
+  ops->print_tty_state = ser_base_print_tty_state;
+  ops->noflush_set_tty_state = ser_base_noflush_set_tty_state;
+  ops->setbaudrate = ser_base_setbaudrate;
+  ops->setstopbits = ser_base_setstopbits;
+  ops->drain_output = ser_base_drain_output;
+  ops->async = ser_base_async;
+  ops->read_prim = pipe_windows_read;
+  ops->write_prim = pipe_windows_write;
+  ops->wait_handle = pipe_wait_handle;
+
+  serial_add_interface (ops);
+
   /* If WinSock works, register the TCP/UDP socket driver.  */
 
   if (WSAStartup (MAKEWORD (1, 0), &wsa_data) != 0)
index 3c6907f56dc7b71298aba31c5a3246bfe849e38f..f0bc4b37be112796edda3133c7654703ebdfc3d5 100644 (file)
@@ -1,3 +1,7 @@
+2006-03-15  Jim Blandy  <jimb@codesourcery.com>
+
+       * libiberty.h (pex_write_input): New declaration.
+
 2006-02-17  Shrirang Khisti  <shrirangk@kpitcummins.com>
             Anil Paranjape   <anilp1@kpitcummins.com>
             Shilin Shakti    <shilins@kpitcummins.com>
index c264cb2ab0ee0df21284133adda17ad30743bcdb..6fdc6e9d0c819fd2534d5a3d3173e0fe98131001 100644 (file)
@@ -448,6 +448,33 @@ extern const char *pex_run (struct pex_obj *obj, int flags,
                            const char *outname, const char *errname,
                            int *err);
 
+/* Return a `FILE' pointer FP for the standard input of the first
+   program in the pipeline; FP is opened for writing.  You must have
+   passed `PEX_USE_PIPES' to the `pex_init' call that returned OBJ.
+   You must close FP yourself with `fclose' to indicate that the
+   pipeline's input is complete.
+
+   The file descriptor underlying FP is marked not to be inherited by
+   child processes.
+
+   This call is not supported on systems which do not support pipes;
+   it returns with an error.  (We could implement it by writing a
+   temporary file, but then you would need to write all your data and
+   close FP before your first call to `pex_run' -- and that wouldn't
+   work on systems that do support pipes: the pipe would fill up, and
+   you would block.  So there isn't any easy way to conceal the
+   differences between the two types of systems.)
+
+   If you call both `pex_write_input' and `pex_read_output', be
+   careful to avoid deadlock.  If the output pipe fills up, so that
+   each program in the pipeline is waiting for the next to read more
+   data, and you fill the input pipe by writing more data to FP, then
+   there is no way to make progress: the only process that could read
+   data from the output pipe is you, but you are blocked on the input
+   pipe.  */
+
+extern FILE *pex_write_input (struct pex_obj *obj, int binary);
+
 /* Read the standard output of the last program to be executed.
    pex_run can not be called after this.  BINARY should be non-zero if
    the file should be opened in binary mode; this is ignored on Unix.
index acdfad0657f583dd41622b10254dd7b69778db6a..549e9b6609fec0ec1555f12ea942999fc6d0c473 100644 (file)
@@ -1,3 +1,24 @@
+2006-03-15  Jim Blandy  <jimb@codesourcery.com>
+
+       * pex-common.c (pex_write_input): New function.
+       * pexecute.txh (pex_write_input): Document it.
+       * pex-common.h (struct pex_funcs): New function ptr fdopenw.
+       * pex-unix.c (pex_unix_fdopenw): New function.
+       (funcs): List it as our fdopenw function.
+       * pex-win32.c (pex_win32_fdopenw): New function.
+       (funcs): List it as our fdopenw function.
+       * pex-djgpp.c (funcs): Leave fdopenw null.
+       * pex-msdos (funcs): Same.
+       * functions.texi: Regenerated.
+
+2006-03-12  Jim Blandy  <jimb@red-bean.com>
+
+       * pex-common.h (struct pex_obj): Doc fixes.
+
+2006-03-11  Jim Blandy  <jimb@red-bean.com>
+
+       * functions.texi: Regenerate.
+
 2006-02-21  Ben Elliston  <bje@au.ibm.com>
 
        * pexecute.c (pwait): Syntax fix for previous change.
index 8b4a50ef45e1a880e5d80f2f80797b7454b39c5b..ab2461dc8d211b26d27de0537ceadc03b78f0f25 100644 (file)
@@ -214,6 +214,26 @@ symbolic name or message.
 
 @end deftypefn
 
+@c argv.c:293
+@deftypefn Extension void expandargv (int *@var{argcp}, char ***@var{argvp})
+
+The @var{argcp} and @code{argvp} arguments are pointers to the usual
+@code{argc} and @code{argv} arguments to @code{main}.  This function
+looks for arguments that begin with the character @samp{@@}.  Any such
+arguments are interpreted as ``response files''.  The contents of the
+response file are interpreted as additional command line options.  In
+particular, the file is separated into whitespace-separated strings;
+each such string is taken as a command-line option.  The new options
+are inserted in place of the option naming the response file, and
+@code{*argcp} and @code{*argvp} will be updated.  If the value of
+@code{*argvp} is modified by this function, then the new value has
+been dynamically allocated and can be deallocated by the caller with
+@code{freeargv}.  However, most callers will simply call
+@code{expandargv} near the beginning of @code{main} and allow the
+operating system to free the memory when the program exits.
+
+@end deftypefn
+
 @c fdmatch.c:23
 @deftypefn Extension int fdmatch (int @var{fd1}, int @var{fd2})
 
@@ -648,14 +668,14 @@ reading and writing.
 
 @end deftypefn
 
-@c pexecute.txh:169
+@c pexecute.txh:198
 @deftypefn Extension void pex_free (struct pex_obj @var{obj})
 
 Clean up and free all data associated with @var{obj}.
 
 @end deftypefn
 
-@c pexecute.txh:144
+@c pexecute.txh:173
 @deftypefn Extension int pex_get_status (struct pex_obj *@var{obj}, int @var{count}, int *@var{vector})
 
 Returns the exit status of all programs run using @var{obj}.
@@ -665,7 +685,7 @@ to @code{pex_run}.  Returns 0 on error, 1 on success.
 
 @end deftypefn
 
-@c pexecute.txh:153
+@c pexecute.txh:182
 @deftypefn Extension int pex_get_times (struct pex_obj *@var{obj}, int @var{count}, struct pex_time *@var{vector})
 
 Returns the process execution times of all programs run using
@@ -682,7 +702,7 @@ process times, all the fields will be set to @code{0}.
 
 @end deftypefn
 
-@c pexecute.txh:1
+@c pexecute.txh:2
 @deftypefn Extension {struct pex_obj *} pex_init (int @var{flags}, const char *@var{pname}, const char *@var{tempbase})
 
 Prepare to execute one or more programs, with standard output of each
@@ -714,7 +734,7 @@ temporary files; it may be @code{NULL} to use a randomly chosen name.
 
 @end deftypefn
 
-@c pexecute.txh:175
+@c pexecute.txh:204
 @deftypefn Extension {const char *} pex_one (int @var{flags}, const char *@var{executable}, char * const *@var{argv}, const char *@var{pname}, const char *@var{outname}, const char *@var{errname}, int *@var{status}, int *@var{err})
 
 An interface to permit the easy execution of a
@@ -727,7 +747,7 @@ be set to the exit status of the program.
 
 @end deftypefn
 
-@c pexecute.txh:132
+@c pexecute.txh:161
 @deftypefn Extension {FILE *} pex_read_output (struct pex_obj *@var{obj}, int @var{binary})
 
 Returns a @code{FILE} pointer which may be used to read the standard
@@ -740,7 +760,7 @@ it will be closed by @code{pex_free}.
 
 @end deftypefn
 
-@c pexecute.txh:32
+@c pexecute.txh:33
 @deftypefn Extension {const char *} pex_run (struct pex_obj *@var{obj}, int @var{flags}, const char *@var{executable}, char * const *@var{argv}, const char *@var{outname}, const char *@var{errname}, int *@var{err})
 
 Execute one program in a pipeline.  On success this returns
@@ -841,7 +861,36 @@ value, or to 0 if there is no relevant @code{errno}.
 
 @end deftypefn
 
-@c pexecute.txh:187
+@c pexecute.txh:133
+@deftypefn Extension {FILE *} pex_write_input (struct pex_obj *@var{obj}, int @var{binary})
+
+Return a @code{FILE} pointer @var{fp} for the standard input of the
+first program in the pipeline; @var{fp} is opened for writing.  You
+must have passed @code{PEX_USE_PIPES} to the @code{pex_init} call that
+returned @var{obj}.  You must close @var{fp} yourself with
+@code{fclose} to indicate that the pipeline's input is complete.
+
+The file descriptor underlying @var{fp} is marked not to be inherited
+by child processes.
+
+This call is not supported on systems which do not support pipes; it
+returns with an error.  (We could implement it by writing a temporary
+file, but then you would need to write all your data and close
+@var{fp} before your first call to @code{pex_run} --- and that
+wouldn't work on systems that do support pipes: the pipe would fill
+up, and you would block.  So there isn't any easy way to conceal the
+differences between the two types of systems.)
+
+If you call both @code{pex_write_input} and @code{pex_read_output}, be
+careful to avoid deadlock.  If the output pipe fills up, so that each
+program in the pipeline is waiting for the next to read more data, and
+you fill the input pipe by writing more data to @var{fp}, then there
+is no way to make progress: the only process that could read data from
+the output pipe is you, but you are blocked on the input pipe.
+
+@end deftypefn
+
+@c pexecute.txh:216
 @deftypefn Extension int pexecute (const char *@var{program}, char * const *@var{argv}, const char *@var{this_pname}, const char *@var{temp_base}, char **@var{errmsg_fmt}, char **@var{errmsg_arg}, int flags)
 
 This is the old interface to execute one or more programs.  It is
@@ -869,7 +918,7 @@ name is unset/removed.
 
 @end deftypefn
 
-@c pexecute.txh:195
+@c pexecute.txh:224
 @deftypefn Extension int pwait (int @var{pid}, int *@var{status}, int @var{flags})
 
 Another part of the old execution interface.
@@ -1194,7 +1243,7 @@ translation is found, returns 0.
 
 @end deftypefn
 
-@c strverscmp.c:24
+@c strverscmp.c:25
 @deftypefun int strverscmp (const char *@var{s1}, const char *@var{s2})
 The @code{strverscmp} function compares the string @var{s1} against
 @var{s2}, considering them as holding indices/version numbers.  Return
index b2ca6e08ce208151554088d44c7b103f5974e839..38e3ac7695648af827f31786979f2233a1495229 100644 (file)
@@ -297,6 +297,52 @@ pex_run (struct pex_obj *obj, int flags, const char *executable,
   return errmsg;
 }
 
+/* Return a FILE pointer for the input of the first program
+   executed.  */
+
+FILE *
+pex_write_input (struct pex_obj *obj, int binary)
+{
+  int p[2];
+  FILE *write_input;
+
+  /* You must call pex_write_input before the first pex_run or pex_one.  */
+  if (obj->count > 0)
+    goto usage_error;
+
+  /* You must be using pipes.  Implementations that don't support
+     pipes clear this flag before calling pex_init_common.  */
+  if (! (obj->flags & PEX_USE_PIPES))
+    goto usage_error;
+
+  /* If we have somehow already selected other input, that's a
+     mistake.  */
+  if ((obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
+      || obj->next_input_name)
+    goto usage_error;
+
+  if (obj->funcs->pipe (obj, p, binary != 0) < 0)
+    return NULL;
+
+  write_input = obj->funcs->fdopenw (obj, p[WRITE_PORT], binary != 0);
+  if (! write_input)
+    {
+      int saved_errno = errno;
+      obj->funcs->close (obj, p[READ_PORT]);
+      obj->funcs->close (obj, p[WRITE_PORT]);
+      errno = saved_errno;
+      return NULL;
+    }
+
+  obj->next_input = p[READ_PORT];
+
+  return write_input;
+
+ usage_error:
+  errno = EINVAL;
+  return NULL;
+}
+
 /* Return a FILE pointer for the output of the last program
    executed.  */
 
index bd4f908769f0808379c5ee4cb8a978767834e10c..13ec98149eaa73e4d403a705e7c85753fbfac5dc 100644 (file)
@@ -61,7 +61,7 @@ struct pex_obj
   int next_input_name_allocated;
   /* Number of child processes.  */
   int count;
-  /* PIDs of child processes; array allocated using maloc.  */
+  /* PIDs of child processes; array allocated using malloc.  */
   long *children;
   /* Exit statuses of child processes; array allocated using malloc.  */
   int *status;
@@ -88,10 +88,11 @@ struct pex_funcs
 {
   /* Open file NAME for reading.  If BINARY is non-zero, open in
      binary mode.  Return >= 0 on success, -1 on error.  */
-  int (*open_read) (struct pex_obj *, const char *name, int binary);
+  int (*open_read) (struct pex_obj *, const char */* name */, int /* binary */);
   /* Open file NAME for writing.  If BINARY is non-zero, open in
      binary mode.  Return >= 0 on success, -1 on error.  */
-  int (*open_write) (struct pex_obj *, const char *name, int binary);
+  int (*open_write) (struct pex_obj *, const char */* name */,
+                     int /* binary */);
   /* Execute a child process.  FLAGS, EXECUTABLE, ARGV, ERR are from
      pex_run.  IN, OUT, ERRDES are each a descriptor, from open_read,
      open_write, or pipe, or they are one of STDIN_FILE_NO,
@@ -99,25 +100,32 @@ struct pex_funcs
      should be closed.  The function should handle the
      PEX_STDERR_TO_STDOUT flag.  Return >= 0 on success, or -1 on
      error and set *ERRMSG and *ERR.  */
-  long (*exec_child) (struct pex_obj *, int flags, const char *executable,
-                     char * const * argv, int in, int out, int errdes,
-                     const char **errmsg, int *err);
+  long (*exec_child) (struct pex_obj *, int /* flags */,
+                      const char */* executable */, char * const * /* argv */,
+                      int /* in */, int /* out */, int /* errdes */,
+                     const char **/* errmsg */, int */* err */);
   /* Close a descriptor.  Return 0 on success, -1 on error.  */
   int (*close) (struct pex_obj *, int);
   /* Wait for a child to complete, returning exit status in *STATUS
      and time in *TIME (if it is not null).  CHILD is from fork.  DONE
      is 1 if this is called via pex_free.  ERRMSG and ERR are as in
      fork.  Return 0 on success, -1 on error.  */
-  int (*wait) (struct pex_obj *, long, int *status, struct pex_time *time,
-              int done, const char **errmsg, int *err);
+  int (*wait) (struct pex_obj *, long /* child */, int * /* status */,
+               struct pex_time * /* time */, int /* done */,
+               const char ** /* errmsg */, int * /* err */);
   /* Create a pipe (only called if PEX_USE_PIPES is set) storing two
-     descriptin in *P.  If BINARY is non-zero, open in binary mode.
-     Return 0 on success, -1 on error.  */
-  int (*pipe) (struct pex_obj *, int *p, int binary);
+     descriptors in P[0] and P[1].  If BINARY is non-zero, open in
+     binary mode.  Return 0 on success, -1 on error.  */
+  int (*pipe) (struct pex_obj *, int * /* p */, int /* binary */);
   /* Get a FILE pointer to read from a file descriptor (only called if
      PEX_USE_PIPES is set).  If BINARY is non-zero, open in binary
      mode.  Return pointer on success, NULL on error.  */
-  FILE * (*fdopenr) (struct pex_obj *, int fd, int binary);
+  FILE * (*fdopenr) (struct pex_obj *, int /* fd */, int /* binary */);
+  /* Get a FILE pointer to write to the file descriptor FD (only
+     called if PEX_USE_PIPES is set).  If BINARY is non-zero, open in
+     binary mode.  Arrange for FD not to be inherited by the child
+     processes.  Return pointer on success, NULL on error.  */
+  FILE * (*fdopenw) (struct pex_obj *, int /* fd */, int /* binary */);
   /* Free any system dependent data associated with OBJ.  May be
      NULL if there is nothing to do.  */
   void (*cleanup) (struct pex_obj *);
index 6e58e3fd8dcc864b975f7d220a5eb57e73a43387..17fbf2cc7e4406205068bbdb68da71dd0e065c47 100644 (file)
@@ -62,6 +62,7 @@ const struct pex_funcs funcs =
   pex_djgpp_wait,
   NULL, /* pipe */
   NULL, /* fdopenr */
+  NULL, /* fdopenw */
   NULL  /* cleanup */
 };
 
index 2256117d1bb0cb7d5d20c1224b01827ee5371023..db22337aa2afcd82fe20c3af5cbbbc76120bdbb6 100644 (file)
@@ -73,6 +73,7 @@ const struct pex_funcs funcs =
   pex_msdos_wait,
   NULL, /* pipe */
   NULL, /* fdopenr */
+  NULL, /* fdopenw */
   pex_msdos_cleanup
 };
 
index 35a545cb17b1dccebf2949472cb75d7df6afd9be..c92a429797128c4ba36aff5676649eeded39da47 100644 (file)
@@ -277,6 +277,7 @@ static int pex_unix_wait (struct pex_obj *, long, int *, struct pex_time *,
                          int, const char **, int *);
 static int pex_unix_pipe (struct pex_obj *, int *, int);
 static FILE *pex_unix_fdopenr (struct pex_obj *, int, int);
+static FILE *pex_unix_fdopenw (struct pex_obj *, int, int);
 static void pex_unix_cleanup (struct pex_obj *);
 
 /* The list of functions we pass to the common routines.  */
@@ -290,6 +291,7 @@ const struct pex_funcs funcs =
   pex_unix_wait,
   pex_unix_pipe,
   pex_unix_fdopenr,
+  pex_unix_fdopenw,
   pex_unix_cleanup
 };
 
@@ -495,6 +497,15 @@ pex_unix_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
   return fdopen (fd, "r");
 }
 
+static FILE *
+pex_unix_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
+                 int binary ATTRIBUTE_UNUSED)
+{
+  if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0)
+    return NULL;
+  return fdopen (fd, "w");
+}
+
 static void
 pex_unix_cleanup (struct pex_obj *obj ATTRIBUTE_UNUSED)
 {
index ed45e5b8bb83a2aa1223873b250c6782498c2bea..221e1b2f095cf062962a43423f5343e14b73524a 100644 (file)
@@ -191,6 +191,7 @@ static int pex_win32_wait (struct pex_obj *, long, int *,
                           struct pex_time *, int, const char **, int *);
 static int pex_win32_pipe (struct pex_obj *, int *, int);
 static FILE *pex_win32_fdopenr (struct pex_obj *, int, int);
+static FILE *pex_win32_fdopenw (struct pex_obj *, int, int);
 
 /* The list of functions we pass to the common routines.  */
 
@@ -203,6 +204,7 @@ const struct pex_funcs funcs =
   pex_win32_wait,
   pex_win32_pipe,
   pex_win32_fdopenr,
+  pex_win32_fdopenw,
   NULL /* cleanup */
 };
 
@@ -702,6 +704,18 @@ pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
   return fdopen (fd, binary ? "rb" : "r");
 }
 
+static FILE *
+pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
+                  int binary)
+{
+  HANDLE h = (HANDLE) _get_osfhandle (fd);
+  if (h == INVALID_HANDLE_VALUE)
+    return NULL;
+  if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
+    return NULL;
+  return fdopen (fd, binary ? "wb" : "w");
+}
+
 #ifdef MAIN
 #include <stdio.h>
 
index 461ff33d018c7ea52ce94933ad81a4fc28f24412..2bfad0c8b751c76d568384789eb44da8b194cb36 100644 (file)
@@ -1,3 +1,4 @@
+@c -*- mode: texinfo -*-
 @deftypefn Extension {struct pex_obj *} pex_init (int @var{flags}, const char *@var{pname}, const char *@var{tempbase})
 
 Prepare to execute one or more programs, with standard output of each
@@ -129,6 +130,34 @@ value, or to 0 if there is no relevant @code{errno}.
 
 @end deftypefn
 
+@deftypefn Extension {FILE *} pex_write_input (struct pex_obj *@var{obj}, int @var{binary})
+
+Return a @code{FILE} pointer @var{fp} for the standard input of the
+first program in the pipeline; @var{fp} is opened for writing.  You
+must have passed @code{PEX_USE_PIPES} to the @code{pex_init} call that
+returned @var{obj}.  You must close @var{fp} yourself with
+@code{fclose} to indicate that the pipeline's input is complete.
+
+The file descriptor underlying @var{fp} is marked not to be inherited
+by child processes.
+
+This call is not supported on systems which do not support pipes; it
+returns with an error.  (We could implement it by writing a temporary
+file, but then you would need to write all your data and close
+@var{fp} before your first call to @code{pex_run} --- and that
+wouldn't work on systems that do support pipes: the pipe would fill
+up, and you would block.  So there isn't any easy way to conceal the
+differences between the two types of systems.)
+
+If you call both @code{pex_write_input} and @code{pex_read_output}, be
+careful to avoid deadlock.  If the output pipe fills up, so that each
+program in the pipeline is waiting for the next to read more data, and
+you fill the input pipe by writing more data to @var{fp}, then there
+is no way to make progress: the only process that could read data from
+the output pipe is you, but you are blocked on the input pipe.
+
+@end deftypefn
+
 @deftypefn Extension {FILE *} pex_read_output (struct pex_obj *@var{obj}, int @var{binary})
 
 Returns a @code{FILE} pointer which may be used to read the standard