diff options
| -rw-r--r-- | .travis.yml | 79 | ||||
| -rw-r--r-- | generic/tclIO.c | 26 | ||||
| -rw-r--r-- | unix/tclUnixSock.c | 49 |
3 files changed, 137 insertions, 17 deletions
diff --git a/.travis.yml b/.travis.yml index 236bb2e..98ef72d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,15 @@ sudo: false language: c - +addons: + apt: + packages: + - binutils-mingw-w64-i686 + - binutils-mingw-w64-x86-64 + - gcc-mingw-w64 + - gcc-mingw-w64-base + - gcc-mingw-w64-i686 + - gcc-mingw-w64-x86-64 + - gcc-multilib matrix: include: # Testing on Linux with various compilers @@ -38,6 +47,13 @@ matrix: env: - BUILD_DIR=unix - CFGOPT="--enable-symbols" + - name: "Linux/GCC/Mem-Debug" + os: linux + dist: bionic + compiler: gcc + env: + - BUILD_DIR=unix + - CFGOPT="--enable-symbols=mem" # C++ build. - name: "Linux/G++/Shared" os: linux @@ -111,6 +127,13 @@ matrix: env: - BUILD_DIR=unix - CFGOPT="--enable-symbols" + - name: "Linux/Clang/Mem-Debug" + os: linux + dist: bionic + compiler: clang + env: + - BUILD_DIR=unix + - CFGOPT="--enable-symbols=mem" # Testing on Mac, various styles - name: "macOS/Xcode 11.3/Shared/Unix-like" os: osx @@ -177,13 +200,6 @@ matrix: os: linux dist: bionic compiler: x86_64-w64-mingw32-gcc - addons: - apt: - packages: - - gcc-mingw-w64-base - - binutils-mingw-w64-x86-64 - - gcc-mingw-w64-x86-64 - - gcc-mingw-w64 env: - BUILD_DIR=win - CFGOPT="--host=x86_64-w64-mingw32 --enable-64bit" @@ -198,14 +214,6 @@ matrix: os: linux dist: bionic compiler: i686-w64-mingw32-gcc - addons: - apt: - packages: - - gcc-mingw-w64-base - - binutils-mingw-w64-i686 - - gcc-mingw-w64-i686 - - gcc-mingw-w64 - - gcc-multilib env: - BUILD_DIR=win - CFGOPT=--host=i686-w64-mingw32 @@ -260,6 +268,15 @@ matrix: script: - cmd.exe //C vcvarsall.bat x64 '&&' nmake 'OPTS=symbols' '-f' makefile.vc all tcltest - cmd.exe //C vcvarsall.bat x64 '&&' nmake 'OPTS=symbols' '-f' makefile.vc test + - name: "Windows/MSVC/Mem-Debug" + os: windows + compiler: cl + env: *vcenv + before_install: *vcpreinst + install: [] + script: + - cmd.exe //C vcvarsall.bat x64 '&&' nmake 'STATS=memdbg' '-f' makefile.vc all tcltest + - cmd.exe //C vcvarsall.bat x64 '&&' nmake 'STATS=memdbg' '-f' makefile.vc test # Test on Windows with MSVC native (32-bit) - name: "Windows/MSVC-x86/Shared" os: windows @@ -306,6 +323,15 @@ matrix: script: - cmd.exe //C vcvarsall.bat x86 '&&' nmake 'OPTS=symbols' '-f' makefile.vc all tcltest - cmd.exe //C vcvarsall.bat x86 '&&' nmake 'OPTS=symbols' '-f' makefile.vc test + - name: "Windows/MSVC-x86/Mem-Debug" + os: windows + compiler: cl + env: *vcenv + before_install: *vcpreinst + install: [] + script: + - cmd.exe //C vcvarsall.bat x86 '&&' nmake 'STATS=memdbg' '-f' makefile.vc all tcltest + - cmd.exe //C vcvarsall.bat x86 '&&' nmake 'STATS=memdbg' '-f' makefile.vc test # Test on Windows with GCC native - name: "Windows/GCC/Shared" os: windows @@ -353,6 +379,13 @@ matrix: - BUILD_DIR=win - CFGOPT="--enable-64bit --enable-symbols" before_install: *makepreinst + - name: "Windows/GCC/Mem-Debug" + os: windows + compiler: gcc + env: + - BUILD_DIR=win + - CFGOPT="--enable-64bit --enable-symbols=mem" + before_install: *makepreinst # Test on Windows with GCC native (32-bit) - name: "Windows/GCC-x86/Shared" os: windows @@ -397,7 +430,21 @@ matrix: - BUILD_DIR=win - CFGOPT="--enable-symbols" before_install: *makepreinst + - name: "Windows/GCC-x86/Mem-Debug" + os: windows + compiler: gcc + env: + - BUILD_DIR=win + - CFGOPT="--enable-symbols=mem" + before_install: *makepreinst before_install: + - |- + case $TRAVIS_OS_NAME in + osx) + brew update + brew install libtommath + ;; + esac - cd ${BUILD_DIR} install: - ./configure ${CFGOPT} --prefix=$HOME || (cat config.log && exit 1) diff --git a/generic/tclIO.c b/generic/tclIO.c index d65f6e6..edce09b 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -3219,6 +3219,9 @@ CutChannel( */ ChanThreadAction((Channel *) chan, TCL_CHANNEL_THREAD_REMOVE); + + /* Channel is not managed by any thread */ + statePtr->managingThread = NULL; } void @@ -3263,6 +3266,9 @@ Tcl_CutChannel( for (; chanPtr != NULL ; chanPtr = chanPtr->upChanPtr) { ChanThreadAction(chanPtr, TCL_CHANNEL_THREAD_REMOVE); } + + /* Channel is not managed by any thread */ + statePtr->managingThread = NULL; } /* @@ -8390,6 +8396,13 @@ Tcl_NotifyChannel( Tcl_Preserve(statePtr); /* + * Avoid processing if the channel owner has been changed. + */ + if (statePtr->managingThread != Tcl_GetCurrentThread()) { + goto done; + } + + /* * If we are flushing in the background, be sure to call FlushChannel for * writable events. Note that we have to discard the writable event so we * don't call any write handlers before the flush is complete. @@ -8423,6 +8436,13 @@ Tcl_NotifyChannel( } else { chPtr = chPtr->nextPtr; } + + /* + * Stop if the channel owner has been changed in-between. + */ + if (chanPtr->state->managingThread != Tcl_GetCurrentThread()) { + goto done; + } } /* @@ -8440,6 +8460,7 @@ Tcl_NotifyChannel( UpdateInterest(chanPtr); } +done: Tcl_Release(statePtr); TclChannelRelease(channel); @@ -8939,6 +8960,11 @@ TclChannelEventScriptInvoker( int result; /* Result of call to eval script. */ /* + * Be sure event executed in managed channel (covering bugs similar [f583715154]). + */ + assert(chanPtr->state->managingThread == Tcl_GetCurrentThread()); + + /* * We must preserve the interpreter so we can report errors on it later. * Note that we do not need to preserve the channel because that is done * by Tcl_NotifyChannel before calling channel handlers. diff --git a/unix/tclUnixSock.c b/unix/tclUnixSock.c index 80de491..b707be4 100644 --- a/unix/tclUnixSock.c +++ b/unix/tclUnixSock.c @@ -129,6 +129,7 @@ struct TcpState { * Static routines for this file: */ +static void TcpAsyncCallback(void *clientData, int mask); static int TcpConnect(Tcl_Interp *interp, TcpState *state); static void TcpAccept(void *data, int mask); static int TcpBlockModeProc(void *data, int mode); @@ -145,6 +146,7 @@ static int TcpInputProc(void *instanceData, char *buf, int toRead, int *errorCode); static int TcpOutputProc(void *instanceData, const char *buf, int toWrite, int *errorCode); +static void TcpThreadActionProc(void *instanceData, int action); static void TcpWatchProc(void *instanceData, int mask); static int WaitForConnect(TcpState *statePtr, int *errorCodePtr); static void WrapNotify(void *clientData, int mask); @@ -174,7 +176,7 @@ static const Tcl_ChannelType tcpChannelType = { NULL, /* flush proc. */ NULL, /* handler proc. */ NULL, /* wide seek proc. */ - NULL, /* thread action proc. */ + TcpThreadActionProc, /* thread action proc. */ NULL /* truncate proc. */ }; @@ -983,6 +985,51 @@ TcpGetOptionProc( /* * ---------------------------------------------------------------------- * + * TcpThreadActionProc -- + * + * Handles detach/attach for asynchronously connecting socket. + * + * Reassigning the file handler associated with thread-related channel + * notification, responsible for callbacks (signaling that asynchronous + * connection attempt has succeeded or failed). + * + * Results: + * None. + * + * ---------------------------------------------------------------------- + */ + +static void +TcpThreadActionProc( + void *instanceData, + int action) +{ + TcpState *statePtr = (TcpState *)instanceData; + + if (GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) { + /* + * Async-connecting socket must get reassigned handler if it have been + * transferred to another thread. Remove the handler if the socket is + * not managed by this thread anymore and create new handler (TSD related) + * so the callback will run in the correct thread, bug [f583715154]. + */ + switch (action) { + case TCL_CHANNEL_THREAD_REMOVE: + CLEAR_BITS(statePtr->flags, TCP_ASYNC_PENDING); + Tcl_DeleteFileHandler(statePtr->fds.fd); + break; + case TCL_CHANNEL_THREAD_INSERT: + Tcl_CreateFileHandler(statePtr->fds.fd, + TCL_WRITABLE | TCL_EXCEPTION, TcpAsyncCallback, statePtr); + SET_BITS(statePtr->flags, TCP_ASYNC_PENDING); + break; + } + } +} + +/* + * ---------------------------------------------------------------------- + * * TcpWatchProc -- * * Initialize the notifier to watch the fd from this channel. |
