diff options
Diffstat (limited to 'generic/tclIORChan.c')
| -rw-r--r-- | generic/tclIORChan.c | 935 | 
1 files changed, 491 insertions, 444 deletions
| diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c index c88629f..94428bb 100644 --- a/generic/tclIORChan.c +++ b/generic/tclIORChan.c @@ -14,12 +14,10 @@   *   * See the file "license.terms" for information on usage and redistribution of   * this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tclIORChan.c,v 1.28.2.11 2010/08/04 16:47:15 andreas_kupries Exp $   */ -#include <tclInt.h> -#include <tclIO.h> +#include "tclInt.h" +#include "tclIO.h"  #include <assert.h>  #ifndef EINVAL @@ -41,6 +39,9 @@ static int		ReflectOutput(ClientData clientData, const char *buf,  			    int toWrite, int *errorCodePtr);  static void		ReflectWatch(ClientData clientData, int mask);  static int		ReflectBlock(ClientData clientData, int mode); +#ifdef TCL_THREADS +static void		ReflectThread(ClientData clientData, int action); +#endif  static Tcl_WideInt	ReflectSeekWide(ClientData clientData,  			    Tcl_WideInt offset, int mode, int *errorCodePtr);  static int		ReflectSeek(ClientData clientData, long offset, @@ -57,24 +58,28 @@ static int		ReflectSetOption(ClientData clientData,   * a version 3 structure.   */ -static Tcl_ChannelType tclRChannelType = { -    "tclrchannel",         /* Type name.                                  */ +static const Tcl_ChannelType tclRChannelType = { +    "tclrchannel",	   /* Type name.				  */      TCL_CHANNEL_VERSION_5, /* v5 channel */ -    ReflectClose,          /* Close channel, clean instance data          */ -    ReflectInput,          /* Handle read request                         */ -    ReflectOutput,         /* Handle write request                        */ -    ReflectSeek,           /* Move location of access point.   NULL'able  */ -    ReflectSetOption,      /* Set options.                     NULL'able  */ -    ReflectGetOption,      /* Get options.                     NULL'able  */ -    ReflectWatch,          /* Initialize notifier                         */ -    NULL,                  /* Get OS handle from the channel.  NULL'able  */ -    NULL,                  /* No close2 support.               NULL'able  */ -    ReflectBlock,          /* Set blocking/nonblocking.        NULL'able  */ -    NULL,                  /* Flush channel. Not used by core. NULL'able  */ -    NULL,                  /* Handle events.                   NULL'able  */ -    ReflectSeekWide,       /* Move access point (64 bit).      NULL'able  */ -    NULL,                  /* thread action */ -    NULL,                  /* truncate */ +    ReflectClose,	   /* Close channel, clean instance data	  */ +    ReflectInput,	   /* Handle read request			  */ +    ReflectOutput,	   /* Handle write request			  */ +    ReflectSeek,	   /* Move location of access point.	NULL'able */ +    ReflectSetOption,	   /* Set options.			NULL'able */ +    ReflectGetOption,	   /* Get options.			NULL'able */ +    ReflectWatch,	   /* Initialize notifier			  */ +    NULL,		   /* Get OS handle from the channel.	NULL'able */ +    NULL,		   /* No close2 support.		NULL'able */ +    ReflectBlock,	   /* Set blocking/nonblocking.		NULL'able */ +    NULL,		   /* Flush channel. Not used by core.	NULL'able */ +    NULL,		   /* Handle events.			NULL'able */ +    ReflectSeekWide,	   /* Move access point (64 bit).	NULL'able */ +#ifdef TCL_THREADS +    ReflectThread,         /* thread action, tracking owner */ +#else +    NULL,		   /* thread action */ +#endif +    NULL		   /* truncate */  };  /* @@ -91,38 +96,20 @@ typedef struct {  				 * command is gone.  				 */  #ifdef TCL_THREADS -    Tcl_ThreadId thread;	/* Thread the 'interp' belongs to. */ +    Tcl_ThreadId thread;	/* Thread the 'interp' belongs to. == Handler thread */ +    Tcl_ThreadId owner;         /* Thread owning the structure.    == Channel thread */  #endif - -    /* See [==] as well. -     * Storage for the command prefix and the additional words required for -     * the invocation of methods in the command handler. -     * -     * argv [0] ... [.] | [argc-2] [argc-1] | [argc]  [argc+2] -     *      cmd ... pfx | method   chan     | detail1 detail2 -     *      ~~~~ CT ~~~            ~~ CT ~~ -     * -     * CT = Belongs to the 'Command handler Thread'. -     */ - -    int argc;			/* Number of preallocated words - 2 */ -    Tcl_Obj **argv;		/* Preallocated array for calling the handler. -				 * args[0] is placeholder for cmd word. -				 * Followed by the arguments in the prefix, -				 * plus 4 placeholders for method, channel, -				 * and at most two varying (method specific) -				 * words. */ -    int methods;		/* Bitmask of supported methods */ - -    /* -     * NOTE (9): Should we have predefined shared literals for the method -     * names? -     */ +    Tcl_Obj *cmd;		/* Callback command prefix */ +    Tcl_Obj *methods;		/* Methods to append to command prefix */ +    Tcl_Obj *name;		/* Name of the channel as created */      int mode;			/* Mask of R/W mode */      int interest;		/* Mask of events the channel is interested  				 * in. */ +    int dead;			/* Boolean signal that some operations +				 * should no longer be attempted. */ +      /*       * Note regarding the usage of timers.       * @@ -161,7 +148,7 @@ typedef struct {   * Event literals. ==================================================   */ -static const char *eventOptions[] = { +static const char *const eventOptions[] = {      "read", "write", NULL  };  typedef enum { @@ -172,7 +159,7 @@ typedef enum {   * Method literals. ==================================================   */ -static const char *methodNames[] = { +static const char *const methodNames[] = {      "blocking",		/* OPT */      "cget",		/* OPT \/ Together or none */      "cgetall",		/* OPT /\ of these two     */ @@ -342,7 +329,8 @@ typedef struct ForwardingEvent {  struct ForwardingResult {      Tcl_ThreadId src;		/* Originating thread. */      Tcl_ThreadId dst;		/* Thread the op was forwarded to. */ -    Tcl_Interp*  dsti;          /* Interpreter in the thread the op was forwarded to. */ +    Tcl_Interp *dsti;		/* Interpreter in the thread the op was +				 * forwarded to. */      /*       * Note regarding 'dsti' above: Its information is also available via the       * chain evPtr->rcPtr->interp, however, as can be seen, two more @@ -364,7 +352,7 @@ typedef struct ThreadSpecificData {       * per-thread version of the per-interpreter map.       */ -    ReflectedChannelMap* rcmPtr; +    ReflectedChannelMap *rcmPtr;  } ThreadSpecificData;  static Tcl_ThreadDataKey dataKey; @@ -388,31 +376,31 @@ TCL_DECLARE_MUTEX(rcForwardMutex)   * leak resources when threads go away.   */ -static void		ForwardOpToOwnerThread(ReflectedChannel *rcPtr, -			    ForwardedOperation op, const VOID *param); +static void		ForwardOpToHandlerThread(ReflectedChannel *rcPtr, +			    ForwardedOperation op, const void *param);  static int		ForwardProc(Tcl_Event *evPtr, int mask);  static void		SrcExitProc(ClientData clientData);  #define FreeReceivedError(p) \ -	if ((p)->base.mustFree) { \ -	    ckfree((p)->base.msgStr); \ +	if ((p)->base.mustFree) {                               \ +	    ckfree((p)->base.msgStr);                           \  	}  #define PassReceivedErrorInterp(i,p) \ -	if ((i) != NULL) { \ -	    Tcl_SetChannelErrorInterp((i), \ -		    Tcl_NewStringObj((p)->base.msgStr, -1)); \ -	} \ +	if ((i) != NULL) {                                      \ +	    Tcl_SetChannelErrorInterp((i),                      \ +		    Tcl_NewStringObj((p)->base.msgStr, -1));    \ +	}                                                       \  	FreeReceivedError(p)  #define PassReceivedError(c,p) \  	Tcl_SetChannelError((c), Tcl_NewStringObj((p)->base.msgStr, -1)); \  	FreeReceivedError(p)  #define ForwardSetStaticError(p,emsg) \ -	(p)->base.code = TCL_ERROR; \ -	(p)->base.mustFree = 0; \ +	(p)->base.code = TCL_ERROR;                             \ +	(p)->base.mustFree = 0;                                 \  	(p)->base.msgStr = (char *) (emsg)  #define ForwardSetDynamicError(p,emsg) \ -	(p)->base.code = TCL_ERROR; \ -	(p)->base.mustFree = 1; \ +	(p)->base.code = TCL_ERROR;                             \ +	(p)->base.mustFree = 1;                                 \  	(p)->base.msgStr = (char *) (emsg)  static void		ForwardSetObjError(ForwardParam *p, Tcl_Obj *objPtr); @@ -441,13 +429,13 @@ static ReflectedChannel * NewReflectedChannel(Tcl_Interp *interp,  static Tcl_Obj *	NextHandle(void);  static void		FreeReflectedChannel(ReflectedChannel *rcPtr);  static int		InvokeTclMethod(ReflectedChannel *rcPtr, -			    const char *method, Tcl_Obj *argOneObj, +			    MethodName method, Tcl_Obj *argOneObj,  			    Tcl_Obj *argTwoObj, Tcl_Obj **resultObjPtr);  static ReflectedChannelMap *	GetReflectedChannelMap(Tcl_Interp *interp);  static void		DeleteReflectedChannelMap(ClientData clientData,  			    Tcl_Interp *interp); -static int              ErrnoReturn(ReflectedChannel *rcPtr, Tcl_Obj* resObj); +static int		ErrnoReturn(ReflectedChannel *rcPtr, Tcl_Obj *resObj);  /*   * Global constant strings (messages). ================== @@ -456,9 +444,7 @@ static int              ErrnoReturn(ReflectedChannel *rcPtr, Tcl_Obj* resObj);   * list-quoting to keep the words of the message together. See also [x].   */ -static const char *msg_read_unsup = "{read not supported by Tcl driver}";  static const char *msg_read_toomuch = "{read delivered more than requested}"; -static const char *msg_write_unsup = "{write not supported by Tcl driver}";  static const char *msg_write_toomuch = "{write wrote more than requested}";  static const char *msg_write_nothing = "{write wrote nothing}";  static const char *msg_seek_beforestart = "{Tried to seek before origin}"; @@ -513,9 +499,11 @@ TclChanCreateObjCmd(      int methods;		/* Bitmask for supported methods. */      Channel *chanPtr;		/* 'chan' resolved to internal struct. */      Tcl_Obj *err;		/* Error message */ -    ReflectedChannelMap* rcmPtr; /* Map of reflected channels with handlers in this interp */ -    Tcl_HashEntry* hPtr;         /* Entry in the above map */ -    int isNew;                   /* Placeholder. */ +    ReflectedChannelMap *rcmPtr; +				/* Map of reflected channels with handlers in +				 * this interp. */ +    Tcl_HashEntry *hPtr;	/* Entry in the above map */ +    int isNew;			/* Placeholder. */      /*       * Syntax:   chan create MODE CMDPREFIX @@ -570,10 +558,6 @@ TclChanCreateObjCmd(      rcId = NextHandle();      rcPtr = NewReflectedChannel(interp, cmdObj, mode, rcId); -    chan = Tcl_CreateChannel(&tclRChannelType, TclGetString(rcId), rcPtr, -	    mode); -    rcPtr->chan = chan; -    chanPtr = (Channel *) chan;      /*       * Invoke 'initialize' and validate that the handler is present and ok. @@ -587,8 +571,9 @@ TclChanCreateObjCmd(      modeObj = DecodeEventMask(mode);      /* assert modeObj.refCount == 1 */ -    result = InvokeTclMethod(rcPtr, "initialize", modeObj, NULL, &resObj); +    result = InvokeTclMethod(rcPtr, METH_INIT, modeObj, NULL, &resObj);      Tcl_DecrRefCount(modeObj); +      if (result != TCL_OK) {  	UnmarshallErrorResult(interp, resObj);  	Tcl_DecrRefCount(resObj);	/* Remove reference held from invoke */ @@ -603,11 +588,9 @@ TclChanCreateObjCmd(       */      if (Tcl_ListObjGetElements(NULL, resObj, &listc, &listv) != TCL_OK) { -	TclNewLiteralStringObj(err, "chan handler \""); -	Tcl_AppendObjToObj(err, cmdObj); -	Tcl_AppendToObj(err, " initialize\" returned non-list: ", -1); -	Tcl_AppendObjToObj(err, resObj); -	Tcl_SetObjResult(interp, err); +        Tcl_SetObjResult(interp, Tcl_ObjPrintf( +                "chan handler \"%s initialize\" returned non-list: %s", +                Tcl_GetString(cmdObj), Tcl_GetString(resObj)));  	Tcl_DecrRefCount(resObj);  	goto error;      } @@ -631,42 +614,37 @@ TclChanCreateObjCmd(      Tcl_DecrRefCount(resObj);      if ((REQUIRED_METHODS & methods) != REQUIRED_METHODS) { -	TclNewLiteralStringObj(err, "chan handler \""); -	Tcl_AppendObjToObj(err, cmdObj); -	Tcl_AppendToObj(err, "\" does not support all required methods", -1); -	Tcl_SetObjResult(interp, err); +        Tcl_SetObjResult(interp, Tcl_ObjPrintf( +                "chan handler \"%s\" does not support all required methods", +                Tcl_GetString(cmdObj)));  	goto error;      }      if ((mode & TCL_READABLE) && !HAS(methods, METH_READ)) { -	TclNewLiteralStringObj(err, "chan handler \""); -	Tcl_AppendObjToObj(err, cmdObj); -	Tcl_AppendToObj(err, "\" lacks a \"read\" method", -1); -	Tcl_SetObjResult(interp, err); +        Tcl_SetObjResult(interp, Tcl_ObjPrintf( +                "chan handler \"%s\" lacks a \"read\" method", +                Tcl_GetString(cmdObj)));  	goto error;      }      if ((mode & TCL_WRITABLE) && !HAS(methods, METH_WRITE)) { -	TclNewLiteralStringObj(err, "chan handler \""); -	Tcl_AppendObjToObj(err, cmdObj); -	Tcl_AppendToObj(err, "\" lacks a \"write\" method", -1); -	Tcl_SetObjResult(interp, err); +        Tcl_SetObjResult(interp, Tcl_ObjPrintf( +                "chan handler \"%s\" lacks a \"write\" method", +                Tcl_GetString(cmdObj)));  	goto error;      }      if (!IMPLIES(HAS(methods, METH_CGET), HAS(methods, METH_CGETALL))) { -	TclNewLiteralStringObj(err, "chan handler \""); -	Tcl_AppendObjToObj(err, cmdObj); -	Tcl_AppendToObj(err, "\" supports \"cget\" but not \"cgetall\"", -1); -	Tcl_SetObjResult(interp, err); +        Tcl_SetObjResult(interp, Tcl_ObjPrintf( +                "chan handler \"%s\" supports \"cget\" but not \"cgetall\"", +                Tcl_GetString(cmdObj)));  	goto error;      }      if (!IMPLIES(HAS(methods, METH_CGETALL), HAS(methods, METH_CGET))) { -	TclNewLiteralStringObj(err, "chan handler \""); -	Tcl_AppendObjToObj(err, cmdObj); -	Tcl_AppendToObj(err, "\" supports \"cgetall\" but not \"cget\"", -1); -	Tcl_SetObjResult(interp, err); +        Tcl_SetObjResult(interp, Tcl_ObjPrintf( +                "chan handler \"%s\" supports \"cgetall\" but not \"cget\"", +                Tcl_GetString(cmdObj)));  	goto error;      } @@ -676,7 +654,11 @@ TclChanCreateObjCmd(       * Everything is fine now.       */ -    rcPtr->methods = methods; +    chan = Tcl_CreateChannel(&tclRChannelType, TclGetString(rcId), rcPtr, +	    mode); +    rcPtr->chan = chan; +    Tcl_Preserve(chan); +    chanPtr = (Channel *) chan;      if ((methods & NULLABLE_METHODS) != NULLABLE_METHODS) {  	/* @@ -685,8 +667,7 @@ TclChanCreateObjCmd(  	 * as the actual channel type.  	 */ -	Tcl_ChannelType *clonePtr = (Tcl_ChannelType *) -		ckalloc(sizeof(Tcl_ChannelType)); +	Tcl_ChannelType *clonePtr = ckalloc(sizeof(Tcl_ChannelType));  	memcpy(clonePtr, &tclRChannelType, sizeof(Tcl_ChannelType)); @@ -715,19 +696,17 @@ TclChanCreateObjCmd(      Tcl_RegisterChannel(interp, chan); -    rcmPtr = GetReflectedChannelMap (interp); -    hPtr   = Tcl_CreateHashEntry(&rcmPtr->map, -				 chanPtr->state->channelName, &isNew); -    if (!isNew) { -	if (chanPtr != Tcl_GetHashValue(hPtr)) { -	    Tcl_Panic("TclChanCreateObjCmd: duplicate channel names"); -	} +    rcmPtr = GetReflectedChannelMap(interp); +    hPtr = Tcl_CreateHashEntry(&rcmPtr->map, chanPtr->state->channelName, +	    &isNew); +    if (!isNew && chanPtr != Tcl_GetHashValue(hPtr)) { +	Tcl_Panic("TclChanCreateObjCmd: duplicate channel names");      }      Tcl_SetHashValue(hPtr, chan);  #ifdef TCL_THREADS      rcmPtr = GetThreadReflectedChannelMap(); -    hPtr   = Tcl_CreateHashEntry(&rcmPtr->map, -				 chanPtr->state->channelName, &isNew); +    hPtr = Tcl_CreateHashEntry(&rcmPtr->map, chanPtr->state->channelName, +	    &isNew);      Tcl_SetHashValue(hPtr, chan);  #endif @@ -735,16 +714,15 @@ TclChanCreateObjCmd(       * Return handle as result of command.       */ -    Tcl_SetObjResult(interp, rcId); +    Tcl_SetObjResult(interp, +            Tcl_NewStringObj(chanPtr->state->channelName, -1));      return TCL_OK; - error: -    /* -     * Signal to ReflectClose to not call 'finalize'. -     */ - -    rcPtr->methods = 0; -    Tcl_Close(interp, chan); +  error: +    Tcl_DecrRefCount(rcPtr->name); +    Tcl_DecrRefCount(rcPtr->methods); +    Tcl_DecrRefCount(rcPtr->cmd); +    ckfree((char*) rcPtr);      return TCL_ERROR;  #undef MODE @@ -769,6 +747,50 @@ TclChanCreateObjCmd(   *----------------------------------------------------------------------   */ +typedef struct ReflectEvent { +    Tcl_Event header; +    ReflectedChannel *rcPtr; +    int events; +} ReflectEvent; + +static int +ReflectEventRun( +    Tcl_Event *ev, +    int flags) +{ +    /* OWNER thread +     * +     * Note: When the channel is closed any pending events of this type are +     * deleted. See ReflectClose() for the Tcl_DeleteEvents() calls +     * accomplishing that. +     */ + +    ReflectEvent *e = (ReflectEvent *) ev; + +    Tcl_NotifyChannel(e->rcPtr->chan, e->events); +    return 1; +} + +static int +ReflectEventDelete( +    Tcl_Event *ev, +    ClientData cd) +{ +    /* OWNER thread +     * +     * Invoked by DeleteThreadReflectedChannelMap() and ReflectClose(). The +     * latter ensures that no pending events of this type are run on an +     * invalid channel. +     */ + +    ReflectEvent *e = (ReflectEvent *) ev; + +    if ((ev->proc != ReflectEventRun) || ((cd != NULL) && (cd != e->rcPtr))) { +        return 0; +    } +    return 1; +} +  int  TclChanPostEventObjCmd(      ClientData clientData, @@ -777,6 +799,8 @@ TclChanPostEventObjCmd(      Tcl_Obj *const *objv)  {      /* +     * Ensure -> HANDLER thread +     *       * Syntax:   chan postevent CHANNEL EVENTSPEC       *           [0]  [1]       [2]     [3]       * @@ -795,8 +819,9 @@ TclChanPostEventObjCmd(  				/* Its associated driver structure */      ReflectedChannel *rcPtr;	/* Associated instance data */      int events;			/* Mask of events to post */ -    ReflectedChannelMap* rcmPtr; /* Map of reflected channels with handlers in this interp */ -    Tcl_HashEntry* hPtr;         /* Entry in the above map */ +    ReflectedChannelMap *rcmPtr;/* Map of reflected channels with handlers in +				 * this interp. */ +    Tcl_HashEntry *hPtr;	/* Entry in the above map */      /*       * Number of arguments... @@ -814,12 +839,12 @@ TclChanPostEventObjCmd(      chanId = TclGetString(objv[CHAN]); -    rcmPtr = GetReflectedChannelMap (interp); -    hPtr = Tcl_FindHashEntry (&rcmPtr->map, chanId); +    rcmPtr = GetReflectedChannelMap(interp); +    hPtr = Tcl_FindHashEntry(&rcmPtr->map, chanId);      if (hPtr == NULL) { -	Tcl_AppendResult(interp, "can not find reflected channel named \"", chanId, -		"\"", NULL); +	Tcl_SetObjResult(interp, Tcl_ObjPrintf( +                "can not find reflected channel named \"%s\"", chanId));  	Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CHANNEL", chanId, NULL);  	return TCL_ERROR;      } @@ -840,7 +865,7 @@ TclChanPostEventObjCmd(       * have gone seriously haywire.       */ -    chan        = Tcl_GetHashValue(hPtr); +    chan = Tcl_GetHashValue(hPtr);      chanTypePtr = Tcl_GetChannelType(chan);      /* @@ -853,13 +878,13 @@ TclChanPostEventObjCmd(       */      if (chanTypePtr->watchProc != &ReflectWatch) { -	Tcl_Panic ("TclChanPostEventObjCmd: channel is not a reflected channel"); +	Tcl_Panic("TclChanPostEventObjCmd: channel is not a reflected channel");      } -    rcPtr = (ReflectedChannel *) Tcl_GetChannelInstanceData(chan); +    rcPtr = Tcl_GetChannelInstanceData(chan);      if (rcPtr->interp != interp) { -	Tcl_Panic ("TclChanPostEventObjCmd: postevent accepted for call from outside interpreter"); +	Tcl_Panic("TclChanPostEventObjCmd: postevent accepted for call from outside interpreter");      }      /* @@ -876,8 +901,9 @@ TclChanPostEventObjCmd(       */      if (events & ~rcPtr->interest) { -	Tcl_AppendResult(interp, "tried to post events channel \"", chanId, -		"\" is not interested in", NULL); +	Tcl_SetObjResult(interp, Tcl_ObjPrintf( +                "tried to post events channel \"%s\" is not interested in", +                chanId));  	return TCL_ERROR;      } @@ -885,7 +911,44 @@ TclChanPostEventObjCmd(       * We have the channel and the events to post.       */ -    Tcl_NotifyChannel(chan, events); +#ifdef TCL_THREADS +    if (rcPtr->owner == rcPtr->thread) { +#endif +        Tcl_NotifyChannel(chan, events); +#ifdef TCL_THREADS +    } else { +        ReflectEvent *ev = ckalloc(sizeof(ReflectEvent)); + +        ev->header.proc = ReflectEventRun; +        ev->events = events; +        ev->rcPtr = rcPtr; + +        /* +         * We are not preserving the structure here. When the channel is +         * closed any pending events are deleted, see ReflectClose(), and +         * ReflectEventDelete(). Trying to preserve and later release when the +         * event is run may generate a situation where the channel structure +         * is deleted but not our structure, crashing in +         * FreeReflectedChannel(). +         * +         * Force creation of the RCM, for proper cleanup on thread teardown. +         * The teardown of unprocessed events is currently coupled to the +         * thread reflected channel map +         */ + +        (void) GetThreadReflectedChannelMap(); + +        /* XXX Race condition !! +         * XXX The destination thread may not exist anymore already. +         * XXX (Delayed postevent executed after channel got removed). +         * XXX Can we detect this ? (check the validity of the owner threadid ?) +         * XXX Actually, in that case the channel should be dead also ! +         */ + +        Tcl_ThreadQueueEvent(rcPtr->owner, (Tcl_Event *) ev, TCL_QUEUE_TAIL); +        Tcl_ThreadAlert(rcPtr->owner); +    } +#endif      /*       * Squash interp results left by the event script. @@ -902,7 +965,7 @@ TclChanPostEventObjCmd(   * Channel error message marshalling utilities.   */ -static Tcl_Obj* +static Tcl_Obj *  MarshallError(      Tcl_Interp *interp)  { @@ -957,7 +1020,7 @@ UnmarshallErrorResult(      }      (void) Tcl_SetReturnOptions(interp, Tcl_NewListObj(numOptions, lv)); -    ((Interp *)interp)->flags &= ~ERR_ALREADY_LOGGED; +    ((Interp *) interp)->flags &= ~ERR_ALREADY_LOGGED;  }  int @@ -1042,11 +1105,12 @@ ReflectClose(      ClientData clientData,      Tcl_Interp *interp)  { -    ReflectedChannel *rcPtr = (ReflectedChannel *) clientData; +    ReflectedChannel *rcPtr = clientData;      int result;			/* Result code for 'close' */      Tcl_Obj *resObj;		/* Result data for 'close' */ -    ReflectedChannelMap* rcmPtr; /* Map of reflected channels with handlers in this interp */ -    Tcl_HashEntry* hPtr;         /* Entry in the above map */ +    ReflectedChannelMap *rcmPtr;/* Map of reflected channels with handlers in +				 * this interp */ +    Tcl_HashEntry *hPtr;	/* Entry in the above map */      if (TclInThreadExit()) {  	/* @@ -1060,21 +1124,23 @@ ReflectClose(  	/*  	 * THREADED => Forward this to the origin thread  	 * -	 * Note: DeleteThreadReflectedChannelMap() is the thread exit handler for the origin -	 * thread. Use this to clean up the structure? Except if lost? +	 * Note: DeleteThreadReflectedChannelMap() is the thread exit handler +	 * for the origin thread. Use this to clean up the structure? Except +	 * if lost?  	 */  #ifdef TCL_THREADS  	if (rcPtr->thread != Tcl_GetCurrentThread()) {  	    ForwardParam p; -	    ForwardOpToOwnerThread(rcPtr, ForwardedClose, &p); +	    ForwardOpToHandlerThread(rcPtr, ForwardedClose, &p);  	    result = p.base.code; -	    /* -	     * FreeReflectedChannel is done in the forwarded operation!, in -	     * the other thread. rcPtr here is gone! -	     */ +            /* +             * Now squash the pending reflection events for this channel. +             */ + +            Tcl_DeleteEvents(ReflectEventDelete, rcPtr);  	    if (result != TCL_OK) {  		FreeReceivedError(&p); @@ -1083,19 +1149,7 @@ ReflectClose(  	}  #endif -        Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); -	return EOK; -    } - -    /* -     * -- No -- ASSERT rcPtr->methods & FLAG(METH_FINAL) -     * -     * A cleaned method mask here implies that the channel creation was -     * aborted, and "finalize" must not be called. -     */ - -    if (rcPtr->methods == 0) { -        Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); +        Tcl_EventuallyFree(rcPtr, (Tcl_FreeProc *) FreeReflectedChannel);  	return EOK;      } @@ -1107,20 +1161,21 @@ ReflectClose(      if (rcPtr->thread != Tcl_GetCurrentThread()) {  	ForwardParam p; -	ForwardOpToOwnerThread(rcPtr, ForwardedClose, &p); +	ForwardOpToHandlerThread(rcPtr, ForwardedClose, &p);  	result = p.base.code; -	/* -	 * FreeReflectedChannel is done in the forwarded operation!, in the -	 * other thread. rcPtr here is gone! -	 */ +        /* +         * Now squash the pending reflection events for this channel. +         */ + +        Tcl_DeleteEvents(ReflectEventDelete, rcPtr);  	if (result != TCL_OK) {  	    PassReceivedErrorInterp(interp, &p);  	}      } else {  #endif -	result = InvokeTclMethod(rcPtr, "finalize", NULL, NULL, &resObj); +	result = InvokeTclMethod(rcPtr, METH_FINAL, NULL, NULL, &resObj);  	if ((result != TCL_OK) && (interp != NULL)) {  	    Tcl_SetChannelErrorInterp(interp, resObj);  	} @@ -1141,24 +1196,24 @@ ReflectClose(  	 * the per-interp DeleteReflectedChannelMap exit-handler.  	 */ -	if (rcPtr->interp) { -	    rcmPtr = GetReflectedChannelMap (rcPtr->interp); -	    hPtr = Tcl_FindHashEntry (&rcmPtr->map,  -				      Tcl_GetChannelName (rcPtr->chan)); +	if (!rcPtr->dead) { +	    rcmPtr = GetReflectedChannelMap(rcPtr->interp); +	    hPtr = Tcl_FindHashEntry(&rcmPtr->map, +		    Tcl_GetChannelName(rcPtr->chan));  	    if (hPtr) { -		Tcl_DeleteHashEntry (hPtr); +		Tcl_DeleteHashEntry(hPtr);  	    }  	}  #ifdef TCL_THREADS -        rcmPtr = GetThreadReflectedChannelMap(); -	hPtr = Tcl_FindHashEntry (&rcmPtr->map,  -				  Tcl_GetChannelName (rcPtr->chan)); +	rcmPtr = GetThreadReflectedChannelMap(); +	hPtr = Tcl_FindHashEntry(&rcmPtr->map, +		Tcl_GetChannelName(rcPtr->chan));  	if (hPtr) { -	    Tcl_DeleteHashEntry (hPtr); +	    Tcl_DeleteHashEntry(hPtr);  	}  #endif -        Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); +        Tcl_EventuallyFree(rcPtr, (Tcl_FreeProc *) FreeReflectedChannel);  #ifdef TCL_THREADS      }  #endif @@ -1188,25 +1243,13 @@ ReflectInput(      int toRead,      int *errorCodePtr)  { -    ReflectedChannel *rcPtr = (ReflectedChannel *) clientData; +    ReflectedChannel *rcPtr = clientData;      Tcl_Obj *toReadObj;      int bytec;			/* Number of returned bytes */      unsigned char *bytev;	/* Array of returned bytes */      Tcl_Obj *resObj;		/* Result data for 'read' */      /* -     * The following check can be done before thread redirection, because we -     * are reading from an item which is readonly, i.e. will never change -     * during the lifetime of the channel. -     */ - -    if (!(rcPtr->methods & FLAG(METH_READ))) { -	SetChannelErrorStr(rcPtr->chan, msg_read_unsup); -	*errorCodePtr = EINVAL; -	return -1; -    } - -    /*       * Are we in the correct thread?       */ @@ -1217,7 +1260,7 @@ ReflectInput(  	p.input.buf = buf;  	p.input.toRead = toRead; -	ForwardOpToOwnerThread(rcPtr, ForwardedInput, &p); +	ForwardOpToHandlerThread(rcPtr, ForwardedInput, &p);  	if (p.base.code != TCL_OK) {  	    if (p.base.code < 0) { @@ -1244,8 +1287,8 @@ ReflectInput(      toReadObj = Tcl_NewIntObj(toRead);      Tcl_IncrRefCount(toReadObj); -    if (InvokeTclMethod(rcPtr, "read", toReadObj, NULL, &resObj)!=TCL_OK) { -	int code = ErrnoReturn (rcPtr, resObj); +    if (InvokeTclMethod(rcPtr, METH_READ, toReadObj, NULL, &resObj)!=TCL_OK) { +	int code = ErrnoReturn(rcPtr, resObj);  	if (code < 0) {  	    *errorCodePtr = -code; @@ -1266,7 +1309,7 @@ ReflectInput(      *errorCodePtr = EOK;      if (bytec > 0) { -	memcpy(buf, bytev, (size_t)bytec); +	memcpy(buf, bytev, (size_t) bytec);      }   stop: @@ -1304,24 +1347,12 @@ ReflectOutput(      int toWrite,      int *errorCodePtr)  { -    ReflectedChannel *rcPtr = (ReflectedChannel *) clientData; +    ReflectedChannel *rcPtr = clientData;      Tcl_Obj *bufObj;      Tcl_Obj *resObj;		/* Result data for 'write' */      int written;      /* -     * The following check can be done before thread redirection, because we -     * are reading from an item which is readonly, i.e. will never change -     * during the lifetime of the channel. -     */ - -    if (!(rcPtr->methods & FLAG(METH_WRITE))) { -	SetChannelErrorStr(rcPtr->chan, msg_write_unsup); -	*errorCodePtr = EINVAL; -	return -1; -    } - -    /*       * Are we in the correct thread?       */ @@ -1332,7 +1363,7 @@ ReflectOutput(  	p.output.buf = buf;  	p.output.toWrite = toWrite; -	ForwardOpToOwnerThread(rcPtr, ForwardedOutput, &p); +	ForwardOpToHandlerThread(rcPtr, ForwardedOutput, &p);  	if (p.base.code != TCL_OK) {  	    if (p.base.code < 0) { @@ -1359,7 +1390,7 @@ ReflectOutput(      bufObj = Tcl_NewByteArrayObj((unsigned char *) buf, toWrite);      Tcl_IncrRefCount(bufObj); -    if (InvokeTclMethod(rcPtr, "write", bufObj, NULL, &resObj) != TCL_OK) { +    if (InvokeTclMethod(rcPtr, METH_WRITE, bufObj, NULL, &resObj) != TCL_OK) {  	int code = ErrnoReturn(rcPtr, resObj);  	if (code < 0) { @@ -1432,7 +1463,7 @@ ReflectSeekWide(      int seekMode,      int *errorCodePtr)  { -    ReflectedChannel *rcPtr = (ReflectedChannel *) clientData; +    ReflectedChannel *rcPtr = clientData;      Tcl_Obj *offObj, *baseObj;      Tcl_Obj *resObj;		/* Result for 'seek' */      Tcl_WideInt newLoc; @@ -1448,7 +1479,7 @@ ReflectSeekWide(  	p.seek.seekMode = seekMode;  	p.seek.offset = offset; -	ForwardOpToOwnerThread(rcPtr, ForwardedSeek, &p); +	ForwardOpToHandlerThread(rcPtr, ForwardedSeek, &p);  	if (p.base.code != TCL_OK) {  	    PassReceivedError(rcPtr->chan, &p); @@ -1466,13 +1497,14 @@ ReflectSeekWide(      Tcl_Preserve(rcPtr); -    offObj = Tcl_NewWideIntObj(offset); -    baseObj = Tcl_NewStringObj((seekMode == SEEK_SET) ? "start" : -	    ((seekMode == SEEK_CUR) ? "current" : "end"), -1); +    offObj  = Tcl_NewWideIntObj(offset); +    baseObj = Tcl_NewStringObj( +            (seekMode == SEEK_SET) ? "start" : +            (seekMode == SEEK_CUR) ? "current" : "end", -1);      Tcl_IncrRefCount(offObj);      Tcl_IncrRefCount(baseObj); -    if (InvokeTclMethod(rcPtr, "seek", offObj, baseObj, &resObj)!=TCL_OK) { +    if (InvokeTclMethod(rcPtr, METH_SEEK, offObj, baseObj, &resObj)!=TCL_OK) {  	Tcl_SetChannelError(rcPtr->chan, resObj);          goto invalid;      } @@ -1540,11 +1572,9 @@ ReflectWatch(      ClientData clientData,      int mask)  { -    ReflectedChannel *rcPtr = (ReflectedChannel *) clientData; +    ReflectedChannel *rcPtr = clientData;      Tcl_Obj *maskObj; -    /* ASSERT rcPtr->methods & FLAG(METH_WATCH) */ -      /*       * We restrict the interest to what the channel can support. IOW there       * will never be write events for a channel which is not writable. @@ -1572,7 +1602,7 @@ ReflectWatch(  	ForwardParam p;  	p.watch.mask = mask; -	ForwardOpToOwnerThread(rcPtr, ForwardedWatch, &p); +	ForwardOpToHandlerThread(rcPtr, ForwardedWatch, &p);  	/*  	 * Any failure from the forward is ignored. We have no place to put @@ -1587,7 +1617,7 @@ ReflectWatch(      maskObj = DecodeEventMask(mask);      /* assert maskObj.refCount == 1 */ -    (void) InvokeTclMethod(rcPtr, "watch", maskObj, NULL, NULL); +    (void) InvokeTclMethod(rcPtr, METH_WATCH, maskObj, NULL, NULL);      Tcl_DecrRefCount(maskObj);      Tcl_Release(rcPtr); @@ -1615,7 +1645,7 @@ ReflectBlock(      ClientData clientData,      int nonblocking)  { -    ReflectedChannel *rcPtr = (ReflectedChannel *) clientData; +    ReflectedChannel *rcPtr = clientData;      Tcl_Obj *blockObj;      int errorNum;		/* EINVAL or EOK (success). */      Tcl_Obj *resObj;		/* Result data for 'blocking' */ @@ -1630,7 +1660,7 @@ ReflectBlock(  	p.block.nonblocking = nonblocking; -	ForwardOpToOwnerThread(rcPtr, ForwardedBlock, &p); +	ForwardOpToHandlerThread(rcPtr, ForwardedBlock, &p);  	if (p.base.code != TCL_OK) {  	    PassReceivedError(rcPtr->chan, &p); @@ -1646,7 +1676,7 @@ ReflectBlock(      Tcl_Preserve(rcPtr); -    if (InvokeTclMethod(rcPtr, "blocking", blockObj, NULL, &resObj) != TCL_OK) { +    if (InvokeTclMethod(rcPtr,METH_BLOCKING,blockObj,NULL,&resObj)!=TCL_OK) {  	Tcl_SetChannelError(rcPtr->chan, resObj);  	errorNum = EINVAL;      } else { @@ -1660,6 +1690,44 @@ ReflectBlock(      return errorNum;  } +#ifdef TCL_THREADS +/* + *---------------------------------------------------------------------- + * + * ReflectThread -- + * + *	This function is invoked to tell the channel about thread movements. + * + * Results: + *	None. + * + * Side effects: + *	Allocates memory. Arbitrary, as it calls upon a script. + * + *---------------------------------------------------------------------- + */ + +static void +ReflectThread( +    ClientData clientData, +    int action) +{ +    ReflectedChannel *rcPtr = clientData; + +    switch (action) { +    case TCL_CHANNEL_THREAD_INSERT: +        rcPtr->owner = Tcl_GetCurrentThread(); +        break; +    case TCL_CHANNEL_THREAD_REMOVE: +        rcPtr->owner = NULL; +        break; +    default: +        Tcl_Panic("Unknown thread action code."); +        break; +    } +} + +#endif  /*   *----------------------------------------------------------------------   * @@ -1683,7 +1751,7 @@ ReflectSetOption(      const char *optionName,	/* Name of requested option */      const char *newValue)	/* The new value */  { -    ReflectedChannel *rcPtr = (ReflectedChannel *) clientData; +    ReflectedChannel *rcPtr = clientData;      Tcl_Obj *optionObj, *valueObj;      int result;			/* Result code for 'configure' */      Tcl_Obj *resObj;		/* Result data for 'configure' */ @@ -1699,7 +1767,7 @@ ReflectSetOption(  	p.setOpt.name = optionName;  	p.setOpt.value = newValue; -	ForwardOpToOwnerThread(rcPtr, ForwardedSetOpt, &p); +	ForwardOpToHandlerThread(rcPtr, ForwardedSetOpt, &p);  	if (p.base.code != TCL_OK) {  	    Tcl_Obj *err = Tcl_NewStringObj(p.base.msgStr, -1); @@ -1720,7 +1788,7 @@ ReflectSetOption(      Tcl_IncrRefCount(optionObj);      Tcl_IncrRefCount(valueObj); -    result = InvokeTclMethod(rcPtr, "configure",optionObj,valueObj, &resObj); +    result = InvokeTclMethod(rcPtr, METH_CONFIGURE,optionObj,valueObj, &resObj);      if (result != TCL_OK) {  	UnmarshallErrorResult(interp, resObj);      } @@ -1760,12 +1828,12 @@ ReflectGetOption(       * The bypass functions are not required.       */ -    ReflectedChannel *rcPtr = (ReflectedChannel*) clientData; +    ReflectedChannel *rcPtr = clientData;      Tcl_Obj *optionObj;      Tcl_Obj *resObj;		/* Result data for 'configure' */      int listc, result = TCL_OK;      Tcl_Obj **listv; -    const char *method; +    MethodName method;      /*       * Are we in the correct thread? @@ -1785,7 +1853,7 @@ ReflectGetOption(  	    opcode = ForwardedGetOpt;  	} -	ForwardOpToOwnerThread(rcPtr, opcode, &p); +	ForwardOpToHandlerThread(rcPtr, opcode, &p);  	if (p.base.code != TCL_OK) {  	    Tcl_Obj *err = Tcl_NewStringObj(p.base.msgStr, -1); @@ -1804,14 +1872,14 @@ ReflectGetOption(  	 * Retrieve all options.  	 */ -	method = "cgetall"; +	method = METH_CGETALL;  	optionObj = NULL;      } else {  	/*  	 * Retrieve the value of one option.  	 */ -	method = "cget"; +	method = METH_CGET;  	optionObj = Tcl_NewStringObj(optionName, -1);          Tcl_IncrRefCount(optionObj);      } @@ -1829,7 +1897,7 @@ ReflectGetOption(       */      if (optionObj != NULL) { -	Tcl_DStringAppend(dsPtr, TclGetString(resObj), -1); +	TclDStringAppendObj(dsPtr, resObj);          goto ok;      } @@ -1861,10 +1929,10 @@ ReflectGetOption(          goto error;      } else {  	int len; -	char *str = Tcl_GetStringFromObj(resObj, &len); +	const char *str = Tcl_GetStringFromObj(resObj, &len);  	if (len) { -	    Tcl_DStringAppend(dsPtr, " ", 1); +	    TclDStringAppendLiteral(dsPtr, " ");  	    Tcl_DStringAppend(dsPtr, str, len);  	}          goto ok; @@ -1928,7 +1996,8 @@ EncodeEventMask(      }      if (listc < 1) { -	Tcl_AppendResult(interp, "bad ", objName, " list: is empty", NULL); +	Tcl_SetObjResult(interp, Tcl_ObjPrintf( +                "bad %s list: is empty", objName));  	return TCL_ERROR;      } @@ -1961,7 +2030,7 @@ EncodeEventMask(   *	This function takes an internal bitmask of events and constructs the   *	equivalent list of event items.   * - * Results: + * Results, Contract:   *	A Tcl_Obj reference. The object will have a refCount of one. The user   *	has to decrement it to release the object.   * @@ -1995,6 +2064,7 @@ DecodeEventMask(      evObj = Tcl_NewStringObj(eventStr, -1);      Tcl_IncrRefCount(evObj); +    /* assert evObj.refCount == 1 */      return evObj;  } @@ -2023,71 +2093,32 @@ NewReflectedChannel(      Tcl_Obj *handleObj)  {      ReflectedChannel *rcPtr; -    int i, listc; -    Tcl_Obj **listv; +    MethodName mn = METH_BLOCKING; -    rcPtr = (ReflectedChannel *) ckalloc(sizeof(ReflectedChannel)); +    rcPtr = ckalloc(sizeof(ReflectedChannel));      /* rcPtr->chan: Assigned by caller. Dummy data here. */ -    /* rcPtr->methods: Assigned by caller. Dummy data here. */      rcPtr->chan = NULL; -    rcPtr->methods = 0;      rcPtr->interp = interp; +    rcPtr->dead = 0;  #ifdef TCL_THREADS      rcPtr->thread = Tcl_GetCurrentThread();  #endif      rcPtr->mode = mode;      rcPtr->interest = 0;		/* Initially no interest registered */ -    /* -     * Method placeholder. -     */ -      /* ASSERT: cmdpfxObj is a Tcl List */ - -    Tcl_ListObjGetElements(interp, cmdpfxObj, &listc, &listv); - -    /* -     * See [==] as well. -     * Storage for the command prefix and the additional words required for -     * the invocation of methods in the command handler. -     * -     * listv [0] [listc-1] | [listc]  [listc+1] | -     * argv  [0]   ... [.] | [argc-2] [argc-1]  | [argc]  [argc+2] -     *       cmd   ... pfx | method   chan      | detail1 detail2 -     */ - -    rcPtr->argc = listc + 2; -    rcPtr->argv = (Tcl_Obj **) ckalloc(sizeof(Tcl_Obj *) * (listc+4)); - -    /* -     * Duplicate object references. -     */ - -    for (i=0; i<listc ; i++) { -	Tcl_Obj *word = rcPtr->argv[i] = listv[i]; - -	Tcl_IncrRefCount(word); -    } - -    i++;				/* Skip placeholder for method */ - -    /* -     * [Bug 1667990]: See [x] in FreeReflectedChannel for release -     */ - -    rcPtr->argv[i] = handleObj; -    Tcl_IncrRefCount(handleObj); - -    /* -     * The next two objects are kept empty, varying arguments. -     */ - -    /* -     * Initialization complete. -     */ - +    rcPtr->cmd = TclListObjCopy(NULL, cmdpfxObj); +    Tcl_IncrRefCount(rcPtr->cmd); +    rcPtr->methods = Tcl_NewListObj(METH_WRITE + 1, NULL); +    while (mn <= METH_WRITE) { +	Tcl_ListObjAppendElement(NULL, rcPtr->methods, +		Tcl_NewStringObj(methodNames[mn++], -1)); +    } +    Tcl_IncrRefCount(rcPtr->methods); +    rcPtr->name = handleObj; +    Tcl_IncrRefCount(rcPtr->name);      return rcPtr;  } @@ -2138,29 +2169,20 @@ FreeReflectedChannel(      ReflectedChannel *rcPtr)  {      Channel *chanPtr = (Channel *) rcPtr->chan; -    int i, n;      if (chanPtr->typePtr != &tclRChannelType) {  	/*  	 * Delete a cloned ChannelType structure.  	 */ -	ckfree((char*) chanPtr->typePtr); +	ckfree(chanPtr->typePtr); +	chanPtr->typePtr = NULL;      } - -    n = rcPtr->argc - 2; -    for (i=0; i<n; i++) { -	Tcl_DecrRefCount(rcPtr->argv[i]); -    } - -    /* -     * [Bug 1667990]: See [x] in NewReflectedChannel for lock. n+1 = argc-1. -     */ - -    Tcl_DecrRefCount(rcPtr->argv[n+1]); - -    ckfree((char*) rcPtr->argv); -    ckfree((char*) rcPtr); +    Tcl_Release(chanPtr); +    Tcl_DecrRefCount(rcPtr->name); +    Tcl_DecrRefCount(rcPtr->methods); +    Tcl_DecrRefCount(rcPtr->cmd); +    ckfree(rcPtr);  }  /* @@ -2190,18 +2212,18 @@ FreeReflectedChannel(  static int  InvokeTclMethod(      ReflectedChannel *rcPtr, -    const char *method, +    MethodName method,      Tcl_Obj *argOneObj,		/* NULL'able */      Tcl_Obj *argTwoObj,		/* NULL'able */      Tcl_Obj **resultObjPtr)	/* NULL'able */  { -    int cmdc;			/* #words in constructed command */      Tcl_Obj *methObj = NULL;	/* Method name in object form */      Tcl_InterpState sr;		/* State of handler interp */      int result;			/* Result code of method invokation */      Tcl_Obj *resObj = NULL;	/* Result of method invokation. */ +    Tcl_Obj *cmd; -    if (!rcPtr->interp) { +    if (rcPtr->dead) {  	/*  	 * The channel is marked as dead. Bail out immediately, with an  	 * appropriate error. @@ -2222,32 +2244,28 @@ InvokeTclMethod(      }      /* -     * NOTE (5): Decide impl. issue: Cache objects with method names? Needs -     * TSD data as reflections can be created in many different threads. -     * NO: Caching of command resolutions means storage per channel. -     */ - -    /* -     * Insert method into the pre-allocated area, after the command prefix, +     * Insert method into the callback command, after the command prefix,       * before the channel id.       */ -    methObj = Tcl_NewStringObj(method, -1); -    Tcl_IncrRefCount(methObj); -    rcPtr->argv[rcPtr->argc - 2] = methObj; +    cmd = TclListObjCopy(NULL, rcPtr->cmd); + +    Tcl_ListObjIndex(NULL, rcPtr->methods, method, &methObj); +    Tcl_ListObjAppendElement(NULL, cmd, methObj); +    Tcl_ListObjAppendElement(NULL, cmd, rcPtr->name);      /*       * Append the additional argument containing method specific details       * behind the channel id. If specified. +     * +     * Because of the contract there is no need to increment the refcounts. +     * The objects will survive the Tcl_EvalObjv without change.       */ -    cmdc = rcPtr->argc;      if (argOneObj) { -	rcPtr->argv[cmdc] = argOneObj; -	cmdc++; +	Tcl_ListObjAppendElement(NULL, cmd, argOneObj);  	if (argTwoObj) { -	    rcPtr->argv[cmdc] = argTwoObj; -	    cmdc++; +	    Tcl_ListObjAppendElement(NULL, cmd, argTwoObj);  	}      } @@ -2256,9 +2274,10 @@ InvokeTclMethod(       * existing state intact.       */ +    Tcl_IncrRefCount(cmd);      sr = Tcl_SaveInterpState(rcPtr->interp, 0 /* Dummy */);      Tcl_Preserve(rcPtr->interp); -    result = Tcl_EvalObjv(rcPtr->interp, cmdc, rcPtr->argv, TCL_EVAL_GLOBAL); +    result = Tcl_EvalObjEx(rcPtr->interp, cmd, TCL_EVAL_GLOBAL);      /*       * We do not try to extract the result information if the caller has no @@ -2284,7 +2303,6 @@ InvokeTclMethod(  	     */  	    if (result != TCL_ERROR) { -		Tcl_Obj *cmd = Tcl_NewListObj(cmdc, rcPtr->argv);  		int cmdLen;  		const char *cmdString = Tcl_GetStringFromObj(cmd, &cmdLen); @@ -2298,25 +2316,17 @@ InvokeTclMethod(  		result = TCL_ERROR;  	    }  	    Tcl_AppendObjToErrorInfo(rcPtr->interp, Tcl_ObjPrintf( -		    "\n    (chan handler subcommand \"%s\")", method)); +		    "\n    (chan handler subcommand \"%s\")", +		    methodNames[method]));  	    resObj = MarshallError(rcPtr->interp);  	}  	Tcl_IncrRefCount(resObj);      } +    Tcl_DecrRefCount(cmd);      Tcl_RestoreInterpState(rcPtr->interp, sr);      Tcl_Release(rcPtr->interp);      /* -     * Cleanup of the dynamic parts of the command. -     * -     * The detail objects survived the Tcl_EvalObjv without change because of -     * the contract. Therefore there is no need to decrement the refcounts. Only -     * the internal method object has to be disposed of. -     */ - -    Tcl_DecrRefCount(methObj); - -    /*       * The resObj has a ref count of 1 at this location. This means that the       * caller of InvokeTclMethod has to dispose of it (but only if it was       * returned to it). @@ -2355,12 +2365,14 @@ InvokeTclMethod(   */  static int -ErrnoReturn(ReflectedChannel *rcPtr, Tcl_Obj* resObj) +ErrnoReturn( +    ReflectedChannel *rcPtr, +    Tcl_Obj *resObj)  {      int code;      Tcl_InterpState sr;		/* State of handler interp */ -    if (!rcPtr->interp) { +    if (rcPtr->dead) {  	return 0;      } @@ -2369,9 +2381,10 @@ ErrnoReturn(ReflectedChannel *rcPtr, Tcl_Obj* resObj)      resObj = Tcl_GetObjResult(rcPtr->interp); -    if (((Tcl_GetIntFromObj(rcPtr->interp, resObj, &code) != TCL_OK) || (code >= 0))) { -	if (strcmp ("EAGAIN",Tcl_GetString(resObj)) == 0) { -	    code = - EAGAIN; +    if (((Tcl_GetIntFromObj(rcPtr->interp, resObj, &code) != TCL_OK) +	    || (code >= 0))) { +	if (strcmp("EAGAIN", Tcl_GetString(resObj)) == 0) { +	    code = -EAGAIN;  	} else {  	    code = 0;  	} @@ -2402,10 +2415,10 @@ static ReflectedChannelMap *  GetReflectedChannelMap(      Tcl_Interp *interp)  { -    ReflectedChannelMap* rcmPtr = Tcl_GetAssocData(interp, RCMKEY, NULL); +    ReflectedChannelMap *rcmPtr = Tcl_GetAssocData(interp, RCMKEY, NULL);      if (rcmPtr == NULL) { -	rcmPtr = (ReflectedChannelMap *) ckalloc(sizeof(ReflectedChannelMap)); +	rcmPtr = ckalloc(sizeof(ReflectedChannelMap));  	Tcl_InitHashTable(&rcmPtr->map, TCL_STRING_KEYS);  	Tcl_SetAssocData(interp, RCMKEY,  		(Tcl_InterpDeleteProc *) DeleteReflectedChannelMap, rcmPtr); @@ -2438,12 +2451,12 @@ DeleteReflectedChannelMap(      ClientData clientData,	/* The per-interpreter data structure. */      Tcl_Interp *interp)		/* The interpreter being deleted. */  { -    ReflectedChannelMap* rcmPtr; /* The map */ +    ReflectedChannelMap *rcmPtr = clientData; +				/* The map */      Tcl_HashSearch hSearch;	 /* Search variable. */      Tcl_HashEntry *hPtr;	 /* Search variable. */ -    ReflectedChannel* rcPtr; +    ReflectedChannel *rcPtr;      Tcl_Channel chan; -  #ifdef TCL_THREADS      ForwardingResult *resultPtr;      ForwardingEvent *evPtr; @@ -2453,7 +2466,7 @@ DeleteReflectedChannelMap(      /*       * Delete all entries. The channels may have been closed already, or will       * be closed later, by the standard IO finalization of an interpreter -     * under destruction.  Except for the channels which were moved to a +     * under destruction. Except for the channels which were moved to a       * different interpreter and/or thread. They do not exist from the IO       * systems point of view and will not get closed. Therefore mark all as       * dead so that any future access will cause a proper error. For channels @@ -2462,20 +2475,17 @@ DeleteReflectedChannelMap(       * this interp.       */ -    rcmPtr = clientData;      for (hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch); -	 hPtr != NULL; -	 hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch)) { - -	chan  = (Tcl_Channel) Tcl_GetHashValue (hPtr); -	rcPtr = (ReflectedChannel *) Tcl_GetChannelInstanceData(chan); - -	rcPtr->interp = NULL; +	    hPtr != NULL; +	    hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch)) { +	chan = Tcl_GetHashValue(hPtr); +	rcPtr = Tcl_GetChannelInstanceData(chan); +	rcPtr->dead = 1;  	Tcl_DeleteHashEntry(hPtr);      }      Tcl_DeleteHashTable(&rcmPtr->map); -    ckfree((char *) &rcmPtr->map); +    ckfree(&rcmPtr->map);  #ifdef TCL_THREADS      /* @@ -2491,10 +2501,13 @@ DeleteReflectedChannelMap(      Tcl_MutexLock(&rcForwardMutex);      for (resultPtr = forwardList; -	 resultPtr != NULL; -	 resultPtr = resultPtr->nextPtr) { +	    resultPtr != NULL; +	    resultPtr = resultPtr->nextPtr) {  	if (resultPtr->dsti != interp) { -	    /* Ignore results/events for other interpreters. */ +	    /* +	     * Ignore results/events for other interpreters. +	     */ +  	    continue;  	} @@ -2504,6 +2517,11 @@ DeleteReflectedChannelMap(  	 */  	evPtr = resultPtr->evPtr; + +	/* Basic crash safety until this routine can get revised [3411310] */ +	if (evPtr == NULL) { +	    continue; +	}  	paramPtr = evPtr->param;  	evPtr->resultPtr = NULL; @@ -2514,6 +2532,7 @@ DeleteReflectedChannelMap(  	Tcl_ConditionNotify(&resultPtr->done);      } +    Tcl_MutexUnlock(&rcForwardMutex);      /*       * Get the map of all channels handled by the current thread. This is a @@ -2524,21 +2543,22 @@ DeleteReflectedChannelMap(      rcmPtr = GetThreadReflectedChannelMap();      for (hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch); -	 hPtr != NULL; -	 hPtr = Tcl_NextHashEntry(&hSearch)) { - -	chan  = (Tcl_Channel) Tcl_GetHashValue (hPtr); -	rcPtr = (ReflectedChannel *) Tcl_GetChannelInstanceData(chan); +	    hPtr != NULL; +	    hPtr = Tcl_NextHashEntry(&hSearch)) { +	chan = Tcl_GetHashValue(hPtr); +	rcPtr = Tcl_GetChannelInstanceData(chan);  	if (rcPtr->interp != interp) { -	    /* Ignore entries for other interpreters */ +	    /* +	     * Ignore entries for other interpreters. +	     */ +  	    continue;  	} +	rcPtr->dead = 1;  	Tcl_DeleteHashEntry(hPtr);      } - -    Tcl_MutexUnlock(&rcForwardMutex);  #endif  } @@ -2561,12 +2581,12 @@ DeleteReflectedChannelMap(   */  static ReflectedChannelMap * -GetThreadReflectedChannelMap() +GetThreadReflectedChannelMap(void)  {      ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);      if (!tsdPtr->rcmPtr) { -	tsdPtr->rcmPtr = (ReflectedChannelMap *) ckalloc(sizeof(ReflectedChannelMap)); +	tsdPtr->rcmPtr = ckalloc(sizeof(ReflectedChannelMap));  	Tcl_InitHashTable(&tsdPtr->rcmPtr->map, TCL_STRING_KEYS);  	Tcl_CreateThreadExitHandler(DeleteThreadReflectedChannelMap, NULL);      } @@ -2581,7 +2601,7 @@ GetThreadReflectedChannelMap()   *   *	Deletes the channel table for a thread. This procedure is invoked when   *	a thread is deleted. The channels have already been marked as dead, in - *      DeleteReflectedChannelMap(). + *	DeleteReflectedChannelMap().   *   * Results:   *	None. @@ -2599,13 +2619,8 @@ DeleteThreadReflectedChannelMap(      Tcl_HashSearch hSearch;	 /* Search variable. */      Tcl_HashEntry *hPtr;	 /* Search variable. */      Tcl_ThreadId self = Tcl_GetCurrentThread(); - -    ReflectedChannelMap* rcmPtr; /* The map */ -    Tcl_Channel chan; -    ReflectedChannel* rcPtr; +    ReflectedChannelMap *rcmPtr; /* The map */      ForwardingResult *resultPtr; -    ForwardingEvent *evPtr; -    ForwardParam *paramPtr;      /*       * The origin thread for one or more reflected channels is gone. @@ -2622,10 +2637,16 @@ DeleteThreadReflectedChannelMap(      Tcl_MutexLock(&rcForwardMutex);      for (resultPtr = forwardList; -	 resultPtr != NULL; -	 resultPtr = resultPtr->nextPtr) { +	    resultPtr != NULL; +	    resultPtr = resultPtr->nextPtr) { +	ForwardingEvent *evPtr; +	ForwardParam *paramPtr; +  	if (resultPtr->dst != self) { -	    /* Ignore results/events for other threads. */ +	    /* +	     * Ignore results/events for other threads. +	     */ +  	    continue;  	} @@ -2635,6 +2656,11 @@ DeleteThreadReflectedChannelMap(  	 */  	evPtr = resultPtr->evPtr; + +	/* Basic crash safety until this routine can get revised [3411310] */ +	if (evPtr == NULL ) { +	    continue; +	}  	paramPtr = evPtr->param;  	evPtr->resultPtr = NULL; @@ -2645,6 +2671,16 @@ DeleteThreadReflectedChannelMap(  	Tcl_ConditionNotify(&resultPtr->done);      } +    Tcl_MutexUnlock(&rcForwardMutex); + +    /* +     * Run over the event queue of this thread and remove all ReflectEvent's +     * still pending. These are inbound events for reflected channels this +     * thread owns but doesn't handle. The inverse of the channel map +     * actually. +     */ + +    Tcl_DeleteEvents(ReflectEventDelete, NULL);      /*       * Get the map of all channels handled by the current thread. This is a @@ -2654,30 +2690,31 @@ DeleteThreadReflectedChannelMap(      rcmPtr = GetThreadReflectedChannelMap();      for (hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch); -	 hPtr != NULL; -	 hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch)) { - -	chan  = (Tcl_Channel) Tcl_GetHashValue (hPtr); -	rcPtr = (ReflectedChannel *) Tcl_GetChannelInstanceData(chan); - -	rcPtr->interp = NULL; +	    hPtr != NULL; +	    hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch)) { +	Tcl_Channel chan = Tcl_GetHashValue(hPtr); +	ReflectedChannel *rcPtr = Tcl_GetChannelInstanceData(chan); +	rcPtr->dead = 1;  	Tcl_DeleteHashEntry(hPtr);      } - -    Tcl_MutexUnlock(&rcForwardMutex); +    ckfree(rcmPtr);  }  static void -ForwardOpToOwnerThread( +ForwardOpToHandlerThread(      ReflectedChannel *rcPtr,	/* Channel instance */      ForwardedOperation op,	/* Forwarded driver operation */ -    const VOID *param)		/* Arguments */ +    const void *param)		/* Arguments */  { +    /* +     * Core of the communication from OWNER to HANDLER thread. +     * The receiver is ForwardProc() below. +     */ +      Tcl_ThreadId dst = rcPtr->thread;      ForwardingEvent *evPtr;      ForwardingResult *resultPtr; -    int result;      /*       * We gather the lock early. This allows us to check the liveness of the @@ -2686,13 +2723,13 @@ ForwardOpToOwnerThread(      Tcl_MutexLock(&rcForwardMutex); -    if (rcPtr->interp == NULL) { +    if (rcPtr->dead) {  	/*  	 * The channel is marked as dead. Bail out immediately, with an  	 * appropriate error. Do not forget to unlock the mutex on this path.  	 */ -	ForwardSetStaticError((ForwardParam *)param, msg_send_dstlost); +	ForwardSetStaticError((ForwardParam *) param, msg_send_dstlost);  	Tcl_MutexUnlock(&rcForwardMutex);  	return;      } @@ -2701,8 +2738,8 @@ ForwardOpToOwnerThread(       * Create and initialize the event and data structures.       */ -    evPtr = (ForwardingEvent *) ckalloc(sizeof(ForwardingEvent)); -    resultPtr = (ForwardingResult *) ckalloc(sizeof(ForwardingResult)); +    evPtr = ckalloc(sizeof(ForwardingEvent)); +    resultPtr = ckalloc(sizeof(ForwardingResult));      evPtr->event.proc = ForwardProc;      evPtr->resultPtr = resultPtr; @@ -2710,8 +2747,8 @@ ForwardOpToOwnerThread(      evPtr->rcPtr = rcPtr;      evPtr->param = (ForwardParam *) param; -    resultPtr->src  = Tcl_GetCurrentThread(); -    resultPtr->dst  = dst; +    resultPtr->src = Tcl_GetCurrentThread(); +    resultPtr->dst = dst;      resultPtr->dsti = rcPtr->interp;      resultPtr->done = NULL;      resultPtr->result = -1; @@ -2726,23 +2763,23 @@ ForwardOpToOwnerThread(      /*       * Ensure cleanup of the event if the origin thread exits while this event -     * is pending or in progress. Exitus of the destination thread is handled -     * by DeleteThreadReflectionChannelMap(), this is set up by -     * GetThreadReflectedChannelMap().  This is what we use the 'forwardList' +     * is pending or in progress. Exit of the destination thread is handled by +     * DeleteThreadReflectedChannelMap(), this is set up by +     * GetThreadReflectedChannelMap(). This is what we use the 'forwardList'       * (see above) for.       */ -    Tcl_CreateThreadExitHandler(SrcExitProc, (ClientData) evPtr); +    Tcl_CreateThreadExitHandler(SrcExitProc, evPtr);      /*       * Queue the event and poke the other thread's notifier.       */ -    Tcl_ThreadQueueEvent(dst, (Tcl_Event *)evPtr, TCL_QUEUE_TAIL); +    Tcl_ThreadQueueEvent(dst, (Tcl_Event *) evPtr, TCL_QUEUE_TAIL);      Tcl_ThreadAlert(dst);      /* -     * (*) Block until the other thread has either processed the transfer or +     * (*) Block until the handler thread has either processed the transfer or       * rejected it.       */ @@ -2760,8 +2797,8 @@ ForwardOpToOwnerThread(      }      /* -     * Unlink result from the forwarder list. -     * No need to lock. Either still locked, or locked by the ConditionWait +     * Unlink result from the forwarder list. No need to lock. Either still +     * locked, or locked by the ConditionWait       */      TclSpliceOut(resultPtr, forwardList); @@ -2779,10 +2816,9 @@ ForwardOpToOwnerThread(       * Note: The event structure has already been deleted.       */ -    Tcl_DeleteThreadExitHandler(SrcExitProc, (ClientData) evPtr); +    Tcl_DeleteThreadExitHandler(SrcExitProc, evPtr); -    result = resultPtr->result; -    ckfree((char*) resultPtr); +    ckfree(resultPtr);  }  static int @@ -2791,6 +2827,11 @@ ForwardProc(      int mask)  {      /* +     * HANDLER thread. + +     * The receiver part for the operations coming from the OWNER thread. +     * See ForwardOpToHandlerThread() for the transmitter. +     *       * Notes regarding access to the referenced data.       *       * In principle the data belongs to the originating thread (see @@ -2809,8 +2850,9 @@ ForwardProc(      Tcl_Interp *interp = rcPtr->interp;      ForwardParam *paramPtr = evPtr->param;      Tcl_Obj *resObj = NULL;	/* Interp result of InvokeTclMethod */ -    ReflectedChannelMap* rcmPtr; /* Map of reflected channels with handlers in this interp */ -    Tcl_HashEntry* hPtr;         /* Entry in the above map */ +    ReflectedChannelMap *rcmPtr;/* Map of reflected channels with handlers in +                                 * this interp. */ +    Tcl_HashEntry *hPtr;	/* Entry in the above map */      /*       * Ignore the event if no one is waiting for its result anymore. @@ -2836,12 +2878,12 @@ ForwardProc(  	 * No parameters/results.  	 */ -	if (InvokeTclMethod(rcPtr, "finalize", NULL, NULL, &resObj)!=TCL_OK) { +	if (InvokeTclMethod(rcPtr, METH_FINAL, NULL, NULL, &resObj)!=TCL_OK) {  	    ForwardSetObjError(paramPtr, resObj);  	}  	/* -	 * Freeing is done here, in the origin thread, because the argv[] +	 * Freeing is done here, in the origin thread, callback command  	 * objects belong to this thread. Deallocating them in a different  	 * thread is not allowed  	 * @@ -2850,17 +2892,17 @@ ForwardProc(  	 * 'postevent') from finding and dereferencing a dangling pointer.  	 */ -	rcmPtr = GetReflectedChannelMap (interp); -	hPtr = Tcl_FindHashEntry (&rcmPtr->map,  -				  Tcl_GetChannelName (rcPtr->chan)); -	Tcl_DeleteHashEntry (hPtr); +	rcmPtr = GetReflectedChannelMap(interp); +	hPtr = Tcl_FindHashEntry(&rcmPtr->map, +                Tcl_GetChannelName(rcPtr->chan)); +	Tcl_DeleteHashEntry(hPtr); -        rcmPtr = GetThreadReflectedChannelMap(); -	hPtr = Tcl_FindHashEntry (&rcmPtr->map,  -				  Tcl_GetChannelName (rcPtr->chan)); -	Tcl_DeleteHashEntry (hPtr); +	rcmPtr = GetThreadReflectedChannelMap(); +	hPtr = Tcl_FindHashEntry(&rcmPtr->map, +                Tcl_GetChannelName(rcPtr->chan)); +	Tcl_DeleteHashEntry(hPtr); -        Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); +	Tcl_EventuallyFree(rcPtr, (Tcl_FreeProc *) FreeReflectedChannel);  	break;      case ForwardedInput: { @@ -2868,8 +2910,8 @@ ForwardProc(          Tcl_IncrRefCount(toReadObj);          Tcl_Preserve(rcPtr); -	if (InvokeTclMethod(rcPtr, "read", toReadObj, NULL, &resObj)!=TCL_OK){ -	    int code = ErrnoReturn (rcPtr, resObj); +	if (InvokeTclMethod(rcPtr, METH_READ, toReadObj, NULL, &resObj)!=TCL_OK){ +	    int code = ErrnoReturn(rcPtr, resObj);  	    if (code < 0) {  		paramPtr->base.code = code; @@ -2892,7 +2934,7 @@ ForwardProc(  		paramPtr->input.toRead = -1;  	    } else {  		if (bytec > 0) { -		    memcpy(paramPtr->input.buf, bytev, (size_t)bytec); +		    memcpy(paramPtr->input.buf, bytev, (size_t) bytec);  		}  		paramPtr->input.toRead = bytec;  	    } @@ -2904,11 +2946,11 @@ ForwardProc(      case ForwardedOutput: {  	Tcl_Obj *bufObj = Tcl_NewByteArrayObj((unsigned char *) -		paramPtr->output.buf, paramPtr->output.toWrite); +                paramPtr->output.buf, paramPtr->output.toWrite);          Tcl_IncrRefCount(bufObj);          Tcl_Preserve(rcPtr); -	if (InvokeTclMethod(rcPtr, "write", bufObj, NULL, &resObj) != TCL_OK) { +	if (InvokeTclMethod(rcPtr, METH_WRITE, bufObj, NULL, &resObj) != TCL_OK) {  	    int code = ErrnoReturn(rcPtr, resObj);  	    if (code < 0) { @@ -2925,7 +2967,9 @@ ForwardProc(  	    int written;  	    if (Tcl_GetIntFromObj(interp, resObj, &written) != TCL_OK) { -		ForwardSetObjError(paramPtr, MarshallError(interp)); +		Tcl_DecrRefCount(resObj); +		resObj = MarshallError(interp); +		ForwardSetObjError(paramPtr, resObj);  		paramPtr->output.toWrite = -1;  	    } else if (written==0 || paramPtr->output.toWrite<written) {  		ForwardSetStaticError(paramPtr, msg_write_toomuch); @@ -2942,14 +2986,14 @@ ForwardProc(      case ForwardedSeek: {  	Tcl_Obj *offObj = Tcl_NewWideIntObj(paramPtr->seek.offset);  	Tcl_Obj *baseObj = Tcl_NewStringObj( -		(paramPtr->seek.seekMode==SEEK_SET) ? "start" : -		(paramPtr->seek.seekMode==SEEK_CUR) ? "current" : "end", -1); +                (paramPtr->seek.seekMode==SEEK_SET) ? "start" : +                (paramPtr->seek.seekMode==SEEK_CUR) ? "current" : "end", -1);          Tcl_IncrRefCount(offObj);          Tcl_IncrRefCount(baseObj);          Tcl_Preserve(rcPtr); -	if (InvokeTclMethod(rcPtr, "seek", offObj, baseObj, &resObj)!=TCL_OK){ +	if (InvokeTclMethod(rcPtr, METH_SEEK, offObj, baseObj, &resObj)!=TCL_OK){  	    ForwardSetObjError(paramPtr, resObj);  	    paramPtr->seek.offset = -1;  	} else { @@ -2968,7 +3012,9 @@ ForwardProc(  		    paramPtr->seek.offset = newLoc;  		}  	    } else { -		ForwardSetObjError(paramPtr, MarshallError(interp)); +		Tcl_DecrRefCount(resObj); +		resObj = MarshallError(interp); +		ForwardSetObjError(paramPtr, resObj);  		paramPtr->seek.offset = -1;  	    }  	} @@ -2983,7 +3029,7 @@ ForwardProc(          /* assert maskObj.refCount == 1 */          Tcl_Preserve(rcPtr); -	(void) InvokeTclMethod(rcPtr, "watch", maskObj, NULL, NULL); +	(void) InvokeTclMethod(rcPtr, METH_WATCH, maskObj, NULL, NULL);  	Tcl_DecrRefCount(maskObj);          Tcl_Release(rcPtr);  	break; @@ -2991,11 +3037,11 @@ ForwardProc(      case ForwardedBlock: {  	Tcl_Obj *blockObj = Tcl_NewBooleanObj(!paramPtr->block.nonblocking); -        Tcl_IncrRefCount(blockObj); +        Tcl_IncrRefCount(blockObj);          Tcl_Preserve(rcPtr); -	if (InvokeTclMethod(rcPtr, "blocking", blockObj, NULL, -		&resObj) != TCL_OK) { +	if (InvokeTclMethod(rcPtr, METH_BLOCKING, blockObj, NULL, +                &resObj) != TCL_OK) {  	    ForwardSetObjError(paramPtr, resObj);  	}          Tcl_Release(rcPtr); @@ -3005,13 +3051,13 @@ ForwardProc(      case ForwardedSetOpt: {  	Tcl_Obj *optionObj = Tcl_NewStringObj(paramPtr->setOpt.name, -1); -	Tcl_Obj *valueObj = Tcl_NewStringObj(paramPtr->setOpt.value, -1); +	Tcl_Obj *valueObj  = Tcl_NewStringObj(paramPtr->setOpt.value, -1);          Tcl_IncrRefCount(optionObj);          Tcl_IncrRefCount(valueObj);          Tcl_Preserve(rcPtr); -	if (InvokeTclMethod(rcPtr, "configure", optionObj, valueObj, -		&resObj) != TCL_OK) { +	if (InvokeTclMethod(rcPtr, METH_CONFIGURE, optionObj, valueObj, +                &resObj) != TCL_OK) {  	    ForwardSetObjError(paramPtr, resObj);  	}          Tcl_Release(rcPtr); @@ -3026,14 +3072,13 @@ ForwardProc(  	 */  	Tcl_Obj *optionObj = Tcl_NewStringObj(paramPtr->getOpt.name, -1); -        Tcl_IncrRefCount(optionObj); +        Tcl_IncrRefCount(optionObj);          Tcl_Preserve(rcPtr); -	if (InvokeTclMethod(rcPtr, "cget", optionObj, NULL, &resObj)!=TCL_OK){ +	if (InvokeTclMethod(rcPtr, METH_CGET, optionObj, NULL, &resObj)!=TCL_OK){  	    ForwardSetObjError(paramPtr, resObj);  	} else { -	    Tcl_DStringAppend(paramPtr->getOpt.value, -		    TclGetString(resObj), -1); +	    TclDStringAppendObj(paramPtr->getOpt.value, resObj);  	}          Tcl_Release(rcPtr);          Tcl_DecrRefCount(optionObj); @@ -3046,7 +3091,7 @@ ForwardProc(  	 */          Tcl_Preserve(rcPtr); -	if (InvokeTclMethod(rcPtr, "cgetall", NULL, NULL, &resObj) != TCL_OK){ +	if (InvokeTclMethod(rcPtr, METH_CGETALL, NULL, NULL, &resObj) != TCL_OK){  	    ForwardSetObjError(paramPtr, resObj);  	} else {  	    /* @@ -3058,8 +3103,10 @@ ForwardProc(  	    Tcl_Obj **listv;  	    if (Tcl_ListObjGetElements(interp, resObj, &listc, -		    &listv) != TCL_OK) { -		ForwardSetObjError(paramPtr, MarshallError(interp)); +                    &listv) != TCL_OK) { +		Tcl_DecrRefCount(resObj); +		resObj = MarshallError(interp); +		ForwardSetObjError(paramPtr, resObj);  	    } else if ((listc % 2) == 1) {  		/*  		 * Odd number of elements is wrong. [x]. @@ -3076,7 +3123,7 @@ ForwardProc(  		const char *str = Tcl_GetStringFromObj(resObj, &len);  		if (len) { -		    Tcl_DStringAppend(paramPtr->getOpt.value, " ", 1); +		    TclDStringAppendLiteral(paramPtr->getOpt.value, " ");  		    Tcl_DStringAppend(paramPtr->getOpt.value, str, len);  		}  	    } @@ -3122,7 +3169,7 @@ static void  SrcExitProc(      ClientData clientData)  { -    ForwardingEvent *evPtr = (ForwardingEvent *) clientData; +    ForwardingEvent *evPtr = clientData;      ForwardingResult *resultPtr;      ForwardParam *paramPtr; @@ -3175,7 +3222,7 @@ ForwardSetObjError(      const char *msgStr = Tcl_GetStringFromObj(obj, &len);      len++; -    ForwardSetDynamicError(paramPtr, ckalloc((unsigned) len)); +    ForwardSetDynamicError(paramPtr, ckalloc(len));      memcpy(paramPtr->base.msgStr, msgStr, (unsigned) len);  }  #endif | 
