merge from gcc
This commit is contained in:
parent
01d3a6ce13
commit
3db2e6ddf6
11 changed files with 387 additions and 51 deletions
|
@ -1,3 +1,7 @@
|
|||
2006-04-11 Jim Blandy <jimb@codesourcery.com>
|
||||
|
||||
* libiberty.h (pex_input_file, pex_input_pipe): New declarations.
|
||||
|
||||
2006-04-06 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
* bfdlink.h (bfd_link_info): Replace need_relax_finalize with
|
||||
|
|
|
@ -448,6 +448,47 @@ 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);
|
||||
|
||||
/* Return a stream for a temporary file to pass to the first program
|
||||
in the pipeline as input. The file name is chosen as for pex_run.
|
||||
pex_run closes the file automatically; don't close it yourself. */
|
||||
|
||||
extern FILE *pex_input_file (struct pex_obj *obj, int flags,
|
||||
const char *in_name);
|
||||
|
||||
/* Return a stream for a pipe connected to the standard input of the
|
||||
first program in the pipeline. You must have passed
|
||||
`PEX_USE_PIPES' to `pex_init'. Close the returned stream
|
||||
yourself. */
|
||||
|
||||
extern FILE *pex_input_pipe (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.
|
||||
|
|
|
@ -1,3 +1,25 @@
|
|||
2006-03-29 Jim Blandy <jimb@codesourcery.com>
|
||||
|
||||
* pex-common.c (pex_input_file, pex_input_pipe): New functions.
|
||||
(pex_init_common): Initialize obj->input_file.
|
||||
(pex_run): Close any file opened by pex_input_file.
|
||||
* pexecute.txh (pex_input_file, pex_input_pipe): New docs.
|
||||
* pex-common.h (struct pex_obj): New field input_file.
|
||||
(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-04-10 Jim Blandy <jimb@codesourcery.com>
|
||||
|
||||
* pex-common.c (temp_file): New function, containing guts of
|
||||
pex-style temporary file name generation.
|
||||
(pex_run): Use it.
|
||||
|
||||
2006-04-06 Carlos O'Donell <carlos@codesourcery.com>
|
||||
|
||||
* Makefile.in: Add install-html, install-html-am, and
|
||||
|
|
|
@ -668,14 +668,14 @@ reading and writing.
|
|||
|
||||
@end deftypefn
|
||||
|
||||
@c pexecute.txh:169
|
||||
@c pexecute.txh:231
|
||||
@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:206
|
||||
@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, 1 on success.
|
|||
|
||||
@end deftypefn
|
||||
|
||||
@c pexecute.txh:153
|
||||
@c pexecute.txh:215
|
||||
@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 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
|
||||
|
@ -734,7 +734,70 @@ temporary files; it may be @code{NULL} to use a randomly chosen name.
|
|||
|
||||
@end deftypefn
|
||||
|
||||
@c pexecute.txh:175
|
||||
@c pexecute.txh:133
|
||||
@deftypefn Extension {FILE *} pex_input_file (struct pex_obj *@var{obj}, int @var{flags}, const char *@var{in_name})
|
||||
|
||||
Return a stream for a temporary file to pass to the first program in
|
||||
the pipeline as input.
|
||||
|
||||
The name of the input file is chosen according to the same rules
|
||||
@code{pex_run} uses to choose output file names, based on
|
||||
@var{in_name}, @var{obj} and the @code{PEX_SUFFIX} bit in @var{flags}.
|
||||
|
||||
Don't call @code{fclose} on the returned stream; the first call to
|
||||
@code{pex_run} closes it automatically.
|
||||
|
||||
If @var{flags} includes @code{PEX_BINARY_OUTPUT}, open the stream in
|
||||
binary mode; otherwise, open it in the default mode. Including
|
||||
@code{PEX_BINARY_OUTPUT} in @var{flags} has no effect on Unix.
|
||||
@end deftypefn
|
||||
|
||||
@c pexecute.txh:150
|
||||
@deftypefn Extension {FILE *} pex_input_pipe (struct pex_obj *@var{obj}, int @var{binary})
|
||||
|
||||
Return a stream @var{fp} for a pipe connected to 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} using @code{fclose} yourself when you have
|
||||
finished writing data to the pipeline.
|
||||
|
||||
The file descriptor underlying @var{fp} is marked not to be inherited
|
||||
by child processes.
|
||||
|
||||
On systems that do not support pipes, this function returns
|
||||
@code{NULL}, and sets @code{errno} to @code{EINVAL}. If you would
|
||||
like to write code that is portable to all systems the @code{pex}
|
||||
functions support, consider using @code{pex_input_file} instead.
|
||||
|
||||
There are two opportunities for deadlock using
|
||||
@code{pex_input_pipe}:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
Most systems' pipes can buffer only a fixed amount of data; a process
|
||||
that writes to a full pipe blocks. Thus, if you write to @file{fp}
|
||||
before starting the first process, you run the risk of blocking when
|
||||
there is no child process yet to read the data and allow you to
|
||||
continue. @code{pex_input_pipe} makes no promises about the
|
||||
size of the pipe's buffer, so if you need to write any data at all
|
||||
before starting the first process in the pipeline, consider using
|
||||
@code{pex_input_file} instead.
|
||||
|
||||
@item
|
||||
Using @code{pex_input_pipe} and @code{pex_read_output} together
|
||||
may also cause 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 itemize
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@c pexecute.txh:237
|
||||
@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 +810,7 @@ be set to the exit status of the program.
|
|||
|
||||
@end deftypefn
|
||||
|
||||
@c pexecute.txh:132
|
||||
@c pexecute.txh:194
|
||||
@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 +823,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 +924,7 @@ value, or to 0 if there is no relevant @code{errno}.
|
|||
|
||||
@end deftypefn
|
||||
|
||||
@c pexecute.txh:187
|
||||
@c pexecute.txh:249
|
||||
@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 +952,7 @@ name is unset/removed.
|
|||
|
||||
@end deftypefn
|
||||
|
||||
@c pexecute.txh:195
|
||||
@c pexecute.txh:257
|
||||
@deftypefn Extension int pwait (int @var{pid}, int *@var{status}, int @var{flags})
|
||||
|
||||
Another part of the old execution interface.
|
||||
|
|
|
@ -67,6 +67,7 @@ pex_init_common (int flags, const char *pname, const char *tempbase,
|
|||
obj->status = NULL;
|
||||
obj->time = NULL;
|
||||
obj->number_waited = 0;
|
||||
obj->input_file = NULL;
|
||||
obj->read_output = NULL;
|
||||
obj->remove_count = 0;
|
||||
obj->remove = NULL;
|
||||
|
@ -91,6 +92,56 @@ pex_add_remove (struct pex_obj *obj, const char *name, int allocated)
|
|||
obj->remove[obj->remove_count - 1] = add;
|
||||
}
|
||||
|
||||
/* Generate a temporary file name based on OBJ, FLAGS, and NAME.
|
||||
Return NULL if we were unable to reserve a temporary filename.
|
||||
|
||||
If non-NULL, the result is either allocated with malloc, or the
|
||||
same pointer as NAME. */
|
||||
static char *
|
||||
temp_file (struct pex_obj *obj, int flags, char *name)
|
||||
{
|
||||
if (name == NULL)
|
||||
{
|
||||
if (obj->tempbase == NULL)
|
||||
{
|
||||
name = make_temp_file (NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
int len = strlen (obj->tempbase);
|
||||
int out;
|
||||
|
||||
if (len >= 6
|
||||
&& strcmp (obj->tempbase + len - 6, "XXXXXX") == 0)
|
||||
name = xstrdup (obj->tempbase);
|
||||
else
|
||||
name = concat (obj->tempbase, "XXXXXX", NULL);
|
||||
|
||||
out = mkstemps (name, 0);
|
||||
if (out < 0)
|
||||
{
|
||||
free (name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This isn't obj->funcs->close because we got the
|
||||
descriptor from mkstemps, not from a function in
|
||||
obj->funcs. Calling close here is just like what
|
||||
make_temp_file does. */
|
||||
close (out);
|
||||
}
|
||||
}
|
||||
else if ((flags & PEX_SUFFIX) != 0)
|
||||
{
|
||||
if (obj->tempbase == NULL)
|
||||
name = make_temp_file (name);
|
||||
else
|
||||
name = concat (obj->tempbase, name, NULL);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/* Run a program. */
|
||||
|
||||
const char *
|
||||
|
@ -111,6 +162,17 @@ pex_run (struct pex_obj *obj, int flags, const char *executable,
|
|||
outname = (char *) orig_outname;
|
||||
outname_allocated = 0;
|
||||
|
||||
/* If the user called pex_input_file, close the file now. */
|
||||
if (obj->input_file)
|
||||
{
|
||||
if (fclose (obj->input_file) == EOF)
|
||||
{
|
||||
errmsg = "closing pipeline input file";
|
||||
goto error_exit;
|
||||
}
|
||||
obj->input_file = NULL;
|
||||
}
|
||||
|
||||
/* Set IN. */
|
||||
|
||||
if (obj->next_input_name != NULL)
|
||||
|
@ -161,49 +223,16 @@ pex_run (struct pex_obj *obj, int flags, const char *executable,
|
|||
}
|
||||
else if ((obj->flags & PEX_USE_PIPES) == 0)
|
||||
{
|
||||
if (outname == NULL)
|
||||
{
|
||||
if (obj->tempbase == NULL)
|
||||
{
|
||||
outname = make_temp_file (NULL);
|
||||
outname_allocated = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int len = strlen (obj->tempbase);
|
||||
outname = temp_file (obj, flags, outname);
|
||||
if (! outname)
|
||||
{
|
||||
*err = 0;
|
||||
errmsg = "could not create temporary file";
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if (len >= 6
|
||||
&& strcmp (obj->tempbase + len - 6, "XXXXXX") == 0)
|
||||
outname = xstrdup (obj->tempbase);
|
||||
else
|
||||
outname = concat (obj->tempbase, "XXXXXX", NULL);
|
||||
|
||||
outname_allocated = 1;
|
||||
|
||||
out = mkstemps (outname, 0);
|
||||
if (out < 0)
|
||||
{
|
||||
*err = 0;
|
||||
errmsg = "could not create temporary output file";
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
/* This isn't obj->funcs->close because we got the
|
||||
descriptor from mkstemps, not from a function in
|
||||
obj->funcs. Calling close here is just like what
|
||||
make_temp_file does. */
|
||||
close (out);
|
||||
out = -1;
|
||||
}
|
||||
}
|
||||
else if ((flags & PEX_SUFFIX) != 0)
|
||||
{
|
||||
if (obj->tempbase == NULL)
|
||||
outname = make_temp_file (outname);
|
||||
else
|
||||
outname = concat (obj->tempbase, outname, NULL);
|
||||
outname_allocated = 1;
|
||||
}
|
||||
if (outname != orig_outname)
|
||||
outname_allocated = 1;
|
||||
|
||||
if ((obj->flags & PEX_SAVE_TEMPS) == 0)
|
||||
{
|
||||
|
@ -290,6 +319,87 @@ pex_run (struct pex_obj *obj, int flags, const char *executable,
|
|||
return errmsg;
|
||||
}
|
||||
|
||||
/* Return a FILE pointer for a temporary file to fill with input for
|
||||
the pipeline. */
|
||||
FILE *
|
||||
pex_input_file (struct pex_obj *obj, int flags, const char *in_name)
|
||||
{
|
||||
char *name = (char *) in_name;
|
||||
FILE *f;
|
||||
|
||||
/* This must be called before the first pipeline stage is run, and
|
||||
there must not have been any other input selected. */
|
||||
if (obj->count != 0
|
||||
|| (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
|
||||
|| obj->next_input_name)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
name = temp_file (obj, flags, name);
|
||||
if (! name)
|
||||
return NULL;
|
||||
|
||||
f = fopen (name, (flags & PEX_BINARY_OUTPUT) ? "wb" : "w");
|
||||
if (! f)
|
||||
{
|
||||
free (name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
obj->input_file = f;
|
||||
obj->next_input_name = name;
|
||||
obj->next_input_name_allocated = (name != in_name);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
/* Return a stream for a pipe connected to the standard input of the
|
||||
first stage of the pipeline. */
|
||||
FILE *
|
||||
pex_input_pipe (struct pex_obj *obj, int binary)
|
||||
{
|
||||
int p[2];
|
||||
FILE *f;
|
||||
|
||||
/* You must call pex_input_pipe 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;
|
||||
|
||||
f = obj->funcs->fdopenw (obj, p[WRITE_PORT], binary != 0);
|
||||
if (! f)
|
||||
{
|
||||
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 f;
|
||||
|
||||
usage_error:
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return a FILE pointer for the output of the last program
|
||||
executed. */
|
||||
|
||||
|
|
|
@ -69,6 +69,8 @@ struct pex_obj
|
|||
struct pex_time *time;
|
||||
/* Number of children we have already waited for. */
|
||||
int number_waited;
|
||||
/* FILE created by pex_input_file. */
|
||||
FILE *input_file;
|
||||
/* FILE created by pex_read_output. */
|
||||
FILE *read_output;
|
||||
/* Number of temporary files to remove. */
|
||||
|
@ -121,6 +123,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 *);
|
||||
|
|
|
@ -62,6 +62,7 @@ const struct pex_funcs funcs =
|
|||
pex_djgpp_wait,
|
||||
NULL, /* pipe */
|
||||
NULL, /* fdopenr */
|
||||
NULL, /* fdopenw */
|
||||
NULL /* cleanup */
|
||||
};
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ const struct pex_funcs funcs =
|
|||
pex_msdos_wait,
|
||||
NULL, /* pipe */
|
||||
NULL, /* fdopenr */
|
||||
NULL, /* fdopenw */
|
||||
pex_msdos_cleanup
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -83,6 +83,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. */
|
||||
|
||||
|
@ -95,6 +96,7 @@ const struct pex_funcs funcs =
|
|||
pex_win32_wait,
|
||||
pex_win32_pipe,
|
||||
pex_win32_fdopenr,
|
||||
pex_win32_fdopenw,
|
||||
NULL /* cleanup */
|
||||
};
|
||||
|
||||
|
@ -766,6 +768,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>
|
||||
|
||||
|
|
|
@ -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,67 @@ value, or to 0 if there is no relevant @code{errno}.
|
|||
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn Extension {FILE *} pex_input_file (struct pex_obj *@var{obj}, int @var{flags}, const char *@var{in_name})
|
||||
|
||||
Return a stream for a temporary file to pass to the first program in
|
||||
the pipeline as input.
|
||||
|
||||
The name of the input file is chosen according to the same rules
|
||||
@code{pex_run} uses to choose output file names, based on
|
||||
@var{in_name}, @var{obj} and the @code{PEX_SUFFIX} bit in @var{flags}.
|
||||
|
||||
Don't call @code{fclose} on the returned stream; the first call to
|
||||
@code{pex_run} closes it automatically.
|
||||
|
||||
If @var{flags} includes @code{PEX_BINARY_OUTPUT}, open the stream in
|
||||
binary mode; otherwise, open it in the default mode. Including
|
||||
@code{PEX_BINARY_OUTPUT} in @var{flags} has no effect on Unix.
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn Extension {FILE *} pex_input_pipe (struct pex_obj *@var{obj}, int @var{binary})
|
||||
|
||||
Return a stream @var{fp} for a pipe connected to 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} using @code{fclose} yourself when you have
|
||||
finished writing data to the pipeline.
|
||||
|
||||
The file descriptor underlying @var{fp} is marked not to be inherited
|
||||
by child processes.
|
||||
|
||||
On systems that do not support pipes, this function returns
|
||||
@code{NULL}, and sets @code{errno} to @code{EINVAL}. If you would
|
||||
like to write code that is portable to all systems the @code{pex}
|
||||
functions support, consider using @code{pex_input_file} instead.
|
||||
|
||||
There are two opportunities for deadlock using
|
||||
@code{pex_input_pipe}:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
Most systems' pipes can buffer only a fixed amount of data; a process
|
||||
that writes to a full pipe blocks. Thus, if you write to @file{fp}
|
||||
before starting the first process, you run the risk of blocking when
|
||||
there is no child process yet to read the data and allow you to
|
||||
continue. @code{pex_input_pipe} makes no promises about the
|
||||
size of the pipe's buffer, so if you need to write any data at all
|
||||
before starting the first process in the pipeline, consider using
|
||||
@code{pex_input_file} instead.
|
||||
|
||||
@item
|
||||
Using @code{pex_input_pipe} and @code{pex_read_output} together
|
||||
may also cause 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 itemize
|
||||
|
||||
@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
|
||||
|
|
Loading…
Reference in a new issue