In article <[EMAIL PROTECTED]>,
        Rocco Caputo <[EMAIL PROTECTED]> writes:
> The event loop libraries may require Ugly Workarounds to behave
> properly.  Tk, for example, will starve I/O watchers if you start a
> 0ms after() timer from a timer callback.  In your example, the
> recursive yield() would prevent select_read() from ever seeing
> activity on the pipe.
> 
Ah, so yield is dispatched as a period 0 alarm in under Tk. And the
alarm starvation workaround just happens to work like this ? Ok.

By the way, in my tests with Tk short alarms can't totally starve
other events, they just seem to have a too high priority.

#!/usr/bin/perl -w
use Tk qw(DONT_WAIT WINDOW_EVENTS FILE_EVENTS DoOneEvent MainLoop);

my $w = Tk::MainWindow->new();

my $acount = 0;
my $rcount = 0;
my $count  = 0;

sub endp {
    return unless ++$count >= 300;
    print "alarm: $acount, readable: $rcount\n";
    exit;
}

sub acount {
    $w->after(0, \&acount);
    $acount++;
    endp();
}
$w->after(0, \&acount);

pipe(local *RD, local *WR) || die "Pipe: $!";
close WR;
$w->fileevent(\*RD, "readable", sub {
    $rcount++;
    endp();
});

MainLoop;

This outputs
alarm: 200, readable: 100

Or you can replace MainLoop by (skipping the Tk::MainWindow->Count test):

DoOneEvent(DONT_WAIT | WINDOW_EVENTS | FILE_EVENTS) while DoOneEvent();

In which case you'd get the more reasonable:
alarm: 150, readable: 150

But maybe that's different in different Tk version.

> Whew.  Now, to solve your problem.
> 
> It might be more reliable to use small delays, perhaps on the order of
> 1/100 second, to detect idleness.  It also might be more efficient, as
> actual work will have precedence over the idleness polling loop.
> 
This is a not a bad idea. Idleness detection will work a bit slower, but it 
will stress the system less so idleness might actually be reached sooner. 
I just wish there was some portable way to decide on a minimum time argument 
where I can be sure it won't get rounded down to 0.

The main problem is that if there ever is an event source (like a periodic
alarm or regularly arriving packets) that happens more often than the idle
timeout, idleness will never be triggered even though the CPU time for it may
well be available.

> In tests, replacing yield("yielder") with delay("yielder", 0.01)
> results in (Tk) output like:
> 
...
>   yielder
>   readable  <-- potential problem
>   yielder
...
> The potential problems are cases where we almost falsely detected
> idleness.  A higher delay value might help.
> 

I suspect the problem actually can't happen after maybe a first startup
exception, but that's again depending too much on internals :-)

For the moment I think I will just keep using a busy yield loop and just
live with the occasional extra trigger of idleness.

Or you could consider adding an "idle" to POE. Tk and Event both
directly support it, and it's easy to add to self-written eventloops :-)

Reply via email to