diff options
-rw-r--r-- | ChangeLog | 29 | ||||
-rw-r--r-- | doc/CrtChannel.3 | 15 | ||||
-rw-r--r-- | generic/tcl.decls | 5 | ||||
-rw-r--r-- | generic/tclDecls.h | 10 | ||||
-rw-r--r-- | generic/tclIO.c | 44 | ||||
-rw-r--r-- | generic/tclIO.h | 4 | ||||
-rw-r--r-- | generic/tclStubInit.c | 3 | ||||
-rw-r--r-- | generic/tclTest.c | 14 | ||||
-rw-r--r-- | tests/io.test | 38 | ||||
-rw-r--r-- | unix/mkLinks | 2 |
10 files changed, 142 insertions, 22 deletions
@@ -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 |