summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tclIO.c88
-rw-r--r--generic/tclIO.h2
-rw-r--r--generic/tclIOCmd.c32
-rw-r--r--generic/tclIORChan.c4
-rw-r--r--generic/tclInt.h2
5 files changed, 77 insertions, 51 deletions
diff --git a/generic/tclIO.c b/generic/tclIO.c
index 1a9ff65..7216423 100644
--- a/generic/tclIO.c
+++ b/generic/tclIO.c
@@ -1547,6 +1547,7 @@ Tcl_CreateChannel(
chanPtr->upChanPtr = NULL;
chanPtr->inQueueHead = NULL;
chanPtr->inQueueTail = NULL;
+ chanPtr->refCount = 0;
/*
* TIP #219, Tcl Channel Reflection API
@@ -1762,6 +1763,7 @@ Tcl_StackChannel(
chanPtr->upChanPtr = NULL;
chanPtr->inQueueHead = NULL;
chanPtr->inQueueTail = NULL;
+ chanPtr->refCount = 0;
/*
* Place new block at the head of a possibly existing list of previously
@@ -1789,6 +1791,31 @@ Tcl_StackChannel(
return (Tcl_Channel) chanPtr;
}
+
+void
+TclChannelPreserve(
+ Tcl_Channel chan)
+{
+ ((Channel *)chan)->refCount++;
+}
+
+void
+TclChannelRelease(
+ Tcl_Channel chan)
+{
+ Channel *chanPtr = (Channel *) chan;
+
+ if (chanPtr->refCount == 0) {
+ Tcl_Panic("Channel released more than preserved");
+ }
+ if (--chanPtr->refCount) {
+ return;
+ }
+ if (chanPtr->typePtr == NULL) {
+ ckfree((char *)chanPtr);
+ }
+}
+
/*
*----------------------------------------------------------------------
@@ -1949,11 +1976,6 @@ Tcl_UnstackChannel(
chanPtr->typePtr = NULL;
- /*
- * AK: Tcl_NotifyChannel may hold a reference to this block of memory
- */
-
- Tcl_EventuallyFree(chanPtr, TCL_DYNAMIC);
UpdateInterest(statePtr->topChanPtr);
if (result != 0) {
@@ -2545,6 +2567,7 @@ FlushChannel(
* of the queued output to the channel.
*/
+ TclChannelPreserve((Tcl_Channel)chanPtr);
while (statePtr->outQueueHead) {
bufPtr = statePtr->outQueueHead;
@@ -2692,7 +2715,7 @@ FlushChannel(
if (GotFlag(statePtr, BG_FLUSH_SCHEDULED)) {
if (wroteSome) {
- return errorCode;
+ goto done;
} else if (statePtr->outQueueHead == NULL) {
ResetFlag(statePtr, BG_FLUSH_SCHEDULED);
(chanPtr->typePtr->watchProc)(chanPtr->instanceData,
@@ -2716,8 +2739,10 @@ FlushChannel(
(statePtr->outQueueHead == NULL) &&
((statePtr->curOutPtr == NULL) ||
IsBufferEmpty(statePtr->curOutPtr))) {
- return CloseChannel(interp, chanPtr, errorCode);
+ errorCode = CloseChannel(interp, chanPtr, errorCode);
}
+ done:
+ TclChannelRelease((Tcl_Channel)chanPtr);
return errorCode;
}
@@ -2890,7 +2915,6 @@ CloseChannel(
downChanPtr->upChanPtr = NULL;
chanPtr->typePtr = NULL;
- Tcl_EventuallyFree(chanPtr, TCL_DYNAMIC);
return Tcl_Close(interp, (Tcl_Channel) downChanPtr);
}
@@ -2898,13 +2922,11 @@ CloseChannel(
* There is only the TOP Channel, so we free the remaining pointers we
* have and then ourselves. Since this is the last of the channels in the
* stack, make sure to free the ChannelState structure associated with it.
- * We use Tcl_EventuallyFree to allow for any last references.
*/
chanPtr->typePtr = NULL;
Tcl_EventuallyFree(statePtr, TCL_DYNAMIC);
- Tcl_EventuallyFree(chanPtr, TCL_DYNAMIC);
return errorCode;
}
@@ -3965,7 +3987,7 @@ Tcl_GetsObj(
*/
chanPtr = statePtr->topChanPtr;
- Tcl_Preserve(chanPtr);
+ TclChannelPreserve((Tcl_Channel)chanPtr);
bufPtr = statePtr->inQueueHead;
encoding = statePtr->encoding;
@@ -4201,9 +4223,9 @@ Tcl_GetsObj(
*/
if (chanPtr != statePtr->topChanPtr) {
- Tcl_Release(chanPtr);
+ TclChannelRelease((Tcl_Channel)chanPtr);
chanPtr = statePtr->topChanPtr;
- Tcl_Preserve(chanPtr);
+ TclChannelPreserve((Tcl_Channel)chanPtr);
}
bufPtr = gs.bufPtr;
@@ -4239,9 +4261,9 @@ Tcl_GetsObj(
* self-modifying reflected transforms.
*/
if (chanPtr != statePtr->topChanPtr) {
- Tcl_Release(chanPtr);
+ TclChannelRelease((Tcl_Channel)chanPtr);
chanPtr = statePtr->topChanPtr;
- Tcl_Preserve(chanPtr);
+ TclChannelPreserve((Tcl_Channel)chanPtr);
}
bufPtr = statePtr->inQueueHead;
if (bufPtr != NULL) {
@@ -4283,12 +4305,12 @@ Tcl_GetsObj(
* self-modifying reflected transforms.
*/
if (chanPtr != statePtr->topChanPtr) {
- Tcl_Release(chanPtr);
+ TclChannelRelease((Tcl_Channel)chanPtr);
chanPtr = statePtr->topChanPtr;
- Tcl_Preserve(chanPtr);
+ TclChannelPreserve((Tcl_Channel)chanPtr);
}
UpdateInterest(chanPtr);
- Tcl_Release(chanPtr);
+ TclChannelRelease((Tcl_Channel)chanPtr);
return copiedTotal;
}
@@ -4334,7 +4356,7 @@ TclGetsObjBinary(
*/
chanPtr = statePtr->topChanPtr;
- Tcl_Preserve(chanPtr);
+ TclChannelPreserve((Tcl_Channel)chanPtr);
bufPtr = statePtr->inQueueHead;
@@ -4535,7 +4557,7 @@ TclGetsObjBinary(
done:
UpdateInterest(chanPtr);
- Tcl_Release(chanPtr);
+ TclChannelRelease((Tcl_Channel)chanPtr);
return copiedTotal;
}
@@ -5159,7 +5181,7 @@ DoReadChars(
chanPtr = statePtr->topChanPtr;
encoding = statePtr->encoding;
factor = UTF_EXPANSION_FACTOR;
- Tcl_Preserve(chanPtr);
+ TclChannelPreserve((Tcl_Channel)chanPtr);
binaryMode = (encoding == NULL)
&& (statePtr->inputTranslation == TCL_TRANSLATE_LF)
@@ -5221,9 +5243,9 @@ DoReadChars(
}
result = GetInput(chanPtr);
if (chanPtr != statePtr->topChanPtr) {
- Tcl_Release(chanPtr);
+ TclChannelRelease((Tcl_Channel)chanPtr);
chanPtr = statePtr->topChanPtr;
- Tcl_Preserve(chanPtr);
+ TclChannelPreserve((Tcl_Channel)chanPtr);
}
if (result != 0) {
if (!GotFlag(statePtr, CHANNEL_BLOCKED)) {
@@ -5251,9 +5273,9 @@ DoReadChars(
* self-modifying reflected transforms.
*/
if (chanPtr != statePtr->topChanPtr) {
- Tcl_Release(chanPtr);
+ TclChannelRelease((Tcl_Channel)chanPtr);
chanPtr = statePtr->topChanPtr;
- Tcl_Preserve(chanPtr);
+ TclChannelPreserve((Tcl_Channel)chanPtr);
}
/*
@@ -5261,7 +5283,7 @@ DoReadChars(
* in the buffers.
*/
UpdateInterest(chanPtr);
- Tcl_Release(chanPtr);
+ TclChannelRelease((Tcl_Channel)chanPtr);
return copied;
}
@@ -7659,7 +7681,7 @@ Tcl_NotifyChannel(
* Preserve the channel struct in case the script closes it.
*/
- Tcl_Preserve(channel);
+ TclChannelPreserve((Tcl_Channel)channel);
Tcl_Preserve(statePtr);
/*
@@ -7709,7 +7731,7 @@ Tcl_NotifyChannel(
}
Tcl_Release(statePtr);
- Tcl_Release(channel);
+ TclChannelRelease(channel);
tsdPtr->nestedHandlerPtr = nh.nestedHandlerPtr;
}
@@ -8189,7 +8211,7 @@ TclChannelEventScriptInvoker(
*/
Tcl_Preserve(interp);
- Tcl_Preserve(chanPtr);
+ TclChannelPreserve((Tcl_Channel)chanPtr);
result = Tcl_EvalObjEx(interp, esPtr->scriptPtr, TCL_EVAL_GLOBAL);
/*
@@ -8206,7 +8228,7 @@ TclChannelEventScriptInvoker(
}
TclBackgroundException(interp, result);
}
- Tcl_Release(chanPtr);
+ TclChannelRelease((Tcl_Channel)chanPtr);
Tcl_Release(interp);
}
@@ -8808,7 +8830,7 @@ DoRead(
ChannelState *statePtr = chanPtr->state;
char *p = dst;
- Tcl_Preserve(chanPtr);
+ TclChannelPreserve((Tcl_Channel)chanPtr);
while (bytesToRead) {
/*
* Each pass through the loop is intended to process up to
@@ -8847,7 +8869,7 @@ DoRead(
if (code) {
/* Read error */
UpdateInterest(chanPtr);
- Tcl_Release(chanPtr);
+ TclChannelRelease((Tcl_Channel)chanPtr);
return -1;
}
@@ -8945,7 +8967,7 @@ DoRead(
ResetFlag(statePtr, CHANNEL_BLOCKED);
}
- Tcl_Release(chanPtr);
+ TclChannelRelease((Tcl_Channel)chanPtr);
return (int)(p - dst);
}
diff --git a/generic/tclIO.h b/generic/tclIO.h
index 59182ec..b4a5405 100644
--- a/generic/tclIO.h
+++ b/generic/tclIO.h
@@ -112,6 +112,8 @@ typedef struct Channel {
ChannelBuffer *inQueueHead; /* Points at first buffer in input queue. */
ChannelBuffer *inQueueTail; /* Points at last buffer in input queue. */
+
+ int refCount;
} Channel;
/*
diff --git a/generic/tclIOCmd.c b/generic/tclIOCmd.c
index afd6272..db1150d 100644
--- a/generic/tclIOCmd.c
+++ b/generic/tclIOCmd.c
@@ -177,7 +177,7 @@ Tcl_PutsObjCmd(
return TCL_ERROR;
}
- Tcl_Preserve(chan);
+ TclChannelPreserve(chan);
result = Tcl_WriteObj(chan, string);
if (result < 0) {
goto error;
@@ -188,7 +188,7 @@ Tcl_PutsObjCmd(
goto error;
}
}
- Tcl_Release(chan);
+ TclChannelRelease(chan);
return TCL_OK;
/*
@@ -204,7 +204,7 @@ Tcl_PutsObjCmd(
TclGetString(chanObjPtr), "\": ",
Tcl_PosixError(interp), NULL);
}
- Tcl_Release(chan);
+ TclChannelRelease(chan);
return TCL_ERROR;
}
@@ -251,7 +251,7 @@ Tcl_FlushObjCmd(
return TCL_ERROR;
}
- Tcl_Preserve(chan);
+ TclChannelPreserve(chan);
if (Tcl_Flush(chan) != TCL_OK) {
/*
* TIP #219.
@@ -265,10 +265,10 @@ Tcl_FlushObjCmd(
TclGetString(chanObjPtr), "\": ",
Tcl_PosixError(interp), NULL);
}
- Tcl_Release(chan);
+ TclChannelRelease(chan);
return TCL_ERROR;
}
- Tcl_Release(chan);
+ TclChannelRelease(chan);
return TCL_OK;
}
@@ -317,7 +317,7 @@ Tcl_GetsObjCmd(
return TCL_ERROR;
}
- Tcl_Preserve(chan);
+ TclChannelPreserve(chan);
linePtr = Tcl_NewObj();
lineLen = Tcl_GetsObj(chan, linePtr);
if (lineLen < 0) {
@@ -353,7 +353,7 @@ Tcl_GetsObjCmd(
Tcl_SetObjResult(interp, linePtr);
}
done:
- Tcl_Release(chan);
+ TclChannelRelease(chan);
return code;
}
@@ -458,7 +458,7 @@ Tcl_ReadObjCmd(
resultPtr = Tcl_NewObj();
Tcl_IncrRefCount(resultPtr);
- Tcl_Preserve(chan);
+ TclChannelPreserve(chan);
charactersRead = Tcl_ReadChars(chan, resultPtr, toRead, 0);
if (charactersRead < 0) {
/*
@@ -474,7 +474,7 @@ Tcl_ReadObjCmd(
TclGetString(chanObjPtr), "\": ",
Tcl_PosixError(interp), NULL);
}
- Tcl_Release(chan);
+ TclChannelRelease(chan);
Tcl_DecrRefCount(resultPtr);
return TCL_ERROR;
}
@@ -493,7 +493,7 @@ Tcl_ReadObjCmd(
}
}
Tcl_SetObjResult(interp, resultPtr);
- Tcl_Release(chan);
+ TclChannelRelease(chan);
Tcl_DecrRefCount(resultPtr);
return TCL_OK;
}
@@ -553,7 +553,7 @@ Tcl_SeekObjCmd(
mode = modeArray[optionIndex];
}
- Tcl_Preserve(chan);
+ TclChannelPreserve(chan);
result = Tcl_Seek(chan, offset, mode);
if (result == Tcl_LongAsWide(-1)) {
/*
@@ -567,10 +567,10 @@ Tcl_SeekObjCmd(
TclGetString(objv[1]), "\": ",
Tcl_PosixError(interp), NULL);
}
- Tcl_Release(chan);
+ TclChannelRelease(chan);
return TCL_ERROR;
}
- Tcl_Release(chan);
+ TclChannelRelease(chan);
return TCL_OK;
}
@@ -617,7 +617,7 @@ Tcl_TellObjCmd(
return TCL_ERROR;
}
- Tcl_Preserve(chan);
+ TclChannelPreserve(chan);
newLoc = Tcl_Tell(chan);
/*
@@ -628,7 +628,7 @@ Tcl_TellObjCmd(
code = TclChanCaughtErrorBypass(interp, chan);
- Tcl_Release(chan);
+ TclChannelRelease(chan);
if (code) {
return TCL_ERROR;
}
diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c
index e1bd6e1..bbb5b88 100644
--- a/generic/tclIORChan.c
+++ b/generic/tclIORChan.c
@@ -649,7 +649,7 @@ TclChanCreateObjCmd(
chan = Tcl_CreateChannel(&tclRChannelType, TclGetString(rcId), rcPtr,
mode);
rcPtr->chan = chan;
- Tcl_Preserve(chan);
+ TclChannelPreserve(chan);
chanPtr = (Channel *) chan;
if ((methods & NULLABLE_METHODS) != NULLABLE_METHODS) {
@@ -2054,7 +2054,7 @@ FreeReflectedChannel(
{
Channel *chanPtr = (Channel *) rcPtr->chan;
- Tcl_Release(chanPtr);
+ TclChannelRelease((Tcl_Channel)chanPtr);
Tcl_DecrRefCount(rcPtr->name);
Tcl_DecrRefCount(rcPtr->methods);
Tcl_DecrRefCount(rcPtr->cmd);
diff --git a/generic/tclInt.h b/generic/tclInt.h
index b30650d..dd66d76 100644
--- a/generic/tclInt.h
+++ b/generic/tclInt.h
@@ -2504,6 +2504,8 @@ MODULE_SCOPE int TclByteArrayMatch(const unsigned char *string,
int strLen, const unsigned char *pattern,
int ptnLen, int flags);
MODULE_SCOPE double TclCeil(mp_int *a);
+MODULE_SCOPE void TclChannelPreserve(Tcl_Channel chan);
+MODULE_SCOPE void TclChannelRelease(Tcl_Channel chan);
MODULE_SCOPE int TclCheckBadOctal(Tcl_Interp *interp, const char *value);
MODULE_SCOPE int TclChanCaughtErrorBypass(Tcl_Interp *interp,
Tcl_Channel chan);