static int FileCloseProc( ClientData instanceData, /* File state. */ Tcl_Interp *interp) /* For error reporting - unused. */ { FileState *fsPtr = instanceData; int errorCode = 0; Tcl_DeleteFileHandler(fsPtr->fd); /* * Do not close standard channels while in thread-exit. */ if (!TclInThreadExit() || ((fsPtr->fd != 0) && (fsPtr->fd != 1) && (fsPtr->fd != 2))) { if (close(fsPtr->fd) < 0) { errorCode = errno; } } ckfree(fsPtr); return errorCode; }
static int ConsoleCloseProc( ClientData instanceData, /* Pointer to ConsoleInfo structure. */ Tcl_Interp *interp) /* For error reporting. */ { ConsoleInfo *consolePtr = (ConsoleInfo *) instanceData; int errorCode; ConsoleInfo *infoPtr, **nextPtrPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); DWORD exitCode; errorCode = 0; /* * Clean up the background thread if necessary. Note that this must be * done before we can close the file, since the thread may be blocking * trying to read from the console. */ if (consolePtr->readThread) { /* * The thread may already have closed on it's own. Check it's exit * code. */ GetExitCodeThread(consolePtr->readThread, &exitCode); if (exitCode == STILL_ACTIVE) { /* * Set the stop event so that if the reader thread is blocked in * ConsoleReaderThread on WaitForMultipleEvents, it will exit * cleanly. */ SetEvent(consolePtr->stopReader); /* * Wait at most 20 milliseconds for the reader thread to close. */ if (WaitForSingleObject(consolePtr->readThread, 20) == WAIT_TIMEOUT) { /* * Forcibly terminate the background thread as a last resort. * 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(&consoleMutex); /* BUG: this leaks memory. */ TerminateThread(consolePtr->readThread, 0); Tcl_MutexUnlock(&consoleMutex); } } CloseHandle(consolePtr->readThread); CloseHandle(consolePtr->readable); CloseHandle(consolePtr->startReader); CloseHandle(consolePtr->stopReader); consolePtr->readThread = NULL; } consolePtr->validMask &= ~TCL_READABLE; /* * 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 (consolePtr->writeThread) { if (consolePtr->toWrite) { /* * We only need to wait if there is something to write. This may * prevent infinite wait on exit. [python bug 216289] */ WaitForSingleObject(consolePtr->writable, INFINITE); } /* * The thread may already have closed on it's own. Check it's exit * code. */ GetExitCodeThread(consolePtr->writeThread, &exitCode); if (exitCode == STILL_ACTIVE) { /* * Set the stop event so that if the reader thread is blocked in * ConsoleWriterThread on WaitForMultipleEvents, it will exit * cleanly. */ SetEvent(consolePtr->stopWriter); /* * Wait at most 20 milliseconds for the writer thread to close. */ if (WaitForSingleObject(consolePtr->writeThread, 20) == WAIT_TIMEOUT) { /* * Forcibly terminate the background thread as a last resort. * 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(&consoleMutex); /* BUG: this leaks memory. */ TerminateThread(consolePtr->writeThread, 0); Tcl_MutexUnlock(&consoleMutex); } } CloseHandle(consolePtr->writeThread); CloseHandle(consolePtr->writable); CloseHandle(consolePtr->startWriter); CloseHandle(consolePtr->stopWriter); consolePtr->writeThread = NULL; } consolePtr->validMask &= ~TCL_WRITABLE; /* * Don't close the Win32 handle if the handle is a standard channel during * the thread exit process. Otherwise, one thread may kill the stdio of * another. */ if (!TclInThreadExit() || ((GetStdHandle(STD_INPUT_HANDLE) != consolePtr->handle) && (GetStdHandle(STD_OUTPUT_HANDLE) != consolePtr->handle) && (GetStdHandle(STD_ERROR_HANDLE) != consolePtr->handle))) { if (CloseHandle(consolePtr->handle) == FALSE) { TclWinConvertError(GetLastError()); errorCode = errno; } } consolePtr->watchMask &= consolePtr->validMask; /* * Remove the file from the list of watched files. */ for (nextPtrPtr = &(tsdPtr->firstConsolePtr), infoPtr = *nextPtrPtr; infoPtr != NULL; nextPtrPtr = &infoPtr->nextPtr, infoPtr = *nextPtrPtr) { if (infoPtr == (ConsoleInfo *)consolePtr) { *nextPtrPtr = infoPtr->nextPtr; break; } } if (consolePtr->writeBuf != NULL) { ckfree(consolePtr->writeBuf); consolePtr->writeBuf = 0; } ckfree((char*) consolePtr); return errorCode; }
static int ConsoleCloseProc( ClientData instanceData, /* Pointer to ConsoleInfo structure. */ Tcl_Interp *interp) /* For error reporting. */ { ConsoleInfo *consolePtr = instanceData; int errorCode = 0; ConsoleInfo *infoPtr, **nextPtrPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * Clean up the background thread if necessary. Note that this must be * done before we can close the file, since the thread may be blocking * trying to read from the console. */ if (consolePtr->reader.thread) { StopChannelThread(&consolePtr->reader); } consolePtr->validMask &= ~TCL_READABLE; /* * 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 (consolePtr->writer.thread) { if (consolePtr->toWrite) { /* * We only need to wait if there is something to write. This may * prevent infinite wait on exit. [Python Bug 216289] */ WaitForSingleObject(consolePtr->writer.readyEvent, INFINITE); } StopChannelThread(&consolePtr->writer); } consolePtr->validMask &= ~TCL_WRITABLE; /* * Don't close the Win32 handle if the handle is a standard channel during * the thread exit process. Otherwise, one thread may kill the stdio of * another. */ if (!TclInThreadExit() || ((GetStdHandle(STD_INPUT_HANDLE) != consolePtr->handle) && (GetStdHandle(STD_OUTPUT_HANDLE) != consolePtr->handle) && (GetStdHandle(STD_ERROR_HANDLE) != consolePtr->handle))) { if (CloseHandle(consolePtr->handle) == FALSE) { TclWinConvertError(GetLastError()); errorCode = errno; } } consolePtr->watchMask &= consolePtr->validMask; /* * Remove the file from the list of watched files. */ for (nextPtrPtr = &(tsdPtr->firstConsolePtr), infoPtr = *nextPtrPtr; infoPtr != NULL; nextPtrPtr = &infoPtr->nextPtr, infoPtr = *nextPtrPtr) { if (infoPtr == (ConsoleInfo *) consolePtr) { *nextPtrPtr = infoPtr->nextPtr; break; } } if (consolePtr->writeBuf != NULL) { ckfree(consolePtr->writeBuf); consolePtr->writeBuf = 0; } ckfree(consolePtr); return errorCode; }