summaryrefslogtreecommitdiffstats
path: root/unix/tclUnixPipe.c
diff options
context:
space:
mode:
Diffstat (limited to 'unix/tclUnixPipe.c')
-rw-r--r--unix/tclUnixPipe.c713
1 files changed, 369 insertions, 344 deletions
diff --git a/unix/tclUnixPipe.c b/unix/tclUnixPipe.c
index d0a5e53..33f51c6 100644
--- a/unix/tclUnixPipe.c
+++ b/unix/tclUnixPipe.c
@@ -1,17 +1,18 @@
-/*
+/*
* tclUnixPipe.c --
*
- * This file implements the UNIX-specific exec pipeline functions, the
- * "pipe" channel driver, and the "pid" Tcl command.
+ * This file implements the UNIX-specific exec pipeline functions,
+ * the "pipe" channel driver, and the "pid" Tcl command.
*
* Copyright (c) 1991-1994 The Regents of the University of California.
* Copyright (c) 1994-1997 Sun Microsystems, Inc.
*
- * See the file "license.terms" for information on usage and redistribution of
- * this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tclInt.h"
+#include "tclPort.h"
#ifdef USE_VFORK
#define fork vfork
@@ -28,58 +29,59 @@
#endif
/*
- * The following macros convert between TclFile's and fd's. The conversion
+ * The following macros convert between TclFile's and fd's. The conversion
* simple involves shifting fd's up by one to ensure that no valid fd is ever
* the same as NULL.
*/
-#define MakeFile(fd) ((TclFile) INT2PTR(((int) (fd)) + 1))
-#define GetFd(file) (PTR2INT(file) - 1)
+#define MakeFile(fd) ((TclFile)(((int)fd)+1))
+#define GetFd(file) (((int)file)-1)
/*
* This structure describes per-instance state of a pipe based channel.
*/
typedef struct PipeState {
- Tcl_Channel channel; /* Channel associated with this file. */
- TclFile inFile; /* Output from pipe. */
- TclFile outFile; /* Input to pipe. */
- TclFile errorFile; /* Error output from pipe. */
- int numPids; /* How many processes are attached to this
- * pipe? */
- Tcl_Pid *pidPtr; /* The process IDs themselves. Allocated by
- * the creator of the pipe. */
- int isNonBlocking; /* Nonzero when the pipe is in nonblocking
- * mode. Used to decide whether to wait for
- * the children at close time. */
+ Tcl_Channel channel;/* Channel associated with this file. */
+ TclFile inFile; /* Output from pipe. */
+ TclFile outFile; /* Input to pipe. */
+ TclFile errorFile; /* Error output from pipe. */
+ int numPids; /* How many processes are attached to this pipe? */
+ Tcl_Pid *pidPtr; /* The process IDs themselves. Allocated by
+ * the creator of the pipe. */
+ int isNonBlocking; /* Nonzero when the pipe is in nonblocking mode.
+ * Used to decide whether to wait for the children
+ * at close time. */
} PipeState;
/*
- * Declarations for local functions defined in this file:
+ * Declarations for local procedures defined in this file:
*/
-static const char * DefaultTempDir(void);
-static int PipeBlockModeProc(ClientData instanceData, int mode);
-static int PipeCloseProc(ClientData instanceData,
- Tcl_Interp *interp);
-static int PipeGetHandleProc(ClientData instanceData,
- int direction, ClientData *handlePtr);
-static int PipeInputProc(ClientData instanceData, char *buf,
- int toRead, int *errorCode);
-static int PipeOutputProc(ClientData instanceData,
- const char *buf, int toWrite, int *errorCode);
-static void PipeWatchProc(ClientData instanceData, int mask);
-static void RestoreSignals(void);
-static int SetupStdFile(TclFile file, int type);
+static int PipeBlockModeProc _ANSI_ARGS_((ClientData instanceData,
+ int mode));
+static int PipeCloseProc _ANSI_ARGS_((ClientData instanceData,
+ Tcl_Interp *interp));
+static int PipeGetHandleProc _ANSI_ARGS_((ClientData instanceData,
+ int direction, ClientData *handlePtr));
+static int PipeInputProc _ANSI_ARGS_((ClientData instanceData,
+ char *buf, int toRead, int *errorCode));
+static int PipeOutputProc _ANSI_ARGS_((
+ ClientData instanceData, CONST char *buf, int toWrite,
+ int *errorCode));
+static void PipeWatchProc _ANSI_ARGS_((ClientData instanceData, int mask));
+static void RestoreSignals _ANSI_ARGS_((void));
+static int SetupStdFile _ANSI_ARGS_((TclFile file, int type));
+static CONST char * DefaultTempDir _ANSI_ARGS_((void));
/*
- * This structure describes the channel type structure for command pipe based
- * I/O:
+ * This structure describes the channel type structure for command pipe
+ * based IO:
*/
static Tcl_ChannelType pipeChannelType = {
"pipe", /* Type name. */
- TCL_CHANNEL_VERSION_5, /* v5 channel */
+ TCL_CHANNEL_VERSION_4, /* v4 channel */
PipeCloseProc, /* Close proc. */
PipeInputProc, /* Input proc. */
PipeOutputProc, /* Output proc. */
@@ -92,9 +94,8 @@ static Tcl_ChannelType pipeChannelType = {
PipeBlockModeProc, /* Set blocking or non-blocking mode.*/
NULL, /* flush proc. */
NULL, /* handler proc. */
- NULL, /* wide seek proc */
- NULL, /* thread action proc */
- NULL /* truncation */
+ NULL, /* wide seek proc */
+ NULL, /* thread action proc */
};
/*
@@ -114,15 +115,15 @@ static Tcl_ChannelType pipeChannelType = {
*/
TclFile
-TclpMakeFile(
- Tcl_Channel channel, /* Channel to get file from. */
- int direction) /* Either TCL_READABLE or TCL_WRITABLE. */
+TclpMakeFile(channel, direction)
+ Tcl_Channel channel; /* Channel to get file from. */
+ int direction; /* Either TCL_READABLE or TCL_WRITABLE. */
{
ClientData data;
- if (Tcl_GetChannelHandle(channel, direction,
- (ClientData *) &data) == TCL_OK) {
- return MakeFile(PTR2INT(data));
+ if (Tcl_GetChannelHandle(channel, direction, (ClientData *) &data)
+ == TCL_OK) {
+ return MakeFile((int)data);
} else {
return (TclFile) NULL;
}
@@ -133,7 +134,7 @@ TclpMakeFile(
*
* TclpOpenFile --
*
- * Open a file for use in a pipeline.
+ * Open a file for use in a pipeline.
*
* Results:
* Returns a new TclFile handle or NULL on failure.
@@ -145,23 +146,23 @@ TclpMakeFile(
*/
TclFile
-TclpOpenFile(
- const char *fname, /* The name of the file to open. */
- int mode) /* In what mode to open the file? */
+TclpOpenFile(fname, mode)
+ CONST char *fname; /* The name of the file to open. */
+ int mode; /* In what mode to open the file? */
{
int fd;
- const char *native;
+ CONST char *native;
Tcl_DString ds;
native = Tcl_UtfToExternalDString(NULL, fname, -1, &ds);
fd = TclOSopen(native, mode, 0666); /* INTL: Native. */
Tcl_DStringFree(&ds);
if (fd != -1) {
- fcntl(fd, F_SETFD, FD_CLOEXEC);
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
/*
- * If the file is being opened for writing, seek to the end so we can
- * append to any data already in the file.
+ * If the file is being opened for writing, seek to the end
+ * so we can append to any data already in the file.
*/
if ((mode & O_WRONLY) && !(mode & O_APPEND)) {
@@ -169,8 +170,8 @@ TclpOpenFile(
}
/*
- * Increment the fd so it can't be 0, which would conflict with the
- * NULL return for errors.
+ * Increment the fd so it can't be 0, which would conflict with
+ * the NULL return for errors.
*/
return MakeFile(fd);
@@ -183,9 +184,9 @@ TclpOpenFile(
*
* TclpCreateTempFile --
*
- * This function creates a temporary file initialized with an optional
- * string, and returns a file handle with the file pointer at the
- * beginning of the file.
+ * This function creates a temporary file initialized with an
+ * optional string, and returns a file handle with the file pointer
+ * at the beginning of the file.
*
* Results:
* A handle to a file.
@@ -197,11 +198,11 @@ TclpOpenFile(
*/
TclFile
-TclpCreateTempFile(
- const char *contents) /* String to write into temp file, or NULL. */
+TclpCreateTempFile(contents)
+ CONST char *contents; /* String to write into temp file, or NULL. */
{
char fileName[L_tmpnam + 9];
- const char *native;
+ CONST char *native;
Tcl_DString dstring;
int fd;
@@ -250,8 +251,8 @@ TclpCreateTempFile(
*----------------------------------------------------------------------
*/
-Tcl_Obj *
-TclpTempFileName(void)
+Tcl_Obj*
+TclpTempFileName()
{
char fileName[L_tmpnam + 9];
Tcl_Obj *result = NULL;
@@ -274,7 +275,7 @@ TclpTempFileName(void)
unlink(fileName); /* INTL: Native. */
result = TclpNativeToNormalized((ClientData) fileName);
- close(fd);
+ close (fd);
return result;
}
@@ -288,10 +289,10 @@ TclpTempFileName(void)
*----------------------------------------------------------------------
*/
-static const char *
+static CONST char *
DefaultTempDir(void)
{
- const char *dir;
+ CONST char *dir;
struct stat buf;
dir = getenv("TMPDIR");
@@ -321,23 +322,23 @@ DefaultTempDir(void)
*
* TclpCreatePipe --
*
- * Creates a pipe - simply calls the pipe() function.
+ * Creates a pipe - simply calls the pipe() function.
*
* Results:
- * Returns 1 on success, 0 on failure.
+ * Returns 1 on success, 0 on failure.
*
* Side effects:
- * Creates a pipe.
+ * Creates a pipe.
*
*----------------------------------------------------------------------
*/
int
-TclpCreatePipe(
- TclFile *readPipe, /* Location to store file handle for read side
- * of pipe. */
- TclFile *writePipe) /* Location to store file handle for write
- * side of pipe. */
+TclpCreatePipe(readPipe, writePipe)
+ TclFile *readPipe; /* Location to store file handle for
+ * read side of pipe. */
+ TclFile *writePipe; /* Location to store file handle for
+ * write side of pipe. */
{
int pipeIds[2];
@@ -370,19 +371,19 @@ TclpCreatePipe(
*/
int
-TclpCloseFile(
- TclFile file) /* The file to close. */
+TclpCloseFile(file)
+ TclFile file; /* The file to close. */
{
int fd = GetFd(file);
/*
* Refuse to close the fds for stdin, stdout and stderr.
*/
-
+
if ((fd == 0) || (fd == 1) || (fd == 2)) {
- return 0;
+ return 0;
}
-
+
Tcl_DeleteFileHandler(fd);
return close(fd);
}
@@ -392,53 +393,55 @@ TclpCloseFile(
*
* TclpCreateProcess --
*
- * Create a child process that has the specified files as its standard
- * input, output, and error. The child process runs asynchronously and
- * runs with the same environment variables as the creating process.
+ * Create a child process that has the specified files as its
+ * standard input, output, and error. The child process runs
+ * asynchronously and runs with the same environment variables
+ * as the creating process.
*
- * The path is searched to find the specified executable.
+ * The path is searched to find the specified executable.
*
* Results:
- * The return value is TCL_ERROR and an error message is left in the
- * interp's result if there was a problem creating the child process.
- * Otherwise, the return value is TCL_OK and *pidPtr is filled with the
- * process id of the child process.
- *
+ * The return value is TCL_ERROR and an error message is left in
+ * the interp's result if there was a problem creating the child
+ * process. Otherwise, the return value is TCL_OK and *pidPtr is
+ * filled with the process id of the child process.
+ *
* Side effects:
* A process is created.
- *
+ *
*---------------------------------------------------------------------------
*/
/* ARGSUSED */
int
-TclpCreateProcess(
- Tcl_Interp *interp, /* Interpreter in which to leave errors that
+TclpCreateProcess(interp, argc, argv, inputFile, outputFile, errorFile,
+ pidPtr)
+ Tcl_Interp *interp; /* Interpreter in which to leave errors that
* occurred when creating the child process.
* Error messages from the child process
* itself are sent to errorFile. */
- int argc, /* Number of arguments in following array. */
- const char **argv, /* Array of argument strings in UTF-8.
+ int argc; /* Number of arguments in following array. */
+ CONST char **argv; /* Array of argument strings in UTF-8.
* argv[0] contains the name of the executable
* translated using Tcl_TranslateFileName
- * call). Additional arguments have not been
+ * call). Additional arguments have not been
* converted. */
- TclFile inputFile, /* If non-NULL, gives the file to use as input
- * for the child process. If inputFile file is
- * not readable or is NULL, the child will
- * receive no standard input. */
- TclFile outputFile, /* If non-NULL, gives the file that receives
- * output from the child process. If
+ TclFile inputFile; /* If non-NULL, gives the file to use as
+ * input for the child process. If inputFile
+ * file is not readable or is NULL, the child
+ * will receive no standard input. */
+ TclFile outputFile; /* If non-NULL, gives the file that
+ * receives output from the child process. If
* outputFile file is not writeable or is
* NULL, output from the child will be
* discarded. */
- TclFile errorFile, /* If non-NULL, gives the file that receives
- * errors from the child process. If errorFile
- * file is not writeable or is NULL, errors
- * from the child will be discarded. errorFile
- * may be the same as outputFile. */
- Tcl_Pid *pidPtr) /* If this function is successful, pidPtr is
- * filled with the process id of the child
+ TclFile errorFile; /* If non-NULL, gives the file that
+ * receives errors from the child process. If
+ * errorFile file is not writeable or is NULL,
+ * errors from the child will be discarded.
+ * errorFile may be the same as outputFile. */
+ Tcl_Pid *pidPtr; /* If this procedure is successful, pidPtr
+ * is filled with the process id of the child
* process. */
{
TclFile errPipeIn, errPipeOut;
@@ -447,30 +450,28 @@ TclpCreateProcess(
Tcl_DString *dsArray;
char **newArgv;
int pid, i;
-
+
errPipeIn = NULL;
errPipeOut = NULL;
pid = -1;
/*
- * Create a pipe that the child can use to return error information if
- * anything goes wrong.
+ * Create a pipe that the child can use to return error
+ * information if anything goes wrong.
*/
if (TclpCreatePipe(&errPipeIn, &errPipeOut) == 0) {
Tcl_AppendResult(interp, "couldn't create pipe: ",
- Tcl_PosixError(interp), NULL);
+ Tcl_PosixError(interp), (char *) NULL);
goto error;
}
/*
- * We need to allocate and convert this before the fork so it is properly
- * deallocated later
+ * We need to allocate and convert this before the fork
+ * so it is properly deallocated later
*/
-
- dsArray = (Tcl_DString *)
- TclStackAlloc(interp, argc * sizeof(Tcl_DString));
- newArgv = (char **) TclStackAlloc(interp, (argc+1) * sizeof(char *));
+ dsArray = (Tcl_DString *) ckalloc(argc * sizeof(Tcl_DString));
+ newArgv = (char **) ckalloc((argc+1) * sizeof(char *));
newArgv[argc] = NULL;
for (i = 0; i < argc; i++) {
newArgv[i] = Tcl_UtfToExternalDString(NULL, argv[i], -1, &dsArray[i]);
@@ -483,7 +484,6 @@ TclpCreateProcess(
* might corrupt the parent: so ensure standard channels are initialized in
* the parent, otherwise SetupStdFile() might initialize them in the child.
*/
-
if (!inputFile) {
Tcl_GetStdChannel(TCL_STDIN);
}
@@ -494,10 +494,8 @@ TclpCreateProcess(
Tcl_GetStdChannel(TCL_STDERR);
}
#endif
-
pid = fork();
if (pid == 0) {
- size_t len;
int joinThisError = errorFile && (errorFile == outputFile);
fd = GetFd(errPipeOut);
@@ -510,13 +508,11 @@ TclpCreateProcess(
|| !SetupStdFile(outputFile, TCL_STDOUT)
|| (!joinThisError && !SetupStdFile(errorFile, TCL_STDERR))
|| (joinThisError &&
- ((dup2(1,2) == -1) || (fcntl(2, F_SETFD, 0) != 0)))) {
+ ((dup2(1,2) == -1) ||
+ (fcntl(2, F_SETFD, 0) != 0)))) {
sprintf(errSpace,
"%dforked process couldn't set up input/output: ", errno);
- len = strlen(errSpace);
- if (len != (size_t) write(fd, errSpace, len)) {
- Tcl_Panic("TclpCreateProcess: unable to write to errPipeOut");
- }
+ write(fd, errSpace, (size_t) strlen(errSpace));
_exit(1);
}
@@ -527,33 +523,29 @@ TclpCreateProcess(
RestoreSignals();
execvp(newArgv[0], newArgv); /* INTL: Native. */
sprintf(errSpace, "%dcouldn't execute \"%.150s\": ", errno, argv[0]);
- len = strlen(errSpace);
- if (len != (size_t) write(fd, errSpace, len)) {
- Tcl_Panic("TclpCreateProcess: unable to write to errPipeOut");
- }
+ write(fd, errSpace, (size_t) strlen(errSpace));
_exit(1);
}
-
+
/*
* Free the mem we used for the fork
*/
-
for (i = 0; i < argc; i++) {
Tcl_DStringFree(&dsArray[i]);
}
- TclStackFree(interp, newArgv);
- TclStackFree(interp, dsArray);
+ ckfree((char *) dsArray);
+ ckfree((char *) newArgv);
if (pid == -1) {
Tcl_AppendResult(interp, "couldn't fork child process: ",
- Tcl_PosixError(interp), NULL);
+ Tcl_PosixError(interp), (char *) NULL);
goto error;
}
/*
- * Read back from the error pipe to see if the child started up OK. The
- * info in the pipe (if any) consists of a decimal errno value followed by
- * an error message.
+ * Read back from the error pipe to see if the child started
+ * up OK. The info in the pipe (if any) consists of a decimal
+ * errno value followed by an error message.
*/
TclpCloseFile(errPipeOut);
@@ -565,26 +557,27 @@ TclpCreateProcess(
char *end;
errSpace[count] = 0;
errno = strtol(errSpace, &end, 10);
- Tcl_AppendResult(interp, end, Tcl_PosixError(interp), NULL);
+ Tcl_AppendResult(interp, end, Tcl_PosixError(interp),
+ (char *) NULL);
goto error;
}
-
+
TclpCloseFile(errPipeIn);
- *pidPtr = (Tcl_Pid) INT2PTR(pid);
+ *pidPtr = (Tcl_Pid) pid;
return TCL_OK;
- error:
+ error:
if (pid != -1) {
/*
- * Reap the child process now if an error occurred during its startup.
- * We don't call this with WNOHANG because that can lead to defunct
- * processes on an MP system. We shouldn't have to worry about hanging
- * here, since this is the error case. [Bug: 6148]
+ * Reap the child process now if an error occurred during its
+ * startup. We don't call this with WNOHANG because that can lead to
+ * defunct processes on an MP system. We shouldn't have to worry
+ * about hanging here, since this is the error case. [Bug: 6148]
*/
- Tcl_WaitPid((Tcl_Pid) INT2PTR(pid), &status, 0);
+ Tcl_WaitPid((Tcl_Pid) pid, &status, 0);
}
-
+
if (errPipeIn) {
TclpCloseFile(errPipeIn);
}
@@ -599,21 +592,21 @@ TclpCreateProcess(
*
* RestoreSignals --
*
- * This function is invoked in a forked child process just before
- * exec-ing a new program to restore all signals to their default
- * settings.
+ * This procedure is invoked in a forked child process just before
+ * exec-ing a new program to restore all signals to their default
+ * settings.
*
* Results:
- * None.
+ * None.
*
* Side effects:
- * Signal settings get changed.
+ * Signal settings get changed.
*
*----------------------------------------------------------------------
*/
-
+
static void
-RestoreSignals(void)
+RestoreSignals()
{
#ifdef SIGABRT
signal(SIGABRT, SIG_DFL);
@@ -673,10 +666,10 @@ RestoreSignals(void)
*
* SetupStdFile --
*
- * Set up stdio file handles for the child process, using the current
- * standard channels if no other files are specified. If no standard
- * channel is defined, or if no file is associated with the channel, then
- * the corresponding standard fd is closed.
+ * Set up stdio file handles for the child process, using the
+ * current standard channels if no other files are specified.
+ * If no standard channel is defined, or if no file is associated
+ * with the channel, then the corresponding standard fd is closed.
*
* Results:
* Returns 1 on success, or 0 on failure.
@@ -688,9 +681,9 @@ RestoreSignals(void)
*/
static int
-SetupStdFile(
- TclFile file, /* File to dup, or NULL. */
- int type) /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR */
+SetupStdFile(file, type)
+ TclFile file; /* File to dup, or NULL. */
+ int type; /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR */
{
Tcl_Channel channel;
int fd;
@@ -699,18 +692,18 @@ SetupStdFile(
* variables. */
switch (type) {
- case TCL_STDIN:
- targetFd = 0;
- direction = TCL_READABLE;
- break;
- case TCL_STDOUT:
- targetFd = 1;
- direction = TCL_WRITABLE;
- break;
- case TCL_STDERR:
- targetFd = 2;
- direction = TCL_WRITABLE;
- break;
+ case TCL_STDIN:
+ targetFd = 0;
+ direction = TCL_READABLE;
+ break;
+ case TCL_STDOUT:
+ targetFd = 1;
+ direction = TCL_WRITABLE;
+ break;
+ case TCL_STDERR:
+ targetFd = 2;
+ direction = TCL_WRITABLE;
+ break;
}
if (!file) {
@@ -726,20 +719,20 @@ SetupStdFile(
return 0;
}
- /*
- * Must clear the close-on-exec flag for the target FD, since some
- * systems (e.g. Ultrix) do not clear the CLOEXEC flag on the
- * target FD.
- */
-
- fcntl(targetFd, F_SETFD, 0);
+ /*
+ * Must clear the close-on-exec flag for the target FD, since
+ * some systems (e.g. Ultrix) do not clear the CLOEXEC flag on
+ * the target FD.
+ */
+
+ fcntl(targetFd, F_SETFD, 0);
} else {
/*
* Since we aren't dup'ing the file, we need to explicitly clear
* the close-on-exec flag.
*/
- fcntl(fd, F_SETFD, 0);
+ fcntl(fd, F_SETFD, 0);
}
} else {
close(targetFd);
@@ -752,8 +745,9 @@ SetupStdFile(
*
* TclpCreateCommandChannel --
*
- * This function is called by the generic IO level to perform the
- * platform specific channel initialization for a command channel.
+ * This function is called by the generic IO level to perform
+ * the platform specific channel initialization for a command
+ * channel.
*
* Results:
* Returns a new channel or NULL on failure.
@@ -765,16 +759,16 @@ SetupStdFile(
*/
Tcl_Channel
-TclpCreateCommandChannel(
- TclFile readFile, /* If non-null, gives the file for reading. */
- TclFile writeFile, /* If non-null, gives the file for writing. */
- TclFile errorFile, /* If non-null, gives the file where errors
+TclpCreateCommandChannel(readFile, writeFile, errorFile, numPids, pidPtr)
+ TclFile readFile; /* If non-null, gives the file for reading. */
+ TclFile writeFile; /* If non-null, gives the file for writing. */
+ TclFile errorFile; /* If non-null, gives the file where errors
* can be read. */
- int numPids, /* The number of pids in the pid array. */
- Tcl_Pid *pidPtr) /* An array of process identifiers. Allocated
- * by the caller, freed when the channel is
- * closed or the processes are detached (in a
- * background exec). */
+ int numPids; /* The number of pids in the pid array. */
+ Tcl_Pid *pidPtr; /* An array of process identifiers.
+ * Allocated by the caller, freed when
+ * the channel is closed or the processes
+ * are detached (in a background exec). */
{
char channelName[16 + TCL_INTEGER_SPACE];
int channelId;
@@ -790,14 +784,15 @@ TclpCreateCommandChannel(
mode = 0;
if (readFile) {
- mode |= TCL_READABLE;
+ mode |= TCL_READABLE;
}
if (writeFile) {
- mode |= TCL_WRITABLE;
+ mode |= TCL_WRITABLE;
}
-
+
/*
- * Use one of the fds associated with the channel as the channel id.
+ * Use one of the fds associated with the channel as the
+ * channel id.
*/
if (readFile) {
@@ -811,14 +806,14 @@ TclpCreateCommandChannel(
}
/*
- * For backward compatibility with previous versions of Tcl, we use
- * "file%d" as the base name for pipes even though it would be more
- * natural to use "pipe%d".
+ * For backward compatibility with previous versions of Tcl, we
+ * use "file%d" as the base name for pipes even though it would
+ * be more natural to use "pipe%d".
*/
sprintf(channelName, "file%d", channelId);
statePtr->channel = Tcl_CreateChannel(&pipeChannelType, channelName,
- (ClientData) statePtr, mode);
+ (ClientData) statePtr, mode);
return statePtr->channel;
}
@@ -827,10 +822,10 @@ TclpCreateCommandChannel(
*
* TclGetAndDetachPids --
*
- * This function is invoked in the generic implementation of a
- * background "exec" (an exec when invoked with a terminating "&") to
- * store a list of the PIDs for processes in a command pipeline in the
- * interp's result and to detach the processes.
+ * This procedure is invoked in the generic implementation of a
+ * background "exec" (An exec when invoked with a terminating "&")
+ * to store a list of the PIDs for processes in a command pipeline
+ * in the interp's result and to detach the processes.
*
* Results:
* None.
@@ -842,12 +837,12 @@ TclpCreateCommandChannel(
*/
void
-TclGetAndDetachPids(
- Tcl_Interp *interp, /* Interpreter to append the PIDs to. */
- Tcl_Channel chan) /* Handle for the pipeline. */
+TclGetAndDetachPids(interp, chan)
+ Tcl_Interp *interp;
+ Tcl_Channel chan;
{
PipeState *pipePtr;
- const Tcl_ChannelType *chanTypePtr;
+ Tcl_ChannelType *chanTypePtr;
int i;
char buf[TCL_INTEGER_SPACE];
@@ -857,18 +852,18 @@ TclGetAndDetachPids(
chanTypePtr = Tcl_GetChannelType(chan);
if (chanTypePtr != &pipeChannelType) {
- return;
+ return;
}
pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan);
for (i = 0; i < pipePtr->numPids; i++) {
- TclFormatInt(buf, (long) TclpGetPid(pipePtr->pidPtr[i]));
- Tcl_AppendElement(interp, buf);
- Tcl_DetachPids(1, &(pipePtr->pidPtr[i]));
+ TclFormatInt(buf, (long) TclpGetPid(pipePtr->pidPtr[i]));
+ Tcl_AppendElement(interp, buf);
+ Tcl_DetachPids(1, &(pipePtr->pidPtr[i]));
}
if (pipePtr->numPids > 0) {
- ckfree((char *) pipePtr->pidPtr);
- pipePtr->numPids = 0;
+ ckfree((char *) pipePtr->pidPtr);
+ pipePtr->numPids = 0;
}
}
@@ -877,8 +872,8 @@ TclGetAndDetachPids(
*
* PipeBlockModeProc --
*
- * Helper function to set blocking and nonblocking modes on a pipe based
- * channel. Invoked by generic IO level code.
+ * Helper procedure to set blocking and nonblocking modes on a
+ * pipe based channel. Invoked by generic IO level code.
*
* Results:
* 0 if successful, errno when failed.
@@ -891,24 +886,67 @@ TclGetAndDetachPids(
/* ARGSUSED */
static int
-PipeBlockModeProc(
- ClientData instanceData, /* Pipe state. */
- int mode) /* The mode to set. Can be one of
- * TCL_MODE_BLOCKING or
- * TCL_MODE_NONBLOCKING. */
+PipeBlockModeProc(instanceData, mode)
+ ClientData instanceData; /* Pipe state. */
+ int mode; /* The mode to set. Can be one of
+ * TCL_MODE_BLOCKING or
+ * TCL_MODE_NONBLOCKING. */
{
- PipeState *psPtr = instanceData;
+ PipeState *psPtr = (PipeState *) instanceData;
+ int curStatus;
+ int fd;
+#ifndef USE_FIONBIO
if (psPtr->inFile) {
- if (TclUnixSetBlockingMode(GetFd(psPtr->inFile), mode) < 0) {
- return errno;
- }
+ fd = GetFd(psPtr->inFile);
+ curStatus = fcntl(fd, F_GETFL);
+ if (mode == TCL_MODE_BLOCKING) {
+ curStatus &= (~(O_NONBLOCK));
+ } else {
+ curStatus |= O_NONBLOCK;
+ }
+ if (fcntl(fd, F_SETFL, curStatus) < 0) {
+ return errno;
+ }
}
if (psPtr->outFile) {
- if (TclUnixSetBlockingMode(GetFd(psPtr->outFile), mode) < 0) {
- return errno;
- }
+ fd = GetFd(psPtr->outFile);
+ curStatus = fcntl(fd, F_GETFL);
+ if (mode == TCL_MODE_BLOCKING) {
+ curStatus &= (~(O_NONBLOCK));
+ } else {
+ curStatus |= O_NONBLOCK;
+ }
+ if (fcntl(fd, F_SETFL, curStatus) < 0) {
+ return errno;
+ }
}
+#endif /* !FIONBIO */
+
+#ifdef USE_FIONBIO
+ if (psPtr->inFile) {
+ fd = GetFd(psPtr->inFile);
+ if (mode == TCL_MODE_BLOCKING) {
+ curStatus = 0;
+ } else {
+ curStatus = 1;
+ }
+ if (ioctl(fd, (int) FIONBIO, &curStatus) < 0) {
+ return errno;
+ }
+ }
+ if (psPtr->outFile != NULL) {
+ fd = GetFd(psPtr->outFile);
+ if (mode == TCL_MODE_BLOCKING) {
+ curStatus = 0;
+ } else {
+ curStatus = 1;
+ }
+ if (ioctl(fd, (int) FIONBIO, &curStatus) < 0) {
+ return errno;
+ }
+ }
+#endif /* USE_FIONBIO */
psPtr->isNonBlocking = (mode == TCL_MODE_NONBLOCKING);
@@ -920,9 +958,9 @@ PipeBlockModeProc(
*
* PipeCloseProc --
*
- * This function is invoked by the generic IO level to perform
- * channel-type-specific cleanup when a command pipeline channel is
- * closed.
+ * This procedure is invoked by the generic IO level to perform
+ * channel-type-specific cleanup when a command pipeline channel
+ * is closed.
*
* Results:
* 0 on success, errno otherwise.
@@ -935,9 +973,9 @@ PipeBlockModeProc(
/* ARGSUSED */
static int
-PipeCloseProc(
- ClientData instanceData, /* The pipe to close. */
- Tcl_Interp *interp) /* For error reporting. */
+PipeCloseProc(instanceData, interp)
+ ClientData instanceData; /* The pipe to close. */
+ Tcl_Interp *interp; /* For error reporting. */
{
PipeState *pipePtr;
Tcl_Channel errChan;
@@ -958,40 +996,42 @@ PipeCloseProc(
}
if (pipePtr->isNonBlocking || TclInExit()) {
+
/*
- * If the channel is non-blocking or Tcl is being cleaned up, just
- * detach the children PIDs, reap them (important if we are in a
- * dynamic load module), and discard the errorFile.
- */
-
- Tcl_DetachPids(pipePtr->numPids, pipePtr->pidPtr);
- Tcl_ReapDetachedProcs();
-
- if (pipePtr->errorFile) {
+ * If the channel is non-blocking or Tcl is being cleaned up, just
+ * detach the children PIDs, reap them (important if we are in a
+ * dynamic load module), and discard the errorFile.
+ */
+
+ Tcl_DetachPids(pipePtr->numPids, pipePtr->pidPtr);
+ Tcl_ReapDetachedProcs();
+
+ if (pipePtr->errorFile) {
TclpCloseFile(pipePtr->errorFile);
- }
+ }
} else {
+
/*
- * Wrap the error file into a channel and give it to the cleanup
- * routine.
- */
+ * Wrap the error file into a channel and give it to the cleanup
+ * routine.
+ */
- if (pipePtr->errorFile) {
+ if (pipePtr->errorFile) {
errChan = Tcl_MakeFileChannel(
- (ClientData) INT2PTR(GetFd(pipePtr->errorFile)), TCL_READABLE);
- } else {
- errChan = NULL;
- }
- result = TclCleanupChildren(interp, pipePtr->numPids, pipePtr->pidPtr,
- errChan);
+ (ClientData) GetFd(pipePtr->errorFile), TCL_READABLE);
+ } else {
+ errChan = NULL;
+ }
+ result = TclCleanupChildren(interp, pipePtr->numPids, pipePtr->pidPtr,
+ errChan);
}
if (pipePtr->numPids != 0) {
- ckfree((char *) pipePtr->pidPtr);
+ ckfree((char *) pipePtr->pidPtr);
}
ckfree((char *) pipePtr);
if (errorCode == 0) {
- return result;
+ return result;
}
return errorCode;
}
@@ -1001,8 +1041,8 @@ PipeCloseProc(
*
* PipeInputProc --
*
- * This function is invoked from the generic IO level to read input from
- * a command pipeline based channel.
+ * This procedure is invoked from the generic IO level to read
+ * input from a command pipeline based channel.
*
* Results:
* The number of bytes read is returned or -1 on error. An output
@@ -1015,29 +1055,30 @@ PipeCloseProc(
*/
static int
-PipeInputProc(
- ClientData instanceData, /* Pipe state. */
- char *buf, /* Where to store data read. */
- int toRead, /* How much space is available in the
- * buffer? */
- int *errorCodePtr) /* Where to store error code. */
+PipeInputProc(instanceData, buf, toRead, errorCodePtr)
+ ClientData instanceData; /* Pipe state. */
+ char *buf; /* Where to store data read. */
+ int toRead; /* How much space is available
+ * in the buffer? */
+ int *errorCodePtr; /* Where to store error code. */
{
PipeState *psPtr = (PipeState *) instanceData;
- int bytesRead; /* How many bytes were actually read from the
- * input device? */
+ int bytesRead; /* How many bytes were actually
+ * read from the input device? */
*errorCodePtr = 0;
-
+
/*
* Assume there is always enough input available. This will block
* appropriately, and read will unblock as soon as a short read is
* possible, if the channel is in blocking mode. If the channel is
- * nonblocking, the read will never block. Some OSes can throw an
- * interrupt error, for which we should immediately retry. [Bug #415131]
+ * nonblocking, the read will never block.
+ * Some OSes can throw an interrupt error, for which we should
+ * immediately retry. [Bug #415131]
*/
do {
- bytesRead = read(GetFd(psPtr->inFile), buf, (size_t) toRead);
+ bytesRead = read (GetFd(psPtr->inFile), buf, (size_t) toRead);
} while ((bytesRead < 0) && (errno == EINTR));
if (bytesRead < 0) {
@@ -1053,12 +1094,13 @@ PipeInputProc(
*
* PipeOutputProc--
*
- * This function is invoked from the generic IO level to write output to
- * a command pipeline based channel.
+ * This procedure is invoked from the generic IO level to write
+ * output to a command pipeline based channel.
*
* Results:
- * The number of bytes written is returned or -1 on error. An output
- * argument contains a POSIX error code if an error occurred, or zero.
+ * The number of bytes written is returned or -1 on error. An
+ * output argument contains a POSIX error code if an error occurred,
+ * or zero.
*
* Side effects:
* Writes output on the output device of the channel.
@@ -1067,11 +1109,11 @@ PipeInputProc(
*/
static int
-PipeOutputProc(
- ClientData instanceData, /* Pipe state. */
- const char *buf, /* The data buffer. */
- int toWrite, /* How many bytes to write? */
- int *errorCodePtr) /* Where to store error code. */
+PipeOutputProc(instanceData, buf, toWrite, errorCodePtr)
+ ClientData instanceData; /* Pipe state. */
+ CONST char *buf; /* The data buffer. */
+ int toWrite; /* How many bytes to write? */
+ int *errorCodePtr; /* Where to store error code. */
{
PipeState *psPtr = (PipeState *) instanceData;
int written;
@@ -1079,8 +1121,8 @@ PipeOutputProc(
*errorCodePtr = 0;
/*
- * Some OSes can throw an interrupt error, for which we should immediately
- * retry. [Bug #415131]
+ * Some OSes can throw an interrupt error, for which we should
+ * immediately retry. [Bug #415131]
*/
do {
@@ -1106,18 +1148,18 @@ PipeOutputProc(
* None.
*
* Side effects:
- * Sets up the notifier so that a future event on the channel will be
- * seen by Tcl.
+ * Sets up the notifier so that a future event on the channel will
+ * be seen by Tcl.
*
*----------------------------------------------------------------------
*/
static void
-PipeWatchProc(
- ClientData instanceData, /* The pipe state. */
- int mask) /* Events of interest; an OR-ed combination of
- * TCL_READABLE, TCL_WRITABLE and
- * TCL_EXCEPTION. */
+PipeWatchProc(instanceData, mask)
+ ClientData instanceData; /* The pipe state. */
+ int mask; /* Events of interest; an OR-ed
+ * combination of TCL_READABLE,
+ * TCL_WRITABEL and TCL_EXCEPTION. */
{
PipeState *psPtr = (PipeState *) instanceData;
int newmask;
@@ -1149,12 +1191,12 @@ PipeWatchProc(
*
* PipeGetHandleProc --
*
- * Called from Tcl_GetChannelHandle to retrieve OS handles from inside a
- * command pipeline based channel.
+ * Called from Tcl_GetChannelHandle to retrieve OS handles from
+ * inside a command pipeline based channel.
*
* Results:
- * Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if there is no
- * handle for the specified direction.
+ * Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if
+ * there is no handle for the specified direction.
*
* Side effects:
* None.
@@ -1163,19 +1205,19 @@ PipeWatchProc(
*/
static int
-PipeGetHandleProc(
- ClientData instanceData, /* The pipe state. */
- int direction, /* TCL_READABLE or TCL_WRITABLE */
- ClientData *handlePtr) /* Where to store the handle. */
+PipeGetHandleProc(instanceData, direction, handlePtr)
+ ClientData instanceData; /* The pipe state. */
+ int direction; /* TCL_READABLE or TCL_WRITABLE */
+ ClientData *handlePtr; /* Where to store the handle. */
{
PipeState *psPtr = (PipeState *) instanceData;
if (direction == TCL_READABLE && psPtr->inFile) {
- *handlePtr = (ClientData) INT2PTR(GetFd(psPtr->inFile));
+ *handlePtr = (ClientData) GetFd(psPtr->inFile);
return TCL_OK;
}
if (direction == TCL_WRITABLE && psPtr->outFile) {
- *handlePtr = (ClientData) INT2PTR(GetFd(psPtr->outFile));
+ *handlePtr = (ClientData) GetFd(psPtr->outFile);
return TCL_OK;
}
return TCL_ERROR;
@@ -1198,18 +1240,19 @@ PipeGetHandleProc(
*/
Tcl_Pid
-Tcl_WaitPid(
- Tcl_Pid pid,
- int *statPtr,
- int options)
+Tcl_WaitPid(pid, statPtr, options)
+ Tcl_Pid pid;
+ int *statPtr;
+ int options;
{
int result;
- pid_t real_pid = (pid_t) PTR2INT(pid);
+ pid_t real_pid;
+ real_pid = (pid_t) pid;
while (1) {
result = (int) waitpid(real_pid, statPtr, options);
if ((result != -1) || (errno != EINTR)) {
- return (Tcl_Pid) INT2PTR(result);
+ return (Tcl_Pid) result;
}
}
}
@@ -1219,8 +1262,8 @@ Tcl_WaitPid(
*
* Tcl_PidObjCmd --
*
- * This function is invoked to process the "pid" Tcl command. See the
- * user documentation for details on what it does.
+ * This procedure is invoked to process the "pid" Tcl command.
+ * See the user documentation for details on what it does.
*
* Results:
* A standard Tcl result.
@@ -1233,49 +1276,39 @@ Tcl_WaitPid(
/* ARGSUSED */
int
-Tcl_PidObjCmd(
- ClientData dummy, /* Not used. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const *objv) /* Argument strings. */
+Tcl_PidObjCmd(dummy, interp, objc, objv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int objc; /* Number of arguments. */
+ Tcl_Obj *CONST *objv; /* Argument strings. */
{
+ Tcl_Channel chan;
+ Tcl_ChannelType *chanTypePtr;
+ PipeState *pipePtr;
+ int i;
+ Tcl_Obj *resultPtr, *longObjPtr;
+
if (objc > 2) {
Tcl_WrongNumArgs(interp, 1, objv, "?channelId?");
return TCL_ERROR;
}
-
if (objc == 1) {
- Tcl_SetObjResult(interp, Tcl_NewLongObj((long) getpid()));
+ Tcl_SetLongObj(Tcl_GetObjResult(interp), (long) getpid());
} else {
- /*
- * Get the channel and make sure that it refers to a pipe.
- */
- Tcl_Channel chan;
- const Tcl_ChannelType *chanTypePtr;
- PipeState *pipePtr;
- int i;
- Tcl_Obj *resultPtr, *longObjPtr;
-
- chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL);
- if (chan == (Tcl_Channel) NULL) {
+ chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL);
+ if (chan == (Tcl_Channel) NULL) {
return TCL_ERROR;
}
chanTypePtr = Tcl_GetChannelType(chan);
if (chanTypePtr != &pipeChannelType) {
return TCL_OK;
}
-
- /*
- * Extract the process IDs from the pipe structure.
- */
-
- pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan);
- resultPtr = Tcl_NewObj();
- for (i = 0; i < pipePtr->numPids; i++) {
+ pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan);
+ resultPtr = Tcl_GetObjResult(interp);
+ for (i = 0; i < pipePtr->numPids; i++) {
longObjPtr = Tcl_NewLongObj((long) TclpGetPid(pipePtr->pidPtr[i]));
Tcl_ListObjAppendElement(NULL, resultPtr, longObjPtr);
}
- Tcl_SetObjResult(interp, resultPtr);
}
return TCL_OK;
}
@@ -1290,21 +1323,13 @@ Tcl_PidObjCmd(
* Results:
* None.
*
- * Notes:
- * This function carries out no operation on Unix.
+ * This procedure carries out no operation on Unix.
*
*----------------------------------------------------------------------
*/
void
-TclpFinalizePipes(void)
+TclpFinalizePipes()
{
}
-
-/*
- * Local Variables:
- * mode: c
- * c-basic-offset: 4
- * fill-column: 78
- * End:
- */
+