… | |
… | |
2 | |
2 | |
3 | Coro::Timer - simple timer package, independent of used event loops |
3 | Coro::Timer - simple timer package, independent of used event loops |
4 | |
4 | |
5 | =head1 SYNOPSIS |
5 | =head1 SYNOPSIS |
6 | |
6 | |
7 | use Coro::Timer; |
7 | use Coro::Timer qw(sleep timeout); |
|
|
8 | # nothing exported by default |
|
|
9 | |
|
|
10 | sleep 10; |
8 | |
11 | |
9 | =head1 DESCRIPTION |
12 | =head1 DESCRIPTION |
10 | |
13 | |
11 | This package implements a simple timer callback system which works |
14 | This package implements a simple timer callback system which works |
12 | independent of the event loop mechanism used. If no event mechanism is |
15 | independent of the event loop mechanism used. If no event mechanism is |
13 | used, it is emulated. The C<Coro::Event> module overwrites functions with |
16 | used, it is emulated. The C<Coro::Event> module overwrites functions with |
14 | versions better suited. |
17 | versions better suited. |
15 | |
18 | |
|
|
19 | This module is not subclassable. |
|
|
20 | |
16 | =over 4 |
21 | =over 4 |
17 | |
22 | |
18 | =cut |
23 | =cut |
19 | |
24 | |
20 | package Coro::Timer; |
25 | package Coro::Timer; |
21 | |
26 | |
22 | no warnings qw(uninitialized); |
27 | BEGIN { eval { require warnings } && warnings->unimport ("uninitialized") } |
23 | |
28 | |
24 | use Carp (); |
29 | use Carp (); |
|
|
30 | use Exporter; |
25 | |
31 | |
26 | use Coro (); |
32 | use Coro (); |
27 | |
33 | |
|
|
34 | BEGIN { |
28 | BEGIN { eval "use Time::HiRes 'time'" } |
35 | eval "use Time::HiRes 'time'"; |
|
|
36 | } |
29 | |
37 | |
30 | $VERSION = 0.52; |
38 | $VERSION = 1.6; |
|
|
39 | @EXPORT_OK = qw(timeout sleep); |
|
|
40 | |
|
|
41 | =item $flag = timeout $seconds; |
|
|
42 | |
|
|
43 | This function will wake up the current coroutine after $seconds |
|
|
44 | seconds and sets $flag to true (it is false initially). If $flag goes |
|
|
45 | out of scope earlier nothing happens. This is used to implement the |
|
|
46 | C<timed_down>, C<timed_wait> etc. primitives. It is used like this: |
|
|
47 | |
|
|
48 | sub timed_wait { |
|
|
49 | my $timeout = Coro::Timer::timeout 60; |
|
|
50 | |
|
|
51 | while (condition false) { |
|
|
52 | schedule; # wait until woken up or timeout |
|
|
53 | return 0 if $timeout; # timed out |
|
|
54 | } |
|
|
55 | return 1; # condition satisfied |
|
|
56 | } |
|
|
57 | |
|
|
58 | =cut |
|
|
59 | |
|
|
60 | # deep magic, expecially the double indirection :(:( |
|
|
61 | sub timeout($) { |
|
|
62 | my $self = \\my $timer; |
|
|
63 | my $current = $Coro::current; |
|
|
64 | $timer = _new_timer(time + $_[0], sub { |
|
|
65 | undef $timer; # set flag |
|
|
66 | $current->ready; |
|
|
67 | }); |
|
|
68 | bless $self, Coro::timeout::; |
|
|
69 | } |
|
|
70 | |
|
|
71 | package Coro::timeout; |
|
|
72 | |
|
|
73 | sub bool { |
|
|
74 | !${${$_[0]}} |
|
|
75 | } |
|
|
76 | |
|
|
77 | sub DESTROY { |
|
|
78 | ${${$_[0]}}->cancel; |
|
|
79 | undef ${${$_[0]}}; # without this it leaks like hell. breaks the circular reference inside the closure |
|
|
80 | } |
|
|
81 | |
|
|
82 | use overload 'bool' => \&bool, '0+' => \&bool; |
|
|
83 | |
|
|
84 | package Coro::Timer; |
|
|
85 | |
|
|
86 | =item sleep $seconds |
|
|
87 | |
|
|
88 | This function works like the built-in sleep, except maybe more precise |
|
|
89 | and, most important, without blocking other coroutines. |
|
|
90 | |
|
|
91 | =cut |
|
|
92 | |
|
|
93 | sub sleep { |
|
|
94 | my $current = $Coro::current; |
|
|
95 | my $timer = _new_timer(time + $_[0], sub { $current->ready }); |
|
|
96 | Coro::schedule; |
|
|
97 | $timer->cancel; |
|
|
98 | } |
31 | |
99 | |
32 | =item $timer = new Coro::Timer at/after => xxx, cb => \&yyy; |
100 | =item $timer = new Coro::Timer at/after => xxx, cb => \&yyy; |
33 | |
101 | |
34 | Create a new timer. |
102 | Create a new timer. |
35 | |
103 | |
… | |
… | |
39 | my $class = shift; |
107 | my $class = shift; |
40 | my %arg = @_; |
108 | my %arg = @_; |
41 | |
109 | |
42 | $arg{at} = time + delete $arg{after} if exists $arg{after}; |
110 | $arg{at} = time + delete $arg{after} if exists $arg{after}; |
43 | |
111 | |
44 | _new_timer($class, $arg{at}, $arg{cb}); |
112 | _new_timer($arg{at}, $arg{cb}); |
45 | } |
113 | } |
46 | |
114 | |
47 | my $timer; |
115 | my $timer; |
48 | my @timer; |
116 | my @timer; |
49 | |
117 | |
50 | unless ($override) { |
118 | unless ($override) { |
51 | $override = 1; |
119 | $override = 1; |
52 | *_new_timer = sub { |
120 | *_new_timer = sub { |
53 | my $self = bless [$_[1], $_[2]], $_[0]; |
121 | my $self = bless [$_[0], $_[1]], Coro::Timer::simple; |
54 | |
122 | |
55 | # my version of rapid prototyping. guys, use a real event module! |
123 | # my version of rapid prototyping. guys, use a real event module! |
56 | @timer = sort { $a->[0] cmp $b->[0] } @timer, $self; |
124 | @timer = sort { $a->[0] cmp $b->[0] } @timer, $self; |
57 | |
125 | |
58 | unless ($timer) { |
126 | unless ($timer) { |
… | |
… | |
66 | } else { |
134 | } else { |
67 | select undef, undef, undef, $timer[0][0] - $NOW; |
135 | select undef, undef, undef, $timer[0][0] - $NOW; |
68 | $NOW = time; |
136 | $NOW = time; |
69 | } |
137 | } |
70 | }; |
138 | }; |
71 | print "hihohihoh ($timer, $timer->{_coro_state})\n"; |
|
|
72 | print "hihohihoy $Coro::current\n"; |
|
|
73 | use Devel::Peek; |
|
|
74 | #Dump($timer); |
|
|
75 | undef $timer; |
139 | undef $timer; |
76 | print "hihohihox $Coro::current\n"; |
|
|
77 | }; |
140 | }; |
78 | $timer->prio(Coro::PRIO_MIN); |
141 | $timer->prio(Coro::PRIO_MIN); |
79 | $timer->ready; |
142 | $timer->ready; |
80 | } |
143 | } |
81 | |
144 | |
82 | $self; |
145 | $self; |
83 | }; |
146 | }; |
84 | |
147 | |
85 | *cancel = sub { |
148 | *Coro::Timer::simple::cancel = sub { |
86 | undef $_[0][1]; |
149 | @{$_[0]} = (); |
87 | }; |
150 | }; |
88 | } |
151 | } |
89 | |
152 | |
90 | =item $timer->cancel |
153 | =item $timer->cancel |
91 | |
154 | |
92 | Cancel the timer (the callback will no longer be called). |
155 | Cancel the timer (the callback will no longer be called). This method MUST |
|
|
156 | be called to remove the timer from memory, otherwise it will never be |
|
|
157 | freed! |
93 | |
158 | |
94 | =cut |
159 | =cut |
95 | |
160 | |
96 | 1; |
161 | 1; |
97 | |
162 | |
98 | =back |
163 | =back |
99 | |
164 | |
100 | =head1 AUTHOR |
165 | =head1 AUTHOR |
101 | |
166 | |
102 | Marc Lehmann <pcg@goof.com> |
167 | Marc Lehmann <schmorp@schmorp.de> |
103 | http://www.goof.com/pcg/marc/ |
168 | http://home.schmorp.de/ |
104 | |
169 | |
105 | =cut |
170 | =cut |
106 | |
171 | |