summaryrefslogtreecommitdiffstats
path: root/win
diff options
context:
space:
mode:
authorandreas_kupries <akupries@shaw.ca>2005-01-27 22:53:23 (GMT)
committerandreas_kupries <akupries@shaw.ca>2005-01-27 22:53:23 (GMT)
commit2123231f4d20076fce7107118855c3b04308298b (patch)
tree222920345572469c253fc4368f14969609001923 /win
parentea9b9e398b69f4bf77129c1ce31259f184ac2120 (diff)
downloadtcl-2123231f4d20076fce7107118855c3b04308298b.zip
tcl-2123231f4d20076fce7107118855c3b04308298b.tar.gz
tcl-2123231f4d20076fce7107118855c3b04308298b.tar.bz2
TIP#218 IMPLEMENTATION
* generic/tclDecls.h: Regenerated from tcl.decls. * generic/tclStubInit.c: * doc/CrtChannel.3: Documentation of extended API, * generic/tcl.decls: extended testsuite, and * generic/tcl.h: implementation. Removal of old * generic/tclIO.c: driver-specific TclpCut/Splice * generic/tclInt.h: functions. Replaced with generic * tests/io.test: thread-action calls through the * unix/tclUnixChan.c: new hooks. Update of all builtin * unix/tclUnixPipe.c: channel drivers to version 4. * unix/tclUnixSock.c: Windows drivers extended to * win/tclWinChan.c: manage thread state in a thread * win/tclWinConsole.c: action handler. * win/tclWinPipe.c: * win/tclWinSerial.c: * win/tclWinSock.c: * mac/tclMacChan.c:
Diffstat (limited to 'win')
-rw-r--r--win/tclWinChan.c114
-rw-r--r--win/tclWinConsole.c80
-rw-r--r--win/tclWinPipe.c67
-rw-r--r--win/tclWinSerial.c87
-rw-r--r--win/tclWinSock.c123
5 files changed, 346 insertions, 125 deletions
diff --git a/win/tclWinChan.c b/win/tclWinChan.c
index 9333726..b743b55 100644
--- a/win/tclWinChan.c
+++ b/win/tclWinChan.c
@@ -9,7 +9,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclWinChan.c,v 1.30.2.2 2005/01/19 22:09:58 mdejong Exp $
+ * RCS: @(#) $Id: tclWinChan.c,v 1.30.2.3 2005/01/27 22:53:36 andreas_kupries Exp $
*/
#include "tclWinInt.h"
@@ -98,6 +98,8 @@ static void FileSetupProc _ANSI_ARGS_((ClientData clientData,
int flags));
static void FileWatchProc _ANSI_ARGS_((ClientData instanceData,
int mask));
+static void FileThreadActionProc _ANSI_ARGS_ ((
+ ClientData instanceData, int action));
/*
@@ -106,7 +108,7 @@ static void FileWatchProc _ANSI_ARGS_((ClientData instanceData,
static Tcl_ChannelType fileChannelType = {
"file", /* Type name. */
- TCL_CHANNEL_VERSION_3, /* v3 channel */
+ TCL_CHANNEL_VERSION_4, /* v4 channel */
FileCloseProc, /* Close proc. */
FileInputProc, /* Input proc. */
FileOutputProc, /* Output proc. */
@@ -120,6 +122,7 @@ static Tcl_ChannelType fileChannelType = {
NULL, /* flush proc. */
NULL, /* handler proc. */
FileWideSeekProc, /* Wide seek proc. */
+ FileThreadActionProc, /* Thread action proc. */
};
#if defined(HAVE_NO_SEH) && defined(TCL_MEM_DEBUG)
@@ -436,11 +439,11 @@ FileCloseProc(instanceData, interp)
if (infoPtr == fileInfoPtr) {
/*
* This channel exists on the thread local list. It should
- * have been removed by an earlier call to TclpCutFileChannel,
+ * have been removed by an earlier Thread Action call,
* but do that now since just deallocating fileInfoPtr would
* leave an deallocated pointer on the thread local list.
*/
- TclpCutFileChannel(fileInfoPtr->channel);
+ FileThreadActionProc(fileInfoPtr,TCL_CHANNEL_THREAD_REMOVE);
break;
}
}
@@ -1319,8 +1322,11 @@ TclWinOpenFileChannel(handle, channelName, permissions, appendMode)
}
infoPtr = (FileInfo *) ckalloc((unsigned) sizeof(FileInfo));
- infoPtr->nextPtr = tsdPtr->firstFilePtr;
- tsdPtr->firstFilePtr = infoPtr;
+ /* TIP #218. Removed the code inserting the new structure
+ * into the global list. This is now handled in the thread
+ * action callbacks, and only there.
+ */
+ infoPtr->nextPtr = NULL;
infoPtr->validMask = permissions;
infoPtr->watchMask = 0;
infoPtr->flags = appendMode;
@@ -1389,10 +1395,9 @@ TclWinFlushDirtyChannels ()
/*
*----------------------------------------------------------------------
*
- * TclpCutFileChannel --
+ * FileThreadActionProc --
*
- * Remove any thread local refs to this channel. See
- * Tcl_CutChannel for more info.
+ * Insert or remove any thread local refs to this channel.
*
* Results:
* None.
@@ -1403,75 +1408,38 @@ TclWinFlushDirtyChannels ()
*----------------------------------------------------------------------
*/
-void
-TclpCutFileChannel(chan)
- Tcl_Channel chan; /* The channel being removed. Must
- * not be referenced in any
- * interpreter. */
+static void
+FileThreadActionProc (instanceData, action)
+ ClientData instanceData;
+ int action;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- Channel *chanPtr = (Channel *) chan;
- FileInfo *infoPtr;
- FileInfo **nextPtrPtr;
- int removed = 0;
+ FileInfo *infoPtr = (FileInfo *) instanceData;
- if (chanPtr->typePtr != &fileChannelType)
- return;
+ if (action == TCL_CHANNEL_THREAD_INSERT) {
+ infoPtr->nextPtr = tsdPtr->firstFilePtr;
+ tsdPtr->firstFilePtr = infoPtr;
+ } else {
+ FileInfo **nextPtrPtr;
+ int removed = 0;
+
+ for (nextPtrPtr = &(tsdPtr->firstFilePtr); (*nextPtrPtr) != NULL;
+ nextPtrPtr = &((*nextPtrPtr)->nextPtr)) {
+ if ((*nextPtrPtr) == infoPtr) {
+ (*nextPtrPtr) = infoPtr->nextPtr;
+ removed = 1;
+ break;
+ }
+ }
- infoPtr = (FileInfo *) chanPtr->instanceData;
+ /*
+ * This could happen if the channel was created in one thread
+ * and then moved to another without updating the thread
+ * local data in each thread.
+ */
- for (nextPtrPtr = &(tsdPtr->firstFilePtr); (*nextPtrPtr) != NULL;
- nextPtrPtr = &((*nextPtrPtr)->nextPtr)) {
- if ((*nextPtrPtr) == infoPtr) {
- (*nextPtrPtr) = infoPtr->nextPtr;
- removed = 1;
- break;
+ if (!removed) {
+ panic("file info ptr not on thread channel list");
}
}
-
- /*
- * This could happen if the channel was created in one thread
- * and then moved to another without updating the thread
- * local data in each thread.
- */
-
- if (!removed)
- panic("file info ptr not on thread channel list");
-
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpSpliceFileChannel --
- *
- * Insert thread local ref for this channel.
- * Tcl_SpliceChannel for more info.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Changes thread local list of valid channels.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclpSpliceFileChannel(chan)
- Tcl_Channel chan; /* The channel being removed. Must
- * not be referenced in any
- * interpreter. */
-{
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- Channel *chanPtr = (Channel *) chan;
- FileInfo *infoPtr;
-
- if (chanPtr->typePtr != &fileChannelType)
- return;
-
- infoPtr = (FileInfo *) chanPtr->instanceData;
-
- infoPtr->nextPtr = tsdPtr->firstFilePtr;
- tsdPtr->firstFilePtr = infoPtr;
}
diff --git a/win/tclWinConsole.c b/win/tclWinConsole.c
index 6d3709c..2370a22 100644
--- a/win/tclWinConsole.c
+++ b/win/tclWinConsole.c
@@ -9,7 +9,7 @@
* 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.11 2002/11/26 22:41:58 davygrvy Exp $
+ * RCS: @(#) $Id: tclWinConsole.c,v 1.11.2.1 2005/01/27 22:53:37 andreas_kupries Exp $
*/
#include "tclWinInt.h"
@@ -148,7 +148,7 @@ static int ConsoleEventProc(Tcl_Event *evPtr, int flags);
static void ConsoleExitHandler(ClientData clientData);
static int ConsoleGetHandleProc(ClientData instanceData,
int direction, ClientData *handlePtr);
-static ThreadSpecificData *ConsoleInit(void);
+static void ConsoleInit(void);
static int ConsoleInputProc(ClientData instanceData, char *buf,
int toRead, int *errorCode);
static int ConsoleOutputProc(ClientData instanceData,
@@ -160,6 +160,9 @@ static DWORD WINAPI ConsoleWriterThread(LPVOID arg);
static void ProcExitHandler(ClientData clientData);
static int WaitForRead(ConsoleInfo *infoPtr, int blocking);
+static void ConsoleThreadActionProc _ANSI_ARGS_ ((
+ ClientData instanceData, int action));
+
/*
* This structure describes the channel type structure for command console
* based IO.
@@ -167,7 +170,7 @@ static int WaitForRead(ConsoleInfo *infoPtr, int blocking);
static Tcl_ChannelType consoleChannelType = {
"console", /* Type name. */
- TCL_CHANNEL_VERSION_2, /* v2 channel */
+ TCL_CHANNEL_VERSION_4, /* v4 channel */
ConsoleCloseProc, /* Close proc. */
ConsoleInputProc, /* Input proc. */
ConsoleOutputProc, /* Output proc. */
@@ -180,6 +183,8 @@ static Tcl_ChannelType consoleChannelType = {
ConsoleBlockModeProc, /* Set blocking or non-blocking mode.*/
NULL, /* flush proc. */
NULL, /* handler proc. */
+ NULL, /* wide seek proc */
+ ConsoleThreadActionProc, /* thread action proc */
};
/*
@@ -198,7 +203,7 @@ static Tcl_ChannelType consoleChannelType = {
*----------------------------------------------------------------------
*/
-static ThreadSpecificData *
+static void
ConsoleInit()
{
ThreadSpecificData *tsdPtr;
@@ -224,7 +229,6 @@ ConsoleInit()
Tcl_CreateEventSource(ConsoleSetupProc, ConsoleCheckProc, NULL);
Tcl_CreateThreadExitHandler(ConsoleExitHandler, NULL);
}
- return tsdPtr;
}
/*
@@ -1170,7 +1174,10 @@ ConsoleReaderThread(LPVOID arg)
*/
Tcl_MutexLock(&consoleMutex);
- Tcl_ThreadAlert(infoPtr->threadId);
+ if (infoPtr->threadId != NULL) {
+ /* TIP #218. When in flight ignore the event, no one will receive it anyway */
+ Tcl_ThreadAlert(infoPtr->threadId);
+ }
Tcl_MutexUnlock(&consoleMutex);
}
@@ -1256,7 +1263,10 @@ ConsoleWriterThread(LPVOID arg)
*/
Tcl_MutexLock(&consoleMutex);
- Tcl_ThreadAlert(infoPtr->threadId);
+ if (infoPtr->threadId != NULL) {
+ /* TIP #218. When in flight ignore the event, no one will receive it anyway */
+ Tcl_ThreadAlert(infoPtr->threadId);
+ }
Tcl_MutexUnlock(&consoleMutex);
}
@@ -1291,10 +1301,9 @@ TclWinOpenConsoleChannel(handle, channelName, permissions)
{
char encoding[4 + TCL_INTEGER_SPACE];
ConsoleInfo *infoPtr;
- ThreadSpecificData *tsdPtr;
DWORD id, modes;
- tsdPtr = ConsoleInit();
+ ConsoleInit();
/*
* See if a channel with this handle already exists.
@@ -1305,9 +1314,12 @@ TclWinOpenConsoleChannel(handle, channelName, permissions)
infoPtr->validMask = permissions;
infoPtr->handle = handle;
+ infoPtr->channel = (Tcl_Channel) NULL;
wsprintfA(encoding, "cp%d", GetConsoleCP());
+ infoPtr->threadId = Tcl_GetCurrentThread();
+
/*
* Use the pointer for the name of the result channel.
* This keeps the channel names unique, since some may share
@@ -1319,8 +1331,6 @@ TclWinOpenConsoleChannel(handle, channelName, permissions)
infoPtr->channel = Tcl_CreateChannel(&consoleChannelType, channelName,
(ClientData) infoPtr, permissions);
- infoPtr->threadId = Tcl_GetCurrentThread();
-
if (permissions & TCL_READABLE) {
/*
* Make sure the console input buffer is ready for only character
@@ -1361,3 +1371,51 @@ TclWinOpenConsoleChannel(handle, channelName, permissions)
return infoPtr->channel;
}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ConsoleThreadActionProc --
+ *
+ * Insert or remove any thread local refs to this channel.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Changes thread local list of valid channels.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+ConsoleThreadActionProc (instanceData, action)
+ ClientData instanceData;
+ int action;
+{
+ ConsoleInfo *infoPtr = (ConsoleInfo *) instanceData;
+
+ /* We do not access firstConsolePtr in the thread structures. This is
+ * not for all serials managed by the thread, but only those we are
+ * watching. Removal of the filevent handlers before transfer thus
+ * takes care of this structure.
+ */
+
+ Tcl_MutexLock(&consoleMutex);
+ if (action == TCL_CHANNEL_THREAD_INSERT) {
+ /* We can't copy the thread information from the channel when
+ * the channel is created. At this time the channel back
+ * pointer has not been set yet. However in that case the
+ * threadId has already been set by TclpCreateCommandChannel
+ * itself, so the structure is still good.
+ */
+
+ ConsoleInit ();
+ if (infoPtr->channel != NULL) {
+ infoPtr->threadId = Tcl_GetChannelThread (infoPtr->channel);
+ }
+ } else {
+ infoPtr->threadId = NULL;
+ }
+ Tcl_MutexUnlock(&consoleMutex);
+}
diff --git a/win/tclWinPipe.c b/win/tclWinPipe.c
index aa54a29..57858f0 100644
--- a/win/tclWinPipe.c
+++ b/win/tclWinPipe.c
@@ -9,7 +9,7 @@
* 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.33.2.8 2004/05/10 20:55:44 davygrvy Exp $
+ * RCS: @(#) $Id: tclWinPipe.c,v 1.33.2.9 2005/01/27 22:53:37 andreas_kupries Exp $
*/
#include "tclWinInt.h"
@@ -205,6 +205,9 @@ static void ProcExitHandler(ClientData clientData);
static int TempFileName(WCHAR name[MAX_PATH]);
static int WaitForRead(PipeInfo *infoPtr, int blocking);
+static void PipeThreadActionProc _ANSI_ARGS_ ((
+ ClientData instanceData, int action));
+
/*
* This structure describes the channel type structure for command pipe
* based IO.
@@ -212,7 +215,7 @@ static int WaitForRead(PipeInfo *infoPtr, int blocking);
static Tcl_ChannelType pipeChannelType = {
"pipe", /* Type name. */
- TCL_CHANNEL_VERSION_2, /* v2 channel */
+ TCL_CHANNEL_VERSION_4, /* v4 channel */
TCL_CLOSE2PROC, /* Close proc. */
PipeInputProc, /* Input proc. */
PipeOutputProc, /* Output proc. */
@@ -225,6 +228,8 @@ static Tcl_ChannelType pipeChannelType = {
PipeBlockModeProc, /* Set blocking or non-blocking mode.*/
NULL, /* flush proc. */
NULL, /* handler proc. */
+ NULL, /* wide seek proc */
+ PipeThreadActionProc, /* thread action proc */
};
/*
@@ -1689,6 +1694,7 @@ TclpCreateCommandChannel(
infoPtr->writeBuf = 0;
infoPtr->writeBufLen = 0;
infoPtr->writeError = 0;
+ infoPtr->channel = (Tcl_Channel) NULL;
/*
* Use one of the fds associated with the channel as the
@@ -2931,7 +2937,10 @@ PipeReaderThread(LPVOID arg)
*/
Tcl_MutexLock(&pipeMutex);
- Tcl_ThreadAlert(infoPtr->threadId);
+ if (infoPtr->threadId != NULL) {
+ /* TIP #218. When in flight ignore the event, no one will receive it anyway */
+ Tcl_ThreadAlert(infoPtr->threadId);
+ }
Tcl_MutexUnlock(&pipeMutex);
}
@@ -3019,10 +3028,60 @@ PipeWriterThread(LPVOID arg)
*/
Tcl_MutexLock(&pipeMutex);
- Tcl_ThreadAlert(infoPtr->threadId);
+ if (infoPtr->threadId != NULL) {
+ /* TIP #218. When in flight ignore the event, no one will receive it anyway */
+ Tcl_ThreadAlert(infoPtr->threadId);
+ }
Tcl_MutexUnlock(&pipeMutex);
}
return 0;
}
+/*
+ *----------------------------------------------------------------------
+ *
+ * PipeThreadActionProc --
+ *
+ * Insert or remove any thread local refs to this channel.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Changes thread local list of valid channels.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+PipeThreadActionProc (instanceData, action)
+ ClientData instanceData;
+ int action;
+{
+ PipeInfo *infoPtr = (PipeInfo *) instanceData;
+
+ /* We do not access firstPipePtr in the thread structures. This is
+ * not for all pipes managed by the thread, but only those we are
+ * watching. Removal of the filevent handlers before transfer thus
+ * takes care of this structure.
+ */
+
+ Tcl_MutexLock(&pipeMutex);
+ if (action == TCL_CHANNEL_THREAD_INSERT) {
+ /* We can't copy the thread information from the channel when
+ * the channel is created. At this time the channel back
+ * pointer has not been set yet. However in that case the
+ * threadId has already been set by TclpCreateCommandChannel
+ * itself, so the structure is still good.
+ */
+
+ PipeInit ();
+ if (infoPtr->channel != NULL) {
+ infoPtr->threadId = Tcl_GetChannelThread (infoPtr->channel);
+ }
+ } else {
+ infoPtr->threadId = NULL;
+ }
+ Tcl_MutexUnlock(&pipeMutex);
+}
diff --git a/win/tclWinSerial.c b/win/tclWinSerial.c
index 17678f2..0d363a5 100644
--- a/win/tclWinSerial.c
+++ b/win/tclWinSerial.c
@@ -11,7 +11,7 @@
*
* Serial functionality implemented by Rolf.Schroedter@dlr.de
*
- * RCS: @(#) $Id: tclWinSerial.c,v 1.25.2.1 2003/05/11 00:31:41 hobbs Exp $
+ * RCS: @(#) $Id: tclWinSerial.c,v 1.25.2.2 2005/01/27 22:53:38 andreas_kupries Exp $
*/
#include "tclWinInt.h"
@@ -190,6 +190,9 @@ static int SerialSetOptionProc _ANSI_ARGS_((ClientData instanceData,
CONST char *value));
static DWORD WINAPI SerialWriterThread(LPVOID arg);
+static void SerialThreadActionProc _ANSI_ARGS_ ((
+ ClientData instanceData, int action));
+
/*
* This structure describes the channel type structure for command serial
* based IO.
@@ -197,7 +200,7 @@ static DWORD WINAPI SerialWriterThread(LPVOID arg);
static Tcl_ChannelType serialChannelType = {
"serial", /* Type name. */
- TCL_CHANNEL_VERSION_2, /* v2 channel */
+ TCL_CHANNEL_VERSION_4, /* v4 channel */
SerialCloseProc, /* Close proc. */
SerialInputProc, /* Input proc. */
SerialOutputProc, /* Output proc. */
@@ -210,6 +213,8 @@ static Tcl_ChannelType serialChannelType = {
SerialBlockProc, /* Set blocking or non-blocking mode.*/
NULL, /* flush proc. */
NULL, /* handler proc. */
+ NULL, /* wide seek proc */
+ SerialThreadActionProc, /* thread action proc */
};
/*
@@ -1346,7 +1351,10 @@ SerialWriterThread(LPVOID arg)
*/
Tcl_MutexLock(&serialMutex);
- Tcl_ThreadAlert(infoPtr->threadId);
+ if (infoPtr->threadId != NULL) {
+ /* TIP #218. When in flight ignore the event, no one will receive it anyway */
+ Tcl_ThreadAlert(infoPtr->threadId);
+ }
Tcl_MutexUnlock(&serialMutex);
}
@@ -1419,16 +1427,25 @@ TclWinOpenSerialChannel(handle, channelName, permissions)
int permissions;
{
SerialInfo *infoPtr;
- ThreadSpecificData *tsdPtr;
DWORD id;
- tsdPtr = SerialInit();
+ SerialInit();
infoPtr = (SerialInfo *) ckalloc((unsigned) sizeof(SerialInfo));
memset(infoPtr, 0, sizeof(SerialInfo));
- infoPtr->validMask = permissions;
- infoPtr->handle = handle;
+ infoPtr->validMask = permissions;
+ infoPtr->handle = handle;
+ infoPtr->channel = (Tcl_Channel) NULL;
+ infoPtr->readable = 0;
+ infoPtr->writable = 1;
+ infoPtr->toWrite = infoPtr->writeQueue = 0;
+ infoPtr->blockTime = SERIAL_DEFAULT_BLOCKTIME;
+ infoPtr->lastEventTime = 0;
+ infoPtr->lastError = infoPtr->error = 0;
+ infoPtr->threadId = Tcl_GetCurrentThread();
+ infoPtr->sysBufRead = 4096;
+ infoPtr->sysBufWrite = 4096;
/*
* Use the pointer to keep the channel names unique, in case
@@ -1440,14 +1457,6 @@ TclWinOpenSerialChannel(handle, channelName, permissions)
infoPtr->channel = Tcl_CreateChannel(&serialChannelType, channelName,
(ClientData) infoPtr, permissions);
- infoPtr->readable = 0;
- infoPtr->writable = 1;
- infoPtr->toWrite = infoPtr->writeQueue = 0;
- infoPtr->blockTime = SERIAL_DEFAULT_BLOCKTIME;
- infoPtr->lastEventTime = 0;
- infoPtr->lastError = infoPtr->error = 0;
- infoPtr->threadId = Tcl_GetCurrentThread();
- infoPtr->sysBufRead = infoPtr->sysBufWrite = 4096;
SetupComm(handle, infoPtr->sysBufRead, infoPtr->sysBufWrite);
PurgeComm(handle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR
@@ -2107,3 +2116,51 @@ SerialGetOptionProc(instanceData, interp, optionName, dsPtr)
"mode pollinterval lasterror queue sysbuffer ttystatus xchar");
}
}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SerialThreadActionProc --
+ *
+ * Insert or remove any thread local refs to this channel.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Changes thread local list of valid channels.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+SerialThreadActionProc (instanceData, action)
+ ClientData instanceData;
+ int action;
+{
+ SerialInfo *infoPtr = (SerialInfo *) instanceData;
+
+ /* We do not access firstSerialPtr in the thread structures. This is
+ * not for all serials managed by the thread, but only those we are
+ * watching. Removal of the filevent handlers before transfer thus
+ * takes care of this structure.
+ */
+
+ Tcl_MutexLock(&serialMutex);
+ if (action == TCL_CHANNEL_THREAD_INSERT) {
+ /* We can't copy the thread information from the channel when
+ * the channel is created. At this time the channel back
+ * pointer has not been set yet. However in that case the
+ * threadId has already been set by TclpCreateCommandChannel
+ * itself, so the structure is still good.
+ */
+
+ SerialInit ();
+ if (infoPtr->channel != NULL) {
+ infoPtr->threadId = Tcl_GetChannelThread (infoPtr->channel);
+ }
+ } else {
+ infoPtr->threadId = NULL;
+ }
+ Tcl_MutexUnlock(&serialMutex);
+}
diff --git a/win/tclWinSock.c b/win/tclWinSock.c
index 3d0d5f0..9af7d3e 100644
--- a/win/tclWinSock.c
+++ b/win/tclWinSock.c
@@ -8,7 +8,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclWinSock.c,v 1.36.2.2 2004/05/06 01:03:56 davygrvy Exp $
+ * RCS: @(#) $Id: tclWinSock.c,v 1.36.2.3 2005/01/27 22:53:39 andreas_kupries Exp $
*/
#include "tclWinInt.h"
@@ -265,6 +265,10 @@ static int WaitForSocketEvent _ANSI_ARGS_((
int *errorCodePtr));
static DWORD WINAPI SocketThread _ANSI_ARGS_((LPVOID arg));
+static void TcpThreadActionProc _ANSI_ARGS_ ((
+ ClientData instanceData, int action));
+
+
/*
* This structure describes the channel type structure for TCP socket
* based IO.
@@ -272,7 +276,7 @@ static DWORD WINAPI SocketThread _ANSI_ARGS_((LPVOID arg));
static Tcl_ChannelType tcpChannelType = {
"tcp", /* Type name. */
- TCL_CHANNEL_VERSION_2, /* v2 channel */
+ TCL_CHANNEL_VERSION_4, /* v4 channel */
TcpCloseProc, /* Close proc. */
TcpInputProc, /* Input proc. */
TcpOutputProc, /* Output proc. */
@@ -285,6 +289,8 @@ static Tcl_ChannelType tcpChannelType = {
TcpBlockProc, /* Set socket into (non-)blocking mode. */
NULL, /* flush proc. */
NULL, /* handler proc. */
+ NULL, /* wide seek proc */
+ TcpThreadActionProc, /* thread action proc */
};
@@ -970,7 +976,7 @@ TcpCloseProc(instanceData, interp)
Tcl_Interp *interp; /* Unused. */
{
SocketInfo *infoPtr = (SocketInfo *) instanceData;
- SocketInfo **nextPtrPtr;
+ /* TIP #218 */
int errorCode = 0;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
@@ -995,20 +1001,12 @@ TcpCloseProc(instanceData, interp)
}
}
- /*
- * Remove the socket from socketList.
+ /* TIP #218. Removed the code removing the structure
+ * from the global socket list. This is now done by
+ * the thread action callbacks, and only there. This
+ * happens before this code is called. We can free
+ * without fear of damanging the list.
*/
-
- WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
- for (nextPtrPtr = &(tsdPtr->socketList); (*nextPtrPtr) != NULL;
- nextPtrPtr = &((*nextPtrPtr)->nextPtr)) {
- if ((*nextPtrPtr) == infoPtr) {
- (*nextPtrPtr) = infoPtr->nextPtr;
- break;
- }
- }
-
- SetEvent(tsdPtr->socketListLock);
ckfree((char *) infoPtr);
return errorCode;
}
@@ -1025,7 +1023,7 @@ TcpCloseProc(instanceData, interp)
* Returns a newly allocated SocketInfo.
*
* Side effects:
- * Adds the socket to the global socket list.
+ * None, except for allocation of memory.
*
*----------------------------------------------------------------------
*/
@@ -1047,10 +1045,11 @@ NewSocketInfo(socket)
infoPtr->acceptProc = NULL;
infoPtr->lastError = 0;
- WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
- infoPtr->nextPtr = tsdPtr->socketList;
- tsdPtr->socketList = infoPtr;
- SetEvent(tsdPtr->socketListLock);
+ /* TIP #218. Removed the code inserting the new structure
+ * into the global list. This is now handled in the thread
+ * action callbacks, and only there.
+ */
+ infoPtr->nextPtr = NULL;
return infoPtr;
}
@@ -1067,7 +1066,7 @@ NewSocketInfo(socket)
* Returns a new SocketInfo, or NULL with an error in interp.
*
* Side effects:
- * Adds a new socket to the socketList.
+ * None, except for allocation of memory.
*
*----------------------------------------------------------------------
*/
@@ -2659,5 +2658,85 @@ TclWinGetServByName(const char * name, const char * proto)
return winSock.getservbyname(name, proto);
}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TcpThreadActionProc --
+ *
+ * Insert or remove any thread local refs to this channel.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Changes thread local list of valid channels.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+TcpThreadActionProc (instanceData, action)
+ ClientData instanceData;
+ int action;
+{
+ ThreadSpecificData *tsdPtr;
+ SocketInfo *infoPtr = (SocketInfo *) instanceData;
+ int notifyCmd;
+
+ if (action == TCL_CHANNEL_THREAD_INSERT) {
+ /*
+ * Ensure that socket subsystem is initialized in this thread, or
+ * else sockets will not work.
+ */
+
+ Tcl_MutexLock(&socketMutex);
+ InitSockets();
+ Tcl_MutexUnlock(&socketMutex);
+ tsdPtr = TCL_TSD_INIT(&dataKey);
+
+ WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
+ infoPtr->nextPtr = tsdPtr->socketList;
+ tsdPtr->socketList = infoPtr;
+ SetEvent(tsdPtr->socketListLock);
+
+ notifyCmd = SELECT;
+ } else {
+ SocketInfo **nextPtrPtr;
+ int removed = 0;
+
+ tsdPtr = TCL_TSD_INIT(&dataKey);
+
+ /* TIP #218, Bugfix: All access to socketList has to be protected by the lock */
+ WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
+ for (nextPtrPtr = &(tsdPtr->socketList); (*nextPtrPtr) != NULL;
+ nextPtrPtr = &((*nextPtrPtr)->nextPtr)) {
+ if ((*nextPtrPtr) == infoPtr) {
+ (*nextPtrPtr) = infoPtr->nextPtr;
+ removed = 1;
+ break;
+ }
+ }
+ SetEvent(tsdPtr->socketListLock);
+
+ /*
+ * This could happen if the channel was created in one thread
+ * and then moved to another without updating the thread
+ * local data in each thread.
+ */
+
+ if (!removed) {
+ Tcl_Panic("file info ptr not on thread channel list");
+ }
+
+ notifyCmd = UNSELECT;
+ }
+
+ /*
+ * Ensure that, or stop, notifications for the socket occur in this thread.
+ */
+
+ SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
+ (WPARAM) notifyCmd, (LPARAM) infoPtr);
+}