diff options
| -rw-r--r-- | tests/socket.test | 8 | ||||
| -rw-r--r-- | win/tclWinSock.c | 135 |
2 files changed, 75 insertions, 68 deletions
diff --git a/tests/socket.test b/tests/socket.test index 82e908a..b628404 100644 --- a/tests/socket.test +++ b/tests/socket.test @@ -2581,6 +2581,14 @@ foreach {servip sc} $x { } } +test socket-bug-31fc36fe47 "Crash listening in multiple threads" \ + -constraints thread -body { + close [socket -server xxx 0] + set tid [thread::create] + thread::send $tid {close [socket -server accept 0]} + thread::release $tid + } -result 0 + ::tcltest::cleanupTests flush stdout return diff --git a/win/tclWinSock.c b/win/tclWinSock.c index 5284ced..f54d8a1 100644 --- a/win/tclWinSock.c +++ b/win/tclWinSock.c @@ -229,7 +229,7 @@ static WNDCLASSW windowClass; static int TcpConnect(Tcl_Interp *interp, TcpState *state); -static void InitSockets(void); +static void InitSocketWindowClass(void); static TcpState * NewSocketInfo(SOCKET socket); static void SocketExitHandler(void *clientData); static LRESULT CALLBACK SocketProc(HWND hwnd, UINT message, WPARAM wParam, @@ -415,11 +415,11 @@ Tcl_GetHostName(void) * * TclInitSockets -- * - * This function just calls InitSockets(), but is protected by a mutex. + * Initialization of sockets for the thread. Also creates message + * handling window class for the process if needed. * * Results: - * Returns TCL_OK if the system supports sockets, or TCL_ERROR with an - * error in interp (if non-NULL). + * Nothing. Panics on failure. * * Side effects: * If not already prepared, initializes the TSD structure and socket @@ -432,13 +432,58 @@ Tcl_GetHostName(void) void TclInitSockets() { - if (!initialized) { - Tcl_MutexLock(&socketMutex); - if (!initialized) { - InitSockets(); - } - Tcl_MutexUnlock(&socketMutex); + /* Then Per thread initialization. */ + DWORD id; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); + + if (tsdPtr != NULL) { + return; + } + + InitSocketWindowClass(); + + /* + * OK, this thread has never done anything with sockets before. Construct + * a worker thread to handle asynchronous events related to sockets + * assigned to _this_ thread. + */ + + tsdPtr = TCL_TSD_INIT(&dataKey); + tsdPtr->pendingTcpState = NULL; + tsdPtr->socketList = NULL; + tsdPtr->hwnd = NULL; + tsdPtr->threadId = Tcl_GetCurrentThread(); + tsdPtr->readyEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + if (tsdPtr->readyEvent == NULL) { + goto initFailure; + } + tsdPtr->socketListLock = CreateEventW(NULL, FALSE, TRUE, NULL); + if (tsdPtr->socketListLock == NULL) { + goto initFailure; } + tsdPtr->socketThread = CreateThread(NULL, 256, SocketThread, tsdPtr, 0, + &id); + if (tsdPtr->socketThread == NULL) { + goto initFailure; + } + + SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST); + + /* + * Wait for the thread to signal when the window has been created and if + * it is ready to go. + */ + + WaitForSingleObject(tsdPtr->readyEvent, INFINITE); + + if (tsdPtr->hwnd != NULL) { + Tcl_CreateEventSource(SocketSetupProc, SocketCheckProc, NULL); + return; + } + + initFailure: + Tcl_Panic("InitSockets failed"); + return; } /* @@ -2322,28 +2367,27 @@ TcpAccept( /* *---------------------------------------------------------------------- * - * InitSockets -- + * InitSocketWindowClass -- * - * Registers the event window for the socket notifier code. - * - * Assumes socketMutex is held. + * Registers the event window class for the socket notifier code. + * Caller must not hold socket mutex lock. * * Results: * None. * * Side effects: - * Register a new window class and creates a - * window for use in asynchronous socket notification. + * Register a new window class. * *---------------------------------------------------------------------- */ static void -InitSockets(void) +InitSocketWindowClass(void) { - DWORD id; - ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); - + if (initialized) { + return; + } + Tcl_MutexLock(&socketMutex); if (!initialized) { initialized = 1; TclCreateLateExitHandler(SocketExitHandler, NULL); @@ -2371,57 +2415,12 @@ InitSockets(void) goto initFailure; } } - - /* - * Check for per-thread initialization. - */ - - if (tsdPtr != NULL) { - return; - } - - /* - * OK, this thread has never done anything with sockets before. Construct - * a worker thread to handle asynchronous events related to sockets - * assigned to _this_ thread. - */ - - tsdPtr = TCL_TSD_INIT(&dataKey); - tsdPtr->pendingTcpState = NULL; - tsdPtr->socketList = NULL; - tsdPtr->hwnd = NULL; - tsdPtr->threadId = Tcl_GetCurrentThread(); - tsdPtr->readyEvent = CreateEventW(NULL, FALSE, FALSE, NULL); - if (tsdPtr->readyEvent == NULL) { - goto initFailure; - } - tsdPtr->socketListLock = CreateEventW(NULL, FALSE, TRUE, NULL); - if (tsdPtr->socketListLock == NULL) { - goto initFailure; - } - tsdPtr->socketThread = CreateThread(NULL, 256, SocketThread, tsdPtr, 0, - &id); - if (tsdPtr->socketThread == NULL) { - goto initFailure; - } - - SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST); - - /* - * Wait for the thread to signal when the window has been created and if - * it is ready to go. - */ - - WaitForSingleObject(tsdPtr->readyEvent, INFINITE); - - if (tsdPtr->hwnd != NULL) { - Tcl_CreateEventSource(SocketSetupProc, SocketCheckProc, NULL); - return; - } + Tcl_MutexUnlock(&socketMutex); + return; initFailure: + Tcl_MutexUnlock(&socketMutex); /* Probably pointless before panicing */ Tcl_Panic("InitSockets failed"); - return; } /* |
