diff options
Diffstat (limited to 'generic/tclIORChan.c')
-rw-r--r-- | generic/tclIORChan.c | 482 |
1 files changed, 258 insertions, 224 deletions
diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c index ca3ab4b..49e2930 100644 --- a/generic/tclIORChan.c +++ b/generic/tclIORChan.c @@ -16,8 +16,8 @@ * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ -#include <tclInt.h> -#include <tclIO.h> +#include "tclInt.h" +#include "tclIO.h" #include <assert.h> #ifndef EINVAL @@ -55,24 +55,24 @@ 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 */ + NULL, /* thread action */ + NULL /* truncate */ }; /* @@ -121,6 +121,9 @@ typedef struct { 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. * @@ -159,7 +162,7 @@ typedef struct { * Event literals. ================================================== */ -static const char *eventOptions[] = { +static const char *const eventOptions[] = { "read", "write", NULL }; typedef enum { @@ -170,7 +173,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 */ @@ -340,7 +343,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 @@ -362,7 +366,7 @@ typedef struct ThreadSpecificData { * per-thread version of the per-interpreter map. */ - ReflectedChannelMap* rcmPtr; + ReflectedChannelMap *rcmPtr; } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; @@ -387,7 +391,7 @@ TCL_DECLARE_MUTEX(rcForwardMutex) */ static void ForwardOpToOwnerThread(ReflectedChannel *rcPtr, - ForwardedOperation op, const VOID *param); + ForwardedOperation op, const void *param); static int ForwardProc(Tcl_Event *evPtr, int mask); static void SrcExitProc(ClientData clientData); @@ -438,6 +442,7 @@ static ReflectedChannel * NewReflectedChannel(Tcl_Interp *interp, Tcl_Obj *cmdpfxObj, int mode, Tcl_Obj *handleObj); static Tcl_Obj * NextHandle(void); static void FreeReflectedChannel(ReflectedChannel *rcPtr); +static void FreeReflectedChannelArgs(ReflectedChannel *rcPtr); static int InvokeTclMethod(ReflectedChannel *rcPtr, const char *method, Tcl_Obj *argOneObj, Tcl_Obj *argTwoObj, Tcl_Obj **resultObjPtr); @@ -445,7 +450,7 @@ static int InvokeTclMethod(ReflectedChannel *rcPtr, 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). ================== @@ -511,9 +516,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 @@ -587,6 +594,7 @@ TclChanCreateObjCmd( /* assert modeObj.refCount == 1 */ result = InvokeTclMethod(rcPtr, "initialize", modeObj, NULL, &resObj); Tcl_DecrRefCount(modeObj); + if (result != TCL_OK) { UnmarshallErrorResult(interp, resObj); Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */ @@ -601,11 +609,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; } @@ -629,42 +635,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; } @@ -683,8 +684,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)); @@ -713,19 +713,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 @@ -733,10 +731,10 @@ TclChanCreateObjCmd( * Return handle as result of command. */ - Tcl_SetObjResult(interp, rcId); + Tcl_SetResult(interp, (char *)chanPtr->state->channelName, TCL_VOLATILE); return TCL_OK; - error: + error: /* * Signal to ReflectClose to not call 'finalize'. */ @@ -793,8 +791,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... @@ -812,12 +811,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_AppendResult(interp, "can not find reflected channel named \"", + chanId, "\"", NULL); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CHANNEL", chanId, NULL); return TCL_ERROR; } @@ -838,7 +837,7 @@ TclChanPostEventObjCmd( * have gone seriously haywire. */ - chan = Tcl_GetHashValue(hPtr); + chan = Tcl_GetHashValue(hPtr); chanTypePtr = Tcl_GetChannelType(chan); /* @@ -851,13 +850,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"); } /* @@ -900,7 +899,7 @@ TclChanPostEventObjCmd( * Channel error message marshalling utilities. */ -static Tcl_Obj* +static Tcl_Obj * MarshallError( Tcl_Interp *interp) { @@ -955,7 +954,7 @@ UnmarshallErrorResult( } (void) Tcl_SetReturnOptions(interp, Tcl_NewListObj(numOptions, lv)); - ((Interp *)interp)->flags &= ~ERR_ALREADY_LOGGED; + ((Interp *) interp)->flags &= ~ERR_ALREADY_LOGGED; } int @@ -1040,11 +1039,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()) { /* @@ -1058,8 +1058,9 @@ 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 @@ -1069,15 +1070,9 @@ ReflectClose( ForwardOpToOwnerThread(rcPtr, ForwardedClose, &p); result = p.base.code; - /* - * FreeReflectedChannel is done in the forwarded operation!, in - * the other thread. rcPtr here is gone! - */ - if (result != TCL_OK) { FreeReceivedError(&p); } - return EOK; } #endif @@ -1108,10 +1103,7 @@ ReflectClose( ForwardOpToOwnerThread(rcPtr, ForwardedClose, &p); result = p.base.code; - /* - * FreeReflectedChannel is done in the forwarded operation!, in the - * other thread. rcPtr here is gone! - */ + Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); if (result != TCL_OK) { PassReceivedErrorInterp(interp, &p); @@ -1139,20 +1131,20 @@ 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 @@ -1186,7 +1178,7 @@ 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 */ @@ -1243,7 +1235,7 @@ ReflectInput( Tcl_IncrRefCount(toReadObj); if (InvokeTclMethod(rcPtr, "read", toReadObj, NULL, &resObj)!=TCL_OK) { - int code = ErrnoReturn (rcPtr, resObj); + int code = ErrnoReturn(rcPtr, resObj); if (code < 0) { *errorCodePtr = -code; @@ -1302,7 +1294,7 @@ ReflectOutput( int toWrite, int *errorCodePtr) { - ReflectedChannel *rcPtr = (ReflectedChannel *) clientData; + ReflectedChannel *rcPtr = clientData; Tcl_Obj *bufObj; Tcl_Obj *resObj; /* Result data for 'write' */ int written; @@ -1430,7 +1422,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; @@ -1464,9 +1456,9 @@ ReflectSeekWide( Tcl_Preserve(rcPtr); - offObj = Tcl_NewWideIntObj(offset); + offObj = Tcl_NewWideIntObj(offset); baseObj = Tcl_NewStringObj((seekMode == SEEK_SET) ? "start" : - ((seekMode == SEEK_CUR) ? "current" : "end"), -1); + ((seekMode == SEEK_CUR) ? "current" : "end"), -1); Tcl_IncrRefCount(offObj); Tcl_IncrRefCount(baseObj); @@ -1538,7 +1530,7 @@ ReflectWatch( ClientData clientData, int mask) { - ReflectedChannel *rcPtr = (ReflectedChannel *) clientData; + ReflectedChannel *rcPtr = clientData; Tcl_Obj *maskObj; /* ASSERT rcPtr->methods & FLAG(METH_WATCH) */ @@ -1613,7 +1605,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' */ @@ -1644,7 +1636,7 @@ ReflectBlock( Tcl_Preserve(rcPtr); - if (InvokeTclMethod(rcPtr, "blocking", blockObj, NULL, &resObj) != TCL_OK) { + if (InvokeTclMethod(rcPtr, "blocking", blockObj, NULL, &resObj)!=TCL_OK) { Tcl_SetChannelError(rcPtr->chan, resObj); errorNum = EINVAL; } else { @@ -1681,7 +1673,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' */ @@ -1758,7 +1750,7 @@ 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; @@ -1859,7 +1851,7 @@ 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); @@ -1959,7 +1951,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. * @@ -1993,6 +1985,7 @@ DecodeEventMask( evObj = Tcl_NewStringObj(eventStr, -1); Tcl_IncrRefCount(evObj); + /* assert evObj.refCount == 1 */ return evObj; } @@ -2024,7 +2017,7 @@ NewReflectedChannel( int i, listc; Tcl_Obj **listv; - 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. */ @@ -2032,6 +2025,7 @@ NewReflectedChannel( rcPtr->chan = NULL; rcPtr->methods = 0; rcPtr->interp = interp; + rcPtr->dead = 0; #ifdef TCL_THREADS rcPtr->thread = Tcl_GetCurrentThread(); #endif @@ -2057,7 +2051,7 @@ NewReflectedChannel( */ rcPtr->argc = listc + 2; - rcPtr->argv = (Tcl_Obj **) ckalloc(sizeof(Tcl_Obj *) * (listc+4)); + rcPtr->argv = ckalloc(sizeof(Tcl_Obj *) * (listc+4)); /* * Duplicate object references. @@ -2132,21 +2126,14 @@ NextHandle(void) } static void -FreeReflectedChannel( +FreeReflectedChannelArgs( ReflectedChannel *rcPtr) { - Channel *chanPtr = (Channel *) rcPtr->chan; - int i, n; - - if (chanPtr->typePtr != &tclRChannelType) { - /* - * Delete a cloned ChannelType structure. - */ + int i, n = rcPtr->argc - 2; - ckfree((char*) chanPtr->typePtr); + if (n < 0) { + return; } - - n = rcPtr->argc - 2; for (i=0; i<n; i++) { Tcl_DecrRefCount(rcPtr->argv[i]); } @@ -2157,8 +2144,28 @@ FreeReflectedChannel( Tcl_DecrRefCount(rcPtr->argv[n+1]); - ckfree((char*) rcPtr->argv); - ckfree((char*) rcPtr); + rcPtr->argc = 1; +} + +static void +FreeReflectedChannel( + ReflectedChannel *rcPtr) +{ + Channel *chanPtr = (Channel *) rcPtr->chan; + + if (chanPtr->typePtr != &tclRChannelType) { + /* + * Delete a cloned ChannelType structure. + */ + + ckfree(chanPtr->typePtr); + chanPtr->typePtr = NULL; + } + + FreeReflectedChannelArgs(rcPtr); + + ckfree(rcPtr->argv); + ckfree(rcPtr); } /* @@ -2199,7 +2206,7 @@ InvokeTclMethod( int result; /* Result code of method invokation */ Tcl_Obj *resObj = NULL; /* Result of method invokation. */ - if (!rcPtr->interp) { + if (rcPtr->dead) { /* * The channel is marked as dead. Bail out immediately, with an * appropriate error. @@ -2237,6 +2244,9 @@ InvokeTclMethod( /* * 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; @@ -2353,12 +2363,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; } @@ -2367,9 +2379,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; } @@ -2400,10 +2413,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); @@ -2436,12 +2449,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; @@ -2451,7 +2464,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 @@ -2460,20 +2473,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 /* @@ -2489,10 +2499,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; } @@ -2502,6 +2515,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; @@ -2512,6 +2530,7 @@ DeleteReflectedChannelMap( Tcl_ConditionNotify(&resultPtr->done); } + Tcl_MutexUnlock(&rcForwardMutex); /* * Get the map of all channels handled by the current thread. This is a @@ -2522,21 +2541,23 @@ 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; + FreeReflectedChannelArgs(rcPtr); Tcl_DeleteHashEntry(hPtr); } - - Tcl_MutexUnlock(&rcForwardMutex); #endif } @@ -2559,12 +2580,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); } @@ -2579,7 +2600,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. @@ -2597,13 +2618,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. @@ -2620,10 +2636,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; } @@ -2633,6 +2655,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; @@ -2643,6 +2670,7 @@ DeleteThreadReflectedChannelMap( Tcl_ConditionNotify(&resultPtr->done); } + Tcl_MutexUnlock(&rcForwardMutex); /* * Get the map of all channels handled by the current thread. This is a @@ -2652,25 +2680,23 @@ 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; + FreeReflectedChannelArgs(rcPtr); Tcl_DeleteHashEntry(hPtr); } - - Tcl_MutexUnlock(&rcForwardMutex); + ckfree(rcmPtr); } static void ForwardOpToOwnerThread( ReflectedChannel *rcPtr, /* Channel instance */ ForwardedOperation op, /* Forwarded driver operation */ - const VOID *param) /* Arguments */ + const void *param) /* Arguments */ { Tcl_ThreadId dst = rcPtr->thread; ForwardingEvent *evPtr; @@ -2683,13 +2709,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; } @@ -2698,8 +2724,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; @@ -2707,8 +2733,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; @@ -2723,19 +2749,19 @@ 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 + * DeleteThreadReflectionChannelMap(), 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); /* @@ -2757,8 +2783,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); @@ -2776,9 +2802,9 @@ ForwardOpToOwnerThread( * Note: The event structure has already been deleted. */ - Tcl_DeleteThreadExitHandler(SrcExitProc, (ClientData) evPtr); + Tcl_DeleteThreadExitHandler(SrcExitProc, evPtr); - ckfree((char*) resultPtr); + ckfree(resultPtr); } static int @@ -2805,8 +2831,10 @@ 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. @@ -2846,17 +2874,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); + FreeReflectedChannelArgs(rcPtr); break; case ForwardedInput: { @@ -2865,7 +2893,7 @@ ForwardProc( Tcl_Preserve(rcPtr); if (InvokeTclMethod(rcPtr, "read", toReadObj, NULL, &resObj)!=TCL_OK){ - int code = ErrnoReturn (rcPtr, resObj); + int code = ErrnoReturn(rcPtr, resObj); if (code < 0) { paramPtr->base.code = code; @@ -2900,7 +2928,7 @@ 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); @@ -2921,7 +2949,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); @@ -2938,8 +2968,8 @@ 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); @@ -2964,7 +2994,9 @@ ForwardProc( paramPtr->seek.offset = newLoc; } } else { - ForwardSetObjError(paramPtr, MarshallError(interp)); + Tcl_DecrRefCount(resObj); + resObj = MarshallError(interp); + ForwardSetObjError(paramPtr, resObj); paramPtr->seek.offset = -1; } } @@ -2991,7 +3023,7 @@ ForwardProc( Tcl_Preserve(rcPtr); if (InvokeTclMethod(rcPtr, "blocking", blockObj, NULL, - &resObj) != TCL_OK) { + &resObj) != TCL_OK) { ForwardSetObjError(paramPtr, resObj); } Tcl_Release(rcPtr); @@ -3001,13 +3033,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) { + &resObj) != TCL_OK) { ForwardSetObjError(paramPtr, resObj); } Tcl_Release(rcPtr); @@ -3029,7 +3061,7 @@ ForwardProc( ForwardSetObjError(paramPtr, resObj); } else { Tcl_DStringAppend(paramPtr->getOpt.value, - TclGetString(resObj), -1); + TclGetString(resObj), -1); } Tcl_Release(rcPtr); Tcl_DecrRefCount(optionObj); @@ -3054,8 +3086,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]. @@ -3118,7 +3152,7 @@ static void SrcExitProc( ClientData clientData) { - ForwardingEvent *evPtr = (ForwardingEvent *) clientData; + ForwardingEvent *evPtr = clientData; ForwardingResult *resultPtr; ForwardParam *paramPtr; @@ -3171,7 +3205,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 |