⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tclunixpipe.c

📁 linux系统下的音频通信
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  * tclUnixPipe.c -- * *	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. * * SCCS: @(#) tclUnixPipe.c 1.37 97/10/31 17:23:37 */#include "tclInt.h"#include "tclPort.h"/* * 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)(((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. */} PipeState;/* * Declarations for local procedures defined in this file: */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, 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 IO: */static Tcl_ChannelType pipeChannelType = {    "pipe",				/* Type name. */    PipeBlockModeProc,			/* Set blocking/nonblocking mode.*/    PipeCloseProc,			/* Close proc. */    PipeInputProc,			/* Input proc. */    PipeOutputProc,			/* Output proc. */    NULL,				/* Seek proc. */    NULL,				/* Set option proc. */    NULL,				/* Get option proc. */    PipeWatchProc,			/* Initialize notifier. */    PipeGetHandleProc,			/* Get OS handles out of channel. */};/* *---------------------------------------------------------------------- * * TclpMakeFile -- * *	Make a TclFile from a channel. * * Results: *	Returns a new TclFile or NULL on failure. * * Side effects: *	None. * *---------------------------------------------------------------------- */TclFileTclpMakeFile(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((int)data);    } else {	return (TclFile) NULL;    }}/* *---------------------------------------------------------------------- * * TclpOpenFile -- * *	Open a file for use in a pipeline.   * * Results: *	Returns a new TclFile handle or NULL on failure. * * Side effects: *	May cause a file to be created on the file system. * *---------------------------------------------------------------------- */TclFileTclpOpenFile(fname, mode)    char *fname;			/* The name of the file to open. */    int mode;				/* In what mode to open the file? */{    int fd;    fd = open(fname, mode, 0666);    if (fd != -1) {        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 (mode & O_WRONLY) {	    lseek(fd, 0, SEEK_END);	}	/*	 * Increment the fd so it can't be 0, which would conflict with	 * the NULL return for errors.	 */	return MakeFile(fd);    }    return NULL;}/* *---------------------------------------------------------------------- * * 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. * * Results: *	A handle to a file. * * Side effects: *	None. * *---------------------------------------------------------------------- */TclFileTclpCreateTempFile(contents, namePtr)    char *contents;		/* String to write into temp file, or NULL. */    Tcl_DString *namePtr;	/* If non-NULL, pointer to initialized 				 * DString that is filled with the name of 				 * the temp file that was created. */{    char fileName[L_tmpnam];    TclFile file;    size_t length = (contents == NULL) ? 0 : strlen(contents);    tmpnam(fileName);    file = TclpOpenFile(fileName, O_RDWR|O_CREAT|O_TRUNC);    unlink(fileName);    if ((file != NULL) && (length > 0)) {	int fd = GetFd(file);	while (1) {	    if (write(fd, contents, length) != -1) {		break;	    } else if (errno != EINTR) {		close(fd);		return NULL;	    }	}	lseek(fd, 0, SEEK_SET);    }    if (namePtr != NULL) {	Tcl_DStringAppend(namePtr, fileName, -1);    }    return file;}/* *---------------------------------------------------------------------- * * TclpCreatePipe -- * *      Creates a pipe - simply calls the pipe() function. * * Results: *      Returns 1 on success, 0 on failure.  * * Side effects: *      Creates a pipe. * *---------------------------------------------------------------------- */intTclpCreatePipe(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];    if (pipe(pipeIds) != 0) {	return 0;    }    fcntl(pipeIds[0], F_SETFD, FD_CLOEXEC);    fcntl(pipeIds[1], F_SETFD, FD_CLOEXEC);    *readPipe = MakeFile(pipeIds[0]);    *writePipe = MakeFile(pipeIds[1]);    return 1;}/* *---------------------------------------------------------------------- * * TclpCloseFile -- * *	Implements a mechanism to close a UNIX file. * * Results: *	Returns 0 on success, or -1 on error, setting errno. * * Side effects: *	The file is closed. * *---------------------------------------------------------------------- */intTclpCloseFile(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;    }        Tcl_DeleteFileHandler(fd);    return close(fd);}/* *---------------------------------------------------------------------- * * 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. * *	The path is searched to find the specified executable.   * * Results: *	The return value is TCL_ERROR and an error message is left in *	interp->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 */intTclpCreateProcess(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. */    char **argv;		/* Array of argument strings.  argv[0]				 * contains the name of the executable				 * converted to native format (using the				 * Tcl_TranslateFileName 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				 * 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 procedure is successful, pidPtr				 * is filled with the process id of the child				 * process. */{    TclFile errPipeIn, errPipeOut;    int joinThisError, count, status, fd;    char errSpace[200];    int pid;        errPipeIn = NULL;    errPipeOut = NULL;    pid = -1;    /*     * 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), (char *) NULL);	goto error;    }    joinThisError = (errorFile == outputFile);    pid = vfork();    if (pid == 0) {	fd = GetFd(errPipeOut);	/*	 * Set up stdio file handles for the child process.	 */	if (!SetupStdFile(inputFile, TCL_STDIN)		|| !SetupStdFile(outputFile, TCL_STDOUT)		|| (!joinThisError && !SetupStdFile(errorFile, TCL_STDERR))		|| (joinThisError &&			((dup2(1,2) == -1) ||			 (fcntl(2, F_SETFD, 0) != 0)))) {	    sprintf(errSpace,		    "%dforked process couldn't set up input/output: ",		    errno);	    write(fd, errSpace, (size_t) strlen(errSpace));	    _exit(1);	}	/*	 * Close the input side of the error pipe.	 */	RestoreSignals();	execvp(argv[0], &argv[0]);	sprintf(errSpace, "%dcouldn't execute \"%.150s\": ", errno,		argv[0]);	write(fd, errSpace, (size_t) strlen(errSpace));	_exit(1);    }    if (pid == -1) {	Tcl_AppendResult(interp, "couldn't fork child process: ",		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.     */    TclpCloseFile(errPipeOut);    errPipeOut = NULL;    fd = GetFd(errPipeIn);    count = read(fd, errSpace, (size_t) (sizeof(errSpace) - 1));    if (count > 0) {	char *end;	errSpace[count] = 0;	errno = strtol(errSpace, &end, 10);	Tcl_AppendResult(interp, end, Tcl_PosixError(interp),		(char *) NULL);	goto error;    }        TclpCloseFile(errPipeIn);    *pidPtr = (Tcl_Pid) pid;    return TCL_OK;    error:    if (pid != -1) {	/*	 * Reap the child process now if an error occurred during its	 * startup.	 */	Tcl_WaitPid((Tcl_Pid) pid, &status, WNOHANG);    }        if (errPipeIn) {	TclpCloseFile(errPipeIn);    }    if (errPipeOut) {	TclpCloseFile(errPipeOut);    }    return TCL_ERROR;}/* *---------------------------------------------------------------------- * * RestoreSignals -- * *      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. * * Side effects: *      Signal settings get changed. * *---------------------------------------------------------------------- */ static voidRestoreSignals(){#ifdef SIGABRT    signal(SIGABRT, SIG_DFL);#endif#ifdef SIGALRM    signal(SIGALRM, SIG_DFL);#endif#ifdef SIGFPE    signal(SIGFPE, SIG_DFL);#endif#ifdef SIGHUP    signal(SIGHUP, SIG_DFL);#endif#ifdef SIGILL    signal(SIGILL, SIG_DFL);#endif#ifdef SIGINT    signal(SIGINT, SIG_DFL);#endif#ifdef SIGPIPE    signal(SIGPIPE, SIG_DFL);#endif#ifdef SIGQUIT    signal(SIGQUIT, SIG_DFL);#endif#ifdef SIGSEGV    signal(SIGSEGV, SIG_DFL);#endif#ifdef SIGTERM    signal(SIGTERM, SIG_DFL);#endif#ifdef SIGUSR1    signal(SIGUSR1, SIG_DFL);#endif#ifdef SIGUSR2    signal(SIGUSR2, SIG_DFL);#endif#ifdef SIGCHLD    signal(SIGCHLD, SIG_DFL);#endif#ifdef SIGCONT    signal(SIGCONT, SIG_DFL);#endif#ifdef SIGTSTP    signal(SIGTSTP, SIG_DFL);#endif#ifdef SIGTTIN    signal(SIGTTIN, SIG_DFL);#endif#ifdef SIGTTOU    signal(SIGTTOU, SIG_DFL);#endif}/* *---------------------------------------------------------------------- * * 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. * * Results: *	Returns 1 on success, or 0 on failure. * * Side effects: *	Replaces stdio fds. * *---------------------------------------------------------------------- */static intSetupStdFile(file, type)    TclFile file;		/* File to dup, or NULL. */    int type;			/* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR */{    Tcl_Channel channel;    int fd;    int targetFd = 0;		/* Initializations here needed only to */    int direction = 0;		/* prevent warnings about using uninitialized				 * 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;    }    if (!file) {	channel = Tcl_GetStdChannel(type);	if (channel) {	    file = TclpMakeFile(channel, direction);	}    }    if (file) {	fd = GetFd(file);	if (fd != targetFd) {	    if (dup2(fd, targetFd) == -1) {		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.             */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -