home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / lib / perl5 / Net / DBus / Reactor.pm < prev    next >
Encoding:
Perl POD Document  |  2006-02-19  |  17.9 KB  |  781 lines

  1. # -*- perl -*-
  2. #
  3. # Copyright (C) 2004-2005 Daniel P. Berrange
  4. #
  5. # This program is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation; either version 2 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18. #
  19. # $Id: Reactor.pm,v 1.9 2006/01/27 15:34:24 dan Exp $
  20.  
  21. =pod
  22.  
  23. =head1 NAME
  24.  
  25. Net::DBus::Reactor - application event loop 
  26.  
  27. =head1 SYNOPSIS
  28.  
  29. Create and run an event loop:
  30.  
  31.    use Net::DBus::Reactor;
  32.    my $reactor = Net::DBus::Reactor->new();
  33.  
  34.    $reactor->run();
  35.  
  36. Manage some file handlers
  37.  
  38.    $reactor->add_read($fd, 
  39.                       Net::DBus::Callback->new(method => sub {
  40.                          my $fd = shift;
  41.                          ...read some data...
  42.                       }, args => [$fd]);
  43.  
  44.    $reactor->add_write($fd, 
  45.                       Net::DBus::Callback->new(method => sub {
  46.                          my $fd = shift;
  47.                          ...write some data...
  48.                       }, args => [$fd]);
  49.  
  50. Temporarily (dis|en)able a handle
  51.  
  52.    # Disable
  53.    $reactor->toggle_read($fd, 0);
  54.    # Enable
  55.    $reactor->toggle_read($fd, 1);
  56.  
  57. Permanently remove a handle
  58.  
  59.    $reactor->remove_read($fd);
  60.  
  61. Manage a regular timeout every 100 milliseconds
  62.  
  63.    my $timer = $reactor->add_timeout(100,
  64.                                      Net::DBus::Callback->new(
  65.               method => sub {
  66.                  ...process the alarm...
  67.               }));
  68.  
  69. Temporarily (dis|en)able a timer
  70.  
  71.    # Disable
  72.    $reactor->toggle_timeout($timer, 0);
  73.    # Enable
  74.    $reactor->toggle_timeout($timer, 1);
  75.  
  76. Permanently remove a timer
  77.  
  78.    $reactor->remove_timeout($timer);
  79.  
  80. Add a post-dispatch hook
  81.  
  82.    my $hook = $reactor->add_hook(Net::DBus::Callback->new(
  83.          method => sub {
  84.             ... do some work...
  85.          }));
  86.  
  87. Remove a hook
  88.  
  89.    $reactor->remove_hook($hook);
  90.  
  91. =head1 DESCRIPTION
  92.  
  93. This class provides a general purpose event loop for
  94. the purposes of multiplexing I/O events and timeouts
  95. in a single process. The underlying implementation is
  96. done using the select system call. File handles can
  97. be registered for monitoring on read, write and exception
  98. (out-of-band data) events. Timers can be registered
  99. to expire with a periodic frequency. These are implemented
  100. using the timeout parameter of the select system call.
  101. Since this parameter merely represents an upper bound
  102. on the amount of time the select system call is allowed
  103. to sleep, the actual period of the timers may vary. Under
  104. normal load this variance is typically 10 milliseconds.
  105. Finally, hooks may be registered which will be invoked on
  106. each iteration of the event loop (ie after processing
  107. the file events, or timeouts indicated by the select
  108. system call returning).
  109.  
  110. =head1 METHODS
  111.  
  112. =over 4
  113.  
  114. =cut
  115.  
  116. package Net::DBus::Reactor;
  117.  
  118. use 5.006;
  119. use strict;
  120. use warnings;
  121. use Carp;
  122. use Net::DBus::Binding::Watch;
  123. use Net::DBus::Callback;
  124. use Time::HiRes qw(gettimeofday);
  125.  
  126. =item my $reactor = Net::DBus::Reactor->new();
  127.  
  128. Creates a new event loop ready for monitoring file handles, or 
  129. generating timeouts. Except in very unsual circumstances (examples
  130. of which I can't think up) it is not neccessary or desriable to
  131. explicitly create new reactor instances. Instead call the L<main>
  132. method to get a handle to the singleton instance.
  133.  
  134. =cut
  135.  
  136. sub new {
  137.     my $proto = shift;
  138.     my $class = ref($proto) || $proto;
  139.     my %params = @_;
  140.     my $self = {};
  141.  
  142.     $self->{fds} = {
  143.     read => {},
  144.     write => {},
  145.     exception => {}
  146.     };
  147.     $self->{timeouts} = [];
  148.     $self->{hooks} = [];
  149.  
  150.     bless $self, $class;
  151.  
  152.     return $self;
  153. }
  154.  
  155. use vars qw($main_reactor);
  156.  
  157. =item $reactor->main
  158.  
  159. Return a handle to the singleton instance of the reactor. This
  160. is the recommended way of getting hold of a reactor, since it
  161. removes the need for modules to pass around handles to their
  162. privately created reactors.
  163.  
  164. =cut
  165.  
  166. sub main {
  167.     my $class = shift;
  168.     $main_reactor = $class->new() unless defined $main_reactor;
  169.     return $main_reactor;
  170. }
  171.  
  172.  
  173. =item $reactor->manage($connection);
  174.  
  175. =item $reactor->manage($server);
  176.  
  177. Registers a C<Net::DBus::Connection> or C<Net::DBus::Server> object
  178. for management by the event loop. This basically involves
  179. hooking up the watch & timeout callbacks to the event loop.
  180. For connections it will also register a hook to invoke the
  181. C<dispatch> method periodically.
  182.  
  183. =cut
  184.  
  185. sub manage {
  186.     my $self = shift;
  187.     my $object = shift;
  188.  
  189.     if ($object->can("set_watch_callbacks")) {
  190.     $object->set_watch_callbacks(sub {
  191.         my $object = shift;
  192.         my $watch = shift;
  193.  
  194.         $self->_manage_watch_on($object, $watch);
  195.     }, sub {
  196.         my $object = shift;
  197.         my $watch = shift;
  198.  
  199.         $self->_manage_watch_off($object, $watch);
  200.     }, sub {
  201.         my $object = shift;
  202.         my $watch = shift;
  203.  
  204.         $self->_manage_watch_toggle($object, $watch);
  205.     });
  206.     }
  207.     
  208.     if ($object->can("set_timeout_callbacks")) {
  209.     $object->set_timeout_callbacks(sub {
  210.         my $object = shift;
  211.         my $timeout = shift;
  212.         
  213.         my $key = $self->add_timeout($timeout->get_interval,
  214.                      Net::DBus::Callback->new(object => $timeout,
  215.                                   method => "handle",
  216.                                   args => []),
  217.                      $timeout->is_enabled);
  218.         $timeout->set_data($key);
  219.     }, sub {
  220.         my $object = shift;
  221.         my $timeout = shift;
  222.         
  223.         my $key = $timeout->get_data;
  224.         $self->remove_timeout($key);
  225.     }, sub {
  226.         my $object = shift;
  227.         my $timeout = shift;
  228.         
  229.         my $key = $timeout->get_data;
  230.         $self->remove_timeout($key,
  231.                   $timeout->is_enabled,
  232.                   $timeout->get_interval);
  233.     });
  234.     }
  235.     
  236.     if ($object->can("dispatch")) {
  237.     $self->add_hook(Net::DBus::Callback->new(object => $object, 
  238.                          method => "dispatch", 
  239.                          args => []), 
  240.             1);
  241.     }
  242.     if ($object->can("flush")) {
  243.     $self->add_hook(Net::DBus::Callback->new(object => $object, 
  244.                          method => "flush", 
  245.                          args => []), 
  246.             1);
  247.     }
  248. }
  249.  
  250.  
  251. sub _manage_watch_on {
  252.     my $self = shift;
  253.     my $object = shift;
  254.     my $watch = shift;
  255.     my $flags = $watch->get_flags;
  256.  
  257.     if ($flags & &Net::DBus::Binding::Watch::READABLE) {
  258.     $self->add_read($watch->get_fileno, 
  259.             Net::DBus::Callback->new(object => $watch, 
  260.                         method => "handle", 
  261.                         args => [&Net::DBus::Binding::Watch::READABLE]), 
  262.             $watch->is_enabled);
  263.     }
  264.     if ($flags & &Net::DBus::Binding::Watch::WRITABLE) {
  265.     $self->add_write($watch->get_fileno, 
  266.              Net::DBus::Callback->new(object => $watch, 
  267.                          method => "handle", 
  268.                          args => [&Net::DBus::Binding::Watch::WRITABLE]), 
  269.              $watch->is_enabled);
  270.     }
  271. #    $self->add_exception($watch->get_fileno, $watch, 
  272. #             Net::DBus::Callback->new(object => $watch, 
  273. #                         method => "handle", 
  274. #                         args => [&Net::DBus::Binding::Watch::ERROR]), 
  275. #             $watch->is_enabled);
  276.     
  277. }
  278.  
  279. sub _manage_watch_off {
  280.     my $self = shift;
  281.     my $object = shift;
  282.     my $watch = shift;
  283.     my $flags = $watch->get_flags;
  284.     
  285.     if ($flags & &Net::DBus::Binding::Watch::READABLE) {
  286.     $self->remove_read($watch->get_fileno);
  287.     }
  288.     if ($flags & &Net::DBus::Binding::Watch::WRITABLE) {
  289.     $self->remove_write($watch->get_fileno);
  290.     }
  291. #    $self->remove_exception($watch->get_fileno);
  292. }
  293.  
  294. sub _manage_watch_toggle {
  295.     my $self = shift;
  296.     my $object = shift;
  297.     my $watch = shift;
  298.     my $flags = $watch->get_flags;
  299.     
  300.     if ($flags & &Net::DBus::Binding::Watch::READABLE) {
  301.     $self->toggle_read($watch->get_fileno, $watch->is_enabled);
  302.     }
  303.     if ($flags & &Net::DBus::Binding::Watch::WRITABLE) {
  304.     $self->toggle_write($watch->get_fileno, $watch->is_enabled);
  305.     }
  306.     $self->toggle_exception($watch->get_fileno, $watch->is_enabled);
  307. }
  308.  
  309.  
  310. =item $reactor->run();
  311.  
  312. Starts the event loop monitoring any registered
  313. file handles and timeouts. At least one file
  314. handle, or timer must have been registered prior
  315. to running the reactor, otherwise it will immediately
  316. exit. The reactor will run until all registered
  317. file handles, or timeouts have been removed, or
  318. disabled. The reactor can be explicitly stopped by
  319. calling the C<shutdown> method.
  320.  
  321. =cut
  322.  
  323. sub run {
  324.     my $self = shift;
  325.  
  326.     $self->{running} = 1;
  327.     while ($self->{running}) { $self->step };
  328. }
  329.  
  330. =item $reactor->shutdown();
  331.  
  332. Explicitly shutdown the reactor after pending
  333. events have been processed.
  334.  
  335. =cut
  336.  
  337. sub shutdown {
  338.     my $self = shift;
  339.     $self->{running} = 0;
  340. }
  341.  
  342. =item $reactor->step();
  343.  
  344. Perform one iteration of the event loop, going to
  345. sleep until an event occurs on a registered file
  346. handle, or a timeout occurrs. This method is generally
  347. not required in day-to-day use.
  348.  
  349. =cut
  350.  
  351. sub step {
  352.     my $self = shift;
  353.    
  354.     my @callbacks = $self->_dispatch_hook();
  355.     
  356.     foreach my $callback (@callbacks) {
  357.     $callback->invoke;
  358.     }
  359.  
  360.     my ($ri, $ric) = $self->_bits("read");
  361.     my ($wi, $wic) = $self->_bits("write");
  362.     my ($ei, $eic) = $self->_bits("exception");
  363.     my $timeout = $self->_timeout($self->_now);
  364.     
  365.     if (!$ric && !$wic && !$eic && !(defined $timeout)) {
  366.     $self->{running} = 0;
  367.     return;
  368.     }
  369.         
  370.     my ($ro, $wo, $eo);
  371.     my $n = select($ro=$ri,$wo=$wi,$eo=$ei, (defined $timeout ? ($timeout ? $timeout/1000 : 0) : undef));
  372.     
  373.     @callbacks = ();
  374.     if ($n) {
  375.     push @callbacks, $self->_dispatch_fd("read", $ro);
  376.     push @callbacks, $self->_dispatch_fd("write", $wo);
  377.     push @callbacks, $self->_dispatch_fd("error", $eo);
  378.     }
  379.     push @callbacks, $self->_dispatch_timeout($self->_now);
  380.     #push @callbacks, $self->_dispatch_hook();
  381.     
  382.     foreach my $callback (@callbacks) {
  383.     $callback->invoke;
  384.     }
  385.  
  386.     return 1;
  387. }
  388.  
  389. sub _now {
  390.     my $self = shift;
  391.     
  392.     my @now = gettimeofday;
  393.     
  394.     return $now[0] * 1000 + (($now[1] - ($now[1] % 1000)) / 1000);
  395. }
  396.  
  397. sub _bits {
  398.     my $self = shift;
  399.     my $type = shift;
  400.     my $vec = '';
  401.  
  402.     my $count = 0;
  403.     foreach (keys %{$self->{fds}->{$type}}) {
  404.     next unless $self->{fds}->{$type}->{$_}->{enabled};
  405.  
  406.     $count++;
  407.     vec($vec, $_, 1) = 1;
  408.     }
  409.     return ($vec, $count);
  410. }
  411.  
  412. sub _timeout {
  413.     my $self = shift;
  414.     my $now = shift;
  415.     
  416.     my $timeout;
  417.     foreach (@{$self->{timeouts}}) {
  418.     next unless $_->{enabled};
  419.  
  420.     my $expired = $now - $_->{last_fired};
  421.     my $interval = ($expired > $_->{interval} ? 0 : $_->{interval} - $expired);
  422.     $timeout = $interval if !(defined $timeout) ||
  423.         ($interval < $timeout);
  424.     }
  425.     return $timeout;
  426. }
  427.  
  428.  
  429. sub _dispatch_fd {
  430.     my $self = shift;
  431.     my $type = shift;
  432.     my $vec = shift;
  433.     
  434.     my @callbacks;
  435.     foreach my $fd (keys %{$self->{fds}->{$type}}) {
  436.     next unless $self->{fds}->{$type}->{$fd}->{enabled};
  437.  
  438.     if (vec($vec, $fd, 1)) {
  439.         my $rec = $self->{fds}->{$type}->{$fd};
  440.         
  441.         push @callbacks, $self->{fds}->{$type}->{$fd}->{callback};
  442.     }
  443.     }
  444.     return @callbacks;
  445. }
  446.  
  447.  
  448. sub _dispatch_timeout {
  449.     my $self = shift;
  450.     my $now = shift;
  451.     
  452.     my @callbacks;
  453.     foreach my $timeout (@{$self->{timeouts}}) {
  454.     next unless $timeout->{enabled};
  455.     my $expired = $now - $timeout->{last_fired};
  456.  
  457.     # Select typically returns a little (0-10 ms) before we 
  458.     # asked it for. (8 milliseconds seems reasonable balance
  459.     # between early timeouts & extra select calls
  460.     if ($expired >= ($timeout->{interval}-8)) {
  461.         $timeout->{last_fired} = $now;
  462.         push @callbacks, $timeout->{callback};
  463.     }
  464.     }
  465.     return @callbacks;
  466. }
  467.  
  468.  
  469. sub _dispatch_hook {
  470.     my $self = shift;
  471.     my $now = shift;
  472.  
  473.     my @callbacks;
  474.     foreach my $hook (@{$self->{hooks}}) {
  475.     next unless $hook->{enabled};
  476.     push @callbacks, $hook->{callback};
  477.     }
  478.     return @callbacks;
  479. }
  480.  
  481.  
  482. =item $reactor->add_read($fd, $callback[, $status]);
  483.  
  484. Registers a file handle for monitoring of read
  485. events. The C<$callback> parameter specifies an
  486. instance of the C<Net::DBus::Callback> object to invoke
  487. each time an event occurs. The optional C<$status>
  488. parameter is a boolean value to specify whether the
  489. watch is initially enabled.
  490.  
  491. =cut
  492.  
  493. sub add_read {
  494.     my $self = shift;
  495.     $self->_add("read", @_);
  496. }
  497.  
  498. =item $reactor->add_write($fd, $callback[, $status]);
  499.  
  500. Registers a file handle for monitoring of write
  501. events. The C<$callback> parameter specifies an
  502. instance of the C<Net::DBus::Callback> object to invoke
  503. each time an event occurs. The optional C<$status>
  504. parameter is a boolean value to specify whether the
  505. watch is initially enabled.
  506.  
  507. =cut
  508.  
  509. sub add_write {
  510.     my $self = shift;
  511.     $self->_add("write", @_);
  512. }
  513.  
  514.  
  515. =item $reactor->add_exception($fd, $callback[, $status]);
  516.  
  517. Registers a file handle for monitoring of exception
  518. events. The C<$callback> parameter specifies an
  519. instance of the C<Net::DBus::Callback> object to invoke
  520. each time an event occurs. The optional C<$status>
  521. parameter is a boolean value to specify whether the
  522. watch is initially enabled.
  523.  
  524. =cut
  525.  
  526. sub add_exception {
  527.     my $self = shift;
  528.     $self->_add("exception", @_);
  529. }
  530.  
  531.  
  532. =item my $id = $reactor->add_timeout($interval, $callback, $status);
  533.  
  534. Registers a new timeout to expire every C<$interval>
  535. milliseconds. The C<$callback> parameter specifies an
  536. instance of the C<Net::DBus::Callback> object to invoke
  537. each time the timeout expires. The optional C<$status>
  538. parameter is a boolean value to specify whether the
  539. timeout is initially enabled. The return parameter is
  540. a unique identifier which can be used to later remove
  541. or disable the timeout.
  542.  
  543. =cut
  544.  
  545. sub add_timeout {
  546.     my $self = shift;
  547.     my $interval = shift;
  548.     my $callback = shift;
  549.     my $enabled = shift;    
  550.     $enabled = 1 unless defined $enabled;
  551.  
  552.     my $key;
  553.     for (my $i = 0 ; $i <= $#{$self->{timeouts}} && !(defined $key); $i++) {
  554.     $key = $i unless defined $self->{timeouts}->[$i];
  555.     }
  556.     $key = $#{$self->{timeouts}}+1 unless defined $key;
  557.     
  558.     $self->{timeouts}->[$key] = {
  559.     interval => $interval,
  560.     last_fired => $self->_now,
  561.     callback => $callback,
  562.     enabled => $enabled
  563.     };
  564.  
  565.     return $key;
  566. }
  567.  
  568.  
  569. =item $reactor->remove_timeout($id);
  570.  
  571. Removes a previously registered timeout specified by
  572. the C<$id> parameter.
  573.  
  574. =cut
  575.  
  576. sub remove_timeout {
  577.     my $self = shift;
  578.     my $key = shift;
  579.     
  580.     die "no timeout active with key '$key'" 
  581.     unless defined $self->{timeouts}->[$key];
  582.  
  583.     $self->{timeouts}->[$key] = undef;
  584. }
  585.  
  586.  
  587. =item $reactor->toggle_timeout($id, $status[, $interval]);
  588.  
  589. Updates the state of a previously registered timeout
  590. specifed by the C<$id> parameter. The C<$status>
  591. parameter specifies whether the timeout is to be enabled
  592. or disabled, while the optional C<$interval> parameter
  593. can be used to change the period of the timeout.
  594.  
  595. =cut
  596.  
  597. sub toggle_timeout {
  598.     my $self = shift;
  599.     my $key = shift;
  600.     my $enabled = shift;
  601.     
  602.     $self->{timeouts}->[$key]->{enabled} = $enabled;
  603.     $self->{timeouts}->[$key]->{interval} = shift if @_;
  604. }
  605.  
  606.  
  607. =item my $id = $reactor->add_hook($callback[, $status]);
  608.  
  609. Registers a new hook to be fired on each iteration
  610. of the event loop. The C<$callback> parameter
  611. specifies an instance of the C<Net::DBus::Callback>
  612. class to invoke. The C<$status> parameter determines
  613. whether the hook is initially enabled, or disabled.
  614. The return parameter is a unique id which should
  615. be used to later remove, or disable the hook.
  616.  
  617. =cut
  618.  
  619. sub add_hook {
  620.     my $self = shift;
  621.     my $callback = shift;
  622.     my $enabled = shift;    
  623.     $enabled = 1 unless defined $enabled;
  624.     
  625.     my $key;
  626.     for (my $i = 0 ; $i <= $#{$self->{hooks}} && !(defined $key); $i++) {
  627.     $key = $i unless defined $self->{hooks}->[$i];
  628.     }
  629.     $key = $#{$self->{hooks}}+1 unless defined $key;
  630.  
  631.     $self->{hooks}->[$key] = {
  632.     callback => $callback,
  633.     enabled => $enabled
  634.     };
  635.  
  636.     return $key;
  637. }
  638.  
  639.  
  640. =item $reactor->remove_hook($id)
  641.  
  642. Removes the previously registered hook identified
  643. by C<$id>.
  644.  
  645. =cut
  646.  
  647. sub remove_hook {
  648.     my $self = shift;
  649.     my $key = shift;
  650.     
  651.     die "no hook present with key '$key'" 
  652.     unless defined $self->{hooks}->[$key];
  653.  
  654.  
  655.     $self->{hooks}->[$key] = undef;
  656. }
  657.  
  658. =item $reactor->toggle_hook($id[, $status])
  659.  
  660. Updates the status of the previously registered
  661. hook identified by C<$id>. The C<$status> parameter
  662. determines whether the hook is to be enabled or
  663. disabled.
  664.  
  665. =cut
  666.  
  667. sub toggle_hook {
  668.     my $self = shift;
  669.     my $key = shift;
  670.     my $enabled = shift;
  671.     
  672.     $self->{hooks}->[$key]->{enabled} = $enabled;
  673. }
  674.  
  675. sub _add {
  676.     my $self = shift;
  677.     my $type = shift;
  678.     my $fd = shift;
  679.     my $callback = shift;
  680.     my $enabled = shift;
  681.     $enabled = 1 unless defined $enabled;
  682.     
  683.     $self->{fds}->{$type}->{$fd} = {
  684.     callback => $callback,
  685.     enabled => $enabled
  686.     };
  687. }
  688.  
  689. =item $reactor->remove_read($fd);
  690.  
  691. =item $reactor->remove_write($fd);
  692.  
  693. =item $reactor->remove_exception($fd);
  694.  
  695. Removes a watch on the file handle C<$fd>.
  696.  
  697. =cut
  698.  
  699. sub remove_read {
  700.     my $self = shift;
  701.     $self->_remove("read", @_);
  702. }
  703.  
  704. sub remove_write {
  705.     my $self = shift;
  706.     $self->_remove("write", @_);
  707. }
  708.  
  709. sub remove_exception {
  710.     my $self = shift;
  711.     $self->_remove("exception", @_);
  712. }
  713.  
  714. sub _remove {
  715.     my $self = shift;
  716.     my $type = shift;
  717.     my $fd = shift;
  718.  
  719.     die "no handle ($type) active with fd '$fd'" 
  720.     unless exists $self->{fds}->{$type}->{$fd};
  721.  
  722.     delete $self->{fds}->{$type}->{$fd};
  723. }
  724.  
  725. =item $reactor->toggle_read($fd, $status);
  726.  
  727. =item $reactor->toggle_write($fd, $status);
  728.  
  729. =item $reactor->toggle_exception($fd, $status);
  730.  
  731. Updates the status of a watch on the file handle C<$fd>.
  732. The C<$status> parameter species whether the watch is
  733. to be enabled or disabled.
  734.  
  735. =cut
  736.  
  737. sub toggle_read {
  738.     my $self = shift;
  739.     $self->_toggle("read", @_);
  740. }
  741.  
  742. sub toggle_write {
  743.     my $self = shift;
  744.     $self->_toggle("write", @_);
  745. }
  746.  
  747. sub toggle_exception {
  748.     my $self = shift;
  749.     $self->_toggle("exception", @_);
  750. }
  751.  
  752. sub _toggle {
  753.     my $self = shift;
  754.     my $type = shift;
  755.     my $fd = shift;
  756.     my $enabled = shift;
  757.  
  758.     $self->{fds}->{$type}->{$fd}->{enabled} = $enabled;
  759. }
  760.  
  761.  
  762. 1;
  763.  
  764. =pod
  765.  
  766. =back
  767.  
  768. =head1 SEE ALSO
  769.  
  770. L<Net::DBus::Callback>, L<Net::DBus::Connection>, L<Net::DBus::Server>
  771.  
  772. =head1 AUTHOR
  773.  
  774. Daniel Berrange E<lt>dan@berrange.comE<gt>
  775.  
  776. =head1 COPYRIGHT
  777.  
  778. Copyright 2004 by Daniel Berrange
  779.  
  780. =cut
  781.