Home     |     .Net Programming    |     cSharp Home    |     Sql Server Home    |     Javascript / Client Side Development     |     Ajax Programming

Ruby on Rails Development     |     Perl Programming     |     C Programming Language     |     C++ Programming     |     IT Jobs

Python Programming Language     |     Laptop Suggestions?    |     TCL Scripting     |     Fortran Programming     |     Scheme Programming Language


 
 
Cervo Technologies
The Right Source to Outsource

MS Dynamics CRM 3.0

TCL(Tool Command Language) Scripting

Quick question about the event loop


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

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

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

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

In article <f2site$9n@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.

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.

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

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.

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.

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

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

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.

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

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

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

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

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 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.)

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

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.

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

Neil Madden wrote:
> Do slave interps have their own event queues? Or is it just threads?

Event queues are per-thread.

Donal.

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

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

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

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

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 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 / San Diego, CA, USA (PST)
     His kernel fu is strong.
     He studied at the Shao Linux Temple.

Add to del.icio.us | Digg this | Stumble it | Powered by Megasolutions Inc