diff options
Diffstat (limited to 'unix/tclUnixPipe.c')
| -rw-r--r-- | unix/tclUnixPipe.c | 713 |
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: - */ + |
