diff options
Diffstat (limited to 'unix/tclUnixPipe.c')
| -rw-r--r-- | unix/tclUnixPipe.c | 840 |
1 files changed, 392 insertions, 448 deletions
diff --git a/unix/tclUnixPipe.c b/unix/tclUnixPipe.c index d01624c..3a4005c 100644 --- a/unix/tclUnixPipe.c +++ b/unix/tclUnixPipe.c @@ -1,75 +1,77 @@ -/* +/* * 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 #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 int PipeBlockModeProc(ClientData instanceData, int mode); -static int PipeClose2Proc(ClientData instanceData, - Tcl_Interp *interp, int flags); -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)); /* - * 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 const Tcl_ChannelType pipeChannelType = { +static Tcl_ChannelType pipeChannelType = { "pipe", /* Type name. */ - TCL_CHANNEL_VERSION_5, /* v5 channel */ - TCL_CLOSE2PROC, /* Close proc. */ + TCL_CHANNEL_VERSION_4, /* v4 channel */ + PipeCloseProc, /* Close proc. */ PipeInputProc, /* Input proc. */ PipeOutputProc, /* Output proc. */ NULL, /* Seek proc. */ @@ -77,13 +79,12 @@ static const Tcl_ChannelType pipeChannelType = { NULL, /* Get option proc. */ PipeWatchProc, /* Initialize notifier. */ PipeGetHandleProc, /* Get OS handles out of channel. */ - PipeClose2Proc, /* close2proc. */ + NULL, /* close2proc. */ 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 */ }; /* @@ -103,17 +104,18 @@ static const 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, &data) != TCL_OK) { - return NULL; + if (Tcl_GetChannelHandle(channel, direction, (ClientData *) &data) + == TCL_OK) { + return MakeFile((int)data); + } else { + return (TclFile) NULL; } - - return MakeFile(PTR2INT(data)); } /* @@ -121,7 +123,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. @@ -133,23 +135,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)) { @@ -157,8 +159,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); @@ -171,9 +173,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. @@ -185,11 +187,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; @@ -238,8 +240,8 @@ TclpCreateTempFile( *---------------------------------------------------------------------- */ -Tcl_Obj * -TclpTempFileName(void) +Tcl_Obj* +TclpTempFileName() { char fileName[L_tmpnam + 9]; Tcl_Obj *result = NULL; @@ -261,67 +263,33 @@ TclpTempFileName(void) fcntl(fd, F_SETFD, FD_CLOEXEC); unlink(fileName); /* INTL: Native. */ - result = TclpNativeToNormalized(fileName); - close(fd); + result = TclpNativeToNormalized((ClientData) fileName); + close (fd); return result; } /* - *----------------------------------------------------------------------------- - * - * TclpTempFileNameForLibrary -- - * - * Constructs a file name in the native file system where a - * dynamically loaded library may be placed. - * - * Results: - * Returns the constructed file name. If an error occurs, - * returns NULL and leaves an error message in the interpreter - * result. - * - * On Unix, it works to load a shared object from a file of any - * name, so this function is merely a thin wrapper around - * TclpTempFileName(). - * - *----------------------------------------------------------------------------- - */ - -Tcl_Obj* -TclpTempFileNameForLibrary(Tcl_Interp* interp, /* Tcl interpreter */ - Tcl_Obj* path) /* Path name of the library - * in the VFS */ -{ - Tcl_Obj* retval; - retval = TclpTempFileName(); - if (retval == NULL) { - Tcl_AppendResult(interp, "couldn't create temporary file: ", - Tcl_PosixError(interp), NULL); - } - return retval; -} - -/* *---------------------------------------------------------------------- * * 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]; @@ -354,19 +322,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); } @@ -376,53 +344,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; @@ -431,29 +401,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 = TclStackAlloc(interp, argc * sizeof(Tcl_DString)); - newArgv = 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]); @@ -466,7 +435,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); } @@ -477,10 +445,8 @@ TclpCreateProcess( Tcl_GetStdChannel(TCL_STDERR); } #endif - pid = fork(); if (pid == 0) { - size_t len; int joinThisError = errorFile && (errorFile == outputFile); fd = GetFd(errPipeOut); @@ -493,13 +459,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); } @@ -510,33 +474,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); @@ -548,26 +508,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); } @@ -582,21 +543,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); @@ -656,10 +617,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. @@ -671,9 +632,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; @@ -682,18 +643,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) { @@ -709,20 +670,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); @@ -735,8 +696,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. @@ -748,20 +710,20 @@ 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; - PipeState *statePtr = ckalloc(sizeof(PipeState)); + PipeState *statePtr = (PipeState *) ckalloc((unsigned) sizeof(PipeState)); int mode; statePtr->inFile = readFile; @@ -773,14 +735,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) { @@ -794,69 +757,26 @@ 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, - statePtr, mode); + (ClientData) statePtr, mode); return statePtr->channel; } /* *---------------------------------------------------------------------- * - * Tcl_CreatePipe -- - * - * System dependent interface to create a pipe for the [chan pipe] - * command. Stolen from TclX. - * - * Results: - * TCL_OK or TCL_ERROR. - * - * Side effects: - * Registers two channels. - * - *---------------------------------------------------------------------- - */ - -int -Tcl_CreatePipe( - Tcl_Interp *interp, /* Errors returned in result. */ - Tcl_Channel *rchan, /* Returned read side. */ - Tcl_Channel *wchan, /* Returned write side. */ - int flags) /* Reserved for future use. */ -{ - int fileNums[2]; - - if (pipe(fileNums) < 0) { - Tcl_AppendResult(interp, "pipe creation failed: ", - Tcl_PosixError(interp), NULL); - return TCL_ERROR; - } - - fcntl(fileNums[0], F_SETFD, FD_CLOEXEC); - fcntl(fileNums[1], F_SETFD, FD_CLOEXEC); - - *rchan = Tcl_MakeFileChannel(INT2PTR(fileNums[0]), TCL_READABLE); - Tcl_RegisterChannel(interp, *rchan); - *wchan = Tcl_MakeFileChannel(INT2PTR(fileNums[1]), TCL_WRITABLE); - Tcl_RegisterChannel(interp, *wchan); - - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * * 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. @@ -868,12 +788,12 @@ Tcl_CreatePipe( */ 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]; @@ -883,18 +803,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(pipePtr->pidPtr); - pipePtr->numPids = 0; + ckfree((char *) pipePtr->pidPtr); + pipePtr->numPids = 0; } } @@ -903,8 +823,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. @@ -917,22 +837,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; - if (psPtr->inFile - && TclUnixSetBlockingMode(GetFd(psPtr->inFile), mode) < 0) { - return errno; +#ifndef USE_FIONBIO + if (psPtr->inFile) { + 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) { + 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 - && TclUnixSetBlockingMode(GetFd(psPtr->outFile), mode) < 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); @@ -942,10 +907,11 @@ PipeBlockModeProc( /* *---------------------------------------------------------------------- * - * PipeClose2Proc + * PipeCloseProc -- * - * This function is invoked by the generic IO level to perform - * pipeline-type-specific half or full-close. + * 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. @@ -956,79 +922,67 @@ PipeBlockModeProc( *---------------------------------------------------------------------- */ + /* ARGSUSED */ static int -PipeClose2Proc( - ClientData instanceData, /* The pipe to close. */ - Tcl_Interp *interp, /* For error reporting. */ - int flags) /* Flags that indicate which side to close. */ +PipeCloseProc(instanceData, interp) + ClientData instanceData; /* The pipe to close. */ + Tcl_Interp *interp; /* For error reporting. */ { - PipeState *pipePtr = instanceData; + PipeState *pipePtr; Tcl_Channel errChan; int errorCode, result; errorCode = 0; result = 0; - - if (((!flags) || (flags & TCL_CLOSE_READ)) && (pipePtr->inFile != NULL)) { + pipePtr = (PipeState *) instanceData; + if (pipePtr->inFile) { if (TclpCloseFile(pipePtr->inFile) < 0) { errorCode = errno; - } else { - pipePtr->inFile = NULL; } } - if (((!flags) || (flags & TCL_CLOSE_WRITE)) && (pipePtr->outFile != NULL) - && (errorCode == 0)) { - if (TclpCloseFile(pipePtr->outFile) < 0) { + if (pipePtr->outFile) { + if ((TclpCloseFile(pipePtr->outFile) < 0) && (errorCode == 0)) { errorCode = errno; - } else { - pipePtr->outFile = NULL; } } - - /* - * If half-closing, stop here. - */ - - if (flags) { - return errorCode; - } 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( - 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(pipePtr->pidPtr); + ckfree((char *) pipePtr->pidPtr); } - ckfree(pipePtr); + ckfree((char *) pipePtr); if (errorCode == 0) { - return result; + return result; } return errorCode; } @@ -1038,8 +992,8 @@ PipeClose2Proc( * * 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 @@ -1052,36 +1006,38 @@ PipeClose2Proc( */ 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 = instanceData; - int bytesRead; /* How many bytes were actually read from the - * input device? */ + PipeState *psPtr = (PipeState *) instanceData; + 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) { *errorCodePtr = errno; return -1; + } else { + return bytesRead; } - return bytesRead; } /* @@ -1089,12 +1045,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. @@ -1103,20 +1060,20 @@ 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 = instanceData; + PipeState *psPtr = (PipeState *) instanceData; int written; *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 { @@ -1126,8 +1083,9 @@ PipeOutputProc( if (written < 0) { *errorCodePtr = errno; return -1; + } else { + return written; } - return written; } /* @@ -1141,27 +1099,28 @@ 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 = instanceData; + PipeState *psPtr = (PipeState *) instanceData; int newmask; if (psPtr->inFile) { newmask = mask & (TCL_READABLE | TCL_EXCEPTION); if (newmask) { Tcl_CreateFileHandler(GetFd(psPtr->inFile), mask, - (Tcl_FileProc *) Tcl_NotifyChannel, psPtr->channel); + (Tcl_FileProc *) Tcl_NotifyChannel, + (ClientData) psPtr->channel); } else { Tcl_DeleteFileHandler(GetFd(psPtr->inFile)); } @@ -1170,7 +1129,8 @@ PipeWatchProc( newmask = mask & (TCL_WRITABLE | TCL_EXCEPTION); if (newmask) { Tcl_CreateFileHandler(GetFd(psPtr->outFile), mask, - (Tcl_FileProc *) Tcl_NotifyChannel, psPtr->channel); + (Tcl_FileProc *) Tcl_NotifyChannel, + (ClientData) psPtr->channel); } else { Tcl_DeleteFileHandler(GetFd(psPtr->outFile)); } @@ -1182,12 +1142,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. @@ -1196,19 +1156,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 = instanceData; + PipeState *psPtr = (PipeState *) instanceData; if (direction == TCL_READABLE && psPtr->inFile) { - *handlePtr = INT2PTR(GetFd(psPtr->inFile)); + *handlePtr = (ClientData) GetFd(psPtr->inFile); return TCL_OK; } if (direction == TCL_WRITABLE && psPtr->outFile) { - *handlePtr = INT2PTR(GetFd(psPtr->outFile)); + *handlePtr = (ClientData) GetFd(psPtr->outFile); return TCL_OK; } return TCL_ERROR; @@ -1231,18 +1191,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; } } } @@ -1252,8 +1213,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. @@ -1266,13 +1227,14 @@ 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; @@ -1281,33 +1243,23 @@ Tcl_PidObjCmd( 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. - */ - - chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL); - if (chan == NULL) { + chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL); + if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } - if (Tcl_GetChannelType(chan) != &pipeChannelType) { + 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; } @@ -1322,21 +1274,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: - */ + |
