--- Coro/Event/Event.pm 2005/11/29 12:36:18 1.30 +++ Coro/Event/Event.pm 2008/04/25 04:28:50 1.54 @@ -20,6 +20,14 @@ 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 This module enables you to create programs using the powerful Event model @@ -34,34 +42,66 @@ Your application should just create all necessary coroutines and then call 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 =cut package Coro::Event; -BEGIN { eval { require warnings } && warnings->unimport ("uninitialized") } +no warnings; use Carp; no warnings; use Coro; +use Coro::Timer; use Event qw(loop unloop); # we are re-exporting this, cooool! use XSLoader; use base Exporter::; -our @EXPORT = qw(loop unloop sweep reschedule); +our @EXPORT = qw(loop unloop sweep); BEGIN { - our $VERSION = 1.5; + our $VERSION = 4.6; 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. @@ -74,15 +114,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, +returning the event. -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. +This is less efficient then calling the constructor once and the next +method often, but it does save typing sometimes. =cut @@ -100,32 +145,35 @@ or croak "event constructor \"Coro::Event->$flavour\" must be called as a static method"; my $w = $new->($class, - desc => $flavour, - @_, - parked => 1, + 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 @@ -141,7 +189,7 @@ =cut sub sweep { - Event::one_event(0); # for now + Event::one_event 0; # for now } =item $result = loop([$timeout]) @@ -150,49 +198,27 @@ 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 - -# no longer do something special - it's done internally now - -#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]"; -# provide hooks for Coro::Timer - -package Coro::Timer; - -unless ($override) { - $override = 1; - *_new_timer = sub { - Event->timer(at => $_[0], cb => $_[1]); - }; -} +$Coro::idle = sub { $event_idle->ready }; 1; +=back + =head1 AUTHOR Marc Lehmann