EV
view release on metacpan or search on metacpan
libev/ev.pod view on Meta::CPAN
configuration will be described, which supports multiple event loops. For
more info about various configuration options please have a look at
B<EMBED> section in this manual. If libev was configured without support
for multiple event loops, then all functions taking an initial argument of
name C<loop> (which is always of type C<struct ev_loop *>) will not have
this argument.
=head2 TIME REPRESENTATION
Libev represents time as a single floating point number, representing
the (fractional) number of seconds since the (POSIX) epoch (in practice
somewhere near the beginning of 1970, details are complicated, don't
ask). This type is called C<ev_tstamp>, which is what you should use
too. It usually aliases to the C<double> type in C. When you need to do
any calculations on it, you should treat it as some floating point value.
Unlike the name component C<stamp> might indicate, it is also used for
time differences (e.g. delays) throughout libev.
=head1 ERROR HANDLING
Libev knows three classes of errors: operating system errors, usage errors
and internal errors (bugs).
When libev catches an operating system error it cannot handle (for example
a system call indicating a condition libev cannot fix), it calls the callback
set via C<ev_set_syserr_cb>, which is supposed to fix the problem or
abort. The default is to print a diagnostic message and to call C<abort
()>.
When libev detects a usage error such as a negative timer interval, then
it will print a diagnostic message and abort (via the C<assert> mechanism,
so C<NDEBUG> will disable this checking): these are programming errors in
the libev caller and need to be fixed there.
Via the C<EV_FREQUENT> macro you can compile in and/or enable extensive
consistency checking code inside libev that can be used to check for
internal inconsistencies, suually caused by application bugs.
Libev also has a few internal error-checking C<assert>ions. These do not
trigger under normal circumstances, as they indicate either a bug in libev
or worse.
=head1 GLOBAL FUNCTIONS
These functions can be called anytime, even before initialising the
library in any way.
=over 4
=item ev_tstamp ev_time ()
Returns the current time as libev would use it. Please note that the
C<ev_now> function is usually faster and also often returns the timestamp
you actually want to know. Also interesting is the combination of
C<ev_now_update> and C<ev_now>.
=item ev_sleep (ev_tstamp interval)
Sleep for the given interval: The current thread will be blocked
until either it is interrupted or the given time interval has
passed (approximately - it might return a bit earlier even if not
interrupted). Returns immediately if C<< interval <= 0 >>.
Basically this is a sub-second-resolution C<sleep ()>.
The range of the C<interval> is limited - libev only guarantees to work
with sleep times of up to one day (C<< interval <= 86400 >>).
=item int ev_version_major ()
=item int ev_version_minor ()
You can find out the major and minor ABI version numbers of the library
you linked against by calling the functions C<ev_version_major> and
C<ev_version_minor>. If you want, you can compare against the global
symbols C<EV_VERSION_MAJOR> and C<EV_VERSION_MINOR>, which specify the
version of the library your program was compiled against.
These version numbers refer to the ABI version of the library, not the
release version.
Usually, it's a good idea to terminate if the major versions mismatch,
as this indicates an incompatible change. Minor versions are usually
compatible to older versions, so a larger minor version alone is usually
not a problem.
Example: Make sure we haven't accidentally been linked against the wrong
version (note, however, that this will not detect other ABI mismatches,
such as LFS or reentrancy).
assert (("libev version mismatch",
ev_version_major () == EV_VERSION_MAJOR
&& ev_version_minor () >= EV_VERSION_MINOR));
=item unsigned int ev_supported_backends ()
Return the set of all backends (i.e. their corresponding C<EV_BACKEND_*>
value) compiled into this binary of libev (independent of their
availability on the system you are running on). See C<ev_default_loop> for
a description of the set values.
Example: make sure we have the epoll method, because yeah this is cool and
a must have and can we have a torrent of it please!!!11
assert (("sorry, no epoll, no sex",
ev_supported_backends () & EVBACKEND_EPOLL));
=item unsigned int ev_recommended_backends ()
Return the set of all backends compiled into this binary of libev and
also recommended for this platform, meaning it will work for most file
descriptor types. This set is often smaller than the one returned by
C<ev_supported_backends>, as for example kqueue is broken on most BSDs
and will not be auto-detected unless you explicitly request it (assuming
you know what you are doing). This is the set of backends that libev will
probe for if you specify no backends explicitly.
=item unsigned int ev_embeddable_backends ()
libev/ev.pod view on Meta::CPAN
=item C<EVFLAG_AUTO>
The default flags value. Use this if you have no clue (it's the right
thing, believe me).
=item C<EVFLAG_NOENV>
If this flag bit is or'ed into the flag value (or the program runs setuid
or setgid) then libev will I<not> look at the environment variable
C<LIBEV_FLAGS>. Otherwise (the default), this environment variable will
override the flags completely if it is found in the environment. This is
useful to try out specific backends to test their performance, to work
around bugs, or to make libev threadsafe (accessing environment variables
cannot be done in a threadsafe way, but usually it works if no other
thread modifies them).
=item C<EVFLAG_FORKCHECK>
Instead of calling C<ev_loop_fork> manually after a fork, you can also
make libev check for a fork in each iteration by enabling this flag.
This works by calling C<getpid ()> on every iteration of the loop,
and thus this might slow down your event loop if you do a lot of loop
iterations and little real work, but is usually not noticeable (on my
GNU/Linux system for example, C<getpid> is actually a simple 5-insn
sequence without a system call and thus I<very> fast, but my GNU/Linux
system also has C<pthread_atfork> which is even faster). (Update: glibc
versions 2.25 apparently removed the C<getpid> optimisation again).
The big advantage of this flag is that you can forget about fork (and
forget about forgetting to tell libev about forking, although you still
have to ignore C<SIGPIPE>) when you use this flag.
This flag setting cannot be overridden or specified in the C<LIBEV_FLAGS>
environment variable.
=item C<EVFLAG_NOINOTIFY>
When this flag is specified, then libev will not attempt to use the
I<inotify> API for its C<ev_stat> watchers. Apart from debugging and
testing, this flag can be useful to conserve inotify file descriptors, as
otherwise each loop using C<ev_stat> watchers consumes one inotify handle.
=item C<EVFLAG_SIGNALFD>
When this flag is specified, then libev will attempt to use the
I<signalfd> API for its C<ev_signal> (and C<ev_child>) watchers. This API
delivers signals synchronously, which makes it both faster and might make
it possible to get the queued signal data. It can also simplify signal
handling with threads, as long as you properly block signals in your
threads that are not interested in handling them.
Signalfd will not be used by default as this changes your signal mask, and
there are a lot of shoddy libraries and programs (glib's threadpool for
example) that can't properly initialise their signal masks.
=item C<EVFLAG_NOSIGMASK>
When this flag is specified, then libev will avoid to modify the signal
mask. Specifically, this means you have to make sure signals are unblocked
when you want to receive them.
This behaviour is useful when you want to do your own signal handling, or
want to handle signals only in specific threads and want to avoid libev
unblocking the signals.
It's also required by POSIX in a threaded program, as libev calls
C<sigprocmask>, whose behaviour is officially unspecified.
=item C<EVFLAG_NOTIMERFD>
When this flag is specified, the libev will avoid using a C<timerfd> to
detect time jumps. It will still be able to detect time jumps, but takes
longer and has a lower accuracy in doing so, but saves a file descriptor
per loop.
The current implementation only tries to use a C<timerfd> when the first
C<ev_periodic> watcher is started and falls back on other methods if it
cannot be created, but this behaviour might change in the future.
=item C<EVBACKEND_SELECT> (value 1, portable select backend)
This is your standard select(2) backend. Not I<completely> standard, as
libev tries to roll its own fd_set with no limits on the number of fds,
but if that fails, expect a fairly low limit on the number of fds when
using this backend. It doesn't scale too well (O(highest_fd)), but its
usually the fastest backend for a low number of (low-numbered :) fds.
To get good performance out of this backend you need a high amount of
parallelism (most of the file descriptors should be busy). If you are
writing a server, you should C<accept ()> in a loop to accept as many
connections as possible during one iteration. You might also want to have
a look at C<ev_set_io_collect_interval ()> to increase the amount of
readiness notifications you get per iteration.
This backend maps C<EV_READ> to the C<readfds> set and C<EV_WRITE> to the
C<writefds> set (and to work around Microsoft Windows bugs, also onto the
C<exceptfds> set on that platform).
=item C<EVBACKEND_POLL> (value 2, poll backend, available everywhere except on windows)
And this is your standard poll(2) backend. It's more complicated
than select, but handles sparse fds better and has no artificial
limit on the number of fds you can use (except it will slow down
considerably with a lot of inactive fds). It scales similarly to select,
i.e. O(total_fds). See the entry for C<EVBACKEND_SELECT>, above, for
performance tips.
This backend maps C<EV_READ> to C<POLLIN | POLLERR | POLLHUP>, and
C<EV_WRITE> to C<POLLOUT | POLLERR | POLLHUP>.
=item C<EVBACKEND_EPOLL> (value 4, Linux)
Use the Linux-specific epoll(7) interface (for both pre- and post-2.6.9
kernels).
For few fds, this backend is a bit little slower than poll and select, but
it scales phenomenally better. While poll and select usually scale like
O(total_fds) where total_fds is the total number of fds (or the highest
fd), epoll scales either O(1) or O(active_fds).
libev/ev.pod view on Meta::CPAN
the timer a lower priority than the I/O watcher ensures that I/O will be
handled first even under adverse conditions (which is usually, but not
always, what you want).
Since idle watchers use the "lock-out" model, meaning that idle watchers
will only be executed when no same or higher priority watchers have
received events, they can be used to implement the "lock-out" model when
required.
For example, to emulate how many other event libraries handle priorities,
you can associate an C<ev_idle> watcher to each such watcher, and in
the normal watcher callback, you just start the idle watcher. The real
processing is done in the idle watcher callback. This causes libev to
continuously poll and process kernel event data for the watcher, but when
the lock-out case is known to be rare (which in turn is rare :), this is
workable.
Usually, however, the lock-out model implemented that way will perform
miserably under the type of load it was designed to handle. In that case,
it might be preferable to stop the real watcher before starting the
idle watcher, so the kernel will not have to process the event in case
the actual processing will be delayed for considerable time.
Here is an example of an I/O watcher that should run at a strictly lower
priority than the default, and which should only process data when no
other events are pending:
ev_idle idle; // actual processing watcher
ev_io io; // actual event watcher
static void
io_cb (EV_P_ ev_io *w, int revents)
{
// stop the I/O watcher, we received the event, but
// are not yet ready to handle it.
ev_io_stop (EV_A_ w);
// start the idle watcher to handle the actual event.
// it will not be executed as long as other watchers
// with the default priority are receiving events.
ev_idle_start (EV_A_ &idle);
}
static void
idle_cb (EV_P_ ev_idle *w, int revents)
{
// actual processing
read (STDIN_FILENO, ...);
// have to start the I/O watcher again, as
// we have handled the event
ev_io_start (EV_P_ &io);
}
// initialisation
ev_idle_init (&idle, idle_cb);
ev_io_init (&io, io_cb, STDIN_FILENO, EV_READ);
ev_io_start (EV_DEFAULT_ &io);
In the "real" world, it might also be beneficial to start a timer, so that
low-priority connections can not be locked out forever under load. This
enables your program to keep a lower latency for important connections
during short periods of high load, while not completely locking out less
important ones.
=head1 WATCHER TYPES
This section describes each watcher in detail, but will not repeat
information given in the last section. Any initialisation/set macros,
functions and members specific to the watcher type are explained.
Most members are additionally marked with either I<[read-only]>, meaning
that, while the watcher is active, you can look at the member and expect
some sensible content, but you must not modify it (you can modify it while
the watcher is stopped to your hearts content), or I<[read-write]>, which
means you can expect it to have some sensible content while the watcher is
active, but you can also modify it (within the same thread as the event
loop, i.e. without creating data races). Modifying it may not do something
sensible or take immediate effect (or do anything at all), but libev will
not crash or malfunction in any way.
In any case, the documentation for each member will explain what the
effects are, and if there are any additional access restrictions.
=head2 C<ev_io> - is this file descriptor readable or writable?
I/O watchers check whether a file descriptor is readable or writable
in each iteration of the event loop, or, more precisely, when reading
would not block the process and writing would at least be able to write
some data. This behaviour is called level-triggering because you keep
receiving events as long as the condition persists. Remember you can stop
the watcher if you don't want to act on the event and neither want to
receive future events.
In general you can register as many read and/or write event watchers per
fd as you want (as long as you don't confuse yourself). Setting all file
descriptors to non-blocking mode is also usually a good idea (but not
required if you know what you are doing).
Another thing you have to watch out for is that it is quite easy to
receive "spurious" readiness notifications, that is, your callback might
be called with C<EV_READ> but a subsequent C<read>(2) will actually block
because there is no data. It is very easy to get into this situation even
with a relatively standard program structure. Thus it is best to always
use non-blocking I/O: An extra C<read>(2) returning C<EAGAIN> is far
preferable to a program hanging until some data arrives.
If you cannot run the fd in non-blocking mode (for example you should
not play around with an Xlib connection), then you have to separately
re-test whether a file descriptor is really ready with a known-to-be good
interface such as poll (fortunately in the case of Xlib, it already does
this on its own, so its quite safe to use). Some people additionally
use C<SIGALRM> and an interval timer, just to be sure you won't block
indefinitely.
But really, best use non-blocking mode.
=head3 The special problem of disappearing file descriptors
Some backends (e.g. kqueue, epoll, linuxaio) need to be told about closing
libev/ev.pod view on Meta::CPAN
Example: The same as above, but use a reschedule callback to do it:
#include <math.h>
static ev_tstamp
my_scheduler_cb (ev_periodic *w, ev_tstamp now)
{
return now + (3600. - fmod (now, 3600.));
}
ev_periodic_init (&hourly_tick, clock_cb, 0., 0., my_scheduler_cb);
Example: Call a callback every hour, starting now:
ev_periodic hourly_tick;
ev_periodic_init (&hourly_tick, clock_cb,
fmod (ev_now (loop), 3600.), 3600., 0);
ev_periodic_start (loop, &hourly_tick);
=head2 C<ev_signal> - signal me when a signal gets signalled!
Signal watchers will trigger an event when the process receives a specific
signal one or more times. Even though signals are very asynchronous, libev
will try its best to deliver signals synchronously, i.e. as part of the
normal event processing, like any other event.
If you want signals to be delivered truly asynchronously, just use
C<sigaction> as you would do without libev and forget about sharing
the signal. You can even use C<ev_async> from a signal handler to
synchronously wake up an event loop.
You can configure as many watchers as you like for the same signal, but
only within the same loop, i.e. you can watch for C<SIGINT> in your
default loop and for C<SIGIO> in another loop, but you cannot watch for
C<SIGINT> in both the default loop and another loop at the same time. At
the moment, C<SIGCHLD> is permanently tied to the default loop.
Only after the first watcher for a signal is started will libev actually
register something with the kernel. It thus coexists with your own signal
handlers as long as you don't register any with libev for the same signal.
If possible and supported, libev will install its handlers with
C<SA_RESTART> (or equivalent) behaviour enabled, so system calls should
not be unduly interrupted. If you have a problem with system calls getting
interrupted by signals you can block all signals in an C<ev_check> watcher
and unblock them in an C<ev_prepare> watcher.
=head3 The special problem of inheritance over fork/execve/pthread_create
Both the signal mask (C<sigprocmask>) and the signal disposition
(C<sigaction>) are unspecified after starting a signal watcher (and after
stopping it again), that is, libev might or might not block the signal,
and might or might not set or restore the installed signal handler (but
see C<EVFLAG_NOSIGMASK>).
While this does not matter for the signal disposition (libev never
sets signals to C<SIG_IGN>, so handlers will be reset to C<SIG_DFL> on
C<execve>), this matters for the signal mask: many programs do not expect
certain signals to be blocked.
This means that before calling C<exec> (from the child) you should reset
the signal mask to whatever "default" you expect (all clear is a good
choice usually).
The simplest way to ensure that the signal mask is reset in the child is
to install a fork handler with C<pthread_atfork> that resets it. That will
catch fork calls done by libraries (such as the libc) as well.
In current versions of libev, the signal will not be blocked indefinitely
unless you use the C<signalfd> API (C<EV_SIGNALFD>). While this reduces
the window of opportunity for problems, it will not go away, as libev
I<has> to modify the signal mask, at least temporarily.
So I can't stress this enough: I<If you do not reset your signal mask when
you expect it to be empty, you have a race condition in your code>. This
is not a libev-specific thing, this is true for most event libraries.
=head3 The special problem of threads signal handling
POSIX threads has problematic signal handling semantics, specifically,
a lot of functionality (sigfd, sigwait etc.) only really works if all
threads in a process block signals, which is hard to achieve.
When you want to use sigwait (or mix libev signal handling with your own
for the same signals), you can tackle this problem by globally blocking
all signals before creating any threads (or creating them with a fully set
sigprocmask) and also specifying the C<EVFLAG_NOSIGMASK> when creating
loops. Then designate one thread as "signal receiver thread" which handles
these signals. You can pass on any signals that libev might be interested
in by calling C<ev_feed_signal>.
=head3 Watcher-Specific Functions and Data Members
=over 4
=item ev_signal_init (ev_signal *, callback, int signum)
=item ev_signal_set (ev_signal *, int signum)
Configures the watcher to trigger on the given signal number (usually one
of the C<SIGxxx> constants).
=item int signum [read-only]
The signal the watcher watches out for.
=back
=head3 Examples
Example: Try to exit cleanly on SIGINT.
static void
sigint_cb (struct ev_loop *loop, ev_signal *w, int revents)
{
ev_break (loop, EVBREAK_ALL);
}
ev_signal signal_watcher;
ev_signal_init (&signal_watcher, sigint_cb, SIGINT);
ev_signal_start (loop, &signal_watcher);
=head2 C<ev_child> - watch out for process status changes
Child watchers trigger when your process receives a SIGCHLD in response to
some child status changes (most typically when a child of yours dies or
exits). It is permissible to install a child watcher I<after> the child
has been forked (which implies it might have already exited), as long
libev/ev.pod view on Meta::CPAN
=item queueing from a thread context
The strategy for threads is different, as you cannot (easily) block
threads but you can easily preempt them, so to queue safely you need to
employ a traditional mutex lock, such as in this pthread example:
static ev_async mysig;
static pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
static void
otherthread (void)
{
// only need to lock the actual queueing operation
pthread_mutex_lock (&mymutex);
queue_put (data);
pthread_mutex_unlock (&mymutex);
ev_async_send (EV_DEFAULT_ &mysig);
}
static void
mysig_cb (EV_P_ ev_async *w, int revents)
{
pthread_mutex_lock (&mymutex);
while (queue_get (&data))
process (data);
pthread_mutex_unlock (&mymutex);
}
=back
=head3 Watcher-Specific Functions and Data Members
=over 4
=item ev_async_init (ev_async *, callback)
Initialises and configures the async watcher - it has no parameters of any
kind. There is a C<ev_async_set> macro, but using it is utterly pointless,
trust me.
=item ev_async_send (loop, ev_async *)
Sends/signals/activates the given C<ev_async> watcher, that is, feeds
an C<EV_ASYNC> event on the watcher into the event loop, and instantly
returns.
Unlike 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).
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: they are set on
C<ev_async_send>, reset when the event loop detects that).
This call incurs the overhead of at most one extra system call per event
loop iteration, if the event loop is blocked, and no syscall at all if
the event loop (or your program) is processing events. That means that
repeated calls are basically free (there is no need to avoid calls for
performance reasons) and that the overhead becomes smaller (typically
zero) under load.
=item bool = ev_async_pending (ev_async *)
Returns a non-zero value when C<ev_async_send> has been called on the
watcher but the event has not yet been processed (or even noted) by the
event loop.
C<ev_async_send> sets a flag in the watcher and wakes up the loop. When
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: there
is a time window between the event loop checking and resetting the async
notification, and the callback being invoked.
=back
=head1 OTHER FUNCTIONS
There are some other functions of possible interest. Described. Here. Now.
=over 4
=item ev_once (loop, int fd, int events, ev_tstamp timeout, callback, arg)
This function combines a simple timer and an I/O watcher, calls your
callback on whichever event happens first and automatically stops both
watchers. This is useful if you want to wait for a single event on an fd
or timeout without having to allocate/configure/start/stop/free one or
more watchers yourself.
If C<fd> is less than 0, then no I/O watcher will be started and the
C<events> argument is being ignored. Otherwise, an C<ev_io> watcher for
the given C<fd> and C<events> set will be created and started.
If C<timeout> is less than 0, then no timeout watcher will be
started. Otherwise an C<ev_timer> watcher with after = C<timeout> (and
repeat = 0) will be started. C<0> is a valid timeout.
The callback has the type C<void (*cb)(int revents, void *arg)> and is
passed an C<revents> set like normal event callbacks (a combination of
C<EV_ERROR>, C<EV_READ>, C<EV_WRITE> or C<EV_TIMER>) and the C<arg>
value passed to C<ev_once>. Note that it is possible to receive I<both>
a timeout and an io event at the same time - you probably should give io
events precedence.
Example: wait up to ten seconds for data to appear on STDIN_FILENO.
static void stdin_ready (int revents, void *arg)
{
if (revents & EV_READ)
/* stdin might have data for us, joy! */;
else if (revents & EV_TIMER)
libev/ev.pod view on Meta::CPAN
struct my_biggy big = (struct my_biggy *)
(((char *)w) - offsetof (struct my_biggy, t1));
}
static void
t2_cb (EV_P_ ev_timer *w, int revents)
{
struct my_biggy big = (struct my_biggy *)
(((char *)w) - offsetof (struct my_biggy, t2));
}
=head2 AVOIDING FINISHING BEFORE RETURNING
Often you have structures like this in event-based programs:
callback ()
{
free (request);
}
request = start_new_request (..., callback);
The intent is to start some "lengthy" operation. The C<request> could be
used to cancel the operation, or do other things with it.
It's not uncommon to have code paths in C<start_new_request> that
immediately invoke the callback, for example, to report errors. Or you add
some caching layer that finds that it can skip the lengthy aspects of the
operation and simply invoke the callback with the result.
The problem here is that this will happen I<before> C<start_new_request>
has returned, so C<request> is not set.
Even if you pass the request by some safer means to the callback, you
might want to do something to the request after starting it, such as
canceling it, which probably isn't working so well when the callback has
already been invoked.
A common way around all these issues is to make sure that
C<start_new_request> I<always> returns before the callback is invoked. If
C<start_new_request> immediately knows the result, it can artificially
delay invoking the callback by using a C<prepare> or C<idle> watcher for
example, or more sneakily, by reusing an existing (stopped) watcher and
pushing it into the pending queue:
ev_set_cb (watcher, callback);
ev_feed_event (EV_A_ watcher, 0);
This way, C<start_new_request> can safely return before the callback is
invoked, while not delaying callback invocation too much.
=head2 MODEL/NESTED EVENT LOOP INVOCATIONS AND EXIT CONDITIONS
Often (especially in GUI toolkits) there are places where you have
I<modal> interaction, which is most easily implemented by recursively
invoking C<ev_run>.
This brings the problem of exiting - a callback might want to finish the
main C<ev_run> call, but not the nested one (e.g. user clicked "Quit", but
a modal "Are you sure?" dialog is still waiting), or just the nested one
and not the main one (e.g. user clocked "Ok" in a modal dialog), or some
other combination: In these cases, a simple C<ev_break> will not work.
The solution is to maintain "break this loop" variable for each C<ev_run>
invocation, and use a loop around C<ev_run> until the condition is
triggered, using C<EVRUN_ONCE>:
// main loop
int exit_main_loop = 0;
while (!exit_main_loop)
ev_run (EV_DEFAULT_ EVRUN_ONCE);
// in a modal watcher
int exit_nested_loop = 0;
while (!exit_nested_loop)
ev_run (EV_A_ EVRUN_ONCE);
To exit from any of these loops, just set the corresponding exit variable:
// exit modal loop
exit_nested_loop = 1;
// exit main program, after modal loop is finished
exit_main_loop = 1;
// exit both
exit_main_loop = exit_nested_loop = 1;
=head2 THREAD LOCKING EXAMPLE
Here is a fictitious example of how to run an event loop in a different
thread from where callbacks are being invoked and watchers are
created/added/removed.
For a real-world example, see the C<EV::Loop::Async> perl module,
which uses exactly this technique (which is suited for many high-level
languages).
The example uses a pthread mutex to protect the loop data, a condition
variable to wait for callback invocations, an async watcher to notify the
event loop thread and an unspecified mechanism to wake up the main thread.
First, you need to associate some data with the event loop:
typedef struct {
pthread_mutex_t lock; /* global loop lock */
pthread_t tid;
pthread_cond_t invoke_cv;
ev_async async_w;
} userdata;
void prepare_loop (EV_P)
{
// for simplicity, we use a static userdata struct.
static userdata u;
ev_async_init (&u.async_w, async_cb);
ev_async_start (EV_A_ &u.async_w);
libev/ev.pod view on Meta::CPAN
All of the following are about amortised time: If an array needs to be
extended, libev needs to realloc and move the whole array, but this
happens asymptotically rarer with higher number of elements, so O(1) might
mean that libev does a lengthy realloc operation in rare cases, but on
average it is much faster and asymptotically approaches constant time.
=over 4
=item Starting and stopping timer/periodic watchers: O(log skipped_other_timers)
This means that, when you have a watcher that triggers in one hour and
there are 100 watchers that would trigger before that, then inserting will
have to skip roughly seven (C<ld 100>) of these watchers.
=item Changing timer/periodic watchers (by autorepeat or calling again): O(log skipped_other_timers)
That means that changing a timer costs less than removing/adding them,
as only the relative motion in the event queue has to be paid for.
=item Starting io/check/prepare/idle/signal/child/fork/async watchers: O(1)
These just add the watcher into an array or at the head of a list.
=item Stopping check/prepare/idle/fork/async watchers: O(1)
=item Stopping an io/signal/child watcher: O(number_of_watchers_for_this_(fd/signal/pid % EV_PID_HASHSIZE))
These watchers are stored in lists, so they need to be walked to find the
correct watcher to remove. The lists are usually short (you don't usually
have many watchers waiting for the same fd or signal: one is typical, two
is rare).
=item Finding the next timer in each loop iteration: O(1)
By virtue of using a binary or 4-heap, the next timer is always found at a
fixed position in the storage array.
=item Each change on a file descriptor per loop iteration: O(number_of_watchers_for_this_fd)
A change means an I/O watcher gets started or stopped, which requires
libev to recalculate its status (and possibly tell the kernel, depending
on backend and whether C<ev_io_set> was used).
=item Activating one watcher (putting it into the pending state): O(1)
=item Priority handling: O(number_of_priorities)
Priorities are implemented by allocating some space for each
priority. When doing priority-based operations, libev usually has to
linearly search all the priorities, but starting/stopping and activating
watchers becomes O(1) with respect to priority handling.
=item Sending an ev_async: O(1)
=item Processing ev_async_send: O(number_of_async_watchers)
=item Processing signals: O(max_signal_number)
Sending involves a system call I<iff> there were no other C<ev_async_send>
calls in the current loop iteration and the loop is currently
blocked. Checking for async and signal events involves iterating over all
running async watchers or all signal numbers.
=back
=head1 PORTING FROM LIBEV 3.X TO 4.X
The major version 4 introduced some incompatible changes to the API.
At the moment, the C<ev.h> header file provides compatibility definitions
for all changes, so most programs should still compile. The compatibility
layer might be removed in later versions of libev, so better update to the
new API early than late.
=over 4
=item C<EV_COMPAT3> backwards compatibility mechanism
The backward compatibility mechanism can be controlled by
C<EV_COMPAT3>. See L</"PREPROCESSOR SYMBOLS/MACROS"> in the L</EMBEDDING>
section.
=item C<ev_default_destroy> and C<ev_default_fork> have been removed
These calls can be replaced easily by their C<ev_loop_xxx> counterparts:
ev_loop_destroy (EV_DEFAULT_UC);
ev_loop_fork (EV_DEFAULT);
=item function/symbol renames
A number of functions and symbols have been renamed:
ev_loop => ev_run
EVLOOP_NONBLOCK => EVRUN_NOWAIT
EVLOOP_ONESHOT => EVRUN_ONCE
ev_unloop => ev_break
EVUNLOOP_CANCEL => EVBREAK_CANCEL
EVUNLOOP_ONE => EVBREAK_ONE
EVUNLOOP_ALL => EVBREAK_ALL
EV_TIMEOUT => EV_TIMER
ev_loop_count => ev_iteration
ev_loop_depth => ev_depth
ev_loop_verify => ev_verify
Most functions working on C<struct ev_loop> objects don't have an
C<ev_loop_> prefix, so it was removed; C<ev_loop>, C<ev_unloop> and
associated constants have been renamed to not collide with the C<struct
ev_loop> anymore and C<EV_TIMER> now follows the same naming scheme
as all other watcher types. Note that C<ev_loop_fork> is still called
C<ev_loop_fork> because it would otherwise clash with the C<ev_fork>
typedef.
=item C<EV_MINIMAL> mechanism replaced by C<EV_FEATURES>
The preprocessor symbol C<EV_MINIMAL> has been replaced by a different
mechanism, C<EV_FEATURES>. Programs using C<EV_MINIMAL> usually compile
( run in 0.776 second using v1.01-cache-2.11-cpan-98e64b0badf )