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

📄 tclwinpipe.c

📁 这是leon3处理器的交叉编译链
💻 C
📖 第 1 页 / 共 5 页
字号:
		SetEvent(pipePtr->stopReader);		/*		 * Wait at most 10 milliseconds for the reader thread to close.		 */		WaitForSingleObject(pipePtr->readThread, 10);		GetExitCodeThread(pipePtr->readThread, &exitCode);		if (exitCode == STILL_ACTIVE) {		    /*		     * The thread must be blocked waiting for the pipe to		     * become readable in ReadFile().  There isn't a clean way		     * to exit the thread from this condition.  We should		     * terminate the child process instead to get the reader		     * thread to fall out of ReadFile with a FALSE.  (below) is		     * not the correct way to do this, but will stay here until		     * a better solution is found.		     *		     * Note that we need to guard against terminating the		     * thread while it is in the middle of Tcl_ThreadAlert		     * because it won't be able to release the notifier lock.		     */		    Tcl_MutexLock(&pipeMutex);		    /* BUG: this leaks memory */		    TerminateThread(pipePtr->readThread, 0);		    /* Wait for the thread to terminate. */		    WaitForSingleObject(pipePtr->readThread, INFINITE);		    Tcl_MutexUnlock(&pipeMutex);		}	    }	    CloseHandle(pipePtr->readThread);	    CloseHandle(pipePtr->readable);	    CloseHandle(pipePtr->startReader);	    CloseHandle(pipePtr->stopReader);	    pipePtr->readThread = NULL;	}	if (TclpCloseFile(pipePtr->readFile) != 0) {	    errorCode = errno;	}	pipePtr->validMask &= ~TCL_READABLE;	pipePtr->readFile = NULL;    }    if ((!flags || (flags & TCL_CLOSE_WRITE))	    && (pipePtr->writeFile != NULL)) {	/*	 * Wait for the writer thread to finish the current buffer, then	 * terminate the thread and close the handles.  If the channel is	 * nonblocking, there should be no pending write operations.	 */	if (pipePtr->writeThread) {	    WaitForSingleObject(pipePtr->writable, INFINITE);	    /*	     * Forcibly terminate the background thread.  We cannot rely on the	     * thread to cleanly terminate itself because we have no way of	     * closing the pipe handle without blocking in the case where the	     * thread is in the middle of an I/O operation.  Note that we need	     * to guard against terminating the thread while it is in the	     * middle of Tcl_ThreadAlert because it won't be able to release	     * the notifier lock.	     */	    Tcl_MutexLock(&pipeMutex);	    TerminateThread(pipePtr->writeThread, 0);	    /*	     * Wait for the thread to terminate.  This ensures that we are	     * completely cleaned up before we leave this function. 	     */	    WaitForSingleObject(pipePtr->writeThread, INFINITE);	    Tcl_MutexUnlock(&pipeMutex);	    CloseHandle(pipePtr->writeThread);	    CloseHandle(pipePtr->writable);	    CloseHandle(pipePtr->startWriter);	    pipePtr->writeThread = NULL;	}	if (TclpCloseFile(pipePtr->writeFile) != 0) {	    if (errorCode == 0) {		errorCode = errno;	    }	}	pipePtr->validMask &= ~TCL_WRITABLE;	pipePtr->writeFile = NULL;    }    pipePtr->watchMask &= pipePtr->validMask;    /*     * Don't free the channel if any of the flags were set.     */    if (flags) {	return errorCode;    }    /*     * Remove the file from the list of watched files.     */    for (nextPtrPtr = &(tsdPtr->firstPipePtr), infoPtr = *nextPtrPtr;	    infoPtr != NULL;	    nextPtrPtr = &infoPtr->nextPtr, infoPtr = *nextPtrPtr) {	if (infoPtr == (PipeInfo *)pipePtr) {	    *nextPtrPtr = infoPtr->nextPtr;	    break;	}    }    /*     * Wrap the error file into a channel and give it to the cleanup     * routine.     */    if (pipePtr->errorFile) {	WinFile *filePtr;	filePtr = (WinFile*)pipePtr->errorFile;	errChan = Tcl_MakeFileChannel((ClientData) filePtr->handle,		TCL_READABLE);	ckfree((char *) filePtr);    } else {        errChan = NULL;    }    result = TclCleanupChildren(interp, pipePtr->numPids, pipePtr->pidPtr,            errChan);    if (pipePtr->numPids > 0) {        ckfree((char *) pipePtr->pidPtr);    }    if (pipePtr->writeBuf != NULL) {	ckfree(pipePtr->writeBuf);    }    ckfree((char*) pipePtr);    if (errorCode == 0) {        return result;    }    return errorCode;}/* *---------------------------------------------------------------------- * * PipeInputProc -- * *	Reads input from the IO channel into the buffer given. Returns *	count of how many bytes were actually read, and an error indication. * * Results: *	A count of how many bytes were read is returned and an error *	indication is returned in an output argument. * * Side effects: *	Reads input from the actual channel. * *---------------------------------------------------------------------- */static intPipeInputProc(    ClientData instanceData,		/* Pipe state. */    char *buf,				/* Where to store data read. */    int bufSize,			/* How much space is available                                         * in the buffer? */    int *errorCode)			/* Where to store error code. */{    PipeInfo *infoPtr = (PipeInfo *) instanceData;    WinFile *filePtr = (WinFile*) infoPtr->readFile;    DWORD count, bytesRead = 0;    int result;    *errorCode = 0;    /*     * Synchronize with the reader thread.     */    result = WaitForRead(infoPtr, (infoPtr->flags & PIPE_ASYNC) ? 0 : 1);    /*     * If an error occurred, return immediately.     */    if (result == -1) {	*errorCode = errno;	return -1;    }    if (infoPtr->readFlags & PIPE_EXTRABYTE) {	/*	 * The reader thread consumed 1 byte as a side effect of	 * waiting so we need to move it into the buffer.	 */	*buf = infoPtr->extraByte;	infoPtr->readFlags &= ~PIPE_EXTRABYTE;	buf++;	bufSize--;	bytesRead = 1;	/*	 * If further read attempts would block, return what we have.	 */	if (result == 0) {	    return bytesRead;	}    }    /*     * Attempt to read bufSize bytes.  The read will return immediately     * if there is any data available.  Otherwise it will block until     * at least one byte is available or an EOF occurs.     */    if (ReadFile(filePtr->handle, (LPVOID) buf, (DWORD) bufSize, &count,	    (LPOVERLAPPED) NULL) == TRUE) {	return bytesRead + count;    } else if (bytesRead) {	/*	 * Ignore errors if we have data to return.	 */	return bytesRead;    }    TclWinConvertError(GetLastError());    if (errno == EPIPE) {	infoPtr->readFlags |= PIPE_EOF;	return 0;    }    *errorCode = errno;    return -1;}/* *---------------------------------------------------------------------- * * PipeOutputProc -- * *	Writes the given output on the IO channel. Returns count of how *	many characters were actually written, and an error indication. * * Results: *	A count of how many characters were written is returned and an *	error indication is returned in an output argument. * * Side effects: *	Writes output on the actual channel. * *---------------------------------------------------------------------- */static intPipeOutputProc(    ClientData instanceData,		/* Pipe state. */    CONST char *buf,			/* The data buffer. */    int toWrite,			/* How many bytes to write? */    int *errorCode)			/* Where to store error code. */{    PipeInfo *infoPtr = (PipeInfo *) instanceData;    WinFile *filePtr = (WinFile*) infoPtr->writeFile;    DWORD bytesWritten, timeout;        *errorCode = 0;    timeout = (infoPtr->flags & PIPE_ASYNC) ? 0 : INFINITE;    if (WaitForSingleObject(infoPtr->writable, timeout) == WAIT_TIMEOUT) {	/*	 * The writer thread is blocked waiting for a write to complete	 * and the channel is in non-blocking mode.	 */	errno = EAGAIN;	goto error;    }        /*     * Check for a background error on the last write.     */    if (infoPtr->writeError) {	TclWinConvertError(infoPtr->writeError);	infoPtr->writeError = 0;	goto error;    }    if (infoPtr->flags & PIPE_ASYNC) {	/*	 * The pipe is non-blocking, so copy the data into the output	 * buffer and restart the writer thread.	 */	if (toWrite > infoPtr->writeBufLen) {	    /*	     * Reallocate the buffer to be large enough to hold the data.	     */	    if (infoPtr->writeBuf) {		ckfree(infoPtr->writeBuf);	    }	    infoPtr->writeBufLen = toWrite;	    infoPtr->writeBuf = ckalloc((unsigned int) toWrite);	}	memcpy(infoPtr->writeBuf, buf, (size_t) toWrite);	infoPtr->toWrite = toWrite;	ResetEvent(infoPtr->writable);	SetEvent(infoPtr->startWriter);	bytesWritten = toWrite;    } else {	/*	 * In the blocking case, just try to write the buffer directly.	 * This avoids an unnecessary copy.	 */	if (WriteFile(filePtr->handle, (LPVOID) buf, (DWORD) toWrite,		&bytesWritten, (LPOVERLAPPED) NULL) == FALSE) {	    TclWinConvertError(GetLastError());	    goto error;	}    }    return bytesWritten;    error:    *errorCode = errno;    return -1;}/* *---------------------------------------------------------------------- * * PipeEventProc -- * *	This function is invoked by Tcl_ServiceEvent when a file event *	reaches the front of the event queue.  This procedure invokes *	Tcl_NotifyChannel on the pipe. * * Results: *	Returns 1 if the event was handled, meaning it should be removed *	from the queue.  Returns 0 if the event was not handled, meaning *	it should stay on the queue.  The only time the event isn't *	handled is if the TCL_FILE_EVENTS flag bit isn't set. * * Side effects: *	Whatever the notifier callback does. * *---------------------------------------------------------------------- */static intPipeEventProc(    Tcl_Event *evPtr,		/* Event to service. */    int flags)			/* Flags that indicate what events to				 * handle, such as TCL_FILE_EVENTS. */{    PipeEvent *pipeEvPtr = (PipeEvent *)evPtr;    PipeInfo *infoPtr;    WinFile *filePtr;    int mask;    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);    if (!(flags & TCL_FILE_EVENTS)) {	return 0;    }    /*     * Search through the list of watched pipes for the one whose handle     * matches the event.  We do this rather than simply dereferencing     * the handle in the event so that pipes can be deleted while the     * event is in the queue.     */    for (infoPtr = tsdPtr->firstPipePtr; infoPtr != NULL;	    infoPtr = infoPtr->nextPtr) {	if (pipeEvPtr->infoPtr == infoPtr) {	    infoPtr->flags &= ~(PIPE_PENDING);	    break;	}    }    /*     * Remove stale events.     */    if (!infoPtr) {	return 1;    }    /*     * Check to see if the pipe is readable.  Note     * that we can't tell if a pipe is writable, so we always report it     * as being writable unless we have detected EOF.     */    filePtr = (WinFile*) ((PipeInfo*)infoPtr)->writeFile;    mask = 0;    if ((infoPtr->watchMask & TCL_WRITABLE) &&	    (WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT)) {	mask = TCL_WRITABLE;    }    filePtr = (WinFile*) ((PipeInfo*)infoPtr)->readFile;    if ((infoPtr->watchMask & TCL_READABLE) &&	    (WaitForRead(infoPtr, 0) >= 0)) {	if (infoPtr->readFlags & PIPE_EOF) {	    mask = TCL_READABLE;	} else {	    mask |= TCL_READABLE;	}    }    /*     * Inform the channel of the events.     */    Tcl_NotifyChannel(infoPtr->channel, infoPtr->watchMask & mask);    return 1;}/* *---------------------------------------------------------------------- * * PipeWatchProc -- * *	Called by the notifier to set up to watch for events on this *	channel. * * Results: *	None. * * Side effects: *	None. * *---------------------------------------------------------------------- */static voidPipeWatchProc(    ClientData instanceData,		/* Pipe state. */    int mask)				/* What events to watch for, OR-ed                                         * combination of TCL_READABLE,                                         * TCL_WRITABLE and TCL_EXCEPTION. */{    PipeInfo **nextPtrPtr, *ptr;    PipeInfo *infoPtr = (PipeInfo *) instanceData;    int oldMask = infoPtr->watchMask;    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);    /*     * Since most of the work is handled by the background threads,     * we just need to update the watchMask and then force the notifier     * to poll once.      */    infoPtr

⌨️ 快捷键说明

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