ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro/Timer.pm
Revision: 1.21
Committed: Wed Jan 12 20:35:35 2005 UTC (19 years, 4 months ago) by root
Branch: MAIN
Changes since 1.20: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 =head1 NAME
2
3 Coro::Timer - simple timer package, independent of used event loops
4
5 =head1 SYNOPSIS
6
7 use Coro::Timer qw(sleep timeout);
8 # nothing exported by default
9
10 sleep 10;
11
12 =head1 DESCRIPTION
13
14 This package implements a simple timer callback system which works
15 independent of the event loop mechanism used. If no event mechanism is
16 used, it is emulated. The C<Coro::Event> module overwrites functions with
17 versions better suited.
18
19 This module is not subclassable.
20
21 =over 4
22
23 =cut
24
25 package Coro::Timer;
26
27 BEGIN { eval { require warnings } && warnings->unimport ("uninitialized") }
28
29 use Carp ();
30 use Exporter;
31
32 use Coro ();
33
34 BEGIN {
35 eval "use Time::HiRes 'time'";
36 }
37
38 $VERSION = 1.0;
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 }
99
100 =item $timer = new Coro::Timer at/after => xxx, cb => \&yyy;
101
102 Create a new timer.
103
104 =cut
105
106 sub new {
107 my $class = shift;
108 my %arg = @_;
109
110 $arg{at} = time + delete $arg{after} if exists $arg{after};
111
112 _new_timer($arg{at}, $arg{cb});
113 }
114
115 my $timer;
116 my @timer;
117
118 unless ($override) {
119 $override = 1;
120 *_new_timer = sub {
121 my $self = bless [$_[0], $_[1]], Coro::Timer::simple;
122
123 # my version of rapid prototyping. guys, use a real event module!
124 @timer = sort { $a->[0] cmp $b->[0] } @timer, $self;
125
126 unless ($timer) {
127 $timer = new Coro sub {
128 my $NOW = time;
129 while (@timer) {
130 Coro::cede;
131 if ($NOW >= $timer[0][0]) {
132 my $next = shift @timer;
133 $next->[1] and $next->[1]->();
134 } else {
135 select undef, undef, undef, $timer[0][0] - $NOW;
136 $NOW = time;
137 }
138 };
139 undef $timer;
140 };
141 $timer->prio(Coro::PRIO_MIN);
142 $timer->ready;
143 }
144
145 $self;
146 };
147
148 *Coro::Timer::simple::cancel = sub {
149 @{$_[0]} = ();
150 };
151 }
152
153 =item $timer->cancel
154
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!
158
159 =cut
160
161 1;
162
163 =back
164
165 =head1 AUTHOR
166
167 Marc Lehmann <pcg@goof.com>
168 http://home.schmorp.de/
169
170 =cut
171