--- Coro/Event/Event.pm 2001/09/24 01:36:20 1.6 +++ Coro/Event/Event.pm 2008/05/29 18:05:53 1.58 @@ -8,7 +8,7 @@ use Coro::Event; sub keyboard : Coro { - my $w = Coro::Event->io(fd => *STDIN, poll => 'r'); + my $w = Coro::Event->io(fd => \*STDIN, poll => 'r'); while() { print "cmd> "; my $ev = $w->next; my $cmd = ; @@ -18,7 +18,15 @@ } } - &loop; + loop; + + # wait for input on stdin for one second + + Coro::Event::do_io (fd => \*STDIN, timeout => 1) & Event::Watcher::R + or die "no input received"; + + # use a separate coroutine for event processing, if impossible in main: + Coro::async { Event::loop }; =head1 DESCRIPTION @@ -32,7 +40,38 @@ function - it will be managed by this module. Your application should just create all necessary coroutines and then call -Coro::Event->main. +Coro::Event::loop. + +Please note that even programs or modules (such as +L) that use "traditional" +event-based/continuation style will run more efficient with this module +then when using only Event. + +=head1 WARNING + +Please note that Event does not support coroutines or threads. That +means that you B block in an event callback. Again: In Event +callbacks, you I call a Coroutine function that blocks +the current coroutine. + +While this seems to work superficially, it will eventually cause memory +corruption and often results in deadlocks. + +Best practise is to always use B for your callbacks. + +=head1 SEMANTICS + +Whenever Event blocks (e.g. in a call to C, C etc.), +this module cede's to all other coroutines with the same or higher +priority. When any coroutines of lower priority are ready, it will not +block but run one of them and then check for events. + +The effect is that coroutines with the same or higher priority than +the blocking coroutine will keep Event from checking for events, while +coroutines with lower priority are being run, but Event checks for new +events after every cede. + +=head1 FUNCTIONS =over 4 @@ -40,26 +79,28 @@ package Coro::Event; -no warnings qw(uninitialized); +no warnings; use Carp; +no warnings; use Coro; -use Event qw(unloop); # we are re-exporting this, cooool! +use Event qw(loop unloop); # we are re-exporting this, cooool! + +use XSLoader; -use base 'Exporter'; +use base Exporter::; -@EXPORT = qw(loop unloop sweep reschedule); +our @EXPORT = qw(loop unloop sweep); BEGIN { - $VERSION = 0.45; + our $VERSION = 4.74; - local $^W = 0; # avoid redefine warning for Coro::ready - require XSLoader; - XSLoader::load Coro::Event, $VERSION; + local $^W = 0; # avoid redefine warning for Coro::ready; + XSLoader::load __PACKAGE__, $VERSION; } -=item $w = Coro::Event->flavour(args...) +=item $w = Coro::Event->flavour (args...) Create and return a watcher of the given type. @@ -72,15 +113,20 @@ =item $w->next -Return the next event of the event queue of the watcher. +Wait for and return the next event of the event queue of the watcher. The +returned event objects support two methods only: C and C, both +of which return integers: the number this watcher was hit for this event, +and the mask of poll events received. =cut -=item do_flavour(args...) +=item do_flavour args... -Create a watcher of the given type and immediately call it's next -method. This is less efficient then calling the constructor once and the -next method often, but it does save typing sometimes. +Create a watcher of the given type and immediately call it's next method, +returning the event. + +This is less efficient then calling the constructor once and the next +method often, but it does save typing sometimes. =cut @@ -94,37 +140,39 @@ # how does one do method-call-by-name? # my $w = $class->SUPER::$flavour(@_); - $_[0] eq Coro::Event:: + shift eq Coro::Event:: or croak "event constructor \"Coro::Event->$flavour\" must be called as a static method"; - my $q = []; # [$coro, $event] - my $w = $new->( - desc => $flavour, - @_, - parked => 1, + my $w = $new->($class, + desc => $flavour, + @_, + parked => 1, ); - _install_std_cb($w, $type); - bless $w, $class; # reblessing due to broken Event + + _install_std_cb $w, $type; + + # reblessing due to Event being broken + bless $w, $class }; *{ $flavour } = $coronew; *{"do_$flavour"} = sub { unshift @_, Coro::Event::; - my $e = (&$coronew)->next; - $e->cancel; # $e = $e->w - $e; + @_ = &$coronew; + &Coro::schedule while &_next; + $_[0]->cancel; + &_event }; } -# double calls to avoid stack-cloning ;() -# is about 10% slower, though. +# do schedule in perl to avoid forcing a stack allocation. +# this is about 10% slower, though. sub next($) { - &Coro::schedule if &_next; $_[0]; + &Coro::schedule while &_next; + &_event } -sub Coro::Event::w { $_[0] } -sub Coro::Event::prio { $_[0]{Coro::Event}[3] } -sub Coro::Event::hits { $_[0]{Coro::Event}[4] } -sub Coro::Event::got { $_[0]{Coro::Event}[5] } +sub Coro::Event::Event::hits { $_[0][3] } +sub Coro::Event::Event::got { $_[0][4] } =item sweep @@ -140,7 +188,7 @@ =cut sub sweep { - one_event(0); # for now + Event::one_event 0; # for now } =item $result = loop([$timeout]) @@ -149,40 +197,31 @@ when using this module - it will ensure correct scheduling in the presence of events. -=begin comment - -Unlike loop's counterpart it is not an error when no watchers are active - -loop silently returns in this case, as if unloop(undef) were called. - -=end comment - -=cut - -sub loop(;$) { - local $Coro::idle = $Coro::current; - Coro::schedule; # become idle task, which is implicitly ready - &Event::loop; -} - =item unloop([$result]) Same as Event::unloop (provided here for your convinience only). =cut -$Coro::idle = new Coro sub { +# very inefficient +our $event_idle = new Coro sub { while () { - Event::one_event; # inefficient - Coro::schedule; + &Event::one_event; + &Coro::schedule; } }; +$event_idle->{desc} = "[Event idle process]"; + +$Coro::idle = sub { $event_idle->ready }; 1; +=back + =head1 AUTHOR - Marc Lehmann - http://www.goof.com/pcg/marc/ + Marc Lehmann + http://home.schmorp.de/ =cut