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

📄 tclunixpipe.c

📁 linux系统下的音频通信
💻 C
📖 第 1 页 / 共 2 页
字号:
                        fcntl(targetFd, F_SETFD, 0);	} else {	    int result;	    /*	     * Since we aren't dup'ing the file, we need to explicitly clear	     * the close-on-exec flag.	     */	    result = fcntl(fd, F_SETFD, 0);	}    } else {	close(targetFd);    }    return 1;}/* *---------------------------------------------------------------------- * * TclpCreateCommandChannel -- * *	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. * * Side effects: *	Allocates a new channel. * *---------------------------------------------------------------------- */Tcl_ChannelTclpCreateCommandChannel(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). */{    char channelName[20];    int channelId;    PipeState *statePtr = (PipeState *) ckalloc((unsigned) sizeof(PipeState));    int mode;    statePtr->inFile = readFile;    statePtr->outFile = writeFile;    statePtr->errorFile = errorFile;    statePtr->numPids = numPids;    statePtr->pidPtr = pidPtr;    statePtr->isNonBlocking = 0;    mode = 0;    if (readFile) {        mode |= TCL_READABLE;    }    if (writeFile) {        mode |= TCL_WRITABLE;    }        /*     * Use one of the fds associated with the channel as the     * channel id.     */    if (readFile) {	channelId = GetFd(readFile);    } else if (writeFile) {	channelId = GetFd(writeFile);    } else if (errorFile) {	channelId = GetFd(errorFile);    } else {	channelId = 0;    }    /*     * 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);    return statePtr->channel;}/* *---------------------------------------------------------------------- * * TclGetAndDetachPids -- * *	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 interp->result and to detach the processes. * * Results: *	None. * * Side effects: *	Modifies interp->result. Detaches processes. * *---------------------------------------------------------------------- */voidTclGetAndDetachPids(interp, chan)    Tcl_Interp *interp;    Tcl_Channel chan;{    PipeState *pipePtr;    Tcl_ChannelType *chanTypePtr;    int i;    char buf[20];    /*     * Punt if the channel is not a command channel.     */    chanTypePtr = Tcl_GetChannelType(chan);    if (chanTypePtr != &pipeChannelType) {        return;    }    pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan);    for (i = 0; i < pipePtr->numPids; i++) {        sprintf(buf, "%ld", 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;    }}/* *---------------------------------------------------------------------- * * PipeBlockModeProc -- * *	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. * * Side effects: *	Sets the device into blocking or non-blocking mode. * *---------------------------------------------------------------------- */	/* ARGSUSED */static intPipeBlockModeProc(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 = (PipeState *) instanceData;    int curStatus;    int fd;#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;        }        curStatus = fcntl(fd, F_GETFL);    }    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 != 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 */        return 0;}/* *---------------------------------------------------------------------- * * PipeCloseProc -- * *	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. * * Side effects: *	Closes the command pipeline channel. * *---------------------------------------------------------------------- */	/* ARGSUSED */static intPipeCloseProc(instanceData, interp)    ClientData instanceData;	/* The pipe to close. */    Tcl_Interp *interp;		/* For error reporting. */{    PipeState *pipePtr;    Tcl_Channel errChan;    int errorCode, result;    errorCode = 0;    result = 0;    pipePtr = (PipeState *) instanceData;    if (pipePtr->inFile) {	if (TclpCloseFile(pipePtr->inFile) < 0) {	    errorCode = errno;	}    }    if (pipePtr->outFile) {	if ((TclpCloseFile(pipePtr->outFile) < 0) && (errorCode == 0)) {	    errorCode = errno;	}    }    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) {	    TclpCloseFile(pipePtr->errorFile);        }    } else {        	/*         * Wrap the error file into a channel and give it to the cleanup         * routine.         */        if (pipePtr->errorFile) {	    errChan = Tcl_MakeFileChannel(		(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);    if (errorCode == 0) {        return result;    }    return errorCode;}/* *---------------------------------------------------------------------- * * PipeInputProc -- * *	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 *	argument contains a POSIX error code if an error occurs, or zero. * * Side effects: *	Reads input from the input device of the channel. * *---------------------------------------------------------------------- */static intPipeInputProc(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? */    *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.     */    bytesRead = read(GetFd(psPtr->inFile), buf, (size_t) toRead);    if (bytesRead > -1) {        return bytesRead;    }    *errorCodePtr = errno;    return -1;}/* *---------------------------------------------------------------------- * * PipeOutputProc-- * *	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. * * Side effects: *	Writes output on the output device of the channel. * *---------------------------------------------------------------------- */static intPipeOutputProc(instanceData, buf, toWrite, errorCodePtr)    ClientData instanceData;		/* Pipe state. */    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;    *errorCodePtr = 0;    written = write(GetFd(psPtr->outFile), buf, (size_t) toWrite);    if (written > -1) {        return written;    }    *errorCodePtr = errno;    return -1;}/* *---------------------------------------------------------------------- * * PipeWatchProc -- * *	Initialize the notifier to watch the fds from this channel. * * Results: *	None. * * Side effects: *	Sets up the notifier so that a future event on the channel will *	be seen by Tcl. * *---------------------------------------------------------------------- */static voidPipeWatchProc(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;    if (psPtr->inFile) {	newmask = mask & (TCL_READABLE | TCL_EXCEPTION);	if (newmask) {	    Tcl_CreateFileHandler(GetFd(psPtr->inFile), mask,		    (Tcl_FileProc *) Tcl_NotifyChannel,		    (ClientData) psPtr->channel);	} else {	    Tcl_DeleteFileHandler(GetFd(psPtr->inFile));	}    }    if (psPtr->outFile) {	newmask = mask & (TCL_WRITABLE | TCL_EXCEPTION);	if (newmask) {	    Tcl_CreateFileHandler(GetFd(psPtr->outFile), mask,		    (Tcl_FileProc *) Tcl_NotifyChannel,		    (ClientData) psPtr->channel);	} else {	    Tcl_DeleteFileHandler(GetFd(psPtr->outFile));	}    }}/* *---------------------------------------------------------------------- * * PipeGetHandleProc -- * *	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.  * * Side effects: *	None. * *---------------------------------------------------------------------- */static intPipeGetHandleProc(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) GetFd(psPtr->inFile);	return TCL_OK;    }    if (direction == TCL_WRITABLE && psPtr->outFile) {	*handlePtr = (ClientData) GetFd(psPtr->outFile);	return TCL_OK;    }    return TCL_ERROR;}/* *---------------------------------------------------------------------- * * Tcl_WaitPid -- * *	Implements the waitpid system call on Unix systems. * * Results: *	Result of calling waitpid. * * Side effects: *	Waits for a process to terminate. * *---------------------------------------------------------------------- */Tcl_PidTcl_WaitPid(pid, statPtr, options)    Tcl_Pid pid;    int *statPtr;    int options;{    int result;    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) result;	}    }}/* *---------------------------------------------------------------------- * * Tcl_PidObjCmd -- * *	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. * * Side effects: *	See the user documentation. * *---------------------------------------------------------------------- */	/* ARGSUSED */intTcl_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_SetLongObj(Tcl_GetObjResult(interp), (long) getpid());    } else {        chan = Tcl_GetChannel(interp, Tcl_GetStringFromObj(objv[1], NULL),		NULL);        if (chan == (Tcl_Channel) NULL) {	    return TCL_ERROR;	}	chanTypePtr = Tcl_GetChannelType(chan);	if (chanTypePtr != &pipeChannelType) {	    return TCL_OK;	}        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);	}    }    return TCL_OK;}

⌨️ 快捷键说明

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