summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjan.nijtmans <nijtmans@users.sourceforge.net>2024-04-22 20:19:22 (GMT)
committerjan.nijtmans <nijtmans@users.sourceforge.net>2024-04-22 20:19:22 (GMT)
commit6e9213a3c4a5d4f7e15204722f1a05f20614f941 (patch)
tree04a26160209e8dfe8a3825910f43a19380202a70
parent60339885f4218887fe55d1c922d9b5f9b990ea89 (diff)
parentd8553a19362fd150910f4e46be68f45d377d4701 (diff)
downloadtcl-6e9213a3c4a5d4f7e15204722f1a05f20614f941.zip
tcl-6e9213a3c4a5d4f7e15204722f1a05f20614f941.tar.gz
tcl-6e9213a3c4a5d4f7e15204722f1a05f20614f941.tar.bz2
Rebase to 9.0
-rw-r--r--generic/tclIO.c82
-rw-r--r--generic/tclIORChan.c66
-rw-r--r--tests/ioCmd.test40
3 files changed, 25 insertions, 163 deletions
diff --git a/generic/tclIO.c b/generic/tclIO.c
index 78cda5c..518adef 100644
--- a/generic/tclIO.c
+++ b/generic/tclIO.c
@@ -167,7 +167,6 @@ static int CheckForDeadChannel(Tcl_Interp *interp,
static void CheckForStdChannelsBeingClosed(Tcl_Channel chan);
static void CleanupChannelHandlers(Tcl_Interp *interp,
Channel *chanPtr);
-static void CleanupTimerHandler(ChannelState *statePtr);
static int CloseChannel(Tcl_Interp *interp, Channel *chanPtr,
int errorCode);
static int CloseChannelPart(Tcl_Interp *interp, Channel *chanPtr,
@@ -3504,11 +3503,6 @@ TclClose(
Tcl_ClearChannelHandlers(chan);
/*
- * Cancel any outstanding timer.
- */
- DeleteTimerHandler(statePtr);
-
- /*
* Invoke the registered close callbacks and delete their records.
*/
@@ -8628,7 +8622,6 @@ UpdateInterest(
{
ChannelState *statePtr = chanPtr->state;
/* State info for channel */
- ChannelBuffer *bufPtr = statePtr->outQueueHead;
int mask = statePtr->interestMask;
if (chanPtr->typePtr == NULL) {
@@ -8706,20 +8699,6 @@ UpdateInterest(
}
}
}
-
- if (!statePtr->timer
- && (mask & TCL_WRITABLE)
- && GotFlag(statePtr, CHANNEL_NONBLOCKING)
- && bufPtr
- && !IsBufferEmpty(bufPtr)
- && !IsBufferFull(bufPtr)
- ) {
- TclChannelPreserve((Tcl_Channel)chanPtr);
- statePtr->timerChanPtr = chanPtr;
- statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
- ChannelTimerProc,chanPtr);
- }
-
ChanWatch(chanPtr, mask);
}
@@ -8748,51 +8727,30 @@ ChannelTimerProc(
/* State info for channel */
ChannelState *statePtr = chanPtr->state;
- /* TclChannelPreserve() must be called before the current function was
- * scheduled, is already in effect. In this function it guards against
- * deallocation in Tcl_NotifyChannel and also keps the channel preserved
- * until ChannelTimerProc is later called again.
- */
-
if (chanPtr->typePtr == NULL) {
- CleanupTimerHandler(statePtr);
- } else {
- Tcl_Preserve(statePtr);
statePtr->timer = NULL;
- if (statePtr->interestMask & TCL_WRITABLE
- && GotFlag(statePtr, CHANNEL_NONBLOCKING)
- && !GotFlag(statePtr, BG_FLUSH_SCHEDULED)) {
+ TclChannelRelease((Tcl_Channel)statePtr->timerChanPtr);
+ statePtr->timerChanPtr = NULL;
+ } else {
+ if (!GotFlag(statePtr, CHANNEL_NEED_MORE_DATA)
+ && (statePtr->interestMask & TCL_READABLE)
+ && (statePtr->inQueueHead != NULL)
+ && IsBufferReady(statePtr->inQueueHead)) {
/*
* Restart the timer in case a channel handler reenters the event loop
* before UpdateInterest gets called by Tcl_NotifyChannel.
*/
statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
ChannelTimerProc,chanPtr);
- Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_WRITABLE);
+ Tcl_Preserve(statePtr);
+ Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_READABLE);
+ Tcl_Release(statePtr);
} else {
- /* The channel may have just been closed from within Tcl_NotifyChannel */
- if (!GotFlag(statePtr, CHANNEL_INCLOSE)) {
- if (!GotFlag(statePtr, CHANNEL_NEED_MORE_DATA)
- && (statePtr->interestMask & TCL_READABLE)
- && (statePtr->inQueueHead != NULL)
- && IsBufferReady(statePtr->inQueueHead)) {
- /*
- * Restart the timer in case a channel handler reenters the event loop
- * before UpdateInterest gets called by Tcl_NotifyChannel.
- */
-
- statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
- ChannelTimerProc,chanPtr);
- Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_READABLE);
- } else {
- CleanupTimerHandler(statePtr);
- UpdateInterest(chanPtr);
- }
- } else {
- CleanupTimerHandler(statePtr);
- }
+ statePtr->timer = NULL;
+ UpdateInterest(chanPtr);
+ TclChannelRelease((Tcl_Channel)statePtr->timerChanPtr);
+ statePtr->timerChanPtr = NULL;
}
- Tcl_Release(statePtr);
}
}
@@ -8803,17 +8761,11 @@ DeleteTimerHandler(
{
if (statePtr->timer != NULL) {
Tcl_DeleteTimerHandler(statePtr->timer);
- CleanupTimerHandler(statePtr);
+ statePtr->timer = NULL;
+ TclChannelRelease((Tcl_Channel)statePtr->timerChanPtr);
+ statePtr->timerChanPtr = NULL;
}
}
-static void
-CleanupTimerHandler(
- ChannelState *statePtr
-){
- TclChannelRelease((Tcl_Channel)statePtr->timerChanPtr);
- statePtr->timer = NULL;
- statePtr->timerChanPtr = NULL;
-}
/*
*----------------------------------------------------------------------
diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c
index fe54f65..5acd950 100644
--- a/generic/tclIORChan.c
+++ b/generic/tclIORChan.c
@@ -54,8 +54,6 @@ static int ReflectSetOption(void *clientData,
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.
@@ -113,17 +111,6 @@ typedef struct {
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.
*
@@ -133,9 +120,11 @@ typedef struct {
*
* See 'refchan', '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;
@@ -949,18 +938,7 @@ TclChanPostEventObjCmd(
#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);
- }
- }
+ Tcl_NotifyChannel(chan, events);
#if TCL_THREADS
} else {
ReflectEvent *ev = (ReflectEvent *)Tcl_Alloc(sizeof(ReflectEvent));
@@ -1008,24 +986,6 @@ 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.
*/
@@ -1224,12 +1184,6 @@ ReflectClose(
Tcl_Free((void *)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);
return EOK;
}
@@ -1299,12 +1253,6 @@ ReflectClose(
Tcl_Free((void *)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);
return (result == TCL_OK) ? EOK : EINVAL;
}
@@ -2253,8 +2201,6 @@ NewReflectedChannel(
rcPtr->chan = NULL;
rcPtr->interp = interp;
rcPtr->dead = 0;
- rcPtr->readTimer = 0;
- rcPtr->writeTimer = 0;
#if TCL_THREADS
rcPtr->thread = Tcl_GetCurrentThread();
#endif
diff --git a/tests/ioCmd.test b/tests/ioCmd.test
index 7f27266..dfa7d06 100644
--- a/tests/ioCmd.test
+++ b/tests/ioCmd.test
@@ -971,17 +971,6 @@ proc onfinal {} {
if {[lindex $hargs 0] ne "finalize"} {return}
return -code return ""
}
-
-proc onwatch {} {
- upvar args hargs
- lassign $hargs watch chan eventspec
- if {$watch ne "watch"} return
- foreach spec $eventspec {
- chan postevent $chan $spec
- }
- return
-}
-
}
# Set everything up in the main thread.
@@ -2063,7 +2052,7 @@ test iocmd-31.6 {chan postevent, posted events do happen} -match glob -body {
close $c
rename foo {}
set res
-} -result {{watch rc* read} {} {} TOCK {watch rc* {}}}
+} -result {{watch rc* read} {} TOCK {} {watch rc* {}}}
test iocmd-31.7 {chan postevent, posted events do happen} -match glob -body {
set res {}
proc foo {args} {oninit; onfinal; track; return}
@@ -2076,7 +2065,7 @@ test iocmd-31.7 {chan postevent, posted events do happen} -match glob -body {
close $c
rename foo {}
set res
-} -result {{watch rc* write} {} {} TOCK {watch rc* {}}}
+} -result {{watch rc* write} {} TOCK {} {watch rc* {}}}
test iocmd-31.8 {chan postevent after close throws error} -match glob -setup {
proc foo {args} {oninit; onfinal; track; return}
proc dummy args { return }
@@ -2089,31 +2078,6 @@ test iocmd-31.8 {chan postevent after close throws error} -match glob -setup {
rename foo {}
rename dummy {}
} -returnCodes error -result {can not find reflected channel named "rc*"}
-test iocmd-31.9 {
- chan postevent
-
- call to current coroutine
-
- see 67a5eabbd3d1
-} -match glob -body {
- set res {}
- proc foo {args} {oninit; onwatch; onfinal; track; return}
- set c [chan create {r w} foo]
- after 0 [list ::apply [list c {
- coroutine c1 ::apply [list c {
- chan event $c readable [list [info coroutine]]
- yield
- set ::done READING
- } [namespace current]] $c
- } [namespace current]] $c]
- set stop [after 10000 {set done TIMEOUT}]
- vwait ::done
- catch {after cancel $stop}
- lappend res $done
- close $c
- rename foo {}
- set res
-} -result {{watch rc* read} READING {watch rc* {}}}
# --- === *** ###########################
# 'Pull the rug' tests. Create channel in a interpreter A, move to