diff options
author | root <root> | 2009-03-04 14:33:10 +0000 |
---|---|---|
committer | root <root> | 2009-03-04 14:33:10 +0000 |
commit | 12e7cbf440b105100ba865eb7ed5f0c8c459d459 (patch) | |
tree | 0c1cb9310ac11f4260b2de0c0631e622ac1e3e48 | |
parent | 9b1d64f822b71dd3b8ee14d11f9f63a64008d3ee (diff) |
*** empty log message ***
-rw-r--r-- | ev.h | 70 | ||||
-rw-r--r-- | ev.pod | 101 |
2 files changed, 96 insertions, 75 deletions
@@ -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 */ @@ -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 |