summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorroot <root>2009-03-04 14:33:10 +0000
committerroot <root>2009-03-04 14:33:10 +0000
commit12e7cbf440b105100ba865eb7ed5f0c8c459d459 (patch)
tree0c1cb9310ac11f4260b2de0c0631e622ac1e3e48
parent9b1d64f822b71dd3b8ee14d11f9f63a64008d3ee (diff)
*** empty log message ***
-rw-r--r--ev.h70
-rw-r--r--ev.pod101
2 files changed, 96 insertions, 75 deletions
diff --git a/ev.h b/ev.h
index 7878e0c..473d4ae 100644
--- a/ev.h
+++ b/ev.h
@@ -530,43 +530,43 @@ void ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revent
ev_set_cb ((ev), cb_); \
} while (0)
-#define ev_io_set(ev,fd_,events_) do { (ev)->fd = (fd_); (ev)->events = (events_) | EV_IOFDSET; } while (0)
-#define ev_timer_set(ev,after_,repeat_) do { ((ev_watcher_time *)(ev))->at = (after_); (ev)->repeat = (repeat_); } while (0)
-#define ev_periodic_set(ev,ofs_,ival_,res_) do { (ev)->offset = (ofs_); (ev)->interval = (ival_); (ev)->reschedule_cb= (res_); } while (0)
-#define ev_signal_set(ev,signum_) do { (ev)->signum = (signum_); } while (0)
-#define ev_child_set(ev,pid_,trace_) do { (ev)->pid = (pid_); (ev)->flags = !!(trace_); } while (0)
-#define ev_stat_set(ev,path_,interval_) do { (ev)->path = (path_); (ev)->interval = (interval_); (ev)->wd = -2; } while (0)
-#define ev_idle_set(ev) /* nop, yes, this is a serious in-joke */
-#define ev_prepare_set(ev) /* nop, yes, this is a serious in-joke */
-#define ev_check_set(ev) /* nop, yes, this is a serious in-joke */
-#define ev_embed_set(ev,other_) do { (ev)->other = (other_); } while (0)
-#define ev_fork_set(ev) /* nop, yes, this is a serious in-joke */
-#define ev_async_set(ev) do { (ev)->sent = 0; } while (0)
-
-#define ev_io_init(ev,cb,fd,events) do { ev_init ((ev), (cb)); ev_io_set ((ev),(fd),(events)); } while (0)
-#define ev_timer_init(ev,cb,after,repeat) do { ev_init ((ev), (cb)); ev_timer_set ((ev),(after),(repeat)); } while (0)
-#define ev_periodic_init(ev,cb,at,ival,res) do { ev_init ((ev), (cb)); ev_periodic_set ((ev),(at),(ival),(res)); } while (0)
-#define ev_signal_init(ev,cb,signum) do { ev_init ((ev), (cb)); ev_signal_set ((ev), (signum)); } while (0)
-#define ev_child_init(ev,cb,pid,trace) do { ev_init ((ev), (cb)); ev_child_set ((ev),(pid),(trace)); } while (0)
-#define ev_stat_init(ev,cb,path,interval) do { ev_init ((ev), (cb)); ev_stat_set ((ev),(path),(interval)); } while (0)
-#define ev_idle_init(ev,cb) do { ev_init ((ev), (cb)); ev_idle_set ((ev)); } while (0)
-#define ev_prepare_init(ev,cb) do { ev_init ((ev), (cb)); ev_prepare_set ((ev)); } while (0)
-#define ev_check_init(ev,cb) do { ev_init ((ev), (cb)); ev_check_set ((ev)); } while (0)
-#define ev_embed_init(ev,cb,other) do { ev_init ((ev), (cb)); ev_embed_set ((ev),(other)); } while (0)
-#define ev_fork_init(ev,cb) do { ev_init ((ev), (cb)); ev_fork_set ((ev)); } while (0)
-#define ev_async_init(ev,cb) do { ev_init ((ev), (cb)); ev_async_set ((ev)); } while (0)
-
-#define ev_is_pending(ev) (0 + ((ev_watcher *)(void *)(ev))->pending) /* ro, true when watcher is waiting for callback invocation */
-#define ev_is_active(ev) (0 + ((ev_watcher *)(void *)(ev))->active) /* ro, true when the watcher has been started */
-
-#define ev_priority(ev) ((((ev_watcher *)(void *)(ev))->priority) + 0)
-#define ev_cb(ev) (ev)->cb /* rw */
-#define ev_set_priority(ev,pri) ((ev_watcher *)(void *)(ev))->priority = (pri)
-
-#define ev_periodic_at(ev) (((ev_watcher_time *)(ev))->at + 0.)
+#define ev_io_set(ev,fd_,events_) do { (ev)->fd = (fd_); (ev)->events = (events_) | EV_IOFDSET; } while (0)
+#define ev_timer_set(ev,after_,repeat_) do { ((ev_watcher_time *)(ev))->at = (after_); (ev)->repeat = (repeat_); } while (0)
+#define ev_periodic_set(ev,ofs_,ival_,rcb_) do { (ev)->offset = (ofs_); (ev)->interval = (ival_); (ev)->reschedule_cb = (rcb_); } while (0)
+#define ev_signal_set(ev,signum_) do { (ev)->signum = (signum_); } while (0)
+#define ev_child_set(ev,pid_,trace_) do { (ev)->pid = (pid_); (ev)->flags = !!(trace_); } while (0)
+#define ev_stat_set(ev,path_,interval_) do { (ev)->path = (path_); (ev)->interval = (interval_); (ev)->wd = -2; } while (0)
+#define ev_idle_set(ev) /* nop, yes, this is a serious in-joke */
+#define ev_prepare_set(ev) /* nop, yes, this is a serious in-joke */
+#define ev_check_set(ev) /* nop, yes, this is a serious in-joke */
+#define ev_embed_set(ev,other_) do { (ev)->other = (other_); } while (0)
+#define ev_fork_set(ev) /* nop, yes, this is a serious in-joke */
+#define ev_async_set(ev) do { (ev)->sent = 0; } while (0)
+
+#define ev_io_init(ev,cb,fd,events) do { ev_init ((ev), (cb)); ev_io_set ((ev),(fd),(events)); } while (0)
+#define ev_timer_init(ev,cb,after,repeat) do { ev_init ((ev), (cb)); ev_timer_set ((ev),(after),(repeat)); } while (0)
+#define ev_periodic_init(ev,cb,ofs,ival,rcb) do { ev_init ((ev), (cb)); ev_periodic_set ((ev),(ofs),(ival),(rcb)); } while (0)
+#define ev_signal_init(ev,cb,signum) do { ev_init ((ev), (cb)); ev_signal_set ((ev), (signum)); } while (0)
+#define ev_child_init(ev,cb,pid,trace) do { ev_init ((ev), (cb)); ev_child_set ((ev),(pid),(trace)); } while (0)
+#define ev_stat_init(ev,cb,path,interval) do { ev_init ((ev), (cb)); ev_stat_set ((ev),(path),(interval)); } while (0)
+#define ev_idle_init(ev,cb) do { ev_init ((ev), (cb)); ev_idle_set ((ev)); } while (0)
+#define ev_prepare_init(ev,cb) do { ev_init ((ev), (cb)); ev_prepare_set ((ev)); } while (0)
+#define ev_check_init(ev,cb) do { ev_init ((ev), (cb)); ev_check_set ((ev)); } while (0)
+#define ev_embed_init(ev,cb,other) do { ev_init ((ev), (cb)); ev_embed_set ((ev),(other)); } while (0)
+#define ev_fork_init(ev,cb) do { ev_init ((ev), (cb)); ev_fork_set ((ev)); } while (0)
+#define ev_async_init(ev,cb) do { ev_init ((ev), (cb)); ev_async_set ((ev)); } while (0)
+
+#define ev_is_pending(ev) (0 + ((ev_watcher *)(void *)(ev))->pending) /* ro, true when watcher is waiting for callback invocation */
+#define ev_is_active(ev) (0 + ((ev_watcher *)(void *)(ev))->active) /* ro, true when the watcher has been started */
+
+#define ev_priority(ev) ((((ev_watcher *)(void *)(ev))->priority) + 0)
+#define ev_cb(ev) (ev)->cb /* rw */
+#define ev_set_priority(ev,pri) ((ev_watcher *)(void *)(ev))->priority = (pri)
+
+#define ev_periodic_at(ev) (((ev_watcher_time *)(ev))->at + 0.)
#ifndef ev_set_cb
-# define ev_set_cb(ev,cb_) ev_cb (ev) = (cb_)
+# define ev_set_cb(ev,cb_) ev_cb (ev) = (cb_)
#endif
/* stopping (enabling, adding) a watcher does nothing if it is already running */
diff --git a/ev.pod b/ev.pod
index 6ebb511..8f597ac 100644
--- a/ev.pod
+++ b/ev.pod
@@ -1598,52 +1598,62 @@ inactivity.
Periodic watchers are also timers of a kind, but they are very versatile
(and unfortunately a bit complex).
-Unlike C<ev_timer>'s, they are not based on real time (or relative time)
-but on wall clock time (absolute time). You can tell a periodic watcher
-to trigger after some specific point in time. For example, if you tell a
-periodic watcher to trigger in 10 seconds (by specifying e.g. C<ev_now ()
-+ 10.>, that is, an absolute time not a delay) and then reset your system
-clock to January of the previous year, then it will take more than year
-to trigger the event (unlike an C<ev_timer>, which would still trigger
-roughly 10 seconds later as it uses a relative timeout).
-
-C<ev_periodic>s can also be used to implement vastly more complex timers,
-such as triggering an event on each "midnight, local time", or other
-complicated rules.
+Unlike C<ev_timer>, periodic watchers are not based on real time (or
+relative time, the physical time that passes) but on wall clock time
+(absolute time, the thing you can read on your calender or clock). The
+difference is that wall clock time can run faster or slower than real
+time, and time jumps are not uncommon (e.g. when you adjust your
+wrist-watch).
+
+You can tell a periodic watcher to trigger after some specific point
+in time: for example, if you tell a periodic watcher to trigger "in 10
+seconds" (by specifying e.g. C<ev_now () + 10.>, that is, an absolute time
+not a delay) and then reset your system clock to January of the previous
+year, then it will take a year or more to trigger the event (unlike an
+C<ev_timer>, which would still trigger roughly 10 seconds after starting
+it, as it uses a relative timeout).
+
+C<ev_periodic> watchers can also be used to implement vastly more complex
+timers, such as triggering an event on each "midnight, local time", or
+other complicated rules. This cannot be done with C<ev_timer> watchers, as
+those cannot react to time jumps.
As with timers, the callback is guaranteed to be invoked only when the
-time (C<at>) has passed, but if multiple periodic timers become ready
-during the same loop iteration, then order of execution is undefined.
+point in time where it is supposed to trigger has passed, but if multiple
+periodic timers become ready during the same loop iteration, then order of
+execution is undefined.
=head3 Watcher-Specific Functions and Data Members
=over 4
-=item ev_periodic_init (ev_periodic *, callback, ev_tstamp at, ev_tstamp interval, reschedule_cb)
+=item ev_periodic_init (ev_periodic *, callback, ev_tstamp offset, ev_tstamp interval, reschedule_cb)
-=item ev_periodic_set (ev_periodic *, ev_tstamp at, ev_tstamp interval, reschedule_cb)
+=item ev_periodic_set (ev_periodic *, ev_tstamp offset, ev_tstamp interval, reschedule_cb)
-Lots of arguments, lets sort it out... There are basically three modes of
+Lots of arguments, let's sort it out... There are basically three modes of
operation, and we will explain them from simplest to most complex:
=over 4
-=item * absolute timer (at = time, interval = reschedule_cb = 0)
+=item * absolute timer (offset = absolute time, interval = 0, reschedule_cb = 0)
In this configuration the watcher triggers an event after the wall clock
-time C<at> has passed. It will not repeat and will not adjust when a time
-jump occurs, that is, if it is to be run at January 1st 2011 then it will
-only run when the system clock reaches or surpasses this time.
+time C<offset> has passed. It will not repeat and will not adjust when a
+time jump occurs, that is, if it is to be run at January 1st 2011 then it
+will be stopped and invoked when the system clock reaches or surpasses
+this point in time.
-=item * repeating interval timer (at = offset, interval > 0, reschedule_cb = 0)
+=item * repeating interval timer (offset = offset within interval, interval > 0, reschedule_cb = 0)
In this mode the watcher will always be scheduled to time out at the next
-C<at + N * interval> time (for some integer N, which can also be negative)
-and then repeat, regardless of any time jumps.
+C<offset + N * interval> time (for some integer N, which can also be
+negative) and then repeat, regardless of any time jumps. The C<offset>
+argument is merely an offset into the C<interval> periods.
This can be used to create timers that do not drift with respect to the
-system clock, for example, here is a C<ev_periodic> that triggers each
-hour, on the hour:
+system clock, for example, here is an C<ev_periodic> that triggers each
+hour, on the hour (with respect to UTC):
ev_periodic_set (&periodic, 0., 3600., 0);
@@ -1654,9 +1664,9 @@ by 3600.
Another way to think about it (for the mathematically inclined) is that
C<ev_periodic> will try to run the callback in this mode at the next possible
-time where C<time = at (mod interval)>, regardless of any time jumps.
+time where C<time = offset (mod interval)>, regardless of any time jumps.
-For numerical stability it is preferable that the C<at> value is near
+For numerical stability it is preferable that the C<offset> value is near
C<ev_now ()> (the current time), but there is no range requirement for
this value, and in fact is often specified as zero.
@@ -1665,15 +1675,16 @@ speed for example), so if C<interval> is very small then timing stability
will of course deteriorate. Libev itself tries to be exact to be about one
millisecond (if the OS supports it and the machine is fast enough).
-=item * manual reschedule mode (at and interval ignored, reschedule_cb = callback)
+=item * manual reschedule mode (offset ignored, interval ignored, reschedule_cb = callback)
-In this mode the values for C<interval> and C<at> are both being
+In this mode the values for C<interval> and C<offset> are both being
ignored. Instead, each time the periodic watcher gets scheduled, the
reschedule callback will be called with the watcher as first, and the
current time as second argument.
-NOTE: I<This callback MUST NOT stop or destroy any periodic watcher,
-ever, or make ANY other event loop modifications whatsoever>.
+NOTE: I<This callback MUST NOT stop or destroy any periodic watcher, ever,
+or make ANY other event loop modifications whatsoever, unless explicitly
+allowed by documentation here>.
If you need to stop it, return C<now + 1e30> (or so, fudge fudge) and stop
it afterwards (e.g. by starting an C<ev_prepare> watcher, which is the
@@ -1713,13 +1724,16 @@ program when the crontabs have changed).
=item ev_tstamp ev_periodic_at (ev_periodic *)
-When active, returns the absolute time that the watcher is supposed to
-trigger next.
+When active, returns the absolute time that the watcher is supposed
+to trigger next. This is not the same as the C<offset> argument to
+C<ev_periodic_set>, but indeed works even in interval and manual
+rescheduling modes.
=item ev_tstamp offset [read-write]
When repeating, this contains the offset value, otherwise this is the
-absolute point in time (the C<at> value passed to C<ev_periodic_set>).
+absolute point in time (the C<offset> value passed to C<ev_periodic_set>,
+although libev might modify this value for better numerical stability).
Can be modified any time, but changes only take effect when the periodic
timer fires or C<ev_periodic_again> is being called.
@@ -2684,9 +2698,14 @@ C<ev_feed_event>, this call is safe to do from other threads, signal or
similar contexts (see the discussion of C<EV_ATOMIC_T> in the embedding
section below on what exactly this means).
-This call incurs the overhead of a system call only once per loop iteration,
-so while the overhead might be noticeable, it doesn't apply to repeated
-calls to C<ev_async_send>.
+Note that, as with other watchers in libev, multiple events might get
+compressed into a single callback invocation (another way to look at this
+is that C<ev_async> watchers are level-triggered, set on C<ev_async_send>,
+reset when the event loop detects that).
+
+This call incurs the overhead of a system call only once per event loop
+iteration, so while the overhead might be noticeable, it doesn't apply to
+repeated calls to C<ev_async_send> for the same event loop.
=item bool = ev_async_pending (ev_async *)
@@ -2699,8 +2718,10 @@ the loop iterates next and checks for the watcher to have become active,
it will reset the flag again. C<ev_async_pending> can be used to very
quickly check whether invoking the loop might be a good idea.
-Not that this does I<not> check whether the watcher itself is pending, only
-whether it has been requested to make this watcher pending.
+Not that this does I<not> check whether the watcher itself is pending,
+only whether it has been requested to make this watcher pending: there
+is a time window between the event loop checking and resetting the async
+notification, and the callback being invoked.
=back