summaryrefslogtreecommitdiffstats
path: root/generic/tclIORChan.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclIORChan.c')
-rw-r--r--generic/tclIORChan.c482
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