disabling fileevent

10 views
Skip to first unread message

anuj

unread,
Feb 16, 2006, 6:25:44 AM2/16/06
to
Hello All,

I am facing a problem with fileevent handling. My code looks something
like this:

readUDP {socket} {
:
# read the incoming message, use it to build the reply message and
send it back to the
# other end
:
}

openSock {} {
:
:
fileevent $sock readable [readUDP $sock]
:
:
}

When the fileevent triggers, the readUDP proc gets called, wherein I am
preparing a reply message. In the meantime, there is another message
coming in from the other end and the fileevent gets triggered. As a
result, readUDP gets called even before I complete building the reply
message.

How should I make sure that I complete the processing (build and send
reply) before entertaining the next incoming message?

Thanks in advance :)

Regards,
Anuj.

Googie

unread,
Feb 16, 2006, 6:53:56 AM2/16/06
to
anuj wrote:
> How should I make sure that I complete the processing (build and send
> reply) before entertaining the next incoming message?

One way is to check in readUDP if there is other(*) request already
processed by this procedure and if it is, then quit current readUDP
call. At the end of the previous (the other one (*) ) processing
procedure check for data on the socket (there should be some data if
other [fileevent] were called before readUDP has finished) and call
readUDP recurently by itself to read awaiting data.

--
Pozdrawiam! (Greetings!)
Googie

Googie

unread,
Feb 16, 2006, 6:55:21 AM2/16/06
to
Googie wrote:
> One way

Just to be accurate - "One way" isn't the same as "The only one way" :)
It's a one from many.

--
Pozdrawiam! (Greetings!)
Googie

Bryan Oakley

unread,
Feb 16, 2006, 7:35:20 AM2/16/06
to
anuj wrote:
> Hello All,
>
> I am facing a problem with fileevent handling. My code looks something
> like this:
>
> readUDP {socket} {
> :
> # read the incoming message, use it to build the reply message and
> send it back to the
> # other end
> :
> }
>
> openSock {} {
> :
> :
> fileevent $sock readable [readUDP $sock]
> :
> :
> }
>
> When the fileevent triggers, the readUDP proc gets called, wherein I am
> preparing a reply message. In the meantime, there is another message
> coming in from the other end and the fileevent gets triggered. As a
> result, readUDP gets called even before I complete building the reply
> message.

The fileevent won't trigger until the app re-enters the event loop. As
long as other code is being processed and it doesn't call 'update' you
don't have to worry about the fileevent.

>
> How should I make sure that I complete the processing (build and send
> reply) before entertaining the next incoming message?

you can either a) turn the fileevent off until you are ready, or b) set
a flag, then check for the flag in the callback. If the flag is set,
don't read from the socket.

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

???

unread,
Feb 16, 2006, 7:46:13 AM2/16/06
to
i think the following sample can be some help
:)

#!/bin/sh
# the below lines execute with tclsh \
exec tclsh "$0" "$@";

set x [socket -myaddr 172.20.1.227 172.20.1.227 8100];

set f [open /root/data r];

fconfigure $x -blocking 0 -buffering line -eofchar \0;

proc Read {x} {
global done;

set line [read $x];
regsub -all {\x1C} $line + str;
puts "recv> $str";
set done 1;
}

proc send {in out} {
gets $in com;

puts "send> $com";
if {![string equal $com quit]} {
regsub -all {\+} $com \x1C str;
puts -nonewline $out $str;
flush $out;
return 0;
} else {
close $out;
return 1;
}
}

fileevent $x readable [list Read $x];

set count 1;

while {1} {
if {![eof $f]} {
send $f $x;
} else {
# puts "close";
close $f;
break;
}
after 70;
puts [incr count];

vwait done;
}
while {1} {
gets stdin com;

puts "send> $com";
if {![string equal $com quit]} {
regsub -all {\+} $com \x1C str;
puts -nonewline $x $str;
flush $x;
} else {
close $x;
}

after 1000 [list set done 2];

vwait done;

}

"anuj" <anuj_...@spanservices.com> ????
news:1140089144.8...@o13g2000cwo.googlegroups.com...

Bruce Hartweg

unread,
Feb 16, 2006, 9:48:43 AM2/16/06
to

anuj wrote:
> Hello All,
>
> I am facing a problem with fileevent handling. My code looks something
> like this:
>
> readUDP {socket} {
> :
> # read the incoming message, use it to build the reply message and
> send it back to the
> # other end
> :
> }
>
> openSock {} {
> :
> :
> fileevent $sock readable [readUDP $sock]
> :
> :
> }
>
> When the fileevent triggers, the readUDP proc gets called, wherein I am
> preparing a reply message. In the meantime, there is another message
> coming in from the other end and the fileevent gets triggered. As a
> result, readUDP gets called even before I complete building the reply
> message.
>

It only gets triggered if you are in an event loop, you must be calling
vwait or update withing the block of code that is building/replying.
Short answer don't do that.

> How should I make sure that I complete the processing (build and send
> reply) before entertaining the next incoming message?
>

Don't allow re-entry into an event loop - fileevents are NOT
interrupts, they cannot break into running code, you must do
something (again an update or vwait) that allows it back in,
so avoid doing that and you should be fine.

Bruce

Neil Madden

unread,
Feb 16, 2006, 3:57:10 PM2/16/06
to
Bruce Hartweg wrote:
> Don't allow re-entry into an event loop - fileevents are NOT
> interrupts, they cannot break into running code, you must do
> something (again an update or vwait) that allows it back in,
> so avoid doing that and you should be fine.

And also be aware of other ways of accidentally re-entering the event
loop. tk_messageBox is one which has bitten me before (it uses vwait or
tkwait internally, which reenters the event loop). Popping up a modal
dialog box to get confirmation from a user in the middle of an event
callback can lead to trouble.

<idea state="half-baked">
It'd be quite nice at times to have something like vwait/tkwait that
instead of reentering the event loop, suspends it and starts a new one.
Perhaps something like:

... in event handler ...
event loop {
set result [tk_messageBox ...]
}
... use $result ...

The new event loop (and any new event sources/handlers) lasts for the
duration of the script (or perhaps until some termination condition is
satified?) and then is deleted, resuming the original event loop.
Without the script it does the equivalent of [vwait forever].

Quite probably I haven't thought this through though... (and I have
absolutely no idea how complex it would be to implement).
</idea>

-- Neil

Bruce Hartweg

unread,
Feb 16, 2006, 5:19:45 PM2/16/06
to

Actually, thats what vwait does, which is why they nest and
only unroll in reverse order. the problem isn't whether it's the
original outermost event loop, on an inner loop, the problem
lies in not having control over what events get processed.

Bruce

Neil Madden

unread,
Feb 16, 2006, 7:02:50 PM2/16/06
to
Bruce Hartweg wrote:
>>
> Actually, thats what vwait does, which is why they nest and
> only unroll in reverse order. the problem isn't whether it's the
> original outermost event loop, on an inner loop, the problem
> lies in not having control over what events get processed.

Sorry, I wasn't clear enough. I meant that the new event loop should
suspend the old one *and all active event sources*. This is different
from vwait/tkwait which starts a new event loop, but using the same
event queue, so previously defined event sources still fire. This is a
problem with the scenario of using a modal dialog in the middle of an
event handler as the same event handler may be reentered leading to all
sorts of unwanted behaviour[1]. Temporarily suspending all event
handlers (and then adding some new ones) would allow you to deal with
the modal interaction without worrying about new events interfering --
they can just queue up until we return to the outer event loop to
service them. Of course, this involves using a context stack of event
queues, so the implementation is probably non-trivial (I don't know how
commited Tcl is to a single event queue per interpreter, or even if it is).

[1] Of course, you could argue that this is bad design. Indeed, the only
time I've ever had to do it (that I remember) was when I was tasked with
implementing a particularly bad spec which mandated such behaviour.

-- Neil

Jeff R

unread,
Feb 17, 2006, 1:33:45 AM2/17/06
to
Neil Madden wrote:

> Bruce Hartweg wrote:
>
>>>
>> Actually, thats what vwait does, which is why they nest and
>> only unroll in reverse order. the problem isn't whether it's the
>> original outermost event loop, on an inner loop, the problem
>> lies in not having control over what events get processed.

> service them. Of course, this involves using a context stack of event

> queues, so the implementation is probably non-trivial (I don't know how
> commited Tcl is to a single event queue per interpreter, or even if it is).

Lately I've been pondering what it would take to remove the nesting
property of vwait. Conceptually it's very simple: instead of vwait
starting its own event loop it would just save the tcl stack and allow
the event loop to run at the top level and when the primary stack (that
is, an event handler) gets back to the top level the main event loop
would check all the saved stacks to see which are runnable and continue
there. However the implementation would be not quite so simple, since
the tcl stack is fairly tightly wedded to the C stack and saving and
restoring the C stack is not such an easy thing to do, especially not
portably (getcontext/setcontext are unix specific, setjmp/longjmp
sometimes have limits on jumping deeper into the stack). It's an
interesting idea (and I think the results would be very useful) but it
would probably require a massive overhaul of the core and lots of public
APIs would break.

Still, has anyone else thought about this?

-J

Darren New

unread,
Feb 17, 2006, 2:06:34 AM2/17/06
to
Jeff R wrote:
> Still, has anyone else thought about this?

Do it yourself. Redefine fileevent and any other event generator you
want to disable on demand. The redefined commands would record a "how to
turn off" script and a "how to turn on" script somewhere global. Then
you can turn off all the events, define new fileevents, run the event
loop a while, then turn off the new events and turn back on the old
events. Could be problematic with events that are generated for you
without definitions, like the threading events or the Tk events, but for
something like a server this would work.

--
Darren New / San Diego, CA, USA (PST)
Is it OK to be obsessive-compulsive
as long as you're not disordered?

Donald Arseneau

unread,
Feb 17, 2006, 3:14:27 AM2/17/06
to
Jeff R <dv...@diphi.com> writes:

> Lately I've been pondering what it would take to remove the nesting property
> of vwait. Conceptually it's very simple: instead of vwait starting its own
> event loop it would just save the tcl stack and allow the event loop to run
> at the top level and when the primary stack (that is, an event handler) gets
> back to the top level the main event loop would check all the saved stacks to
> see which are runnable and continue there.
>

> Still, has anyone else thought about this?

Yes!

There is:

http://groups.google.com/group/comp.lang.tcl/browse_thread/thread/cef62ad5341cf5b8/5c7460c2a53dfa3e

I recall asking somewhere about a multi-stack model for the event loop, but I can't
find it with google groups.

--
Donald Arseneau as...@triumf.ca

Colin Macleod

unread,
Feb 17, 2006, 8:15:44 AM2/17/06
to
Jeff R wrote:

> Lately I've been pondering what it would take to remove the nesting
> property of vwait. Conceptually it's very simple: instead of vwait
> starting its own event loop it would just save the tcl stack and allow
> the event loop to run at the top level and when the primary stack (that
> is, an event handler) gets back to the top level the main event loop
> would check all the saved stacks to see which are runnable and continue
> there. However the implementation would be not quite so simple, since
> the tcl stack is fairly tightly wedded to the C stack and saving and
> restoring the C stack is not such an easy thing to do, especially not
> portably (getcontext/setcontext are unix specific, setjmp/longjmp
> sometimes have limits on jumping deeper into the stack). It's an
> interesting idea (and I think the results would be very useful) but it
> would probably require a massive overhaul of the core and lots of public
> APIs would break.
>
> Still, has anyone else thought about this?

I spent a while thinking about this last summer, but then real life got
in the way of pursuing it further :-)

The practicalities are tricky. You need:
1) A portable coroutine implementation to handle swapping the C stacks.
The Portable Coroutine Library at
http://www.xmailserver.org/libpcl.html could be suitable, but it's
under GPL so not suitable to integrate with Tcl. We could implement
our own - use getcontext/makecontext/swapcontext on Unixes where
available, probably fibers on Windows, setjmp/longjmp otherwise. I
played around with getcontext/etc but don't have time to continue this
anytime soon.
2) Identify and save/restore the relevant Tcl interp context which is
not on the C stack - I didn't get very far with this.

BUT, I became convinced that actually making this work could be a huge
win. We could have a coroutine package providing the following
commands:

co::vwait var - like old vwait but not nesting - multiple vwaits can be
active in parallel.

co::after ms - current routine pauses for (at least) ms millisecond,
meanwhile events are processed.

co::read / co::gets - current routine reads input from channel when it
becomes available, meanwhile events are processed. This is an
alternative to fileevent, but inverting the flow of control. Useful
when processing the input involves changes of state, which would have
to be managed explicitly in a fileevent-based program.

BTW, I see all this as quite different, but complementary, to the
thread support we already have.

Colin.

Bruce Hartweg

unread,
Feb 17, 2006, 9:31:36 AM2/17/06
to

Neil Madden wrote:
> Bruce Hartweg wrote:
>>>
>> Actually, thats what vwait does, which is why they nest and
>> only unroll in reverse order. the problem isn't whether it's the
>> original outermost event loop, on an inner loop, the problem
>> lies in not having control over what events get processed.
>
> Sorry, I wasn't clear enough. I meant that the new event loop should
> suspend the old one *and all active event sources*. This is different
> from vwait/tkwait which starts a new event loop, but using the same
> event queue, so previously defined event sources still fire. This is a
> problem with the scenario of using a modal dialog in the middle of an
> event handler as the same event handler may be reentered leading to all
> sorts of unwanted behaviour[1]. Temporarily suspending all event
> handlers (and then adding some new ones) would allow you to deal with
> the modal interaction without worrying about new events interfering --
> they can just queue up until we return to the outer event loop to
> service them. Of course, this involves using a context stack of event
> queues, so the implementation is probably non-trivial (I don't know how
> commited Tcl is to a single event queue per interpreter, or even if it is).
>

for some things that would work (and I agree could be useful in certain
circumstances), but there are a few "gotchas" still lurking there - this
idea is fine for event sources you control (fileevents etc) but what
about GUI events? the are coming from a single source - how do yuou know
a priori which event s to process in your new loop/queue and which one
to stack up on the old queue for later? IN some cases (like message box)
this is handled by grabs preventing it but in others you have some real
ambiguity. Also what about idle events? if they are just stacking up on
some other processing loop the the user is going to get a non-responsive
locked up GUI.

Intersting topic, but generally I just try to design my apps to avoid
the issue more than work around it, but sometime the message_box is so
handy to inline, if there was a way for it not to deal with non-GUI
events it could be a handy addition.

Bruce

Reply all
Reply to author
Forward
0 new messages