Skip to content

Commit

Permalink
added one_tick method to Mojo::Reactor and Mojo::Reactor::EV
Browse files Browse the repository at this point in the history
  • Loading branch information
kraih committed Mar 21, 2012
1 parent 39b7345 commit 9a2c14e
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 53 deletions.
1 change: 1 addition & 0 deletions Changes
@@ -1,6 +1,7 @@
This file documents the revision history for Perl extension Mojolicious.

2.65 2012-03-22 00:00:00
- Added one_tick method to Mojo::Reactor and Mojo::Reactor::EV.
- Improved documentation.
- Improved tests.

Expand Down
11 changes: 3 additions & 8 deletions lib/Mojo/IOLoop.pm
Expand Up @@ -102,8 +102,7 @@ sub is_running {
sub one_tick {
my $self = shift;
$self = $self->singleton unless ref $self;
$self->timer(shift // 0.025 => sub { shift->stop });
$self->start;
$self->reactor->one_tick;
}

sub recurring {
Expand Down Expand Up @@ -162,7 +161,6 @@ sub start {
$self = $self->singleton unless ref $self;
croak 'Mojo::IOLoop already running' if $self->is_running;
$self->reactor->start;
return $self;
}

sub stop {
Expand Down Expand Up @@ -505,11 +503,8 @@ Check if loop is running.
Mojo::IOLoop->one_tick;
$loop->one_tick;
$loop->one_tick(0.25);
$loop->one_tick(0);
Run reactor for roughly one tick and try not to block longer than the given
amount of time in seconds.
Run reactor for roughly one tick.
=head2 C<recurring>
Expand All @@ -521,7 +516,7 @@ amount of time in seconds.
# Run multiple reactors next to each other
my $loop2 = Mojo::IOLoop->new;
Mojo::IOLoop->recurring(0 => sub { $loop2->one_tick(0) });
Mojo::IOLoop->recurring(0 => sub { $loop2->one_tick });
=head2 C<server>
Expand Down
82 changes: 47 additions & 35 deletions lib/Mojo/Reactor.pm
Expand Up @@ -45,12 +45,52 @@ sub is_readable {
sub is_running { shift->{running} }

# "This was such a pleasant St. Patrick's Day until Irish people showed up."
sub one_tick {
my $self = shift;

# Remember state
(my $state, $self->{running}) = ($self->{running}, 1);

# I/O
my $poll = $self->_poll;
$poll->poll(0.025);
$self->_sandbox('Read', $self->{io}->{fileno $_}->{cb}, 0)
for $poll->handles(POLLIN | POLLHUP | POLLERR);
$self->_sandbox('Write', $self->{io}->{fileno $_}->{cb}, 1)
for $poll->handles(POLLOUT);

# Wait for timeout
usleep 25000 unless keys %{$self->{io}};

# Timers
while (my ($id, $t) = each %{$self->{timers} || {}}) {
my $after = $t->{after} || 0;
if ($after <= time - ($t->{started} || $t->{recurring} || 0)) {

# Normal timer
if ($t->{started}) { $self->drop($id) }

# Recurring timer
elsif ($after && $t->{recurring}) { $t->{recurring} += $after }

# Handle timer
if (my $cb = $t->{cb}) { $self->_sandbox("Timer $id", $cb) }
}
}

# Restore state if necessary
$self->{running} = $state if $self->{running};
}

sub recurring { shift->_timer(pop, after => pop, recurring => time) }

sub start {
my $self = shift;
return if $self->{running}++;
$self->_one_tick while $self->{running};
while ($self->{running}) {
$self->one_tick;
$self->stop unless keys(%{$self->{timers}}) || keys(%{$self->{io}});
}
}

sub stop { delete shift->{running} }
Expand Down Expand Up @@ -80,40 +120,6 @@ sub _timer {
return $id;
}

sub _one_tick {
my $self = shift;

# I/O
my $poll = $self->_poll;
$poll->poll(0.025);
$self->_sandbox('Read', $self->{io}->{fileno $_}->{cb}, 0)
for $poll->handles(POLLIN | POLLHUP | POLLERR);
$self->_sandbox('Write', $self->{io}->{fileno $_}->{cb}, 1)
for $poll->handles(POLLOUT);

# Wait for timeout
usleep 25000 unless keys %{$self->{io}};

# Timers
while (my ($id, $t) = each %{$self->{timers} || {}}) {
my $after = $t->{after} || 0;
if ($after <= time - ($t->{started} || $t->{recurring} || 0)) {

# Normal timer
if ($t->{started}) { $self->drop($id) }

# Recurring timer
elsif ($after && $t->{recurring}) { $t->{recurring} += $after }

# Handle timer
if (my $cb = $t->{cb}) { $self->_sandbox("Timer $id", $cb) }
}
}

# Stop automatically
$self->stop unless keys(%{$self->{timers}}) || keys(%{$self->{io}});
}

sub _poll { shift->{poll} ||= IO::Poll->new }

sub _sandbox {
Expand Down Expand Up @@ -222,6 +228,12 @@ sockets.
Check if reactor is running.
=head2 C<one_tick>
$reactor->one_tick;
Run reactor for roughly one tick.
=head2 C<recurring>
my $id = $reactor->recurring(0.25 => sub {...});
Expand Down
8 changes: 8 additions & 0 deletions lib/Mojo/Reactor/EV.pm
Expand Up @@ -13,6 +13,8 @@ sub new { $EV++ ? Mojo::Reactor->new : shift->SUPER::new }

sub is_running {EV::depth}

sub one_tick { EV::run(EV::RUN_NOWAIT) }

sub recurring { shift->_timer(shift, 1, @_) }

# "Wow, Barney. You brought a whole beer keg.
Expand Down Expand Up @@ -110,6 +112,12 @@ Construct a new L<Mojo::Reactor::EV> object.
Check if reactor is running.
=head2 C<one_tick>
$reactor->one_tick;
Run reactor for roughly one tick.
=head2 C<recurring>
my $id = $reactor->recurring(0.25 => sub {...});
Expand Down
8 changes: 4 additions & 4 deletions t/mojo/reactor.t
Expand Up @@ -98,14 +98,14 @@ my ($timer, $recurring);
$reactor->timer(0 => sub { $timer++ });
$reactor->drop($reactor->timer(0 => sub { $timer++ }));
my $id = $reactor->recurring(0 => sub { $recurring++ });
$reactor->timer(0 => sub { shift->stop });
$reactor->start;
$reactor->one_tick;
is $readable, 2, 'handle is readable again';
is $writable, 2, 'handle is writable again';
is $timer, 1, 'timer was triggered';
is $recurring, 1, 'recurring was triggered';
$reactor->timer(0 => sub { shift->stop });
$reactor->start;
my $done = 0;
$reactor->timer(0 => sub { $done = shift->is_running });
$reactor->one_tick while !$done;
is $readable, 3, 'handle is readable again';
is $writable, 3, 'handle is writable again';
is $timer, 1, 'timer was not triggered';
Expand Down
8 changes: 4 additions & 4 deletions t/mojo/reactor_ev.t
Expand Up @@ -99,14 +99,14 @@ my ($timer, $recurring);
$reactor->timer(0 => sub { $timer++ });
$reactor->drop($reactor->timer(0 => sub { $timer++ }));
my $id = $reactor->recurring(0 => sub { $recurring++ });
$reactor->timer(0 => sub { shift->stop });
$reactor->start;
$reactor->one_tick;
is $readable, 2, 'handle is readable again';
is $writable, 2, 'handle is writable again';
is $timer, 1, 'timer was triggered';
is $recurring, 1, 'recurring was triggered';
$reactor->timer(0 => sub { shift->stop });
$reactor->start;
my $done = 0;
$reactor->timer(0 => sub { $done = shift->is_running });
$reactor->one_tick while !$done;
is $readable, 3, 'handle is readable again';
is $writable, 3, 'handle is writable again';
is $timer, 1, 'timer was not triggered';
Expand Down
2 changes: 1 addition & 1 deletion t/mojo/user_agent_online.t
Expand Up @@ -41,7 +41,7 @@ $ua->get(
);
$loop->start;
$ua = undef;
$loop->one_tick(0);
$loop->one_tick;
ok !$loop->stream($id), 'loop not tainted';
is $code, 301, 'right status';

Expand Down
2 changes: 1 addition & 1 deletion t/mojolicious/lite_app.t
Expand Up @@ -1398,7 +1398,7 @@ $t->get_ok('/dynamic/inline')->status_is(200)
->content_is("dynamic inline 2\n");

# User agent timer
$tua->ioloop->one_tick('0.1');
$tua->ioloop->one_tick;
is $timer,
"/root.html\n/root.html\n/root.html\n/root.html\n/root.html\nworks!",
'right content';
Expand Down

0 comments on commit 9a2c14e

Please sign in to comment.