summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog29
-rw-r--r--doc/CrtChannel.315
-rw-r--r--generic/tcl.decls5
-rw-r--r--generic/tclDecls.h10
-rw-r--r--generic/tclIO.c44
-rw-r--r--generic/tclIO.h4
-rw-r--r--generic/tclStubInit.c3
-rw-r--r--generic/tclTest.c14
-rw-r--r--tests/io.test38
-rw-r--r--unix/mkLinks2
10 files changed, 142 insertions, 22 deletions
diff --git a/ChangeLog b/ChangeLog
index b8e824b..b13a624 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,32 @@
+2001-03-30 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * All of the changes below belong to TIP #10 [Tcl I/O Enhancement:
+ Thread-Aware Channels]. See also [Patch #403358] at SF.
+
+ * generic/tclIO.h (struct ChannelState, line 236f): Extended the
+ structure with a new field of type 'Tcl_ThreadId' to hold the id
+ of the thread currently managing all channels with this state.
+
+ Note: This structure is shared by all channels in a stack of
+ transformations.
+
+ * generic/tclIO.c (Tcl_CreateChannel, lines 1058-1065): Modified
+ to store the Id of the current thread in the 'ChannelState' of
+ the new channel.
+
+ * generic/tclIO.c (Tcl_SpliceChannel, lines 2265-2270): Modified
+ in the same manner as 'Tcl_CreateChannel' as the channel will be
+ managed by the current thread afterward.
+
+ * generic/tclIO.c (Tcl_GetChannelThread, lines 1478-1503):
+ * generic/tcl.decls (Tcl_GetChannelThread, lines 1504-1506): New
+ API function to retrieve the Id of the managing thread from a
+ channel. Implementation and declaration.
+
+ * generic/tclTest.c (TestChannelCmd, lines 4520-4532): Added
+ subcommand 'mthread' to query a channel about its managing
+ thread.
+
2001-03-29 Mo DeJong <mdejong@redhat.com>
* tests/interp.test: Print out warning when
diff --git a/doc/CrtChannel.3 b/doc/CrtChannel.3
index 8fe8dee..9cab385 100644
--- a/doc/CrtChannel.3
+++ b/doc/CrtChannel.3
@@ -5,13 +5,13 @@
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
-'\" RCS: @(#) $Id: CrtChannel.3,v 1.8 2000/10/06 21:06:08 hobbs Exp $
+'\" RCS: @(#) $Id: CrtChannel.3,v 1.9 2001/03/30 23:06:39 andreas_kupries Exp $
.so man.macros
.TH Tcl_CreateChannel 3 8.3 Tcl "Tcl Library Procedures"
.BS
'\" Note: do not modify the .SH NAME line immediately below!
.SH NAME
-Tcl_CreateChannel, Tcl_GetChannelInstanceData, Tcl_GetChannelType, Tcl_GetChannelName, Tcl_GetChannelHandle, Tcl_GetChannelMode, Tcl_GetChannelBufferSize, Tcl_SetChannelBufferSize, Tcl_NotifyChannel, Tcl_BadChannelOption, Tcl_ChannelName, Tcl_ChannelVersion, Tcl_ChannelBlockModeProc, Tcl_ChannelCloseProc, Tcl_ChannelClose2Proc, Tcl_ChannelInputProc, Tcl_ChannelOutputProc, Tcl_ChannelSeekProc, Tcl_ChannelSetOptionProc, Tcl_ChannelGetOptionProc, Tcl_ChannelWatchProc, Tcl_ChannelGetHandleProc, Tcl_ChannelFlushProc, Tcl_ChannelHandlerProc, Tcl_IsChannelShared, Tcl_IsChannelRegistered, Tcl_CutChannel, Tcl_SpliceChannel, Tcl_IsChannelExisting, Tcl_ClearChannelHandlers \- procedures for creating and manipulating channels
+Tcl_CreateChannel, Tcl_GetChannelInstanceData, Tcl_GetChannelType, Tcl_GetChannelName, Tcl_GetChannelHandle, Tcl_GetChannelMode, Tcl_GetChannelBufferSize, Tcl_SetChannelBufferSize, Tcl_NotifyChannel, Tcl_BadChannelOption, Tcl_ChannelName, Tcl_ChannelVersion, Tcl_ChannelBlockModeProc, Tcl_ChannelCloseProc, Tcl_ChannelClose2Proc, Tcl_ChannelInputProc, Tcl_ChannelOutputProc, Tcl_ChannelSeekProc, Tcl_ChannelSetOptionProc, Tcl_ChannelGetOptionProc, Tcl_ChannelWatchProc, Tcl_ChannelGetHandleProc, Tcl_ChannelFlushProc, Tcl_ChannelHandlerProc, Tcl_IsChannelShared, Tcl_IsChannelRegistered, Tcl_CutChannel, Tcl_SpliceChannel, Tcl_IsChannelExisting, Tcl_ClearChannelHandlers, Tcl_GetChannelThread \- procedures for creating and manipulating channels
.SH SYNOPSIS
.nf
\fB#include <tcl.h>\fR
@@ -31,6 +31,11 @@ char *
int
\fBTcl_GetChannelHandle\fR(\fIchannel, direction, handlePtr\fR)
.sp
+.VS 8.4
+Tcl_ThreadId
+\fBTcl_GetChannelThread\fR(\fIchannel\fR)
+.VE
+.sp
int
\fBTcl_GetChannelBufferSize\fR(\fIchannel\fR)
.sp
@@ -215,6 +220,12 @@ the channel does not have a device handle for the specified direction,
then \fBTCL_ERROR\fR is returned instead. Different channel drivers
will return different types of handle. Refer to the manual entries
for each driver to determine what type of handle is returned.
+.VS 8.4
+.PP
+\fBTcl_GetChannelThread\fR returns the id of the thread currently managing
+the specified \fIchannel\fR. This allows channel drivers to send their file
+events to the correct event queue even for a multi-threaded core.
+.VE
.PP
\fBTcl_GetChannelMode\fR returns an OR-ed combination of \fBTCL_READABLE\fR
and \fBTCL_WRITABLE\fR, indicating whether the channel is open for input
diff --git a/generic/tcl.decls b/generic/tcl.decls
index 6c1e790..ada4049 100644
--- a/generic/tcl.decls
+++ b/generic/tcl.decls
@@ -10,7 +10,7 @@
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
-# RCS: @(#) $Id: tcl.decls,v 1.43 2001/01/18 19:09:55 andreas_kupries Exp $
+# RCS: @(#) $Id: tcl.decls,v 1.44 2001/03/30 23:06:39 andreas_kupries Exp $
library tcl
@@ -1501,6 +1501,9 @@ declare 431 generic {
declare 432 generic {
int Tcl_AttemptSetObjLength(Tcl_Obj *objPtr, int length)
}
+declare 433 generic {
+ Tcl_ThreadId Tcl_GetChannelThread(Tcl_Channel channel)
+}
##############################################################################
diff --git a/generic/tclDecls.h b/generic/tclDecls.h
index 6caae64..06e9b89 100644
--- a/generic/tclDecls.h
+++ b/generic/tclDecls.h
@@ -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: tclDecls.h,v 1.45 2001/03/26 22:16:54 dgp Exp $
+ * RCS: @(#) $Id: tclDecls.h,v 1.46 2001/03/30 23:06:39 andreas_kupries Exp $
*/
#ifndef _TCLDECLS
@@ -1350,6 +1350,9 @@ EXTERN char * Tcl_AttemptDbCkrealloc _ANSI_ARGS_((char * ptr,
/* 432 */
EXTERN int Tcl_AttemptSetObjLength _ANSI_ARGS_((
Tcl_Obj * objPtr, int length));
+/* 433 */
+EXTERN Tcl_ThreadId Tcl_GetChannelThread _ANSI_ARGS_((
+ Tcl_Channel channel));
typedef struct TclStubHooks {
struct TclPlatStubs *tclPlatStubs;
@@ -1850,6 +1853,7 @@ typedef struct TclStubs {
char * (*tcl_AttemptRealloc) _ANSI_ARGS_((char * ptr, unsigned int size)); /* 430 */
char * (*tcl_AttemptDbCkrealloc) _ANSI_ARGS_((char * ptr, unsigned int size, char * file, int line)); /* 431 */
int (*tcl_AttemptSetObjLength) _ANSI_ARGS_((Tcl_Obj * objPtr, int length)); /* 432 */
+ Tcl_ThreadId (*tcl_GetChannelThread) _ANSI_ARGS_((Tcl_Channel channel)); /* 433 */
} TclStubs;
#ifdef __cplusplus
@@ -3630,6 +3634,10 @@ extern TclStubs *tclStubsPtr;
#define Tcl_AttemptSetObjLength \
(tclStubsPtr->tcl_AttemptSetObjLength) /* 432 */
#endif
+#ifndef Tcl_GetChannelThread
+#define Tcl_GetChannelThread \
+ (tclStubsPtr->tcl_GetChannelThread) /* 433 */
+#endif
#endif /* defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) */
diff --git a/generic/tclIO.c b/generic/tclIO.c
index 1718d15..2c1bc34 100644
--- a/generic/tclIO.c
+++ b/generic/tclIO.c
@@ -10,7 +10,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclIO.c,v 1.28 2001/01/30 17:32:06 dgp Exp $
+ * RCS: @(#) $Id: tclIO.c,v 1.29 2001/03/30 23:06:39 andreas_kupries Exp $
*/
#include "tclInt.h"
@@ -1056,6 +1056,14 @@ Tcl_CreateChannel(typePtr, chanName, instanceData, mask)
tsdPtr->firstCSPtr = statePtr;
/*
+ * TIP #10. Mark the current thread as the one managing the new
+ * channel. Note: 'Tcl_GetCurrentThread' returns sensible
+ * values even for a non-threaded core.
+ */
+
+ statePtr->managingThread = Tcl_GetCurrentThread ();
+
+ /*
* Install this channel in the first empty standard channel slot, if
* the channel was previously closed explicitly.
*/
@@ -1471,6 +1479,32 @@ Tcl_GetChannelInstanceData(chan)
/*
*----------------------------------------------------------------------
*
+ * Tcl_GetChannelThread --
+ *
+ * Given a channel structure, returns the thread managing it.
+ * TIP #10
+ *
+ * Results:
+ * Returns the id of the thread managing the channel.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Tcl_ThreadId
+Tcl_GetChannelThread(chan)
+ Tcl_Channel chan; /* The channel to return managing thread for. */
+{
+ Channel *chanPtr = (Channel *) chan; /* The actual channel. */
+
+ return chanPtr->state->managingThread;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* Tcl_GetChannelType --
*
* Given a channel structure, returns the channel type structure.
@@ -2254,6 +2288,14 @@ Tcl_SpliceChannel(chan)
statePtr->nextCSPtr = tsdPtr->firstCSPtr;
tsdPtr->firstCSPtr = statePtr;
+
+ /*
+ * TIP #10. Mark the current thread as the new one managing this
+ * channel. Note: 'Tcl_GetCurrentThread' returns sensible
+ * values even for a non-threaded core.
+ */
+
+ statePtr->managingThread = Tcl_GetCurrentThread ();
}
/*
diff --git a/generic/tclIO.h b/generic/tclIO.h
index b232cba..caac702 100644
--- a/generic/tclIO.h
+++ b/generic/tclIO.h
@@ -10,7 +10,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclIO.h,v 1.2 2000/09/28 06:38:21 hobbs Exp $
+ * RCS: @(#) $Id: tclIO.h,v 1.3 2001/03/30 23:06:40 andreas_kupries Exp $
*/
/*
@@ -233,6 +233,8 @@ typedef struct ChannelState {
* long as the channel state. Never NULL. */
struct ChannelState *nextCSPtr;
/* Next in list of channels currently open. */
+ Tcl_ThreadId managingThread; /* TIP #10: Id of the thread managing
+ * this stack of channels. */
} ChannelState;
/*
diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c
index cb42cc0..35fada8 100644
--- a/generic/tclStubInit.c
+++ b/generic/tclStubInit.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: tclStubInit.c,v 1.47 2001/01/18 19:09:55 andreas_kupries Exp $
+ * RCS: @(#) $Id: tclStubInit.c,v 1.48 2001/03/30 23:06:40 andreas_kupries Exp $
*/
#include "tclInt.h"
@@ -836,6 +836,7 @@ TclStubs tclStubs = {
Tcl_AttemptRealloc, /* 430 */
Tcl_AttemptDbCkrealloc, /* 431 */
Tcl_AttemptSetObjLength, /* 432 */
+ Tcl_GetChannelThread, /* 433 */
};
/* !END!: Do not edit above this line. */
diff --git a/generic/tclTest.c b/generic/tclTest.c
index c27e7e2..1aa28d2 100644
--- a/generic/tclTest.c
+++ b/generic/tclTest.c
@@ -13,7 +13,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclTest.c,v 1.22 2000/11/24 11:27:37 dkf Exp $
+ * RCS: @(#) $Id: tclTest.c,v 1.23 2001/03/30 23:06:40 andreas_kupries Exp $
*/
#define TCL_TEST
@@ -4517,6 +4517,18 @@ TestChannelCmd(clientData, interp, argc, argv)
return TCL_OK;
}
+ if ((cmdName[0] == 'm') && (strncmp(cmdName, "mthread", len) == 0)) {
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "channel name required",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ TclFormatInt(buf, Tcl_GetChannelThread (chan));
+ Tcl_AppendResult(interp, buf, (char *) NULL);
+ return TCL_OK;
+ }
+
if ((cmdName[0] == 'n') && (strncmp(cmdName, "name", len) == 0)) {
if (argc != 3) {
Tcl_AppendResult(interp, "channel name required",
diff --git a/tests/io.test b/tests/io.test
index 9c93903..044a803 100644
--- a/tests/io.test
+++ b/tests/io.test
@@ -12,7 +12,7 @@
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
-# RCS: @(#) $Id: io.test,v 1.14 2000/04/10 17:19:00 ericm Exp $
+# RCS: @(#) $Id: io.test,v 1.15 2001/03/30 23:06:40 andreas_kupries Exp $
if {[lsearch [namespace children] ::tcltest] == -1} {
package require tcltest
@@ -6722,6 +6722,29 @@ test io-58.1 {Tcl_NotifyChannel and error when closing} {unixOrPc} {
list $x $result
} {1 {gets {normal message from pipe} gets {} catch {error message from pipe}}}
+
+
+if {[info commands testthread] != {}} {
+ set mainthread [testthread id]
+} else {
+ set mainthread 0
+}
+
+test io-59.1 {Thread reference of channels} {
+ # TIP #10
+ # More complicated tests (like that the reference changes as a
+ # channel is moved from thread to thread) can be done only in the
+ # extension which fully implements the moving of channels between
+ # threads, i.e. 'Threads'. Or we have to extend [testthread] as well.
+
+ set f [open longfile r]
+ set result [testchannel mthread $f]
+ close $f
+ set result
+} $mainthread
+
+
+
# cleanup
foreach file [list fooBar longfile script output test1 pipe my_script foo \
bar test2 test3 cat stdout] {
@@ -6730,16 +6753,3 @@ foreach file [list fooBar longfile script output test1 pipe my_script foo \
::tcltest::restoreState
::tcltest::cleanupTests
return
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/unix/mkLinks b/unix/mkLinks
index 4cb02cb..79dc91d 100644
--- a/unix/mkLinks
+++ b/unix/mkLinks
@@ -165,6 +165,7 @@ if test -r CrtChannel.3; then
rm -f Tcl_SpliceChannel.3
rm -f Tcl_IsChannelExisting.3
rm -f Tcl_ClearChannelHandlers.3
+ rm -f Tcl_GetChannelThread.3
ln CrtChannel.3 Tcl_CreateChannel.3
ln CrtChannel.3 Tcl_GetChannelInstanceData.3
ln CrtChannel.3 Tcl_GetChannelType.3
@@ -195,6 +196,7 @@ if test -r CrtChannel.3; then
ln CrtChannel.3 Tcl_SpliceChannel.3
ln CrtChannel.3 Tcl_IsChannelExisting.3
ln CrtChannel.3 Tcl_ClearChannelHandlers.3
+ ln CrtChannel.3 Tcl_GetChannelThread.3
fi
if test -r CrtChnlHdlr.3; then
rm -f Tcl_CreateChannelHandler.3