Subject: | Reactor doesn't shutdown as soon as possible |
The reactor doesn't perform the shutdown method as soon as possible. It
tries to go through the pending events before it can shutdown. In some
occasions the reactor will have no pending events and will perform a select.
This is not very practical because even though the reactor is in
'shutdown' mode it will try to perform one last request which can make
it wait forever until a file selector is ready. If a service is using
the reactor then it will wait until a client connects and sends a
message to then shutdown. Furthermore, the client will receive an error
because his message will not be managed properly.
I have a patch and a test case.
Run the test case in a shell:
perl shutdown-server.pl
Then, in a different shell send a shutdown message to the server:
dbus-send --print-reply --session --dest=org.example.HelloWorld /
org.example.HelloWorld.Shutdown
dbus-send --print-reply --session --dest=org.example.HelloWorld /
org.example.HelloWorld.Shutdown
The first call to Shutdown will fail to stop the service, while the
second call will return with the following error message:
Error org.freedesktop.DBus.Error.NoReply: Message did not receive a
reply (timeout by message bus)
Subject: | dbus-reactor.patch |
--- Reactor.pm 2008-02-21 02:38:50.000000000 +0100
+++ /usr/lib/perl5/Net/DBus/Reactor.pm 2008-09-07 17:20:58.000000000 +0200
@@ -362,8 +362,15 @@
if (!$ric && !$wic && !$eic && !(defined $timeout)) {
$self->{running} = 0;
- return;
}
+
+ # If one of the callbacks called shutdown the reactor shouldn't wait for new
+ # events (select) otherwise if we have no timeouts the reactor will need to
+ # wait until there's a next event until it can shutdown. In the case of a
+ # service this means that the reactor will wait until a new message is
+ # received and then it will shutdown without answering to the peer!
+ return unless $self->{running};
+
my ($ro, $wo, $eo);
my $n = select($ro=$ri,$wo=$wi,$eo=$ei, (defined $timeout ? ($timeout ? $timeout/1000 : 0) : undef));
Subject: | shutdown-server.pl |
#!/usr/bin/perl
use warnings;
use strict;
#
# D-Bus Service with two methods:
# string HelloWorld() -> Returns a greeting
# void Shutdown() -> Tells the service to end
#
package HelloWorld;
use base qw(Net::DBus::Object);
use Net::DBus::Exporter qw(org.example.HelloWorld);
sub new {
my $class = shift;
my ($service, $shutdown) = @_;
my $self = $class->SUPER::new($service, "/");
bless $self, $class;
$self->{shutdown} = $shutdown;
return $self;
}
dbus_method("HelloWorld", [], ["string"]);
sub HelloWorld {
return "Hello world";
}
dbus_method("Shutdown", [], []);
sub Shutdown {
my $self = shift;
$self->{shutdown}->();
}
package main;
use Net::DBus;
use Net::DBus::Reactor;
my $bus = Net::DBus->session();
my $service = $bus->export_service("org.example.HelloWorld");
my $loop = Net::DBus::Reactor->main();
my $object = HelloWorld->new($service, sub {$loop->shutdown()});
$loop->run();