Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Rebase to 9.0 |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | bug-18f4a94d03 |
Files: | files | file ages | folders |
SHA3-256: |
4594340282fcf51e7a1ea1659357008d |
User & Date: | jan.nijtmans 2024-04-30 11:51:20 |
Context
2024-04-30
| ||
11:51 | Rebase to 9.0 Leaf check-in: 4594340282 user: jan.nijtmans tags: bug-18f4a94d03 | |
2024-04-29
| ||
11:53 | Eliminate warnings in tclTest(Obj).c, caused by our -Wc++-compat flag. check-in: f21c1c01d1 user: jan.nijtmans tags: trunk, main | |
2024-04-22
| ||
20:19 | Rebase to 9.0 check-in: 3b005a2c2d user: jan.nijtmans tags: bug-18f4a94d03 | |
Changes
Changes to generic/tclIO.c.
︙ | ︙ | |||
163 164 165 166 167 168 169 | static int CheckChannelErrors(ChannelState *statePtr, int direction); static int CheckForDeadChannel(Tcl_Interp *interp, ChannelState *statePtr); static void CheckForStdChannelsBeingClosed(Tcl_Channel chan); static void CleanupChannelHandlers(Tcl_Interp *interp, Channel *chanPtr); | < | 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | static int CheckChannelErrors(ChannelState *statePtr, int direction); static int CheckForDeadChannel(Tcl_Interp *interp, ChannelState *statePtr); static void CheckForStdChannelsBeingClosed(Tcl_Channel chan); static void CleanupChannelHandlers(Tcl_Interp *interp, Channel *chanPtr); static int CloseChannel(Tcl_Interp *interp, Channel *chanPtr, int errorCode); static int CloseChannelPart(Tcl_Interp *interp, Channel *chanPtr, int errorCode, int flags); static int CloseWrite(Tcl_Interp *interp, Channel *chanPtr); static void CommonGetsCleanup(Channel *chanPtr); static int CopyData(CopyState *csPtr, int mask); |
︙ | ︙ | |||
3499 3500 3501 3502 3503 3504 3505 | TclDecrRefCount(statePtr->chanMsg); statePtr->chanMsg = NULL; } } Tcl_ClearChannelHandlers(chan); | < < < < < | 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 | TclDecrRefCount(statePtr->chanMsg); statePtr->chanMsg = NULL; } } Tcl_ClearChannelHandlers(chan); /* * Invoke the registered close callbacks and delete their records. */ while (statePtr->closeCbPtr != NULL) { cbPtr = statePtr->closeCbPtr; statePtr->closeCbPtr = cbPtr->nextPtr; |
︙ | ︙ | |||
8624 8625 8626 8627 8628 8629 8630 | static void UpdateInterest( Channel *chanPtr) /* Channel to update. */ { ChannelState *statePtr = chanPtr->state; /* State info for channel */ | < | 8618 8619 8620 8621 8622 8623 8624 8625 8626 8627 8628 8629 8630 8631 | static void UpdateInterest( Channel *chanPtr) /* Channel to update. */ { ChannelState *statePtr = chanPtr->state; /* State info for channel */ int mask = statePtr->interestMask; if (chanPtr->typePtr == NULL) { /* Do not update interest on a closed channel */ return; } |
︙ | ︙ | |||
8702 8703 8704 8705 8706 8707 8708 | TclChannelPreserve((Tcl_Channel)chanPtr); statePtr->timerChanPtr = chanPtr; statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME, ChannelTimerProc, chanPtr); } } } | < < < < < < < < < < < < < < | 8695 8696 8697 8698 8699 8700 8701 8702 8703 8704 8705 8706 8707 8708 | TclChannelPreserve((Tcl_Channel)chanPtr); statePtr->timerChanPtr = chanPtr; statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME, ChannelTimerProc, chanPtr); } } } ChanWatch(chanPtr, mask); } /* *---------------------------------------------------------------------- * * ChannelTimerProc -- |
︙ | ︙ | |||
8744 8745 8746 8747 8748 8749 8750 | ChannelTimerProc( void *clientData) { Channel *chanPtr = (Channel *)clientData; /* State info for channel */ ChannelState *statePtr = chanPtr->state; | < < < < < < | > > | < | | | < < < < < < < < < < < < | < < | > | | | < < > | | < < < < < < < | < | < | > | 8723 8724 8725 8726 8727 8728 8729 8730 8731 8732 8733 8734 8735 8736 8737 8738 8739 8740 8741 8742 8743 8744 8745 8746 8747 8748 8749 8750 8751 8752 8753 8754 8755 8756 8757 8758 8759 8760 8761 8762 8763 8764 8765 8766 8767 8768 8769 8770 8771 8772 8773 8774 | ChannelTimerProc( void *clientData) { Channel *chanPtr = (Channel *)clientData; /* State info for channel */ ChannelState *statePtr = chanPtr->state; if (chanPtr->typePtr == NULL) { statePtr->timer = NULL; 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_Preserve(statePtr); Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_READABLE); Tcl_Release(statePtr); } else { statePtr->timer = NULL; UpdateInterest(chanPtr); TclChannelRelease((Tcl_Channel)statePtr->timerChanPtr); statePtr->timerChanPtr = NULL; } } } static void DeleteTimerHandler( ChannelState *statePtr ) { if (statePtr->timer != NULL) { Tcl_DeleteTimerHandler(statePtr->timer); statePtr->timer = NULL; TclChannelRelease((Tcl_Channel)statePtr->timerChanPtr); statePtr->timerChanPtr = NULL; } } /* *---------------------------------------------------------------------- * * Tcl_CreateChannelHandler -- * |
︙ | ︙ |
Changes to generic/tclIORChan.c.
︙ | ︙ | |||
50 51 52 53 54 55 56 | Tcl_Interp *interp, const char *optionName, Tcl_DString *dsPtr); static int ReflectSetOption(void *clientData, Tcl_Interp *interp, const char *optionName, const char *newValue); static int ReflectTruncate(void *clientData, long long length); | < < | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | Tcl_Interp *interp, const char *optionName, Tcl_DString *dsPtr); static int ReflectSetOption(void *clientData, Tcl_Interp *interp, const char *optionName, const char *newValue); static int ReflectTruncate(void *clientData, long long length); /* * The C layer channel type/driver definition used by the reflection. */ static const Tcl_ChannelType tclRChannelType = { "tclrchannel", /* Type name. */ |
︙ | ︙ | |||
109 110 111 112 113 114 115 | int mode; /* Mask of R/W mode */ int interest; /* Mask of events the channel is interested * in. */ int dead; /* Boolean signal that some operations * should no longer be attempted. */ | < < < < < < < < < < < > > | > | < | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | int mode; /* Mask of R/W mode */ 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. * * Most channel implementations need a timer in the C level to ensure that * data in buffers is flushed out through the generation of fake file * events. * * See 'refchan', 'memchan', etc. * * 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 * channels. Each interpreter which has the handler command for one or more * reflected channels records them in such a table, so that 'chan postevent' |
︙ | ︙ | |||
945 946 947 948 949 950 951 | /* * We have the channel and the events to post. */ #if TCL_THREADS if (rcPtr->owner == rcPtr->thread) { #endif | | < < < < < < < < < < < | 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 | /* * We have the channel and the events to post. */ #if TCL_THREADS if (rcPtr->owner == rcPtr->thread) { #endif Tcl_NotifyChannel(chan, events); #if TCL_THREADS } else { ReflectEvent *ev = (ReflectEvent *)Tcl_Alloc(sizeof(ReflectEvent)); ev->header.proc = ReflectEventRun; ev->events = events; ev->rcPtr = rcPtr; |
︙ | ︙ | |||
1003 1004 1005 1006 1007 1008 1009 | Tcl_ResetResult(interp); return TCL_OK; #undef CHAN #undef EVENT } | < < < < < < < < < < < < < < < < < < | 981 982 983 984 985 986 987 988 989 990 991 992 993 994 | Tcl_ResetResult(interp); return TCL_OK; #undef CHAN #undef EVENT } /* * Channel error message marshalling utilities. */ static Tcl_Obj * MarshallError( |
︙ | ︙ | |||
1220 1221 1222 1223 1224 1225 1226 | #endif tctPtr = ((Channel *)rcPtr->chan)->typePtr; if (tctPtr && tctPtr != &tclRChannelType) { Tcl_Free((void *)tctPtr); ((Channel *)rcPtr->chan)->typePtr = NULL; } | < < < < < < | 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 | #endif tctPtr = ((Channel *)rcPtr->chan)->typePtr; if (tctPtr && tctPtr != &tclRChannelType) { Tcl_Free((void *)tctPtr); ((Channel *)rcPtr->chan)->typePtr = NULL; } Tcl_EventuallyFree(rcPtr, FreeReflectedChannel); return EOK; } /* * Are we in the correct thread? */ |
︙ | ︙ | |||
1295 1296 1297 1298 1299 1300 1301 | } #endif tctPtr = ((Channel *)rcPtr->chan)->typePtr; if (tctPtr && tctPtr != &tclRChannelType) { Tcl_Free((void *)tctPtr); ((Channel *)rcPtr->chan)->typePtr = NULL; } | < < < < < < | 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 | } #endif tctPtr = ((Channel *)rcPtr->chan)->typePtr; if (tctPtr && tctPtr != &tclRChannelType) { Tcl_Free((void *)tctPtr); ((Channel *)rcPtr->chan)->typePtr = NULL; } Tcl_EventuallyFree(rcPtr, FreeReflectedChannel); return (result == TCL_OK) ? EOK : EINVAL; } /* *---------------------------------------------------------------------- * |
︙ | ︙ | |||
2249 2250 2251 2252 2253 2254 2255 | rcPtr = (ReflectedChannel *)Tcl_Alloc(sizeof(ReflectedChannel)); /* rcPtr->chan: Assigned by caller. Dummy data here. */ rcPtr->chan = NULL; rcPtr->interp = interp; rcPtr->dead = 0; | < < | 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 | rcPtr = (ReflectedChannel *)Tcl_Alloc(sizeof(ReflectedChannel)); /* rcPtr->chan: Assigned by caller. Dummy data here. */ rcPtr->chan = NULL; rcPtr->interp = interp; rcPtr->dead = 0; #if TCL_THREADS rcPtr->thread = Tcl_GetCurrentThread(); #endif rcPtr->mode = mode; rcPtr->interest = 0; /* Initially no interest registered */ rcPtr->cmd = TclListObjCopy(NULL, cmdpfxObj); |
︙ | ︙ |
Changes to tests/ioCmd.test.
︙ | ︙ | |||
967 968 969 970 971 972 973 | return -code return $args } proc onfinal {} { upvar args hargs if {[lindex $hargs 0] ne "finalize"} {return} return -code return "" } | < < < < < < < < < < < | 967 968 969 970 971 972 973 974 975 976 977 978 979 980 | return -code return $args } proc onfinal {} { upvar args hargs if {[lindex $hargs 0] ne "finalize"} {return} return -code return "" } } # Set everything up in the main thread. eval $helperscript # --- --- --- --------- --------- --------- # method finalize |
︙ | ︙ | |||
2059 2060 2061 2062 2063 2064 2065 | set stop [after 15000 {lappend res TIMEOUT; set tock 1}] after 1000 {note [chan postevent $c r]} vwait ::tock catch {after cancel $stop} close $c rename foo {} set res | | | < < < < < < < < < < < < < < < < < < < < < < < < < | 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 | set stop [after 15000 {lappend res TIMEOUT; set tock 1}] after 1000 {note [chan postevent $c r]} vwait ::tock catch {after cancel $stop} close $c rename foo {} set res } -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} set c [chan create {r w} foo] note [fileevent $c writable {lappend res TOCK; set tock 1}] set stop [after 15000 {lappend res TIMEOUT; set tock 1}] after 1000 {note [chan postevent $c w]} vwait ::tock catch {after cancel $stop} close $c rename foo {} set res } -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 } set c [chan create {r w} foo] fileevent $c readable dummy } -body { close $c chan postevent $c read } -cleanup { rename foo {} rename dummy {} } -returnCodes error -result {can not find reflected channel named "rc*"} # --- === *** ########################### # 'Pull the rug' tests. Create channel in a interpreter A, move to # other interpreter B, destroy the origin interpreter (A) before or # during access from B. Must not crash, must return proper errors. test iocmd-32.0 {origin interpreter of moved channel gone} -match glob -body { |
︙ | ︙ |