Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Quick question about the event loop

61 views
Skip to first unread message

Andrew Falanga

unread,
May 21, 2007, 11:22:48 AM5/21/07
to
Hi,

I'm working on a script which will have to rely heavily on the event
loop using vwait. Not having much experience with the event loop, I
have one very simple question (actually, I guess I have two
questions).

1) If two events occur "simultaneously," do the event handlers get
called simultaneously, or linearly? I realize that events most likely
never occur at the same time, but what about "virtually" the same
time.

2) When an event occurs and the handler is called, is the event loop
exited to process the event? I guess I'm wondering if an event occurs
while one is already being processed, will the second event block
until the first is completed processing, or will the second event be
handled when it occurs?

Thanks,
Andy

Alexandre Ferrieux

unread,
May 21, 2007, 12:04:03 PM5/21/07
to
On May 21, 5:22 pm, Andrew Falanga <af300...@gmail.com> wrote:
>
> 1) If two events occur "simultaneously," do the event handlers get
> called simultaneously, or linearly?

Linearly, that is, sequentially.
All vwait does is (approximately):

while (1) fetch_one_event_and_call_its_handler();

> 2) When an event occurs and the handler is called, is the event loop
> exited to process the event?

Not "exited", but "up the stack", hence waiting until we return.


> I guess I'm wondering if an event occurs
> while one is already being processed, will the second event block
> until the first is completed processing, or will the second event be
> handled when it occurs?

The second event will be dequeued and handled only after the first
handler has returned.

Bottom line: don't worry, Tcl is as single-threaded as can be, as long
as you don't use the Thread package. Vwait is design exactly for this:
do many brilliant asynchronous things, without any reentrance/deadlock
nightmare.

You're on the good track by the way. Many a newcomer starts talking
about threads before even learning about [vwait]. Congrats !

-Alex


Bryan Oakley

unread,
May 21, 2007, 12:59:10 PM5/21/07
to

All of that is correct, but I'd say that unless you *really* understand
the event loop, never call vwait more than zero or one times. Zero if
you're running wish, once if you're running tclsh.

Like Alexandre explained, the event loops is just that -- a loop. It's
not some mysterious multi-threaded beast. It's really no different
conceptually than:

while {1} {
get the next event
process the next event
}

Realize that if "process the next event" includes a vwait, your code now
looks like this:

while {1} {
get the next event
while {1} {
get the next event
process the next event
}
}

In other words, each call to "vwait" in effect creates a new
(potentially) infinite loop. Each of these loops can only be terminated
in reverse order (last one first). These loops do *not* run in parallel.
Only after the inner-most vwait terminates can the next higher loop
continue.


--
Bryan Oakley
http://www.tclscripting.com

Neil Madden

unread,
May 21, 2007, 12:55:09 PM5/21/07
to
Alexandre Ferrieux wrote:
...

>> I guess I'm wondering if an event occurs
>> while one is already being processed, will the second event block
>> until the first is completed processing, or will the second event be
>> handled when it occurs?
>
> The second event will be dequeued and handled only after the first
> handler has returned.
>
> Bottom line: don't worry, Tcl is as single-threaded as can be, as long
> as you don't use the Thread package. Vwait is design exactly for this:
> do many brilliant asynchronous things, without any reentrance/deadlock
> nightmare.
...

The main gotcha to look out for is re-entering the event loop.
Basically, your event handlers should never call [vwait] or [tkwait] or
[update] or any command which calls one of these (such as most of the
tk_* commands that pop up dialogs). There is advice on the wiki about
how to restructure an application to avoid this: http://wiki.tcl.tk/1255

Otherwise, you can assume that each event handler runs to completion as
an atomic action.

-- Neil

Cameron Laird

unread,
May 21, 2007, 1:49:43 PM5/21/07
to
In article <f2site$9n7$1...@oyez.ccc.nottingham.ac.uk>,

Neil Madden <n...@cs.nott.ac.uk> wrote:
>...
>
>The main gotcha to look out for is re-entering the event loop.
>Basically, your event handlers should never call [vwait] or [tkwait] or
>[update] or any command which calls one of these (such as most of the
>tk_* commands that pop up dialogs). There is advice on the wiki about
>how to restructure an application to avoid this: http://wiki.tcl.tk/1255
.
.
.
... such a "gotcha" that we sometimes simplify this to,
"you don't need [update], and you need at most one [vwait]."
While that's not entirely true, it helps focus attention in
productive directions.

Darren New

unread,
May 21, 2007, 8:29:25 PM5/21/07
to
Neil Madden wrote:
> The main gotcha to look out for is re-entering the event loop.
> Basically, your event handlers should never call [vwait] or [tkwait] or
> [update] or any command which calls one of these

Unfortunately, a number of the useful packages in Tcllib call these for
you. (http, smtp, etc) If there were a way to time-out a socket call
without using the event loop, it would help in these cases, IME.

--
Darren New / San Diego, CA, USA (PST)
His kernel fu is strong.
He studied at the Shao Linux Temple.

Alexandre Ferrieux

unread,
May 22, 2007, 4:36:27 AM5/22/07
to
On May 22, 2:29 am, Darren New <d...@san.rr.com> wrote:
>
> [...] If there were a way to time-out a socket call

> without using the event loop, it would help in these cases, IME.

You're right that something's missing there.

But I don't think it is "without using the event loop". Indeed, it
would be a shame to force the http package to implement a timeout
*without* after+fileevent (because it would be forced to redo it in C
-- yuck !).

Instead, I think the real need is to temporarily disable all the
previous handlers:

vwaitadmin push
fileevent ...
after ...
vwait ::mypackage::mybreak ;# the nested one
vwaitadmin pop

Rationale for introducing a new primitive: currently, only fileevents
can be introspected in pure Tcl by iterating over [info channels], and
they are easy to enable/disable. Tk handlers are much harder to
enumerate (to say the least). And [after] handlers are just not
reachable, and even if we could enumerate them, we couldn't re-enable
them with the same ID after disabling them (which is mandatory because
the calling script may have stored the ID). Not even speaking about
other, exotic event sources like those in Snack...

But of course I realize this is not trivial to implement !

-Alex

Donal K. Fellows

unread,
May 22, 2007, 11:30:36 AM5/22/07
to
Alexandre Ferrieux wrote:
> Tk handlers are much harder to enumerate (to say the least).

But there's only one that matters: the (internal, hidden) fileevent on
the (internal, hidden) low-level X file descriptor. Disabling it is
easiest from C though for sure.

> And [after] handlers are just not reachable,

Actually, there's [after info]...

> and even if we could enumerate them, we couldn't re-enable
> them with the same ID after disabling them (which is mandatory because
> the calling script may have stored the ID).

Which is a proper objection.

> Not even speaking about
> other, exotic event sources like those in Snack...

Actually, those are file(descriptor)events, timer events, or direct
injections into the event queue in (indirect) response to one of the
other kind of events. If you want real exotic stuff, try messages from
other threads or signals...

Donal.

Darren New

unread,
May 22, 2007, 12:01:21 PM5/22/07
to
Alexandre Ferrieux wrote:
> Instead, I think the real need is to temporarily disable all the
> previous handlers:

While that's a fairly simple solution compared to mine, I think an even
better solution would be to have continuations. A command that would do
just what vwait does now *without* nesting would be another useful
addition. (Altho, honestly, in the particular case biting me right now,
I'm not sure it would be all that helpful.)

In any case, some way of returning to the top-level event loop in the
middle of something without having to turn all your code inside out
manually would be a great addition too. I don't expect this will ever
happen, given that I can't imagine how to do it without breaking the
integration with C.

Alexandre Ferrieux

unread,
May 22, 2007, 3:18:58 PM5/22/07
to
On May 22, 5:30 pm, "Donal K. Fellows"

<donal.k.fell...@manchester.ac.uk> wrote:
> Alexandre Ferrieux wrote:
> > Tk handlers are much harder to enumerate (to say the least).
>
> But there's only one that matters: the (internal, hidden) fileevent on
> the (internal, hidden) low-level X file descriptor. Disabling it is
> easiest from C though for sure.

Except on Windows it's not a file descriptor ;-)

> > And [after] handlers are just not reachable,
>
> Actually, there's [after info]...

Oops -- long time since I last checked those new goodies !

> > and even if we could enumerate them, we couldn't re-enable
> > them with the same ID after disabling them (which is mandatory because
> > the calling script may have stored the ID).
>
> Which is a proper objection.

Yessss

>
> > Not even speaking about
> > other, exotic event sources like those in Snack...
>
> Actually, those are file(descriptor)events, timer events, or direct
> injections into the event queue in (indirect) response to one of the
> other kind of events. If you want real exotic stuff, try messages from
> other threads or signals...

Well, exotic or not, we still don't have a way of frrezing them
today ...
I'd happily TIP for [vwaitadmin] if there were a tad more demand.
Darren ?

-Alex

Darren New

unread,
May 22, 2007, 6:47:38 PM5/22/07
to
Alexandre Ferrieux wrote:
> I'd happily TIP for [vwaitadmin] if there were a tad more demand.
> Darren ?

I have the work-arounds for what I'm doing, and as I can't really even
use 8.5 conviently yet, any actual "demand" I have for this would be
problematic.

I think if you work it out, you have to make it work with existing
libraries. I.e., you should be able to wrap up the http and/or smtp
calls with the new command, so you don't have to change http or smtp to
make it work the way you want. (From what I can tell, your proposal does
this already, but it's hard to be sure without thinking about it a whole
bunch.)

But yes, thinking on it, a convenient way to suspend all current events
would be useful. Questions are likely to come up with multiple
vwaitadmin push calls, what happens if you do

vwaitadmin push
fileevent ...
vwaitadmin pop
(is the fileevent still around?)
vwaitadmin push
(is the fileevent disabled now?)

I think the simple answers would work, but again I'd have to think about
it a whole bunch. Possibly adding sufficient introspection to stuff that
this can be done at the command level as a library might be better...
Difficult with Tk, I'd think. I mostly write servers, so all the
Tk-based stuff isn't something I've had problems with.

Alexandre Ferrieux

unread,
May 22, 2007, 7:10:07 PM5/22/07
to
On May 23, 12:47 am, Darren New <d...@san.rr.com> wrote:
> [...] so you don't have to change http or smtp to

> make it work the way you want. (From what I can tell, your proposal does
> this already, but it's hard to be sure without thinking about it a whole
> bunch.)

Yes, this transparency is the exact purpose of my proposal.
The idea is that between a push/pop pair, you have a clear slate,
exactly like on interp init.
All previously registered handlers are "frozen", but reactivated when
you cross the "pop".

>
> Questions are likely to come up with multiple
> vwaitadmin push calls, what happens if you do
>
> vwaitadmin push
> fileevent ...
> vwaitadmin pop
> (is the fileevent still around?)

No. The handler state is restored as it was before the push.
(with possible delayed-removal of fileevents whose channels have been
closed between push and pop)

> vwaitadmin push
> (is the fileevent disabled now?)

Which fileevent ? ;-)
The slate is empty here.

> I think the simple answers would work, but again I'd have to think about
> it a whole bunch. Possibly adding sufficient introspection to stuff that
> this can be done at the command level as a library might be better...

Yes, I had thought about this too. I would also have preferred the
introspection method, because it allows to write much less in C and
much more in Tcl, however it adds a big load of complexity because it
implies to invent a script-level representation for handlers which are
internal (like Windows Event objects or hidden /dev/dsp file
descriptor in Snack, or the equally hidden X11 socket fd); and as
mentioned above, to make it worse, even already scriptable handlers
like [after] are currently not "freezable"...

While a more traditional, monolithic C implementation would simply
juggle the pointers to (a stack of) saved and current list-of-event-
sources (off the top of my hat -- currently I'm ignorant of all the
details)...

-Alex


Alexandre Ferrieux

unread,
May 22, 2007, 7:10:29 PM5/22/07
to
On May 23, 12:47 am, Darren New <d...@san.rr.com> wrote:
> [...] so you don't have to change http or smtp to

> make it work the way you want. (From what I can tell, your proposal does
> this already, but it's hard to be sure without thinking about it a whole
> bunch.)

Yes, this transparency is the exact purpose of my proposal.


The idea is that between a push/pop pair, you have a clear slate,
exactly like on interp init.
All previously registered handlers are "frozen", but reactivated when
you cross the "pop".

>


> Questions are likely to come up with multiple
> vwaitadmin push calls, what happens if you do
>
> vwaitadmin push
> fileevent ...
> vwaitadmin pop
> (is the fileevent still around?)

No. The handler state is restored as it was before the push.


(with possible delayed-removal of fileevents whose channels have been
closed between push and pop)

> vwaitadmin push


> (is the fileevent disabled now?)

Which fileevent ? ;-)


The slate is empty here.

> I think the simple answers would work, but again I'd have to think about


> it a whole bunch. Possibly adding sufficient introspection to stuff that
> this can be done at the command level as a library might be better...

Yes, I had thought about this too. I would also have preferred the

Alexandre Ferrieux

unread,
May 22, 2007, 7:10:53 PM5/22/07
to
On May 23, 12:47 am, Darren New <d...@san.rr.com> wrote:
> [...] so you don't have to change http or smtp to

> make it work the way you want. (From what I can tell, your proposal does
> this already, but it's hard to be sure without thinking about it a whole
> bunch.)

Yes, this transparency is the exact purpose of my proposal.


The idea is that between a push/pop pair, you have a clear slate,
exactly like on interp init.
All previously registered handlers are "frozen", but reactivated when
you cross the "pop".

>


> Questions are likely to come up with multiple
> vwaitadmin push calls, what happens if you do
>
> vwaitadmin push
> fileevent ...
> vwaitadmin pop
> (is the fileevent still around?)

No. The handler state is restored as it was before the push.


(with possible delayed-removal of fileevents whose channels have been
closed between push and pop)

> vwaitadmin push


> (is the fileevent disabled now?)

Which fileevent ? ;-)


The slate is empty here.

> I think the simple answers would work, but again I'd have to think about


> it a whole bunch. Possibly adding sufficient introspection to stuff that
> this can be done at the command level as a library might be better...

Yes, I had thought about this too. I would also have preferred the

Alexandre Ferrieux

unread,
May 22, 2007, 7:10:59 PM5/22/07
to
On May 23, 12:47 am, Darren New <d...@san.rr.com> wrote:
> [...] so you don't have to change http or smtp to

> make it work the way you want. (From what I can tell, your proposal does
> this already, but it's hard to be sure without thinking about it a whole
> bunch.)

Yes, this transparency is the exact purpose of my proposal.


The idea is that between a push/pop pair, you have a clear slate,
exactly like on interp init.
All previously registered handlers are "frozen", but reactivated when
you cross the "pop".

>


> Questions are likely to come up with multiple
> vwaitadmin push calls, what happens if you do
>
> vwaitadmin push
> fileevent ...
> vwaitadmin pop
> (is the fileevent still around?)

No. The handler state is restored as it was before the push.


(with possible delayed-removal of fileevents whose channels have been
closed between push and pop)

> vwaitadmin push


> (is the fileevent disabled now?)

Which fileevent ? ;-)


The slate is empty here.

> I think the simple answers would work, but again I'd have to think about


> it a whole bunch. Possibly adding sufficient introspection to stuff that
> this can be done at the command level as a library might be better...

Yes, I had thought about this too. I would also have preferred the

Darren New

unread,
May 22, 2007, 7:37:06 PM5/22/07
to
Alexandre Ferrieux wrote:
>> vwaitadmin push
>> fileevent ...
>> vwaitadmin pop
>> (is the fileevent still around?)
>
> No. The handler state is restored as it was before the push.

See, I'm not sure that's reasonable. If I put in a fileevent that you
don't even realize is in there, I wouldn't want it turned off again. I
don't want "pop" to restore the previous state. I want it to reenable
what "push" turned off, without disabling anything new, for example.

If I call [pack] between push and pop, and then call vwaitadmin pop
before I return, I don't want to update idletasks there lost, do I? I
don't want [after] handlers started between push and pop to disappear
when I do a pop. That wouldn't make sense to me.

> (with possible delayed-removal of fileevents whose channels have been
> closed between push and pop)

I suspect there are a bunch more things like that. Widgets deleted?

>> vwaitadmin push
>> (is the fileevent disabled now?)
>
> Which fileevent ? ;-)
> The slate is empty here.

Right. I meant, a second call to "push" doesn't reenable what was
enabled in the previous call to push. Logical, but something you'd have
to think about, or at least document. (Not everyone thinks the same way
about these things.)

Donal K. Fellows

unread,
May 23, 2007, 4:17:57 AM5/23/07
to
Alexandre Ferrieux wrote:
> Yes, this transparency is the exact purpose of my proposal.
> The idea is that between a push/pop pair, you have a clear slate,
> exactly like on interp init.
> All previously registered handlers are "frozen", but reactivated when
> you cross the "pop".

That's error-prone. Better to have it so that the magical command takes
a script argument and runs that script with all handlers defined before
it starts disabled, re-enabling them when the script terminates. For
why, see the analogy from SQLite with transactions:

$db eval {BEGIN TRANSACTION}
set code [catch {
...
$db eval ...
...
} error]
if {$code == 1} {
$db eval {ROLLBACK TRANSACTION}
error $error
} else {
$db eval {COMMIT TRANSACTION}
# Note that this is flaky; see sqlite docs for why
}

vs:

$db transaction {
...
$db eval ...
...
}

(For those of you with C++ experience, this is exactly like RAII. Except
with syntax that doesn't suck.)

Donal.

Neil Madden

unread,
May 23, 2007, 8:27:58 AM5/23/07
to
Donal K. Fellows wrote:
> Alexandre Ferrieux wrote:
>> Yes, this transparency is the exact purpose of my proposal.
>> The idea is that between a push/pop pair, you have a clear slate,
>> exactly like on interp init.
>> All previously registered handlers are "frozen", but reactivated when
>> you cross the "pop".
>
> That's error-prone. Better to have it so that the magical command takes
> a script argument and runs that script with all handlers defined before
> it starts disabled, re-enabling them when the script terminates.
...

Agreed. This is a much nicer interface. The existing [vwait] command
could be extended to support this:

vwait name ?script?

With the script argument it suspends the current event loop and starts a
new one (a new notifier/event queue). All event sources created within
the script are created on the new event queue. The event loop then runs
on the new queue until the variable is set, at which point the new
notifier is destroyed (along with all new event sources) and the old one
reinstated.

An alternative would be to make an event queue/notifier a first-class
object at the Tcl level so that you can do something like:

set q [event queue]
$q chan event $sock readable ...
$q vwait myvar ;# loop on this event queue only

Do slave interps have their own event queues? Or is it just threads?

-- Neil

Donal K. Fellows

unread,
May 23, 2007, 10:37:55 AM5/23/07
to
Neil Madden wrote:
> Do slave interps have their own event queues? Or is it just threads?

Event queues are per-thread.

Donal.

Alexandre Ferrieux

unread,
May 23, 2007, 11:39:38 AM5/23/07
to
On May 23, 1:37 am, Darren New <d...@san.rr.com> wrote:
>
> > No. The handler state is restored as it was before the push.
>
> See, I'm not sure that's reasonable. If I put in a fileevent that you
> don't even realize is in there, I wouldn't want it turned off again. I
> don't want "pop" to restore the previous state. I want it to reenable
> what "push" turned off, without disabling anything new, for example.

That's your way of seeing it; it is different, and more complicated to
implement since you have to merge lists of handlers, while mine just
has to juggle the [event queue] objects suggested by Neil.

> If I call [pack] between push and pop, and then call vwaitadmin pop
> before I return, I don't want to update idletasks there lost, do I? I

The idea behind this was more to put small atomic things between push
and pop, like the async socket with timeout of your http example; not
intended for heavyweight Tk fiddling...

> don't want [after] handlers started between push and pop to disappear
> when I do a pop. That wouldn't make sense to me.

Same remark. Your aim seems to be different after all. Not surprising
our specs diverge.

-Alex

Alexandre Ferrieux

unread,
May 23, 2007, 11:42:05 AM5/23/07
to
On May 23, 10:17 am, "Donal K. Fellows"

<donal.k.fell...@manchester.ac.uk> wrote:
> Alexandre Ferrieux wrote:
> > All previously registered handlers are "frozen", but reactivated when
> > you cross the "pop".
>
> That's error-prone. Better to have it so that the magical command takes
> a script argument ...

Sure. I only wanted to focus on the core primitive, without
immediately coupling it with an eval/uplevel... But granted, this is
superior from the user's standpoint.

-Alex

Alexandre Ferrieux

unread,
May 23, 2007, 11:42:54 AM5/23/07
to
On May 23, 10:17 am, "Donal K. Fellows"
<donal.k.fell...@manchester.ac.uk> wrote:
> Alexandre Ferrieux wrote:
> > All previously registered handlers are "frozen", but reactivated when
> > you cross the "pop".
>
> That's error-prone. Better to have it so that the magical command takes

Alexandre Ferrieux

unread,
May 23, 2007, 11:44:22 AM5/23/07
to
On May 23, 10:17 am, "Donal K. Fellows"
<donal.k.fell...@manchester.ac.uk> wrote:
> Alexandre Ferrieux wrote:
> > All previously registered handlers are "frozen", but reactivated when
> > you cross the "pop".
>
> That's error-prone. Better to have it so that the magical command takes

Alexandre Ferrieux

unread,
May 23, 2007, 11:45:36 AM5/23/07
to
On May 23, 10:17 am, "Donal K. Fellows"
<donal.k.fell...@manchester.ac.uk> wrote:
> Alexandre Ferrieux wrote:
> > All previously registered handlers are "frozen", but reactivated when
> > you cross the "pop".
>
> That's error-prone. Better to have it so that the magical command takes

Darren New

unread,
May 23, 2007, 12:46:23 PM5/23/07
to
Alexandre Ferrieux wrote:
> That's your way of seeing it; it is different, and more complicated to
> implement since you have to merge lists of handlers, while mine just
> has to juggle the [event queue] objects suggested by Neil.

Oh, I was thinking perhaps you'd have a flag on each event source that
says whether you actually invoke what it's supposed to fire or not.
I.e., disable or enable the event source, skipping over disabled ones,
like [update idle] skips over non-idle events. Then push would disable
all enabled events and remember which those were, and pop would just
reenable those it disabled.

>> If I call [pack] between push and pop, and then call vwaitadmin pop
>> before I return, I don't want to update idletasks there lost, do I? I
>
> The idea behind this was more to put small atomic things between push
> and pop, like the async socket with timeout of your http example; not
> intended for heavyweight Tk fiddling...

Right.

>> don't want [after] handlers started between push and pop to disappear
>> when I do a pop. That wouldn't make sense to me.
>
> Same remark. Your aim seems to be different after all. Not surprising
> our specs diverge.

That's my aim too. I just think it's more robust if my library doesn't
mysteriously stop working simply because someone else made an "atomic"
event.

Consider this example:
I send a mail message. The library I use to do this leaves the socket to
the mail server open, with a file-event that watches for the remote side
to close the socket (due to a timeout) and cleans up its local internal
state if that happens. Like a PHP "persistant" connection. Now, the
caller wraps things up, sends a message, and then unwraps. The mail
library stops cleaning up internal state when the remote server closes
the socket. I can't even imagine how you'd begin to track down such a
memory leak, let alone cure it easily.

I think a better design would be "pause all event sources now set up,
don't trigger anything I'm not expecting, and run that stuff. Then, when
I say so, unpause all the stuff I put on hold." Rather than "reset the
state of the world".

Darren New

unread,
May 23, 2007, 12:53:23 PM5/23/07
to
Alexandre Ferrieux wrote:
> That's your way of seeing it; it is different, and more complicated to
> implement since you have to merge lists of handlers, while mine just
> has to juggle the [event queue] objects suggested by Neil.

To phrase it a different way...

I think tipping something that is more error prone and more difficult to
use simply because it's easier to implement isn't really in the Tcl
spirit of things. I'm also not convinced it's particularly easier to
implement. (Of course, if you already have in mind how to implement it,
you might have to rethink from scratch to make it easy.)

What, other than being easier to implement, is the benefit of throwing
away new events when you pop the vwait? What kind of problem does it solve?

Alexandre Ferrieux

unread,
May 23, 2007, 3:56:24 PM5/23/07
to
On May 23, 10:17 am, "Donal K. Fellows"
<donal.k.fell...@manchester.ac.uk> wrote:
> Alexandre Ferrieux wrote:
> > All previously registered handlers are "frozen", but reactivated when
> > you cross the "pop".
>
> That's error-prone. Better to have it so that the magical command takes

Alexandre Ferrieux

unread,
May 23, 2007, 4:54:56 PM5/23/07
to
On May 23, 2:27 pm, Neil Madden <n...@cs.nott.ac.uk> wrote:
>
> ... The existing [vwait] command

> could be extended to support this:
>
> vwait name ?script?
>

Neil, this is Maddenly elegant !

While we're at it, in addition to the list of event sources, the
environment of [vwait] also contains [bgerror].
When a package uses your nested [vwait name {...}], it is also likely
that any error within a handler will better be routed to a package-
specific bgerror, rather than the one of the caller. Then, what about

vwait varname script bgscript

> An alternative would be to make an event queue/notifier a first-class
> object at the Tcl level so that you can do something like:

That's a possibility, but much lower level, and duplicating [vwait],
[fileevent] etc as methods of the queue objects. If they have the same
power (not checked), I'd personally prefer your first suggestion...

-Alex

Alexandre Ferrieux

unread,
May 23, 2007, 4:56:12 PM5/23/07
to
On May 23, 2:27 pm, Neil Madden <n...@cs.nott.ac.uk> wrote:
>
> ... The existing [vwait] command

> could be extended to support this:
>
> vwait name ?script?
>

Neil, this is Maddenly elegant !

While we're at it, in addition to the list of event sources, the
environment of [vwait] also contains [bgerror].
When a package uses your nested [vwait name {...}], it is also likely
that any error within a handler will better be routed to a package-
specific bgerror, rather than the one of the caller. Then, what about

vwait varname script bgscript

> An alternative would be to make an event queue/notifier a first-class


> object at the Tcl level so that you can do something like:

That's a possibility, but much lower level, and duplicating [vwait],

Alexandre Ferrieux

unread,
May 23, 2007, 5:16:26 PM5/23/07
to
On May 23, 2:27 pm, Neil Madden <n...@cs.nott.ac.uk> wrote:
>
> ... The existing [vwait] command

> could be extended to support this:
>
> vwait name ?script?
>

Neil, this is Maddenly elegant !

While we're at it, in addition to the list of event sources, the
environment of [vwait] also contains [bgerror].
When a package uses your nested [vwait name {...}], it is also likely
that any error within a handler will better be routed to a package-
specific bgerror, rather than the one of the caller. Then, what about

vwait varname script bgscript

> An alternative would be to make an event queue/notifier a first-class


> object at the Tcl level so that you can do something like:

That's a possibility, but much lower level, and duplicating [vwait],

Neil Madden

unread,
May 24, 2007, 9:49:45 AM5/24/07
to
Alexandre Ferrieux wrote:
> On May 23, 2:27 pm, Neil Madden <n...@cs.nott.ac.uk> wrote:
>> ... The existing [vwait] command
>> could be extended to support this:
>>
>> vwait name ?script?
>>
>
> Neil, this is Maddenly elegant !

Thank you. Hopefully this can form a TIP when the details are worked out
(although I don't have much time to work on it myself at the moment).
That said, given that 8.5 is in feature freeze at the moment, and IIRC
any 8.6 will be primarily for OO, I wonder if someone could comment on
what the prospects are for new project TIPs submitted now? Will they
have to wait for Tcl 9? Might these kinds of suggestions be better
logged as feature requests on the tracker for now?

-- Neil

Donal K. Fellows

unread,
May 24, 2007, 10:31:38 AM5/24/07
to
Neil Madden wrote:
> That said, given that 8.5 is in feature freeze at the moment, and IIRC
> any 8.6 will be primarily for OO, I wonder if someone could comment on
> what the prospects are for new project TIPs submitted now?

Their prospects depend almost entirely on whether someone does the work
to do an implementation. :-)

Donal.

Melissa Schrumpf

unread,
May 24, 2007, 9:45:26 PM5/24/07
to
Alexandre Ferrieux wrote:
> On May 22, 5:30 pm, "Donal K. Fellows" wrote:
> > Alexandre Ferrieux wrote:

> > Actually, there's [after info]...

> > > and even if we could enumerate them, we couldn't re-enable


> > > them with the same ID after disabling them (which is mandatory because
> > > the calling script may have stored the ID).
> >
> > Which is a proper objection.
>
> Yessss

But not insurmountable. Indirection, something like:

set ::AFTER_EVENTS(next) 0

proc afterHandle {} {
set next aft#$::AFTER_EVENTS(next)
incr ::AFTER_EVENTS(next)
if {$::AFTER_EVENTS(next)>0xffffffff} { set ::AFTER_EVENTS(next) 0 }
return AFT#$next
}

set myafter [afterHandle]
set ::AFTER_EVENTS($myafter) [after $time [list \
unset ::AFTER_EVENTS($myafter); $event $myafter]
...
#do something with stored event

If, somewhere else, you [after cancel] an event to restart it at a later
time, and want to restart it, just replace its entry in ::AFTER_EVENTS
with the new after#.

--
MKS

Alexandre Ferrieux

unread,
May 25, 2007, 9:59:22 AM5/25/07
to
On May 25, 3:45 am, Melissa Schrumpf
<m_schrumpf_at_yahoo_com_...@microsoft.com> wrote:

> Alexandre Ferrieux wrote:
> > > > there's [after info]...
> > > > and even if we could enumerate them, we couldn't re-enable
> > > > them with the same ID after disabling them (which is mandatory because
> > > > the calling script may have stored the ID).
>
>
> But not insurmountable. Indirection, [...]

The point was we're serious on not having to touch existing
scripts ;-)

-Alex

Darren New

unread,
May 25, 2007, 12:12:29 PM5/25/07
to
Alexandre Ferrieux wrote:
> Sure. I only wanted to focus on the core primitive, without
> immediately coupling it with an eval/uplevel... But granted, this is
> superior from the user's standpoint.

What actually is preventing this from being implemented in pure Tcl
right now? Other than [after] not allowing one to set which ID it
assigns to the event, is there anything else? The sources of events, at
the Tcl level, are [after], [fileevent], and [bind], yes? Would it be
sufficient to let [after] set the ID and simply have one configure-like
command that turns on or off all bindings?

Alexandre Ferrieux

unread,
May 25, 2007, 1:26:08 PM5/25/07
to
On May 25, 6:12 pm, Darren New <d...@san.rr.com> wrote:
> Alexandre Ferrieux wrote:
> > Sure. I only wanted to focus on the core primitive, without
> > immediately coupling it with an eval/uplevel... But granted, this is
> > superior from the user's standpoint.
>
> What actually is preventing this from being implemented in pure Tcl
> right now? Other than [after] not allowing one to set which ID it
> assigns to the event, is there anything else?

For this one, sure, we could override [after] so that it yields ids
from a faked naming space (with an array to link to the true ids). But
this would mean a performance hit for *all* [after]'s...

> The sources of events, at
> the Tcl level, are [after], [fileevent], and [bind], yes?

For those created by scripts, yes. But what about those created
internally in C by extensions ?
Not to speak of those which are not even fileevents nor GUI (the
notifier API allows that, e.g. event objects in Windows, like in
Snack)...

Because of this, to follow your approach, we'd at least need to expose
at script level each individual C event-source (not necessarily event
handler). I'm not saying this is impossible though. But as soon as C
is necessary, I prefer Donal+Neil's bullet-proof higher level API
(provided it allows to solve the same problems -- you may argue on
this).

-Alex

Darren New

unread,
May 25, 2007, 2:52:12 PM5/25/07
to
Alexandre Ferrieux wrote:
> For those created by scripts, yes. But what about those created
> internally in C by extensions ?

Yes, OK. It was, after all, a question and not a suggestion. :-)

> is necessary, I prefer Donal+Neil's bullet-proof higher level API
> (provided it allows to solve the same problems -- you may argue on
> this).

No argument. I was just trying to figure out if it was simple with a
tiny patch to make it work. I'd forgotten that C extensions can add
their own event sources.

In any case, I still think disabling new event sources when the callee
returns is a bad idea. Imagine if the callee ends with

toplevel .result
label .result.status -text "All Done!"
pack .result.status
return

You couldn't get rid of that window if you turned off the bindings.
Stuff like that is what I'm worried about.

Nuff said.

Alexandre Ferrieux

unread,
May 27, 2007, 10:25:04 AM5/27/07
to
On May 25, 8:52 pm, Darren New <d...@san.rr.com> wrote:
>
> In any case, I still think disabling new event sources when the callee
> returns is a bad idea. Imagine if the callee ends with
> [creating a non-transient widget]

> You couldn't get rid of that window if you turned off the bindings.
> Stuff like that is what I'm worried about.

Yes, you're right it doesn't fit. The problem with Tk is that a single
eventsource encompasses many things, while this freezing tool is
rather designed for pointwise sources like fileevents (Tk is just one
fileevent on X...).

But do you have a real need for this ?
For example, "modal dialogs" are implemented by restricting the
effects of mouse and keyboard events to a given widget hierarchy,
rather than truly disabling the bindings of other windows.
Your sample case sounds odd to me: why would you want to create some
perennial widget from within the event-freeze context ? (this context
being rather tailored to packages wanting to do some transient, hidden
asynchronous interaction, there yield back...)

-Alex

Darren New

unread,
May 27, 2007, 12:42:36 PM5/27/07
to
Alexandre Ferrieux wrote:
> But do you have a real need for this ?

Right now, I'm just discussing possibilities.

Another possibility is that someone writes code that starts up two event
sources (like fileevent and after, for a timeout), returns the results
upon the fileevent, and leaves the [after] running to clean up.

For example, you might have someone write an http GET command that
starts an [after] for a timeout and a [fileevent] to read the data,
returning a token. Then, instead of canceling the [after] when the
[fileevent] fires, the [after] is left to run and simply checks how much
it needs to do when it fires. If the [after] fires before the
[fileevent], it fills in the timeout structure and closes the socket, an
if it fires after, it simply cleans up anything specific to the [after]
handling, and if it fires after the user has already cleaned up the
token, it simply does nothing.

Or I have a routine to store something in a database, or send an email,
or query a remote server of whatever stripe, or start up a thread to
handle background processing, and if you don't call me back within N
seconds, I close the socket/thread/whatever and reopen it next time you
call. But you've wrapped up the call and turned off the event that would
eventually close the socket, because you didn't know I'd implemented
that efficiency improvement.

This sort of internal processing would break if you turned off new event
sources after the first return. It's the sort of thing that people who
are aware of your extension might be careful about. It's also the sort
of thing that would probably be easier to handle if there were better GC
in Tcl. But I can envision all kinds of hard-to-figure-out memory leaks,
where you're following the API of the package, but your caller wraps you
up in a way that breaks the package in ways you don't notice until
suddenly you're out of memory.

Except for being easier to implement, I don't know of any reason you'd
want to turn off new event sources on a "push". It's not like a
graphical context, where you're overwriting settings. Event sources are
all independent. What's the actual benefit to the end user of turning
off events created in the nested context?

Alexandre Ferrieux

unread,
May 27, 2007, 2:47:56 PM5/27/07
to
On May 27, 6:42 pm, Darren New <d...@san.rr.com> wrote:
> What's the actual benefit to the end user of turning
> off events created in the nested context?

The symmetry of a save/restore has its benefits: what if, inside the
nested context, the package happens to register fileevents on top of
yours (that is, on the same channels) ? They may be temporarily
useful, but once out of the nested context, it sure wouldn't be cool
not to re-enable yours... And if, following your suggestion, we simply
re-enable them *over* the nested ones, then from the package
developer's point of view this becomes very fragile, because he must
be prepared to see them survive or not, depending on the weather. The
save/restore has the benefit of a rock-solid contract.

-Alex

Darren New

unread,
May 27, 2007, 6:44:34 PM5/27/07
to
Alexandre Ferrieux wrote:
> The symmetry of a save/restore has its benefits: what if, inside the
> nested context, the package happens to register fileevents on top of
> yours (that is, on the same channels) ?

There's already a mechanism in place for dealing with that. If the
library takes a channel name and overwrites the fileevent associated
with it, the author already either saves your file event and puts it
back (or invokes it) appropriately, or you already restore your own file
event after calling the library.

Do you know of any library that registers file events on top of a
channel you pass in and doesn't put them back when it's done and doesn't
tell you it has done this in the documentation? Is there any good reason
for someone writing a library like that?

> They may be temporarily
> useful, but once out of the nested context, it sure wouldn't be cool
> not to re-enable yours...

There's another example. Doesn't TLS do something like this? So if you
open the socket in a nested context, you're kind of screwed if you turn
off TLS's file event handling permanently between opening and closing
the socket.

I didn't think the vwait push or vwait pop should affect what event
sources are registered. It should just stop them from firing, in exactly
the same way (conceptually speaking) that [update idletasks] stops
fileevents from firing while letting some [after] events fire.

> And if, following your suggestion, we simply
> re-enable them *over* the nested ones,

I don't know what you mean "over" the nested ones. A channel can only
have one fileevent script associated with it. If a library takes an
existing channel and clobbers the fileevent, it's gone, regardless of
whether the event loop is running or not. If vwait pop "put it back"
after your code intentionally removed it, that would be most distressing.

For example, if you turn off your file event, call a library which gets
an EOF (synchronously) and then closes the socket, I'd think it would be
a Bad Idea to let file events start firing again.

> then from the package
> developer's point of view this becomes very fragile, because he must
> be prepared to see them survive or not, depending on the weather.

It's not depending on the weather. It's depending on whether the library
he calls fiddles with the mode, fileevents, or open status of the
channels passed in. I don't imagine I'd want the fileevents that the
library explicitly removed put back on any more than I'd want closed
windows reopened or canceled afters rescheduled or closed files reopened.

> The save/restore has the benefit of a rock-solid contract.

Except that existing libraries aren't adhering to the contract. There's
nothing right now that says you can't return from a routine someone
might want to make atomic with other event sources turned on.

Anyway, it really doesn't. You've already pointed out that if the
library closes a file or socket or whatever, you can't put the
fileevents back.

Basically, what I'm saying is that [vwait push] and [vwait pop] should
be affecting the caller of [vwait push] and [vwait pop], without
affecting what's called in between. I haven't seen any example of pseudo
code that would imply that me calling [vwait pop] at a higher level
should affect the results of what's already been done in the past. I
want to call [vwait push] to turn off *my* event sources, not to turn
off the event sources of the thing I'm about to call. I want [vwait pop]
to undo [vwait push], not undo everything *between* the two calls.

Alexandre Ferrieux

unread,
May 28, 2007, 8:02:26 AM5/28/07
to
On May 28, 12:44 am, Darren New <d...@san.rr.com> wrote:
> [good arguments]

Darren, I'm starting to see your light.. sorry it took so long ;-)
You win the privilege of TIPping !

-Alex


Darren New

unread,
May 30, 2007, 11:05:09 AM5/30/07
to
Alexandre Ferrieux wrote:
> Darren, I'm starting to see your light.. sorry it took so long ;-)
> You win the privilege of TIPping !

Honestly, it's going to be a while. I would be glad to, but I'm just a
bit too busy.

0 new messages