Re: GUI-safe polling loop
- From: muppet <scott asofyet org>
- To: Matthew Braid <ptkperl mdb id au>
- Cc: gtk-perl-list gnome org
- Subject: Re: GUI-safe polling loop
- Date: Thu, 1 Feb 2007 22:05:34 -0500
On Feb 1, 2007, at 8:10 PM, Matthew Braid wrote:
Just wanted to know if what I'm doing makes sense.
I'm trying to poll for a child process being finished in a way that  
will not freeze the GUI up, but also won't let the surrounding code  
continue until the child process is finished.
GLib provides GChildWatch, which is a GSource that fires when a given  
pid exits.  The Right Way to do this is along the lines of
    my $loop = Glib::MainLoop->new;
    $id = Glib::ChildWatch->add ($child_pid, sub { $loop->exit; 0 });
    $loop->run;
However, on looking through GMainLoop.xs just now, it appears that  
g_child_watch_add() is not bound to perl.
:-P
Another thought would be to create your own GSource in perl, and hook  
that into the main loop.  Of course, the utilities you need to do  
that are (you guessed it) also not bound to perl.
Dammit.
Assuming $kid is the process id of the child, is the following code
reasonable or am I missing something basic:
use POSIX qw/WNOHANG/;
require Glib;
#...
while (1) {
  last if waitpid($kid, WNOHANG); # Check if we're done
  my $ml = Glib::MainLoop->new;
  Glib::Timeout->add(2000, sub { $ml->quit; return 0 });
  $ml->run;
}
This gives you a timer granularity, which means that you won't  
acknowledge the child's termination in a timely manner.  To fix that,  
you shorten the timeout, which increases the load.
The real solution is to use something that fires from SIGCHLD to wake  
up a source being polled by the main loop.  (This is what GChildWatch  
does...)  So, a pure-perl reimplementation of GChildWatch might look  
like this:
#!/usr/bin/perl -w
package Mup::ChildWatch;
use strict;
use Glib;
#
# A little private mapping of PIDs to callbacks and their data.
#
my %callback;
#
# One of the very few things that are safe to do from async signal  
handlers
# is to write to a pipe.  It just so happens that pipes are one of  
the things
# we can easily monitor in the main loop.  So, here, we'll create a  
pipe to
# which we'll write in the SIGCHLD handler, and then monitor in the  
main loop.
#
pipe CHLDEXITREAD, CHLDEXITWRITE;
#
# Install our CHLD handler.  Of course, it's usually very bad form  
for library
# code to install signal handlers, so i don't think of this as a perfect
# solution...  but in here, when we get a CHLD, we'll tickle the pipe  
with a
# byte so as to wake up the event source.
#
$SIG{CHLD} = sub { syswrite CHLDEXITWRITE, "1"; };
#
# Now, install a watch on the other end of the pipe.  This will wake  
up in the
# main loop when the signal handler has written to it.  That's our  
signal to
# reap all the processes we can, invoking the appropriate callbacks  
if any
# are registered.
#
Glib::IO->add_watch (fileno CHLDEXITREAD, 'in', sub {
        my $dummy;
        sysread CHLDEXITREAD, $dummy, 1;
        while (-1 != (my $pid = wait)) {
                print "reaped pid $pid\n";
                use Data::Dumper;
                print Dumper(\%callback);
                if ($callback{$pid}) {
                        print "invoking callback ... \n";
                        $callback{$pid}{callback}->($callback{$pid}{data});
                        __PACKAGE__->remove ($pid);
                }
        }
        1;
});
#
# And some public interface that walks and talks like  
Glib::ChildWatch would.
#
sub add {
        my ($class, $pid, $callback, $data) = @_;
        $callback{$pid} = { callback => $callback, data => $data };
        return $pid;
}
sub remove {
        my ($class, $pid) = @_;
        delete $callback{$pid};
}
package main;
my $pid = fork;
die "couldn't fork: $!\n" unless defined $pid;
if (!$pid) {
        sleep 1 + rand(2);
        exit 0;
}
my $loop = Glib::MainLoop->new;
Mup::ChildWatch->add ($pid, sub { print "whee\n"; $loop->quit });
$loop->run;
__END__
--
Doing a good job around here is like wetting your pants in a dark  
suit; you get a warm feeling, but no one notices.
  -- unknown
[
Date Prev][
Date Next]   [
Thread Prev][
Thread Next]   
[
Thread Index]
[
Date Index]
[
Author Index]