This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFA: add 'pex_write_input' to libiberty pipeline library


src/libiberty/ChangeLog:
2006-03-13  Jim Blandy  <jimb@red-bean.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.

src/include/ChangeLog:
2006-03-13  Jim Blandy  <jimb@red-bean.com>

	* libiberty.h (pex_write_input): New declaration.

Index: src/libiberty/pexecute.txh
===================================================================
--- src.orig/libiberty/pexecute.txh
+++ src/libiberty/pexecute.txh
@@ -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 @
 
 @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
Index: src/libiberty/pex-common.c
===================================================================
--- src.orig/libiberty/pex-common.c
+++ src/libiberty/pex-common.c
@@ -297,6 +297,52 @@ pex_run (struct pex_obj *obj, int flags,
   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: src/libiberty/pex-common.h
===================================================================
--- src.orig/libiberty/pex-common.h
+++ src/libiberty/pex-common.h
@@ -121,6 +121,11 @@ struct pex_funcs
      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 */);
+  /* 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: src/libiberty/pex-djgpp.c
===================================================================
--- src.orig/libiberty/pex-djgpp.c
+++ src/libiberty/pex-djgpp.c
@@ -62,6 +62,7 @@ const struct pex_funcs funcs =
   pex_djgpp_wait,
   NULL, /* pipe */
   NULL, /* fdopenr */
+  NULL, /* fdopenw */
   NULL  /* cleanup */
 };
 
Index: src/libiberty/pex-msdos.c
===================================================================
--- src.orig/libiberty/pex-msdos.c
+++ src/libiberty/pex-msdos.c
@@ -73,6 +73,7 @@ const struct pex_funcs funcs =
   pex_msdos_wait,
   NULL, /* pipe */
   NULL, /* fdopenr */
+  NULL, /* fdopenw */
   pex_msdos_cleanup
 };
 
Index: src/libiberty/pex-unix.c
===================================================================
--- src.orig/libiberty/pex-unix.c
+++ src/libiberty/pex-unix.c
@@ -277,6 +277,7 @@ static int pex_unix_wait (struct pex_obj
 			  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 AT
   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: src/libiberty/pex-win32.c
===================================================================
--- src.orig/libiberty/pex-win32.c
+++ src/libiberty/pex-win32.c
@@ -191,6 +191,7 @@ static int pex_win32_wait (struct pex_ob
 			   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 A
   return fdopen (fd, binary ? "rb" : "r");
 }
 
+static FILE *
+pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
+		   int binary)
+{
+  HANDLE h = _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: src/include/libiberty.h
===================================================================
--- src.orig/include/libiberty.h
+++ src/include/libiberty.h
@@ -448,6 +448,33 @@ extern const char *pex_run (struct pex_o
 			    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: src/libiberty/functions.texi
===================================================================
--- src.orig/libiberty/functions.texi
+++ src/libiberty/functions.texi
@@ -668,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}.
@@ -685,7 +685,7 @@ to @code{pex_run}.  Returns 0 on error, 
 
 @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
@@ -702,7 +702,7 @@ process times, all the fields will be se
 
 @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
@@ -734,7 +734,7 @@ temporary files; it may be @code{NULL} t
 
 @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
@@ -747,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
@@ -760,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
@@ -861,7 +861,36 @@ value, or to 0 if there is no relevant @
 
 @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
@@ -889,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.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]