diff options
Diffstat (limited to 'generic/tclIORChan.c')
| -rw-r--r-- | generic/tclIORChan.c | 1245 |
1 files changed, 428 insertions, 817 deletions
diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c index 31ead91..c9939d6 100644 --- a/generic/tclIORChan.c +++ b/generic/tclIORChan.c @@ -10,14 +10,14 @@ * * See TIP #219 for the specification of this functionality. * - * Copyright © 2004-2005 ActiveState, a division of Sophos + * Copyright (c) 2004-2005 ActiveState, a divison of Sophos * * See the file "license.terms" for information on usage and redistribution of * 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 @@ -31,66 +31,48 @@ * Signatures of all functions used in the C layer of the reflection. */ -static int ReflectClose(void *clientData, - Tcl_Interp *interp, int flags); -static int ReflectInput(void *clientData, char *buf, +static int ReflectClose(ClientData clientData, + Tcl_Interp *interp); +static int ReflectInput(ClientData clientData, char *buf, int toRead, int *errorCodePtr); -static int ReflectOutput(void *clientData, const char *buf, +static int ReflectOutput(ClientData clientData, const char *buf, int toWrite, int *errorCodePtr); -static void ReflectWatch(void *clientData, int mask); -static int ReflectBlock(void *clientData, int mode); -#if TCL_THREADS -static void ReflectThread(void *clientData, int action); -static int ReflectEventRun(Tcl_Event *ev, int flags); -static int ReflectEventDelete(Tcl_Event *ev, void *cd); -#endif -static long long ReflectSeekWide(void *clientData, - long long offset, int mode, int *errorCodePtr); -#ifndef TCL_NO_DEPRECATED -static int ReflectSeek(void *clientData, long offset, +static void ReflectWatch(ClientData clientData, int mask); +static int ReflectBlock(ClientData clientData, int mode); +static Tcl_WideInt ReflectSeekWide(ClientData clientData, + Tcl_WideInt offset, int mode, int *errorCodePtr); +static int ReflectSeek(ClientData clientData, long offset, int mode, int *errorCodePtr); -#endif -static int ReflectGetOption(void *clientData, +static int ReflectGetOption(ClientData clientData, Tcl_Interp *interp, const char *optionName, Tcl_DString *dsPtr); -static int ReflectSetOption(void *clientData, +static int ReflectSetOption(ClientData clientData, Tcl_Interp *interp, const char *optionName, const char *newValue); -static int ReflectTruncate(void *clientData, - long long length); -static void TimerRunRead(void *clientData); -static void TimerRunWrite(void *clientData); /* - * The C layer channel type/driver definition used by the reflection. + * The C layer channel type/driver definition used by the reflection. This is + * a version 3 structure. */ -static const Tcl_ChannelType tclRChannelType = { - "tclrchannel", /* Type name. */ +static Tcl_ChannelType tclRChannelType = { + "tclrchannel", /* Type name. */ TCL_CHANNEL_VERSION_5, /* v5 channel */ - TCL_CLOSE2PROC, /* Close channel, clean instance data */ - ReflectInput, /* Handle read request */ - ReflectOutput, /* Handle write request */ -#ifndef TCL_NO_DEPRECATED - ReflectSeek, /* Move location of access point. NULL'able */ -#else - NULL, -#endif - ReflectSetOption, /* Set options. NULL'able */ - ReflectGetOption, /* Get options. NULL'able */ - ReflectWatch, /* Initialize notifier */ - NULL, /* Get OS handle from the channel. NULL'able */ - ReflectClose, /* 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 */ -#if TCL_THREADS - ReflectThread, /* thread action, tracking owner */ -#else - NULL, /* thread action */ -#endif - ReflectTruncate /* Truncate. NULL'able */ + 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 */ }; /* @@ -106,9 +88,8 @@ typedef struct { * interpreter/thread containing its Tcl * command is gone. */ -#if TCL_THREADS - Tcl_ThreadId thread; /* Thread the 'interp' belongs to. == Handler thread */ - Tcl_ThreadId owner; /* Thread owning the structure. == Channel thread */ +#ifdef TCL_THREADS + Tcl_ThreadId thread; /* Thread the 'interp' belongs to. */ #endif Tcl_Obj *cmd; /* Callback command prefix */ Tcl_Obj *methods; /* Methods to append to command prefix */ @@ -118,20 +99,6 @@ typedef struct { int interest; /* Mask of events the channel is interested * in. */ - int dead; /* Boolean signal that some operations - * should no longer be attempted. */ - - Tcl_TimerToken readTimer; /* - A token for the timer that is scheduled in - order to call Tcl_NotifyChannel when the - channel is readable - */ - Tcl_TimerToken writeTimer; /* - A token for the timer that is scheduled in - order to call Tcl_NotifyChannel when the - channel is writable - */ - /* * Note regarding the usage of timers. * @@ -139,16 +106,18 @@ typedef struct { * data in buffers is flushed out through the generation of fake file * events. * - * See 'refchan', 'memchan', etc. + * See 'rechan', 'memchan', etc. * - * A timer is used here as well in order to ensure at least on pass through - * the event loop when a channel becomes ready. See issues 67a5eabbd3d1 and - * ef28eb1f1516. + * Here this is _not_ required. Interest in events is posted to the Tcl + * level via 'watch'. And posting of events is possible from the Tcl level + * as well, via 'chan postevent'. This means that the generation of all + * events, fake or not, timer based or not, is completely in the hands of + * the Tcl level. Therefore no timer here. */ } ReflectedChannel; /* - * Structure of the table mapping from channel handles to reflected + * Structure of the table maping from channel handles to reflected * channels. Each interpreter which has the handler command for one or more * reflected channels records them in such a table, so that 'chan postevent' * is able to find them even if the actual channel was moved to a different @@ -168,7 +137,7 @@ typedef struct { * Event literals. ================================================== */ -static const char *const eventOptions[] = { +static const char *eventOptions[] = { "read", "write", NULL }; typedef enum { @@ -179,7 +148,7 @@ typedef enum { * Method literals. ================================================== */ -static const char *const methodNames[] = { +static const char *methodNames[] = { "blocking", /* OPT */ "cget", /* OPT \/ Together or none */ "cgetall", /* OPT /\ of these two */ @@ -188,7 +157,6 @@ static const char *const methodNames[] = { "initialize", /* */ "read", /* OPT */ "seek", /* OPT */ - "truncate", /* OPT */ "watch", /* */ "write", /* OPT */ NULL @@ -202,7 +170,6 @@ typedef enum { METH_INIT, METH_READ, METH_SEEK, - METH_TRUNCATE, METH_WATCH, METH_WRITE } MethodName; @@ -212,17 +179,16 @@ typedef enum { (FLAG(METH_INIT) | FLAG(METH_FINAL) | FLAG(METH_WATCH)) #define NULLABLE_METHODS \ (FLAG(METH_BLOCKING) | FLAG(METH_SEEK) | \ - FLAG(METH_CONFIGURE) | FLAG(METH_CGET) | \ - FLAG(METH_CGETALL) | FLAG(METH_TRUNCATE)) + FLAG(METH_CONFIGURE) | FLAG(METH_CGET) | FLAG(METH_CGETALL)) #define RANDW \ (TCL_READABLE | TCL_WRITABLE) #define IMPLIES(a,b) ((!(a)) || (b)) #define NEGIMPL(a,b) -#define HAS(x,f) ((x) & FLAG(f)) +#define HAS(x,f) (x & FLAG(f)) -#if TCL_THREADS +#ifdef TCL_THREADS /* * Thread specific types and structures. * @@ -243,8 +209,7 @@ typedef enum { ForwardedBlock, ForwardedSetOpt, ForwardedGetOpt, - ForwardedGetOptAll, - ForwardedTruncate + ForwardedGetOptAll } ForwardedOperation; /* @@ -258,7 +223,7 @@ typedef enum { * sharing problems. */ -typedef struct { +typedef struct ForwardParamBase { int code; /* O: Ok/Fail of the cmd handler */ char *msgStr; /* O: Error message for handler failure */ int mustFree; /* O: True if msgStr is allocated, false if @@ -274,13 +239,13 @@ typedef struct { struct ForwardParamInput { ForwardParamBase base; /* "Supertype". MUST COME FIRST. */ char *buf; /* O: Where to store the read bytes */ - Tcl_Size toRead; /* I: #bytes to read, + int toRead; /* I: #bytes to read, * O: #bytes actually read */ }; struct ForwardParamOutput { ForwardParamBase base; /* "Supertype". MUST COME FIRST. */ const char *buf; /* I: Where the bytes to write come from */ - Tcl_Size toWrite; /* I: #bytes to write, + int toWrite; /* I: #bytes to write, * O: #bytes actually written */ }; struct ForwardParamSeek { @@ -307,10 +272,6 @@ struct ForwardParamGetOpt { const char *name; /* Name of option to get, maybe NULL */ Tcl_DString *value; /* Result */ }; -struct ForwardParamTruncate { - ForwardParamBase base; /* "Supertype". MUST COME FIRST. */ - Tcl_WideInt length; /* I: Length of file. */ -}; /* * Now join all these together in a single union for convenience. @@ -325,7 +286,6 @@ typedef union ForwardParam { struct ForwardParamBlock block; struct ForwardParamSetOpt setOpt; struct ForwardParamGetOpt getOpt; - struct ForwardParamTruncate truncate; } ForwardParam; /* @@ -338,7 +298,7 @@ typedef struct ForwardingResult ForwardingResult; * General event structure, with reference to operation specific data. */ -typedef struct { +typedef struct ForwardingEvent { Tcl_Event event; /* Basic event data, has to be first item */ ForwardingResult *resultPtr; ForwardedOperation op; /* Forwarded driver operation */ @@ -358,8 +318,7 @@ typedef struct { 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 @@ -375,13 +334,13 @@ struct ForwardingResult { * results. */ }; -typedef struct { +typedef struct ThreadSpecificData { /* * Table of all reflected channels owned by this thread. This is the * per-thread version of the per-interpreter map. */ - ReflectedChannelMap *rcmPtr; + ReflectedChannelMap* rcmPtr; } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; @@ -405,37 +364,37 @@ TCL_DECLARE_MUTEX(rcForwardMutex) * leak resources when threads go away. */ -static void ForwardOpToHandlerThread(ReflectedChannel *rcPtr, - ForwardedOperation op, const void *param); +static void ForwardOpToOwnerThread(ReflectedChannel *rcPtr, + ForwardedOperation op, const VOID *param); static int ForwardProc(Tcl_Event *evPtr, int mask); -static void SrcExitProc(void *clientData); +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); static ReflectedChannelMap * GetThreadReflectedChannelMap(void); -static Tcl_ExitProc DeleteThreadReflectedChannelMap; +static void DeleteThreadReflectedChannelMap(ClientData clientData); #endif /* TCL_THREADS */ @@ -456,15 +415,15 @@ static Tcl_Obj * DecodeEventMask(int mask); static ReflectedChannel * NewReflectedChannel(Tcl_Interp *interp, Tcl_Obj *cmdpfxObj, int mode, Tcl_Obj *handleObj); static Tcl_Obj * NextHandle(void); -static Tcl_FreeProc FreeReflectedChannel; +static void FreeReflectedChannel(ReflectedChannel *rcPtr); static int InvokeTclMethod(ReflectedChannel *rcPtr, MethodName method, Tcl_Obj *argOneObj, Tcl_Obj *argTwoObj, Tcl_Obj **resultObjPtr); static ReflectedChannelMap * GetReflectedChannelMap(Tcl_Interp *interp); -static Tcl_InterpDeleteProc DeleteReflectedChannelMap; -static int ErrnoReturn(ReflectedChannel *rcPtr, Tcl_Obj *resObj); -static void MarkDead(ReflectedChannel *rcPtr); +static void DeleteReflectedChannelMap(ClientData clientData, + Tcl_Interp *interp); +static int ErrnoReturn(ReflectedChannel *rcPtr, Tcl_Obj* resObj); /* * Global constant strings (messages). ================== @@ -477,7 +436,7 @@ static const char *msg_read_toomuch = "{read delivered more than requested}"; 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}"; -#if TCL_THREADS +#ifdef TCL_THREADS static const char *msg_send_originlost = "{Channel thread lost}"; #endif /* TCL_THREADS */ static const char *msg_send_dstlost = "{Owner lost}"; @@ -507,7 +466,7 @@ static const char *msg_dstlost = "-code 1 -level 0 -errorcode NONE -errorinfo int TclChanCreateObjCmd( - TCL_UNUSED(void *), + ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) @@ -520,7 +479,7 @@ TclChanCreateObjCmd( Tcl_Obj *cmdNameObj; /* Command name */ Tcl_Channel chan; /* Token for the new channel */ Tcl_Obj *modeObj; /* mode in obj form for method call */ - Tcl_Size listc; /* Result of 'initialize', and of */ + int listc; /* Result of 'initialize', and of */ Tcl_Obj **listv; /* its sublist in the 2nd element */ int methIndex; /* Encoded method name */ int result; /* Result code for 'initialize' */ @@ -528,11 +487,9 @@ 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 @@ -556,10 +513,9 @@ TclChanCreateObjCmd( /* * First argument is a list of modes. Allowed entries are "read", "write". - * Empty list is uncommon, but allowed. Abbreviations are ok. + * Expect at least one list element. Abbreviations are ok. */ - modeObj = objv[MODE]; if (EncodeEventMask(interp, "mode", objv[MODE], &mode) != TCL_OK) { return TCL_ERROR; } @@ -587,9 +543,6 @@ TclChanCreateObjCmd( rcId = NextHandle(); rcPtr = NewReflectedChannel(interp, cmdObj, mode, rcId); - if (!rcPtr) { - return TCL_ERROR; - } /* * Invoke 'initialize' and validate that the handler is present and ok. @@ -605,7 +558,6 @@ TclChanCreateObjCmd( /* assert modeObj.refCount == 1 */ 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 */ @@ -619,10 +571,12 @@ TclChanCreateObjCmd( * Compare open mode against optional r/w. */ - if (TclListObjGetElements(NULL, resObj, &listc, &listv) != TCL_OK) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "chan handler \"%s initialize\" returned non-list: %s", - TclGetString(cmdObj), TclGetString(resObj))); + 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_DecrRefCount(resObj); goto error; } @@ -646,37 +600,42 @@ TclChanCreateObjCmd( Tcl_DecrRefCount(resObj); if ((REQUIRED_METHODS & methods) != REQUIRED_METHODS) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "chan handler \"%s\" does not support all required methods", - TclGetString(cmdObj))); + TclNewLiteralStringObj(err, "chan handler \""); + Tcl_AppendObjToObj(err, cmdObj); + Tcl_AppendToObj(err, "\" does not support all required methods", -1); + Tcl_SetObjResult(interp, err); goto error; } if ((mode & TCL_READABLE) && !HAS(methods, METH_READ)) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "chan handler \"%s\" lacks a \"read\" method", - TclGetString(cmdObj))); + TclNewLiteralStringObj(err, "chan handler \""); + Tcl_AppendObjToObj(err, cmdObj); + Tcl_AppendToObj(err, "\" lacks a \"read\" method", -1); + Tcl_SetObjResult(interp, err); goto error; } if ((mode & TCL_WRITABLE) && !HAS(methods, METH_WRITE)) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "chan handler \"%s\" lacks a \"write\" method", - TclGetString(cmdObj))); + TclNewLiteralStringObj(err, "chan handler \""); + Tcl_AppendObjToObj(err, cmdObj); + Tcl_AppendToObj(err, "\" lacks a \"write\" method", -1); + Tcl_SetObjResult(interp, err); goto error; } if (!IMPLIES(HAS(methods, METH_CGET), HAS(methods, METH_CGETALL))) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "chan handler \"%s\" supports \"cget\" but not \"cgetall\"", - TclGetString(cmdObj))); + TclNewLiteralStringObj(err, "chan handler \""); + Tcl_AppendObjToObj(err, cmdObj); + Tcl_AppendToObj(err, "\" supports \"cget\" but not \"cgetall\"", -1); + Tcl_SetObjResult(interp, err); goto error; } if (!IMPLIES(HAS(methods, METH_CGETALL), HAS(methods, METH_CGET))) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "chan handler \"%s\" supports \"cgetall\" but not \"cget\"", - TclGetString(cmdObj))); + TclNewLiteralStringObj(err, "chan handler \""); + Tcl_AppendObjToObj(err, cmdObj); + Tcl_AppendToObj(err, "\" supports \"cgetall\" but not \"cget\"", -1); + Tcl_SetObjResult(interp, err); goto error; } @@ -699,7 +658,8 @@ TclChanCreateObjCmd( * as the actual channel type. */ - Tcl_ChannelType *clonePtr = (Tcl_ChannelType *)ckalloc(sizeof(Tcl_ChannelType)); + Tcl_ChannelType *clonePtr = (Tcl_ChannelType *) + ckalloc(sizeof(Tcl_ChannelType)); memcpy(clonePtr, &tclRChannelType, sizeof(Tcl_ChannelType)); @@ -714,14 +674,9 @@ TclChanCreateObjCmd( clonePtr->blockModeProc = NULL; } if (!(methods & FLAG(METH_SEEK))) { -#ifndef TCL_NO_DEPRECATED clonePtr->seekProc = NULL; -#endif clonePtr->wideSeekProc = NULL; } - if (!(methods & FLAG(METH_TRUNCATE))) { - clonePtr->truncateProc = NULL; - } chanPtr->typePtr = clonePtr; } @@ -733,17 +688,19 @@ TclChanCreateObjCmd( Tcl_RegisterChannel(interp, chan); - rcmPtr = GetReflectedChannelMap(interp); - hPtr = Tcl_CreateHashEntry(&rcmPtr->map, chanPtr->state->channelName, - &isNew); - if (!isNew && chanPtr != Tcl_GetHashValue(hPtr)) { - Tcl_Panic("TclChanCreateObjCmd: duplicate channel names"); + 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"); + } } Tcl_SetHashValue(hPtr, chan); -#if TCL_THREADS +#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 @@ -751,15 +708,14 @@ TclChanCreateObjCmd( * Return handle as result of command. */ - Tcl_SetObjResult(interp, - Tcl_NewStringObj(chanPtr->state->channelName, -1)); + Tcl_SetObjResult(interp, rcId); return TCL_OK; - error: + error: Tcl_DecrRefCount(rcPtr->name); Tcl_DecrRefCount(rcPtr->methods); Tcl_DecrRefCount(rcPtr->cmd); - ckfree(rcPtr); + ckfree((char*) rcPtr); return TCL_ERROR; #undef MODE @@ -784,62 +740,14 @@ TclChanCreateObjCmd( *---------------------------------------------------------------------- */ -#if TCL_THREADS -typedef struct { - Tcl_Event header; - ReflectedChannel *rcPtr; - int events; -} ReflectEvent; - -static int -ReflectEventRun( - Tcl_Event *ev, - TCL_UNUSED(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, - void *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; -} -#endif - int TclChanPostEventObjCmd( - TCL_UNUSED(void *), + ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { /* - * Ensure -> HANDLER thread - * * Syntax: chan postevent CHANNEL EVENTSPEC * [0] [1] [2] [3] * @@ -858,9 +766,8 @@ 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... @@ -878,34 +785,33 @@ 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_SetObjResult(interp, Tcl_ObjPrintf( - "can not find reflected channel named \"%s\"", chanId)); - Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CHANNEL", chanId, (void *)NULL); + Tcl_AppendResult(interp, "can not find reflected channel named \"", chanId, + "\"", NULL); + Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CHANNEL", chanId, NULL); return TCL_ERROR; } /* - * Note that the search above subsumes several of the older checks, - * namely: + * Note that the search above subsumes several of the older checks, namely: * - * (1) Does the channel handle refer to a reflected channel? + * (1) Does the channel handle refer to a reflected channel ? * (2) Is the post event issued from the interpreter holding the handler - * of the reflected channel? + * of the reflected channel ? * * A successful search answers yes to both. Because the map holds only * handles of reflected channels, and only of such whose handler is * defined in this interpreter. * - * We keep the old checks for both, for paranoia, but abort now instead of - * throwing errors, as failure now means that our internal data structures + * We keep the old checks for both, for paranioa, but abort now instead of + * throwing errors, as failure now means that our internal datastructures * have gone seriously haywire. */ - chan = (Tcl_Channel)Tcl_GetHashValue(hPtr); + chan = Tcl_GetHashValue(hPtr); chanTypePtr = Tcl_GetChannelType(chan); /* @@ -918,13 +824,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 = (ReflectedChannel *) 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"); } /* @@ -935,20 +841,14 @@ TclChanPostEventObjCmd( if (EncodeEventMask(interp, "event", objv[EVENT], &events) != TCL_OK) { return TCL_ERROR; } - if (events == 0) { - Tcl_SetObjResult(interp, - Tcl_NewStringObj("bad event list: is empty", -1)); - return TCL_ERROR; - } /* * Check that the channel is actually interested in the provided events. */ if (events & ~rcPtr->interest) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "tried to post events channel \"%s\" is not interested in", - chanId)); + Tcl_AppendResult(interp, "tried to post events channel \"", chanId, + "\" is not interested in", NULL); return TCL_ERROR; } @@ -956,56 +856,7 @@ TclChanPostEventObjCmd( * We have the channel and the events to post. */ -#if TCL_THREADS - if (rcPtr->owner == rcPtr->thread) { -#endif - if (events & TCL_READABLE) { - if (rcPtr->readTimer == NULL) { - rcPtr->readTimer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME, - TimerRunRead, rcPtr); - } - } - if (events & TCL_WRITABLE) { - if (rcPtr->writeTimer == NULL) { - rcPtr->writeTimer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME, - TimerRunWrite, rcPtr); - } - } -#if TCL_THREADS - } else { - ReflectEvent *ev = (ReflectEvent *)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_QUEUE_ALERT_IF_EMPTY); - } -#endif + Tcl_NotifyChannel(chan, events); /* * Squash interp results left by the event script. @@ -1018,29 +869,11 @@ TclChanPostEventObjCmd( #undef EVENT } -static void -TimerRunRead( - void *clientData) -{ - ReflectedChannel *rcPtr = (ReflectedChannel *)clientData; - rcPtr->readTimer = NULL; - Tcl_NotifyChannel(rcPtr->chan, TCL_READABLE); -} - -static void -TimerRunWrite( - void *clientData) -{ - ReflectedChannel *rcPtr = (ReflectedChannel *)clientData; - rcPtr->writeTimer = NULL; - Tcl_NotifyChannel(rcPtr->chan, TCL_WRITABLE); -} - /* * Channel error message marshalling utilities. */ -static Tcl_Obj * +static Tcl_Obj* MarshallError( Tcl_Interp *interp) { @@ -1065,10 +898,10 @@ UnmarshallErrorResult( Tcl_Interp *interp, Tcl_Obj *msgObj) { - Tcl_Size lc; + int lc; Tcl_Obj **lv; int explicitResult; - Tcl_Size numOptions; + int numOptions; /* * Process the caught message. @@ -1076,11 +909,11 @@ UnmarshallErrorResult( * Syntax = (option value)... ?message? * * Bad syntax causes a panic. This is OK because the other side uses - * Tcl_GetReturnOptions and list construction functions to marshal the + * Tcl_GetReturnOptions and list construction functions to marshall the * information; if we panic here, something has gone badly wrong already. */ - if (TclListObjGetElements(interp, msgObj, &lc, &lv) != TCL_OK) { + if (Tcl_ListObjGetElements(interp, msgObj, &lc, &lv) != TCL_OK) { Tcl_Panic("TclChanCaughtErrorBypass: Bad syntax of caught result"); } if (interp == NULL) { @@ -1095,7 +928,7 @@ UnmarshallErrorResult( } (void) Tcl_SetReturnOptions(interp, Tcl_NewListObj(numOptions, lv)); - ((Interp *) interp)->flags &= ~ERR_ALREADY_LOGGED; + ((Interp *)interp)->flags &= ~ERR_ALREADY_LOGGED; } int @@ -1164,10 +997,10 @@ TclChanCaughtErrorBypass( * ReflectClose -- * * This function is invoked when the channel is closed, to delete the - * driver-specific instance data. + * driver specific instance data. * * Results: - * A Posix error. + * A posix error. * * Side effects: * Releases memory. Arbitrary, as it calls upon a script. @@ -1177,70 +1010,57 @@ TclChanCaughtErrorBypass( static int ReflectClose( - void *clientData, - Tcl_Interp *interp, - int flags) + ClientData clientData, + Tcl_Interp *interp) { - ReflectedChannel *rcPtr = (ReflectedChannel *)clientData; + ReflectedChannel *rcPtr = (ReflectedChannel *) 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 */ - const Tcl_ChannelType *tctPtr; - - if ((flags & (TCL_CLOSE_READ | TCL_CLOSE_WRITE)) != 0) { - return EINVAL; - } + ReflectedChannelMap* rcmPtr; /* Map of reflected channels with handlers in this interp */ + Tcl_HashEntry* hPtr; /* Entry in the above map */ + Tcl_ChannelType *tctPtr; if (TclInThreadExit()) { /* * This call comes from TclFinalizeIOSystem. There are no * interpreters, and therefore we cannot call upon the handler command - * anymore. Threading is irrelevant as well. Simply clean up all - * the C level data structures and leave the Tcl level to the other + * anymore. Threading is irrelevant as well. We simply clean up all + * our C level data structures and leave the Tcl level to the other * finalization functions. */ /* * 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? */ -#if TCL_THREADS +#ifdef TCL_THREADS if (rcPtr->thread != Tcl_GetCurrentThread()) { ForwardParam p; - ForwardOpToHandlerThread(rcPtr, ForwardedClose, &p); + ForwardOpToOwnerThread(rcPtr, ForwardedClose, &p); result = p.base.code; - /* - * Now squash the pending reflection events for this channel. - */ - - Tcl_DeleteEvents(ReflectEventDelete, rcPtr); + /* + * FreeReflectedChannel is done in the forwarded operation!, in + * the other thread. rcPtr here is gone! + */ if (result != TCL_OK) { FreeReceivedError(&p); } + return EOK; } #endif tctPtr = ((Channel *)rcPtr->chan)->typePtr; if (tctPtr && tctPtr != &tclRChannelType) { - ckfree(tctPtr); + ckfree((char *)tctPtr); ((Channel *)rcPtr->chan)->typePtr = NULL; } - if (rcPtr->readTimer != NULL) { - Tcl_DeleteTimerHandler(rcPtr->readTimer); - } - if (rcPtr->writeTimer != NULL) { - Tcl_DeleteTimerHandler(rcPtr->writeTimer); - } - Tcl_EventuallyFree(rcPtr, FreeReflectedChannel); + Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); return EOK; } @@ -1248,18 +1068,17 @@ ReflectClose( * Are we in the correct thread? */ -#if TCL_THREADS +#ifdef TCL_THREADS if (rcPtr->thread != Tcl_GetCurrentThread()) { ForwardParam p; - ForwardOpToHandlerThread(rcPtr, ForwardedClose, &p); + ForwardOpToOwnerThread(rcPtr, ForwardedClose, &p); result = p.base.code; - /* - * Now squash the pending reflection events for this channel. - */ - - Tcl_DeleteEvents(ReflectEventDelete, rcPtr); + /* + * FreeReflectedChannel is done in the forwarded operation!, in the + * other thread. rcPtr here is gone! + */ if (result != TCL_OK) { PassReceivedErrorInterp(interp, &p); @@ -1287,35 +1106,32 @@ ReflectClose( * the per-interp DeleteReflectedChannelMap exit-handler. */ - if (!rcPtr->dead) { - rcmPtr = GetReflectedChannelMap(rcPtr->interp); - hPtr = Tcl_FindHashEntry(&rcmPtr->map, - Tcl_GetChannelName(rcPtr->chan)); + if (rcPtr->interp) { + rcmPtr = GetReflectedChannelMap (rcPtr->interp); + hPtr = Tcl_FindHashEntry (&rcmPtr->map, + Tcl_GetChannelName (rcPtr->chan)); if (hPtr) { - Tcl_DeleteHashEntry(hPtr); + Tcl_DeleteHashEntry (hPtr); } } -#if TCL_THREADS - rcmPtr = GetThreadReflectedChannelMap(); - hPtr = Tcl_FindHashEntry(&rcmPtr->map, - Tcl_GetChannelName(rcPtr->chan)); +#ifdef TCL_THREADS + rcmPtr = GetThreadReflectedChannelMap(); + hPtr = Tcl_FindHashEntry (&rcmPtr->map, + Tcl_GetChannelName (rcPtr->chan)); if (hPtr) { - Tcl_DeleteHashEntry(hPtr); + Tcl_DeleteHashEntry (hPtr); } - } #endif - tctPtr = ((Channel *)rcPtr->chan)->typePtr; - if (tctPtr && tctPtr != &tclRChannelType) { - ckfree(tctPtr); - ((Channel *)rcPtr->chan)->typePtr = NULL; - } - if (rcPtr->readTimer != NULL) { - Tcl_DeleteTimerHandler(rcPtr->readTimer); - } - if (rcPtr->writeTimer != NULL) { - Tcl_DeleteTimerHandler(rcPtr->writeTimer); + + tctPtr = ((Channel *)rcPtr->chan)->typePtr; + if (tctPtr && tctPtr != &tclRChannelType) { + ckfree((char *)tctPtr); + ((Channel *)rcPtr->chan)->typePtr = NULL; + } + Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); +#ifdef TCL_THREADS } - Tcl_EventuallyFree(rcPtr, FreeReflectedChannel); +#endif return (result == TCL_OK) ? EOK : EINVAL; } @@ -1337,14 +1153,14 @@ ReflectClose( static int ReflectInput( - void *clientData, + ClientData clientData, char *buf, int toRead, int *errorCodePtr) { - ReflectedChannel *rcPtr = (ReflectedChannel *)clientData; + ReflectedChannel *rcPtr = (ReflectedChannel *) clientData; Tcl_Obj *toReadObj; - Tcl_Size bytec; /* Number of returned bytes */ + int bytec; /* Number of returned bytes */ unsigned char *bytev; /* Array of returned bytes */ Tcl_Obj *resObj; /* Result data for 'read' */ @@ -1352,27 +1168,24 @@ ReflectInput( * Are we in the correct thread? */ -#if TCL_THREADS +#ifdef TCL_THREADS if (rcPtr->thread != Tcl_GetCurrentThread()) { ForwardParam p; p.input.buf = buf; p.input.toRead = toRead; - ForwardOpToHandlerThread(rcPtr, ForwardedInput, &p); + ForwardOpToOwnerThread(rcPtr, ForwardedInput, &p); if (p.base.code != TCL_OK) { if (p.base.code < 0) { - /* - * No error message, this is an errno signal. - */ - + /* No error message, this is an errno signal. */ *errorCodePtr = -p.base.code; } else { PassReceivedError(rcPtr->chan, &p); *errorCodePtr = EINVAL; } - p.input.toRead = TCL_INDEX_NONE; + p.input.toRead = -1; } else { *errorCodePtr = EOK; } @@ -1386,11 +1199,11 @@ ReflectInput( Tcl_Preserve(rcPtr); - TclNewIntObj(toReadObj, toRead); + toReadObj = Tcl_NewIntObj(toRead); Tcl_IncrRefCount(toReadObj); if (InvokeTclMethod(rcPtr, METH_READ, toReadObj, NULL, &resObj)!=TCL_OK) { - int code = ErrnoReturn(rcPtr, resObj); + int code = ErrnoReturn (rcPtr, resObj); if (code < 0) { *errorCodePtr = -code; @@ -1405,13 +1218,13 @@ ReflectInput( if (toRead < bytec) { SetChannelErrorStr(rcPtr->chan, msg_read_toomuch); - goto invalid; + goto invalid; } *errorCodePtr = EOK; if (bytec > 0) { - memcpy(buf, bytev, bytec); + memcpy(buf, bytev, (size_t)bytec); } stop: @@ -1444,12 +1257,12 @@ ReflectInput( static int ReflectOutput( - void *clientData, + ClientData clientData, const char *buf, int toWrite, int *errorCodePtr) { - ReflectedChannel *rcPtr = (ReflectedChannel *)clientData; + ReflectedChannel *rcPtr = (ReflectedChannel *) clientData; Tcl_Obj *bufObj; Tcl_Obj *resObj; /* Result data for 'write' */ int written; @@ -1458,21 +1271,18 @@ ReflectOutput( * Are we in the correct thread? */ -#if TCL_THREADS +#ifdef TCL_THREADS if (rcPtr->thread != Tcl_GetCurrentThread()) { ForwardParam p; p.output.buf = buf; p.output.toWrite = toWrite; - ForwardOpToHandlerThread(rcPtr, ForwardedOutput, &p); + ForwardOpToOwnerThread(rcPtr, ForwardedOutput, &p); if (p.base.code != TCL_OK) { if (p.base.code < 0) { - /* - * No error message, this is an errno signal. - */ - + /* No error message, this is an errno signal. */ *errorCodePtr = -p.base.code; } else { PassReceivedError(rcPtr->chan, &p); @@ -1523,8 +1333,8 @@ ReflectOutput( if ((written == 0) && (toWrite > 0)) { /* - * The handler claims to have written nothing of what it was given. - * That is bad. + * The handler claims to have written nothing of what it was + * given. That is bad. */ SetChannelErrorStr(rcPtr->chan, msg_write_nothing); @@ -1571,14 +1381,14 @@ ReflectOutput( *---------------------------------------------------------------------- */ -static long long +static Tcl_WideInt ReflectSeekWide( - void *clientData, - long long offset, + ClientData clientData, + Tcl_WideInt offset, int seekMode, int *errorCodePtr) { - ReflectedChannel *rcPtr = (ReflectedChannel *)clientData; + ReflectedChannel *rcPtr = (ReflectedChannel *) clientData; Tcl_Obj *offObj, *baseObj; Tcl_Obj *resObj; /* Result for 'seek' */ Tcl_WideInt newLoc; @@ -1587,14 +1397,14 @@ ReflectSeekWide( * Are we in the correct thread? */ -#if TCL_THREADS +#ifdef TCL_THREADS if (rcPtr->thread != Tcl_GetCurrentThread()) { ForwardParam p; p.seek.seekMode = seekMode; p.seek.offset = offset; - ForwardOpToHandlerThread(rcPtr, ForwardedSeek, &p); + ForwardOpToOwnerThread(rcPtr, ForwardedSeek, &p); if (p.base.code != TCL_OK) { PassReceivedError(rcPtr->chan, &p); @@ -1612,10 +1422,9 @@ ReflectSeekWide( Tcl_Preserve(rcPtr); - TclNewIntObj(offObj, 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); @@ -1629,7 +1438,7 @@ ReflectSeekWide( goto invalid; } - if (newLoc < 0) { + if (newLoc < Tcl_LongAsWide(0)) { SetChannelErrorStr(rcPtr->chan, msg_seek_beforestart); goto invalid; } @@ -1647,10 +1456,9 @@ ReflectSeekWide( goto stop; } -#ifndef TCL_NO_DEPRECATED static int ReflectSeek( - void *clientData, + ClientData clientData, long offset, int seekMode, int *errorCodePtr) @@ -1662,10 +1470,9 @@ ReflectSeek( * routine. */ - return ReflectSeekWide(clientData, offset, seekMode, + return (int) ReflectSeekWide(clientData, Tcl_LongAsWide(offset), seekMode, errorCodePtr); } -#endif /* *---------------------------------------------------------------------- @@ -1686,10 +1493,10 @@ ReflectSeek( static void ReflectWatch( - void *clientData, + ClientData clientData, int mask) { - ReflectedChannel *rcPtr = (ReflectedChannel *)clientData; + ReflectedChannel *rcPtr = (ReflectedChannel *) clientData; Tcl_Obj *maskObj; /* @@ -1708,16 +1515,18 @@ ReflectWatch( return; } + rcPtr->interest = mask; + /* * Are we in the correct thread? */ -#if TCL_THREADS +#ifdef TCL_THREADS if (rcPtr->thread != Tcl_GetCurrentThread()) { ForwardParam p; p.watch.mask = mask; - ForwardOpToHandlerThread(rcPtr, ForwardedWatch, &p); + ForwardOpToOwnerThread(rcPtr, ForwardedWatch, &p); /* * Any failure from the forward is ignored. We have no place to put @@ -1730,7 +1539,6 @@ ReflectWatch( Tcl_Preserve(rcPtr); - rcPtr->interest = mask; maskObj = DecodeEventMask(mask); /* assert maskObj.refCount == 1 */ (void) InvokeTclMethod(rcPtr, METH_WATCH, maskObj, NULL, NULL); @@ -1748,7 +1556,7 @@ ReflectWatch( * is required of it. * * Results: - * A Posix error number. + * A posix error number. * * Side effects: * Allocates memory. Arbitrary, as it calls upon a script. @@ -1758,10 +1566,10 @@ ReflectWatch( static int ReflectBlock( - void *clientData, + ClientData clientData, int nonblocking) { - ReflectedChannel *rcPtr = (ReflectedChannel *)clientData; + ReflectedChannel *rcPtr = (ReflectedChannel *) clientData; Tcl_Obj *blockObj; int errorNum; /* EINVAL or EOK (success). */ Tcl_Obj *resObj; /* Result data for 'blocking' */ @@ -1770,13 +1578,13 @@ ReflectBlock( * Are we in the correct thread? */ -#if TCL_THREADS +#ifdef TCL_THREADS if (rcPtr->thread != Tcl_GetCurrentThread()) { ForwardParam p; p.block.nonblocking = nonblocking; - ForwardOpToHandlerThread(rcPtr, ForwardedBlock, &p); + ForwardOpToOwnerThread(rcPtr, ForwardedBlock, &p); if (p.base.code != TCL_OK) { PassReceivedError(rcPtr->chan, &p); @@ -1792,7 +1600,7 @@ ReflectBlock( Tcl_Preserve(rcPtr); - if (InvokeTclMethod(rcPtr,METH_BLOCKING,blockObj,NULL,&resObj)!=TCL_OK) { + if (InvokeTclMethod(rcPtr, METH_BLOCKING, blockObj, NULL, &resObj) != TCL_OK) { Tcl_SetChannelError(rcPtr->chan, resObj); errorNum = EINVAL; } else { @@ -1806,44 +1614,6 @@ ReflectBlock( return errorNum; } -#if 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( - void *clientData, - int action) -{ - ReflectedChannel *rcPtr = (ReflectedChannel *)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 /* *---------------------------------------------------------------------- * @@ -1862,12 +1632,12 @@ ReflectThread( static int ReflectSetOption( - void *clientData, /* Channel to query */ + ClientData clientData, /* Channel to query */ Tcl_Interp *interp, /* Interpreter to leave error messages in */ const char *optionName, /* Name of requested option */ const char *newValue) /* The new value */ { - ReflectedChannel *rcPtr = (ReflectedChannel *)clientData; + ReflectedChannel *rcPtr = (ReflectedChannel *) clientData; Tcl_Obj *optionObj, *valueObj; int result; /* Result code for 'configure' */ Tcl_Obj *resObj; /* Result data for 'configure' */ @@ -1876,14 +1646,14 @@ ReflectSetOption( * Are we in the correct thread? */ -#if TCL_THREADS +#ifdef TCL_THREADS if (rcPtr->thread != Tcl_GetCurrentThread()) { ForwardParam p; p.setOpt.name = optionName; p.setOpt.value = newValue; - ForwardOpToHandlerThread(rcPtr, ForwardedSetOpt, &p); + ForwardOpToOwnerThread(rcPtr, ForwardedSetOpt, &p); if (p.base.code != TCL_OK) { Tcl_Obj *err = Tcl_NewStringObj(p.base.msgStr, -1); @@ -1934,7 +1704,7 @@ ReflectSetOption( static int ReflectGetOption( - void *clientData, /* Channel to query */ + ClientData clientData, /* Channel to query */ Tcl_Interp *interp, /* Interpreter to leave error messages in */ const char *optionName, /* Name of reuqested option */ Tcl_DString *dsPtr) /* String to place the result into */ @@ -1944,11 +1714,10 @@ ReflectGetOption( * The bypass functions are not required. */ - ReflectedChannel *rcPtr = (ReflectedChannel *)clientData; + ReflectedChannel *rcPtr = (ReflectedChannel*) clientData; Tcl_Obj *optionObj; Tcl_Obj *resObj; /* Result data for 'configure' */ - Tcl_Size listc; - int result = TCL_OK; + int listc, result = TCL_OK; Tcl_Obj **listv; MethodName method; @@ -1956,9 +1725,9 @@ ReflectGetOption( * Are we in the correct thread? */ -#if TCL_THREADS +#ifdef TCL_THREADS if (rcPtr->thread != Tcl_GetCurrentThread()) { - ForwardedOperation opcode; + int opcode; ForwardParam p; p.getOpt.name = optionName; @@ -1970,7 +1739,7 @@ ReflectGetOption( opcode = ForwardedGetOpt; } - ForwardOpToHandlerThread(rcPtr, opcode, &p); + ForwardOpToOwnerThread(rcPtr, opcode, &p); if (p.base.code != TCL_OK) { Tcl_Obj *err = Tcl_NewStringObj(p.base.msgStr, -1); @@ -2014,7 +1783,7 @@ ReflectGetOption( */ if (optionObj != NULL) { - TclDStringAppendObj(dsPtr, resObj); + Tcl_DStringAppend(dsPtr, TclGetString(resObj), -1); goto ok; } @@ -2029,7 +1798,7 @@ ReflectGetOption( * result is a valid list. Nor that the list has an even number elements. */ - if (TclListObjGetElements(interp, resObj, &listc, &listv) != TCL_OK) { + if (Tcl_ListObjGetElements(interp, resObj, &listc, &listv) != TCL_OK) { goto error; } @@ -2041,15 +1810,15 @@ ReflectGetOption( Tcl_ResetResult(interp); Tcl_SetObjResult(interp, Tcl_ObjPrintf( "Expected list with even number of " - "elements, got %" TCL_SIZE_MODIFIER "d element%s instead", listc, + "elements, got %d element%s instead", listc, (listc == 1 ? "" : "s"))); goto error; } else { - Tcl_Size len; - const char *str = TclGetStringFromObj(resObj, &len); + int len; + char *str = Tcl_GetStringFromObj(resObj, &len); if (len) { - TclDStringAppendLiteral(dsPtr, " "); + Tcl_DStringAppend(dsPtr, " ", 1); Tcl_DStringAppend(dsPtr, str, len); } goto ok; @@ -2070,73 +1839,6 @@ ReflectGetOption( } /* - *---------------------------------------------------------------------- - * - * ReflectTruncate -- - * - * This function is invoked to truncate a channel's file size. - * - * Results: - * A standard Tcl result code. - * - * Side effects: - * Arbitrary, as it calls upon a Tcl script. - * - *---------------------------------------------------------------------- - */ - -static int -ReflectTruncate( - void *clientData, /* Channel to query */ - long long length) /* Length to truncate to. */ -{ - ReflectedChannel *rcPtr = (ReflectedChannel *)clientData; - Tcl_Obj *lenObj; - int errorNum; /* EINVAL or EOK (success). */ - Tcl_Obj *resObj; /* Result for 'truncate' */ - - /* - * Are we in the correct thread? - */ - -#if TCL_THREADS - if (rcPtr->thread != Tcl_GetCurrentThread()) { - ForwardParam p; - - p.truncate.length = length; - - ForwardOpToHandlerThread(rcPtr, ForwardedTruncate, &p); - - if (p.base.code != TCL_OK) { - PassReceivedError(rcPtr->chan, &p); - return EINVAL; - } - - return EOK; - } -#endif - - /* ASSERT: rcPtr->method & FLAG(METH_TRUNCATE) */ - - Tcl_Preserve(rcPtr); - - lenObj = Tcl_NewWideIntObj(length); - Tcl_IncrRefCount(lenObj); - - if (InvokeTclMethod(rcPtr,METH_TRUNCATE,lenObj,NULL,&resObj)!=TCL_OK) { - Tcl_SetChannelError(rcPtr->chan, resObj); - errorNum = EINVAL; - } else { - errorNum = EOK; - } - - Tcl_DecrRefCount(lenObj); - Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */ - Tcl_Release(rcPtr); - return errorNum; -} - -/* * Helpers. ========================================================= */ @@ -2146,10 +1848,10 @@ ReflectTruncate( * EncodeEventMask -- * * This function takes a list of event items and constructs the - * equivalent internal bitmask. The list may be empty but will usually - * contain at least one element. Valid elements are "read", "write", or - * any unique abbreviation of them. Note that the bitmask is not changed - * if problems are encountered. + * equivalent internal bitmask. The list must contain at least one + * element. Elements are "read", "write", or any unique abbreviation of + * them. Note that the bitmask is not changed if problems are + * encountered. * * Results: * A standard Tcl error code. A bitmask where TCL_READABLE and/or @@ -2170,12 +1872,17 @@ EncodeEventMask( int *mask) { int events; /* Mask of events to post */ - Tcl_Size listc; /* #elements in eventspec list */ + int listc; /* #elements in eventspec list */ Tcl_Obj **listv; /* Elements of eventspec list */ int evIndex; /* Id of event for an element of the eventspec * list. */ - if (TclListObjGetElements(interp, obj, &listc, &listv) != TCL_OK) { + if (Tcl_ListObjGetElements(interp, obj, &listc, &listv) != TCL_OK) { + return TCL_ERROR; + } + + if (listc < 1) { + Tcl_AppendResult(interp, "bad ", objName, " list: is empty", NULL); return TCL_ERROR; } @@ -2208,7 +1915,7 @@ EncodeEventMask( * This function takes an internal bitmask of events and constructs the * equivalent list of event items. * - * Results, Contract: + * Results: * A Tcl_Obj reference. The object will have a refCount of one. The user * has to decrement it to release the object. * @@ -2222,7 +1929,7 @@ static Tcl_Obj * DecodeEventMask( int mask) { - const char *eventStr; + register const char *eventStr; Tcl_Obj *evObj; switch (mask & RANDW) { @@ -2242,7 +1949,6 @@ DecodeEventMask( evObj = Tcl_NewStringObj(eventStr, -1); Tcl_IncrRefCount(evObj); - /* assert evObj.refCount == 1 */ return evObj; } @@ -2271,27 +1977,25 @@ NewReflectedChannel( Tcl_Obj *handleObj) { ReflectedChannel *rcPtr; - int mn = 0; + MethodName mn = METH_BLOCKING; - rcPtr = (ReflectedChannel *)ckalloc(sizeof(ReflectedChannel)); + rcPtr = (ReflectedChannel *) ckalloc(sizeof(ReflectedChannel)); /* rcPtr->chan: Assigned by caller. Dummy data here. */ rcPtr->chan = NULL; rcPtr->interp = interp; - rcPtr->dead = 0; - rcPtr->readTimer = 0; - rcPtr->writeTimer = 0; -#if TCL_THREADS +#ifdef TCL_THREADS rcPtr->thread = Tcl_GetCurrentThread(); #endif rcPtr->mode = mode; rcPtr->interest = 0; /* Initially no interest registered */ + /* ASSERT: cmdpfxObj is a Tcl List */ rcPtr->cmd = TclListObjCopy(NULL, cmdpfxObj); Tcl_IncrRefCount(rcPtr->cmd); rcPtr->methods = Tcl_NewListObj(METH_WRITE + 1, NULL); - while (mn <= (int)METH_WRITE) { + while (mn <= METH_WRITE) { Tcl_ListObjAppendElement(NULL, rcPtr->methods, Tcl_NewStringObj(methodNames[mn++], -1)); } @@ -2314,7 +2018,7 @@ NewReflectedChannel( * refcount of the returned object is -- zero --. * * Side effects: - * May allocate memory. Mutex-protected critical section locks out other + * May allocate memory. Mutex protected critical section locks out other * threads for a short time. * *---------------------------------------------------------------------- @@ -2345,22 +2049,15 @@ NextHandle(void) static void FreeReflectedChannel( - char *blockPtr) + ReflectedChannel *rcPtr) { - ReflectedChannel *rcPtr = (ReflectedChannel *) blockPtr; Channel *chanPtr = (Channel *) rcPtr->chan; TclChannelRelease((Tcl_Channel)chanPtr); - if (rcPtr->name) { - Tcl_DecrRefCount(rcPtr->name); - } - if (rcPtr->methods) { - Tcl_DecrRefCount(rcPtr->methods); - } - if (rcPtr->cmd) { - Tcl_DecrRefCount(rcPtr->cmd); - } - ckfree(rcPtr); + Tcl_DecrRefCount(rcPtr->name); + Tcl_DecrRefCount(rcPtr->methods); + Tcl_DecrRefCount(rcPtr->cmd); + ckfree((char*) rcPtr); } /* @@ -2369,7 +2066,7 @@ FreeReflectedChannel( * InvokeTclMethod -- * * This function is used to invoke the Tcl level of a reflected channel. - * It handles all the command assembly, invocation, and generic state and + * It handles all the command assembly, invokation, and generic state and * result mgmt. It does *not* handle thread redirection; that is the * responsibility of clients of this function. * @@ -2397,11 +2094,11 @@ InvokeTclMethod( { Tcl_Obj *methObj = NULL; /* Method name in object form */ Tcl_InterpState sr; /* State of handler interp */ - int result; /* Result code of method invocation */ - Tcl_Obj *resObj = NULL; /* Result of method invocation. */ + int result; /* Result code of method invokation */ + Tcl_Obj *resObj = NULL; /* Result of method invokation. */ Tcl_Obj *cmd; - if (rcPtr->dead) { + if (!rcPtr->interp) { /* * The channel is marked as dead. Bail out immediately, with an * appropriate error. @@ -2427,6 +2124,7 @@ InvokeTclMethod( */ cmd = TclListObjCopy(NULL, rcPtr->cmd); + Tcl_ListObjIndex(NULL, rcPtr->methods, method, &methObj); Tcl_ListObjAppendElement(NULL, cmd, methObj); Tcl_ListObjAppendElement(NULL, cmd, rcPtr->name); @@ -2434,9 +2132,6 @@ 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. */ if (argOneObj) { @@ -2454,7 +2149,7 @@ InvokeTclMethod( Tcl_IncrRefCount(cmd); sr = Tcl_SaveInterpState(rcPtr->interp, 0 /* Dummy */); Tcl_Preserve(rcPtr->interp); - result = Tcl_EvalObjEx(rcPtr->interp, cmd, TCL_EVAL_GLOBAL); + result = Tcl_GlobalEvalObj(rcPtr->interp, cmd); /* * We do not try to extract the result information if the caller has no @@ -2480,8 +2175,8 @@ InvokeTclMethod( */ if (result != TCL_ERROR) { - Tcl_Size cmdLen; - const char *cmdString = TclGetStringFromObj(cmd, &cmdLen); + int cmdLen; + const char *cmdString = Tcl_GetStringFromObj(cmd, &cmdLen); Tcl_IncrRefCount(cmd); Tcl_ResetResult(rcPtr->interp); @@ -2535,21 +2230,19 @@ InvokeTclMethod( * None. * * Users: - * ReflectInput/Output(), to enable the signaling of EAGAIN on 0-sized - * short reads/writes. + * ReflectInput/Output(), to enable the signaling of EAGAIN + * on 0-sized short reads/writes. * *---------------------------------------------------------------------- */ 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->dead) { + if (!rcPtr->interp) { return 0; } @@ -2558,10 +2251,9 @@ ErrnoReturn( resObj = Tcl_GetObjResult(rcPtr->interp); - if (((Tcl_GetIntFromObj(rcPtr->interp, resObj, &code) != TCL_OK) - || (code >= 0))) { - if (strcmp("EAGAIN", TclGetString(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; } @@ -2592,12 +2284,13 @@ static ReflectedChannelMap * GetReflectedChannelMap( Tcl_Interp *interp) { - ReflectedChannelMap *rcmPtr = (ReflectedChannelMap *)Tcl_GetAssocData(interp, RCMKEY, NULL); + ReflectedChannelMap* rcmPtr = Tcl_GetAssocData(interp, RCMKEY, NULL); if (rcmPtr == NULL) { - rcmPtr = (ReflectedChannelMap *)ckalloc(sizeof(ReflectedChannelMap)); + rcmPtr = (ReflectedChannelMap *) ckalloc(sizeof(ReflectedChannelMap)); Tcl_InitHashTable(&rcmPtr->map, TCL_STRING_KEYS); - Tcl_SetAssocData(interp, RCMKEY, DeleteReflectedChannelMap, rcmPtr); + Tcl_SetAssocData(interp, RCMKEY, + (Tcl_InterpDeleteProc *) DeleteReflectedChannelMap, rcmPtr); } return rcmPtr; } @@ -2616,46 +2309,24 @@ GetReflectedChannelMap( * * Side effects: * Deletes the hash table of channels. May close channels. May flush - * output on closed channels. Removes any channelEvent handlers that were + * output on closed channels. Removes any channeEvent handlers that were * registered in this interpreter. * *---------------------------------------------------------------------- */ static void -MarkDead( - ReflectedChannel *rcPtr) -{ - if (rcPtr->dead) { - return; - } - if (rcPtr->name) { - Tcl_DecrRefCount(rcPtr->name); - rcPtr->name = NULL; - } - if (rcPtr->methods) { - Tcl_DecrRefCount(rcPtr->methods); - rcPtr->methods = NULL; - } - if (rcPtr->cmd) { - Tcl_DecrRefCount(rcPtr->cmd); - rcPtr->cmd = NULL; - } - rcPtr->dead = 1; -} - -static void DeleteReflectedChannelMap( - void *clientData, /* The per-interpreter data structure. */ + ClientData clientData, /* The per-interpreter data structure. */ Tcl_Interp *interp) /* The interpreter being deleted. */ { - ReflectedChannelMap *rcmPtr = (ReflectedChannelMap *)clientData; - /* The map */ + ReflectedChannelMap* rcmPtr; /* The map */ Tcl_HashSearch hSearch; /* Search variable. */ Tcl_HashEntry *hPtr; /* Search variable. */ - ReflectedChannel *rcPtr; + ReflectedChannel* rcPtr; Tcl_Channel chan; -#if TCL_THREADS + +#ifdef TCL_THREADS ForwardingResult *resultPtr; ForwardingEvent *evPtr; ForwardParam *paramPtr; @@ -2664,7 +2335,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 @@ -2673,19 +2344,22 @@ 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); + hPtr != NULL; + hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch)) { + + chan = (Tcl_Channel) Tcl_GetHashValue (hPtr); + rcPtr = (ReflectedChannel *) Tcl_GetChannelInstanceData(chan); + + rcPtr->interp = NULL; - MarkDead(rcPtr); Tcl_DeleteHashEntry(hPtr); } Tcl_DeleteHashTable(&rcmPtr->map); - ckfree(&rcmPtr->map); + ckfree((char *) &rcmPtr->map); -#if TCL_THREADS +#ifdef TCL_THREADS /* * The origin interpreter for one or more reflected channels is gone. */ @@ -2699,13 +2373,10 @@ 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; } @@ -2720,14 +2391,6 @@ DeleteReflectedChannelMap( */ evPtr = resultPtr->evPtr; - - /* - * Basic crash safety until this routine can get revised [3411310] - */ - - if (evPtr == NULL) { - continue; - } paramPtr = evPtr->param; if (!evPtr) { continue; @@ -2741,7 +2404,6 @@ DeleteReflectedChannelMap( Tcl_ConditionNotify(&resultPtr->done); } - Tcl_MutexUnlock(&rcForwardMutex); /* * Get the map of all channels handled by the current thread. This is a @@ -2752,28 +2414,25 @@ 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)) { - if (rcPtr->interp != interp) { - /* - * Ignore entries for other interpreters. - */ + chan = (Tcl_Channel) Tcl_GetHashValue (hPtr); + rcPtr = (ReflectedChannel *) Tcl_GetChannelInstanceData(chan); + if (rcPtr->interp != interp) { + /* Ignore entries for other interpreters */ continue; } - MarkDead(rcPtr); Tcl_DeleteHashEntry(hPtr); } -#else - (void)interp; + + Tcl_MutexUnlock(&rcForwardMutex); #endif } -#if TCL_THREADS +#ifdef TCL_THREADS /* *---------------------------------------------------------------------- * @@ -2792,12 +2451,12 @@ DeleteReflectedChannelMap( */ static ReflectedChannelMap * -GetThreadReflectedChannelMap(void) +GetThreadReflectedChannelMap() { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!tsdPtr->rcmPtr) { - tsdPtr->rcmPtr = (ReflectedChannelMap *)ckalloc(sizeof(ReflectedChannelMap)); + tsdPtr->rcmPtr = (ReflectedChannelMap *) ckalloc(sizeof(ReflectedChannelMap)); Tcl_InitHashTable(&tsdPtr->rcmPtr->map, TCL_STRING_KEYS); Tcl_CreateThreadExitHandler(DeleteThreadReflectedChannelMap, NULL); } @@ -2812,7 +2471,7 @@ GetThreadReflectedChannelMap(void) * * 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. @@ -2825,14 +2484,18 @@ GetThreadReflectedChannelMap(void) static void DeleteThreadReflectedChannelMap( - TCL_UNUSED(void *)) + ClientData clientData) /* The per-thread data structure. */ { Tcl_HashSearch hSearch; /* Search variable. */ Tcl_HashEntry *hPtr; /* Search variable. */ Tcl_ThreadId self = Tcl_GetCurrentThread(); - ReflectedChannelMap *rcmPtr; /* The map */ + + ReflectedChannelMap* rcmPtr; /* The map */ + Tcl_Channel chan; + ReflectedChannel* rcPtr; ForwardingResult *resultPtr; - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + ForwardingEvent *evPtr; + ForwardParam *paramPtr; /* * The origin thread for one or more reflected channels is gone. @@ -2842,23 +2505,17 @@ DeleteThreadReflectedChannelMap( /* * Go through the list of pending results and cancel all whose events were - * destined for this thread. While this is in progress we block any other - * access to the list of pending results. + * destined for this thread. While this is in progress we block any + * other access to the list of pending results. */ Tcl_MutexLock(&rcForwardMutex); for (resultPtr = forwardList; - resultPtr != NULL; - resultPtr = resultPtr->nextPtr) { - ForwardingEvent *evPtr; - ForwardParam *paramPtr; - + resultPtr != NULL; + resultPtr = resultPtr->nextPtr) { if (resultPtr->dst != self) { - /* - * Ignore results/events for other threads. - */ - + /* Ignore results/events for other threads. */ continue; } @@ -2873,14 +2530,6 @@ DeleteThreadReflectedChannelMap( */ evPtr = resultPtr->evPtr; - - /* - * Basic crash safety until this routine can get revised [3411310] - */ - - if (evPtr == NULL ) { - continue; - } paramPtr = evPtr->param; if (!evPtr) { continue; @@ -2894,16 +2543,6 @@ 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 @@ -2912,30 +2551,27 @@ DeleteThreadReflectedChannelMap( */ rcmPtr = GetThreadReflectedChannelMap(); - tsdPtr->rcmPtr = NULL; for (hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch); - hPtr != NULL; - hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch)) { - Tcl_Channel chan = (Tcl_Channel)Tcl_GetHashValue(hPtr); - ReflectedChannel *rcPtr = (ReflectedChannel *)Tcl_GetChannelInstanceData(chan); + hPtr != NULL; + hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch)) { + + chan = (Tcl_Channel) Tcl_GetHashValue (hPtr); + rcPtr = (ReflectedChannel *) Tcl_GetChannelInstanceData(chan); + + rcPtr->interp = NULL; - MarkDead(rcPtr); Tcl_DeleteHashEntry(hPtr); } - ckfree(rcmPtr); + + Tcl_MutexUnlock(&rcForwardMutex); } static void -ForwardOpToHandlerThread( +ForwardOpToOwnerThread( 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; @@ -2947,13 +2583,13 @@ ForwardOpToHandlerThread( Tcl_MutexLock(&rcForwardMutex); - if (rcPtr->dead) { + if (rcPtr->interp == NULL) { /* * 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; } @@ -2962,8 +2598,8 @@ ForwardOpToHandlerThread( * Create and initialize the event and data structures. */ - evPtr = (ForwardingEvent *)ckalloc(sizeof(ForwardingEvent)); - resultPtr = (ForwardingResult *)ckalloc(sizeof(ForwardingResult)); + evPtr = (ForwardingEvent *) ckalloc(sizeof(ForwardingEvent)); + resultPtr = (ForwardingResult *) ckalloc(sizeof(ForwardingResult)); evPtr->event.proc = ForwardProc; evPtr->resultPtr = resultPtr; @@ -2971,8 +2607,8 @@ ForwardOpToHandlerThread( 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; @@ -2983,30 +2619,27 @@ ForwardOpToHandlerThread( */ TclSpliceIn(resultPtr, forwardList); - - /* - * Do not unlock here. That is done by the ConditionWait. - */ + /* Do not unlock here. That is done by the ConditionWait */ /* * Ensure cleanup of the event if the origin thread exits while this event - * 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' + * 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' * (see above) for. */ - Tcl_CreateThreadExitHandler(SrcExitProc, evPtr); + Tcl_CreateThreadExitHandler(SrcExitProc, (ClientData) evPtr); /* * Queue the event and poke the other thread's notifier. */ - Tcl_ThreadQueueEvent(dst, (Tcl_Event *) evPtr, - TCL_QUEUE_TAIL|TCL_QUEUE_ALERT_IF_EMPTY); + Tcl_ThreadQueueEvent(dst, (Tcl_Event *)evPtr, TCL_QUEUE_TAIL); + Tcl_ThreadAlert(dst); /* - * (*) Block until the handler thread has either processed the transfer or + * (*) Block until the other thread has either processed the transfer or * rejected it. */ @@ -3024,8 +2657,8 @@ ForwardOpToHandlerThread( } /* - * 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); @@ -3043,26 +2676,21 @@ ForwardOpToHandlerThread( * Note: The event structure has already been deleted. */ - Tcl_DeleteThreadExitHandler(SrcExitProc, evPtr); + Tcl_DeleteThreadExitHandler(SrcExitProc, (ClientData) evPtr); - ckfree(resultPtr); + ckfree((char*) resultPtr); } static int ForwardProc( Tcl_Event *evGPtr, - TCL_UNUSED(int) /* mask */) + 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 - * evPtr->src), however this thread is currently blocked at (*), i.e., + * evPtr->src), however this thread is currently blocked at (*), i.e. * quiescent. Because of this we can treat the data as belonging to us, * without fear of race conditions. I.e. we can read and write as we like. * @@ -3077,9 +2705,8 @@ 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. @@ -3105,6 +2732,8 @@ ForwardProc( * No parameters/results. */ + Tcl_ChannelType *tctPtr; + if (InvokeTclMethod(rcPtr, METH_FINAL, NULL, NULL, &resObj)!=TCL_OK) { ForwardSetObjError(paramPtr, resObj); } @@ -3119,51 +2748,55 @@ 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); - MarkDead(rcPtr); + rcmPtr = GetThreadReflectedChannelMap(); + hPtr = Tcl_FindHashEntry (&rcmPtr->map, + Tcl_GetChannelName (rcPtr->chan)); + Tcl_DeleteHashEntry (hPtr); + + tctPtr = ((Channel *)rcPtr->chan)->typePtr; + if (tctPtr && tctPtr != &tclRChannelType) { + ckfree((char *)tctPtr); + ((Channel *)rcPtr->chan)->typePtr = NULL; + } + Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); break; } case ForwardedInput: { - Tcl_Obj *toReadObj; - - TclNewIntObj(toReadObj, paramPtr->input.toRead); - Tcl_IncrRefCount(toReadObj); + Tcl_Obj *toReadObj = Tcl_NewIntObj(paramPtr->input.toRead); + Tcl_IncrRefCount(toReadObj); - Tcl_Preserve(rcPtr); + Tcl_Preserve(rcPtr); if (InvokeTclMethod(rcPtr, METH_READ, toReadObj, NULL, &resObj)!=TCL_OK){ - int code = ErrnoReturn(rcPtr, resObj); + int code = ErrnoReturn (rcPtr, resObj); if (code < 0) { paramPtr->base.code = code; } else { ForwardSetObjError(paramPtr, resObj); } - paramPtr->input.toRead = TCL_IO_FAILURE; + paramPtr->input.toRead = -1; } else { /* * Process a regular result. */ - Tcl_Size bytec; /* Number of returned bytes */ + int bytec; /* Number of returned bytes */ unsigned char *bytev; /* Array of returned bytes */ bytev = Tcl_GetByteArrayFromObj(resObj, &bytec); if (paramPtr->input.toRead < bytec) { ForwardSetStaticError(paramPtr, msg_read_toomuch); - paramPtr->input.toRead = TCL_IO_FAILURE; + paramPtr->input.toRead = -1; } else { if (bytec > 0) { - memcpy(paramPtr->input.buf, bytev, bytec); + memcpy(paramPtr->input.buf, bytev, (size_t)bytec); } paramPtr->input.toRead = bytec; } @@ -3175,7 +2808,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); @@ -3196,9 +2829,7 @@ ForwardProc( int written; if (Tcl_GetIntFromObj(interp, resObj, &written) != TCL_OK) { - Tcl_DecrRefCount(resObj); - resObj = MarshallError(interp); - ForwardSetObjError(paramPtr, resObj); + ForwardSetObjError(paramPtr, MarshallError(interp)); paramPtr->output.toWrite = -1; } else if (written==0 || paramPtr->output.toWrite<written) { ForwardSetStaticError(paramPtr, msg_write_toomuch); @@ -3213,18 +2844,15 @@ ForwardProc( } case ForwardedSeek: { - Tcl_Obj *offObj; - Tcl_Obj *baseObj; - - TclNewIntObj(offObj, paramPtr->seek.offset); - baseObj = Tcl_NewStringObj( + 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); - Tcl_IncrRefCount(offObj); - Tcl_IncrRefCount(baseObj); + Tcl_IncrRefCount(offObj); + Tcl_IncrRefCount(baseObj); - Tcl_Preserve(rcPtr); + Tcl_Preserve(rcPtr); if (InvokeTclMethod(rcPtr, METH_SEEK, offObj, baseObj, &resObj)!=TCL_OK){ ForwardSetObjError(paramPtr, resObj); paramPtr->seek.offset = -1; @@ -3237,16 +2865,14 @@ ForwardProc( Tcl_WideInt newLoc; if (Tcl_GetWideIntFromObj(interp, resObj, &newLoc) == TCL_OK) { - if (newLoc < 0) { + if (newLoc < Tcl_LongAsWide(0)) { ForwardSetStaticError(paramPtr, msg_seek_beforestart); paramPtr->seek.offset = -1; } else { paramPtr->seek.offset = newLoc; } } else { - Tcl_DecrRefCount(resObj); - resObj = MarshallError(interp); - ForwardSetObjError(paramPtr, resObj); + ForwardSetObjError(paramPtr, MarshallError(interp)); paramPtr->seek.offset = -1; } } @@ -3261,7 +2887,6 @@ ForwardProc( /* assert maskObj.refCount == 1 */ Tcl_Preserve(rcPtr); - rcPtr->interest = paramPtr->watch.mask; (void) InvokeTclMethod(rcPtr, METH_WATCH, maskObj, NULL, NULL); Tcl_DecrRefCount(maskObj); Tcl_Release(rcPtr); @@ -3270,11 +2895,11 @@ ForwardProc( case ForwardedBlock: { Tcl_Obj *blockObj = Tcl_NewBooleanObj(!paramPtr->block.nonblocking); - Tcl_IncrRefCount(blockObj); + Tcl_Preserve(rcPtr); if (InvokeTclMethod(rcPtr, METH_BLOCKING, blockObj, NULL, - &resObj) != TCL_OK) { + &resObj) != TCL_OK) { ForwardSetObjError(paramPtr, resObj); } Tcl_Release(rcPtr); @@ -3284,13 +2909,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, METH_CONFIGURE, optionObj, valueObj, - &resObj) != TCL_OK) { + &resObj) != TCL_OK) { ForwardSetObjError(paramPtr, resObj); } Tcl_Release(rcPtr); @@ -3305,13 +2930,14 @@ ForwardProc( */ Tcl_Obj *optionObj = Tcl_NewStringObj(paramPtr->getOpt.name, -1); - Tcl_IncrRefCount(optionObj); + Tcl_Preserve(rcPtr); if (InvokeTclMethod(rcPtr, METH_CGET, optionObj, NULL, &resObj)!=TCL_OK){ ForwardSetObjError(paramPtr, resObj); } else { - TclDStringAppendObj(paramPtr->getOpt.value, resObj); + Tcl_DStringAppend(paramPtr->getOpt.value, + TclGetString(resObj), -1); } Tcl_Release(rcPtr); Tcl_DecrRefCount(optionObj); @@ -3332,31 +2958,29 @@ ForwardProc( * NOTE (4) as well. */ - Tcl_Size listc; + int listc; Tcl_Obj **listv; - if (TclListObjGetElements(interp, resObj, &listc, - &listv) != TCL_OK) { - Tcl_DecrRefCount(resObj); - resObj = MarshallError(interp); - ForwardSetObjError(paramPtr, resObj); + if (Tcl_ListObjGetElements(interp, resObj, &listc, + &listv) != TCL_OK) { + ForwardSetObjError(paramPtr, MarshallError(interp)); } else if ((listc % 2) == 1) { /* * Odd number of elements is wrong. [x]. */ - char *buf = (char *)ckalloc(200); - snprintf(buf, 200, - "{Expected list with even number of elements, got %" TCL_SIZE_MODIFIER "d %s instead}", + char *buf = ckalloc(200); + sprintf(buf, + "{Expected list with even number of elements, got %d %s instead}", listc, (listc == 1 ? "element" : "elements")); ForwardSetDynamicError(paramPtr, buf); } else { - Tcl_Size len; - const char *str = TclGetStringFromObj(resObj, &len); + int len; + const char *str = Tcl_GetStringFromObj(resObj, &len); if (len) { - TclDStringAppendLiteral(paramPtr->getOpt.value, " "); + Tcl_DStringAppend(paramPtr->getOpt.value, " ", 1); Tcl_DStringAppend(paramPtr->getOpt.value, str, len); } } @@ -3364,19 +2988,6 @@ ForwardProc( Tcl_Release(rcPtr); break; - case ForwardedTruncate: { - Tcl_Obj *lenObj = Tcl_NewWideIntObj(paramPtr->truncate.length); - - Tcl_IncrRefCount(lenObj); - Tcl_Preserve(rcPtr); - if (InvokeTclMethod(rcPtr,METH_TRUNCATE,lenObj,NULL,&resObj)!=TCL_OK) { - ForwardSetObjError(paramPtr, resObj); - } - Tcl_Release(rcPtr); - Tcl_DecrRefCount(lenObj); - break; - } - default: /* * Bad operation code. @@ -3413,9 +3024,9 @@ ForwardProc( static void SrcExitProc( - void *clientData) + ClientData clientData) { - ForwardingEvent *evPtr = (ForwardingEvent *)clientData; + ForwardingEvent *evPtr = (ForwardingEvent *) clientData; ForwardingResult *resultPtr; ForwardParam *paramPtr; @@ -3464,12 +3075,12 @@ ForwardSetObjError( ForwardParam *paramPtr, Tcl_Obj *obj) { - Tcl_Size len; - const char *msgStr = TclGetStringFromObj(obj, &len); + int len; + const char *msgStr = Tcl_GetStringFromObj(obj, &len); len++; - ForwardSetDynamicError(paramPtr, ckalloc(len)); - memcpy(paramPtr->base.msgStr, msgStr, len); + ForwardSetDynamicError(paramPtr, ckalloc((unsigned) len)); + memcpy(paramPtr->base.msgStr, msgStr, (unsigned) len); } #endif |
