Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | * win/tclWinConsole.c: * win/tclWinPipe.c: * win/tclWinSerial.c: Fixed race condition where background threads were terminated while they still held a lock in the notifier. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | core-8-1-branch-old |
Files: | files | file ages | folders |
SHA1: |
9c78cc3ee23e83636356212ebfd7a854 |
User & Date: | stanton 1999-04-05 21:58:15.000 |
Context
1999-04-05
| ||
22:18 | * tests/tests/socket.test: Changed so tests don't reuse sockets, since Windows is slow to release so... check-in: 32d82f87bd user: stanton tags: core-8-1-branch-old | |
21:58 | * win/tclWinConsole.c: * win/tclWinPipe.c: * win/tclWinSerial.c: Fixed race condition where backgrou... check-in: 9c78cc3ee2 user: stanton tags: core-8-1-branch-old | |
1999-04-03
| ||
03:02 | removed windows-tk restriction on code that forked another shell--able to make this change because b... check-in: 03e6eecd77 user: hershey tags: core-8-1-branch-old | |
Changes
Changes to win/tclWinConsole.c.
1 2 3 4 5 6 7 8 9 10 11 | /* * tclWinConsole.c -- * * This file implements the Windows-specific console functions, * and the "console" channel driver. * * Copyright (c) 1999 by Scriptics Corp. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * | | | > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | /* * tclWinConsole.c -- * * This file implements the Windows-specific console functions, * and the "console" channel driver. * * Copyright (c) 1999 by Scriptics Corp. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: tclWinConsole.c,v 1.1.2.7 1999/04/05 21:58:15 stanton Exp $ */ #include "tclWinInt.h" #include <dos.h> #include <fcntl.h> #include <io.h> #include <sys/stat.h> /* * The following variable is used to tell whether this module has been * initialized. */ static int initialized = 0; /* * The consoleMutex locks around access to the initialized variable, and it is * used to protect background threads from being terminated while they are * using APIs that hold locks. */ TCL_DECLARE_MUTEX(consoleMutex) /* * Bit masks used in the flags field of the ConsoleInfo structure below. */ #define CONSOLE_PENDING (1<<0) /* Message is pending in the queue. */ #define CONSOLE_ASYNC (1<<1) /* Channel is non-blocking. */ |
︙ | ︙ | |||
199 200 201 202 203 204 205 | /* * Check the initialized flag first, then check again in the mutex. * This is a speed enhancement. */ if (!initialized) { | | | | 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | /* * Check the initialized flag first, then check again in the mutex. * This is a speed enhancement. */ if (!initialized) { Tcl_MutexLock(&consoleMutex); if (!initialized) { initialized = 1; Tcl_CreateExitHandler(ProcExitHandler, NULL); } Tcl_MutexUnlock(&consoleMutex); } tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); if (tsdPtr == NULL) { tsdPtr = TCL_TSD_INIT(&dataKey); tsdPtr->firstConsolePtr = NULL; Tcl_CreateEventSource(ConsoleSetupProc, ConsoleCheckProc, NULL); |
︙ | ︙ | |||
262 263 264 265 266 267 268 | *---------------------------------------------------------------------- */ static void ProcExitHandler( ClientData clientData) /* Old window proc */ { | | | | 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 | *---------------------------------------------------------------------- */ static void ProcExitHandler( ClientData clientData) /* Old window proc */ { Tcl_MutexLock(&consoleMutex); initialized = 0; Tcl_MutexUnlock(&consoleMutex); } /* *---------------------------------------------------------------------- * * ConsoleSetupProc -- * |
︙ | ︙ | |||
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 | /* * 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) { TerminateThread(consolePtr->readThread, 0); /* * Wait for the thread to terminate. This ensures that we are * completely cleaned up before we leave this function. */ WaitForSingleObject(consolePtr->readThread, INFINITE); | > > > > > > > > > > > > | 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 | /* * 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) { /* * Forcibly terminate the background thread. We cannot rely on the * thread to cleanly terminate itself because we have no way of * closing the 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(&consoleMutex); TerminateThread(consolePtr->readThread, 0); Tcl_MutexUnlock(&consoleMutex); /* * Wait for the thread to terminate. This ensures that we are * completely cleaned up before we leave this function. */ WaitForSingleObject(consolePtr->readThread, INFINITE); |
︙ | ︙ | |||
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 | * 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) { WaitForSingleObject(consolePtr->writable, INFINITE); TerminateThread(consolePtr->writeThread, 0); /* * Wait for the thread to terminate. This ensures that we are * completely cleaned up before we leave this function. */ WaitForSingleObject(consolePtr->writeThread, INFINITE); | > > > > > > > > > > > > > | 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 | * 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) { WaitForSingleObject(consolePtr->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 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(&consoleMutex); TerminateThread(consolePtr->writeThread, 0); Tcl_MutexUnlock(&consoleMutex); /* * Wait for the thread to terminate. This ensures that we are * completely cleaned up before we leave this function. */ WaitForSingleObject(consolePtr->writeThread, INFINITE); |
︙ | ︙ | |||
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 | /* * Signal the main thread by signalling the readable event and * then waking up the notifier thread. */ SetEvent(infoPtr->readable); Tcl_ThreadAlert(infoPtr->threadId); } return 0; /* NOT REACHED */ } /* *---------------------------------------------------------------------- * | > > > > > > > > > | 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 | /* * Signal the main thread by signalling the readable event and * then waking up the notifier thread. */ SetEvent(infoPtr->readable); /* * Alert the foreground thread. Note that we need to treat this like * a critical section so the foreground thread does not terminate * this thread while we are holding a mutex in the notifier code. */ Tcl_MutexLock(&consoleMutex); Tcl_ThreadAlert(infoPtr->threadId); Tcl_MutexUnlock(&consoleMutex); } return 0; /* NOT REACHED */ } /* *---------------------------------------------------------------------- * |
︙ | ︙ | |||
1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 | /* * Signal the main thread by signalling the writable event and * then waking up the notifier thread. */ SetEvent(infoPtr->writable); Tcl_ThreadAlert(infoPtr->threadId); } return 0; /* NOT REACHED */ } /* | > > > > > > > > > | 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 | /* * Signal the main thread by signalling the writable event and * then waking up the notifier thread. */ SetEvent(infoPtr->writable); /* * Alert the foreground thread. Note that we need to treat this like * a critical section so the foreground thread does not terminate * this thread while we are holding a mutex in the notifier code. */ Tcl_MutexLock(&consoleMutex); Tcl_ThreadAlert(infoPtr->threadId); Tcl_MutexUnlock(&consoleMutex); } return 0; /* NOT REACHED */ } /* |
︙ | ︙ |
Changes to win/tclWinPipe.c.
1 2 3 4 5 6 7 8 9 10 11 | /* * tclWinPipe.c -- * * This file implements the Windows-specific exec pipeline functions, * the "pipe" channel driver, and the "pid" Tcl command. * * Copyright (c) 1996-1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * | | > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | /* * tclWinPipe.c -- * * This file implements the Windows-specific exec pipeline functions, * the "pipe" channel driver, and the "pid" Tcl command. * * Copyright (c) 1996-1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: tclWinPipe.c,v 1.1.2.10 1999/04/05 21:58:16 stanton Exp $ */ #include "tclWinInt.h" #include <dos.h> #include <fcntl.h> #include <io.h> #include <sys/stat.h> /* * The following variable is used to tell whether this module has been * initialized. */ static int initialized = 0; /* * The pipeMutex locks around access to the initialized and procList variables, * and it is used to protect background threads from being terminated while * they are using APIs that hold locks. */ TCL_DECLARE_MUTEX(pipeMutex) /* * The following defines identify the various types of applications that * run under windows. There is special case code for the various types. */ #define APPL_NONE 0 |
︙ | ︙ | |||
270 271 272 273 274 275 276 | /* * Check the initialized flag first, then check again in the mutex. * This is a speed enhancement. */ if (!initialized) { | | | | 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | /* * Check the initialized flag first, then check again in the mutex. * This is a speed enhancement. */ if (!initialized) { Tcl_MutexLock(&pipeMutex); if (!initialized) { initialized = 1; procList = NULL; Tcl_CreateExitHandler(ProcExitHandler, NULL); } Tcl_MutexUnlock(&pipeMutex); } tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); if (tsdPtr == NULL) { tsdPtr = TCL_TSD_INIT(&dataKey); tsdPtr->firstPipePtr = NULL; Tcl_CreateEventSource(PipeSetupProc, PipeCheckProc, NULL); |
︙ | ︙ | |||
333 334 335 336 337 338 339 | *---------------------------------------------------------------------- */ static void ProcExitHandler( ClientData clientData) /* Old window proc */ { | | | | 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 | *---------------------------------------------------------------------- */ static void ProcExitHandler( ClientData clientData) /* Old window proc */ { Tcl_MutexLock(&pipeMutex); initialized = 0; Tcl_MutexUnlock(&pipeMutex); } /* *---------------------------------------------------------------------- * * PipeSetupProc -- * |
︙ | ︙ | |||
952 953 954 955 956 957 958 | unsigned long TclpGetPid( Tcl_Pid pid) /* The HANDLE of the child process. */ { ProcInfo *infoPtr; | | | | | 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 | unsigned long TclpGetPid( Tcl_Pid pid) /* The HANDLE of the child process. */ { ProcInfo *infoPtr; Tcl_MutexLock(&pipeMutex); for (infoPtr = procList; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->hProcess == (HANDLE) pid) { Tcl_MutexUnlock(&pipeMutex); return infoPtr->dwProcessId; } } Tcl_MutexUnlock(&pipeMutex); return (unsigned long) -1; } /* *---------------------------------------------------------------------- * * TclpCreateProcess -- |
︙ | ︙ | |||
2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 | /* * 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 pipe. */ if (pipePtr->readThread) { TerminateThread(pipePtr->readThread, 0); /* * Wait for the thread to terminate. This ensures that we are * completely cleaned up before we leave this function. */ WaitForSingleObject(pipePtr->readThread, INFINITE); | > > > > > > > > > > > > | 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 | /* * 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 pipe. */ if (pipePtr->readThread) { /* * 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->readThread, 0); Tcl_MutexUnlock(&pipeMutex); /* * Wait for the thread to terminate. This ensures that we are * completely cleaned up before we leave this function. */ WaitForSingleObject(pipePtr->readThread, INFINITE); |
︙ | ︙ | |||
2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 | * 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); 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); 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) { | > > > > > > > > > > > > > > > > | 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 | * 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); Tcl_MutexUnlock(&pipeMutex); /* * Wait for the thread to terminate. This ensures that we are * completely cleaned up before we leave this function. */ WaitForSingleObject(pipePtr->writeThread, INFINITE); 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) { |
︙ | ︙ | |||
2711 2712 2713 2714 2715 2716 2717 | return 0; } /* * Find the process on the process list. */ | | | | 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 | return 0; } /* * Find the process on the process list. */ Tcl_MutexLock(&pipeMutex); prevPtrPtr = &procList; for (infoPtr = procList; infoPtr != NULL; prevPtrPtr = &infoPtr->nextPtr, infoPtr = infoPtr->nextPtr) { if (infoPtr->hProcess == (HANDLE) pid) { break; } } Tcl_MutexUnlock(&pipeMutex); /* * If the pid is not one of the processes we know about (we started it) * then do nothing. */ if (infoPtr == NULL) { |
︙ | ︙ | |||
2796 2797 2798 2799 2800 2801 2802 | TclWinAddProcess(hProcess, id) HANDLE hProcess; /* Handle to process */ DWORD id; /* Global process identifier */ { ProcInfo *procPtr = (ProcInfo *) ckalloc(sizeof(ProcInfo)); procPtr->hProcess = hProcess; procPtr->dwProcessId = id; | | | | 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 | TclWinAddProcess(hProcess, id) HANDLE hProcess; /* Handle to process */ DWORD id; /* Global process identifier */ { ProcInfo *procPtr = (ProcInfo *) ckalloc(sizeof(ProcInfo)); procPtr->hProcess = hProcess; procPtr->dwProcessId = id; Tcl_MutexLock(&pipeMutex); procPtr->nextPtr = procList; procList = procPtr; Tcl_MutexUnlock(&pipeMutex); } /* *---------------------------------------------------------------------- * * Tcl_PidObjCmd -- * |
︙ | ︙ | |||
3004 3005 3006 3007 3008 3009 3010 | */ static DWORD WINAPI PipeReaderThread(LPVOID arg) { PipeInfo *infoPtr = (PipeInfo *)arg; HANDLE *handle = ((WinFile *) infoPtr->readFile)->handle; | | > | | 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 | */ static DWORD WINAPI PipeReaderThread(LPVOID arg) { PipeInfo *infoPtr = (PipeInfo *)arg; HANDLE *handle = ((WinFile *) infoPtr->readFile)->handle; DWORD count, err; int done = 0; while (!done) { /* * Wait for the main thread to signal before attempting to wait. */ WaitForSingleObject(infoPtr->startReader, INFINITE); /* |
︙ | ︙ | |||
3028 3029 3030 3031 3032 3033 3034 | || (PeekNamedPipe(handle, NULL, 0, NULL, &count, NULL) == FALSE)) { /* * The error is a result of an EOF condition, so set the * EOF bit before signalling the main thread. */ | > | > > > < > > > > > > > > > > > > > | | 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 | || (PeekNamedPipe(handle, NULL, 0, NULL, &count, NULL) == FALSE)) { /* * The error is a result of an EOF condition, so set the * EOF bit before signalling the main thread. */ err = GetLastError(); if (err == ERROR_BROKEN_PIPE) { infoPtr->readFlags |= PIPE_EOF; done = 1; } else if (err == ERROR_INVALID_HANDLE) { break; } } else if (count == 0) { if (ReadFile(handle, &(infoPtr->extraByte), 1, &count, NULL) != FALSE) { /* * One byte was consumed as a side effect of waiting * for the pipe to become readable. */ infoPtr->readFlags |= PIPE_EXTRABYTE; } else { err = GetLastError(); if (err == ERROR_BROKEN_PIPE) { /* * The error is a result of an EOF condition, so set the * EOF bit before signalling the main thread. */ infoPtr->readFlags |= PIPE_EOF; done = 1; } else if (err == ERROR_INVALID_HANDLE) { break; } } } /* * Signal the main thread by signalling the readable event and * then waking up the notifier thread. */ SetEvent(infoPtr->readable); /* * Alert the foreground thread. Note that we need to treat this like * a critical section so the foreground thread does not terminate * this thread while we are holding a mutex in the notifier code. */ Tcl_MutexLock(&pipeMutex); Tcl_ThreadAlert(infoPtr->threadId); Tcl_MutexUnlock(&pipeMutex); } return 0; } /* *---------------------------------------------------------------------- * * PipeWriterThread -- * |
︙ | ︙ | |||
3091 3092 3093 3094 3095 3096 3097 3098 | PipeWriterThread(LPVOID arg) { PipeInfo *infoPtr = (PipeInfo *)arg; HANDLE *handle = ((WinFile *) infoPtr->writeFile)->handle; DWORD count, toWrite; char *buf; | > | > > > > > > > > > > | | 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 | PipeWriterThread(LPVOID arg) { PipeInfo *infoPtr = (PipeInfo *)arg; HANDLE *handle = ((WinFile *) infoPtr->writeFile)->handle; DWORD count, toWrite; char *buf; int done = 0; while (!done) { /* * Wait for the main thread to signal before attempting to write. */ WaitForSingleObject(infoPtr->startWriter, INFINITE); buf = infoPtr->writeBuf; toWrite = infoPtr->toWrite; /* * Loop until all of the bytes are written or an error occurs. */ while (toWrite > 0) { if (WriteFile(handle, buf, toWrite, &count, NULL) == FALSE) { infoPtr->writeError = GetLastError(); done = 1; break; } else { toWrite -= count; buf += count; } } /* * Signal the main thread by signalling the writable event and * then waking up the notifier thread. */ SetEvent(infoPtr->writable); /* * Alert the foreground thread. Note that we need to treat this like * a critical section so the foreground thread does not terminate * this thread while we are holding a mutex in the notifier code. */ Tcl_MutexLock(&pipeMutex); Tcl_ThreadAlert(infoPtr->threadId); Tcl_MutexUnlock(&pipeMutex); } return 0; } |
Changes to win/tclWinSerial.c.
1 2 3 4 5 6 7 8 9 10 11 | /* * Tclwinserial.c -- * * This file implements the Windows-specific serial port functions, * and the "serial" channel driver. * * Copyright (c) 1999 by Scriptics Corp. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * | | > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | /* * Tclwinserial.c -- * * This file implements the Windows-specific serial port functions, * and the "serial" channel driver. * * Copyright (c) 1999 by Scriptics Corp. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: tclWinSerial.c,v 1.1.2.6 1999/04/05 21:58:16 stanton Exp $ */ #include "tclWinInt.h" #include <dos.h> #include <fcntl.h> #include <io.h> #include <sys/stat.h> /* * The following variable is used to tell whether this module has been * initialized. */ static int initialized = 0; /* * The serialMutex locks around access to the initialized variable, and it is * used to protect background threads from being terminated while they are * using APIs that hold locks. */ TCL_DECLARE_MUTEX(serialMutex) /* * Bit masks used in the flags field of the SerialInfo structure below. */ #define SERIAL_PENDING (1<<0) /* Message is pending in the queue. */ #define SERIAL_ASYNC (1<<1) /* Channel is non-blocking. */ |
︙ | ︙ | |||
193 194 195 196 197 198 199 | /* * Check the initialized flag first, then check it again in the mutex. * This is a speed enhancement. */ if (!initialized) { | | | | 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | /* * Check the initialized flag first, then check it again in the mutex. * This is a speed enhancement. */ if (!initialized) { Tcl_MutexLock(&serialMutex); if (!initialized) { initialized = 1; Tcl_CreateExitHandler(ProcExitHandler, NULL); } Tcl_MutexUnlock(&serialMutex); } tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); if (tsdPtr == NULL) { tsdPtr = TCL_TSD_INIT(&dataKey); tsdPtr->firstSerialPtr = NULL; Tcl_CreateEventSource(SerialSetupProc, SerialCheckProc, NULL); |
︙ | ︙ | |||
256 257 258 259 260 261 262 | *---------------------------------------------------------------------- */ static void ProcExitHandler( ClientData clientData) /* Old window proc */ { | | | | 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | *---------------------------------------------------------------------- */ static void ProcExitHandler( ClientData clientData) /* Old window proc */ { Tcl_MutexLock(&serialMutex); initialized = 0; Tcl_MutexUnlock(&serialMutex); } /* *---------------------------------------------------------------------- * * SerialSetupProc -- * |
︙ | ︙ | |||
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 | SerialInfo *serialPtr = (SerialInfo *) instanceData; int errorCode, result = 0; SerialInfo *infoPtr, **nextPtrPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); errorCode = 0; if (serialPtr->readThread) { TerminateThread(serialPtr->readThread, 0); /* * Wait for the thread to terminate. This ensures that we are * completely cleaned up before we leave this function. */ WaitForSingleObject(serialPtr->readThread, INFINITE); CloseHandle(serialPtr->readThread); CloseHandle(serialPtr->readable); CloseHandle(serialPtr->startReader); serialPtr->readThread = NULL; } serialPtr->validMask &= ~TCL_READABLE; if (serialPtr->writeThread) { WaitForSingleObject(serialPtr->writable, INFINITE); TerminateThread(serialPtr->writeThread, 0); /* * Wait for the thread to terminate. This ensures that we are * completely cleaned up before we leave this function. */ WaitForSingleObject(serialPtr->writeThread, INFINITE); | > > > > > > > > > > > > > > > > > > > > > > > > > > | 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 | SerialInfo *serialPtr = (SerialInfo *) instanceData; int errorCode, result = 0; SerialInfo *infoPtr, **nextPtrPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); errorCode = 0; if (serialPtr->readThread) { /* * Forcibly terminate the background thread. We cannot rely on the * thread to cleanly terminate itself because we have no way of * closing the 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(&serialMutex); TerminateThread(serialPtr->readThread, 0); Tcl_MutexUnlock(&serialMutex); /* * Wait for the thread to terminate. This ensures that we are * completely cleaned up before we leave this function. */ WaitForSingleObject(serialPtr->readThread, INFINITE); CloseHandle(serialPtr->readThread); CloseHandle(serialPtr->readable); CloseHandle(serialPtr->startReader); serialPtr->readThread = NULL; } serialPtr->validMask &= ~TCL_READABLE; if (serialPtr->writeThread) { WaitForSingleObject(serialPtr->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 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(&serialMutex); TerminateThread(serialPtr->writeThread, 0); Tcl_MutexUnlock(&serialMutex); /* * Wait for the thread to terminate. This ensures that we are * completely cleaned up before we leave this function. */ WaitForSingleObject(serialPtr->writeThread, INFINITE); |
︙ | ︙ | |||
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 | /* * Signal the main thread by signalling the readable event and * then waking up the notifier thread. */ SetEvent(infoPtr->readable); Tcl_ThreadAlert(infoPtr->threadId); } return 0; /* NOT REACHED */ } /* *---------------------------------------------------------------------- * | > > > > > > > > > | 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 | /* * Signal the main thread by signalling the readable event and * then waking up the notifier thread. */ SetEvent(infoPtr->readable); /* * Alert the foreground thread. Note that we need to treat this like * a critical section so the foreground thread does not terminate * this thread while we are holding a mutex in the notifier code. */ Tcl_MutexLock(&serialMutex); Tcl_ThreadAlert(infoPtr->threadId); Tcl_MutexUnlock(&serialMutex); } return 0; /* NOT REACHED */ } /* *---------------------------------------------------------------------- * |
︙ | ︙ | |||
1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 | /* * Signal the main thread by signalling the writable event and * then waking up the notifier thread. */ SetEvent(infoPtr->writable); Tcl_ThreadAlert(infoPtr->threadId); } return 0; /* NOT REACHED */ } /* *---------------------------------------------------------------------- * | > > > > > > > > > | | 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 | /* * Signal the main thread by signalling the writable event and * then waking up the notifier thread. */ SetEvent(infoPtr->writable); /* * Alert the foreground thread. Note that we need to treat this like * a critical section so the foreground thread does not terminate * this thread while we are holding a mutex in the notifier code. */ Tcl_MutexLock(&serialMutex); Tcl_ThreadAlert(infoPtr->threadId); Tcl_MutexUnlock(&serialMutex); } return 0; /* NOT REACHED */ } /* *---------------------------------------------------------------------- * * TclWinOpenSerialChannel -- * * Constructs a Serial port channel for the specified standard OS handle. * This is a helper function to break up the construction of * channels into File, Console, or Serial. * * Results: * Returns the new channel, or NULL. |
︙ | ︙ |