From f00667682ef34d61b3f0f77e5bc3983fc40c55ef Mon Sep 17 00:00:00 2001 From: root Date: Tue, 11 Jan 2011 13:45:28 +0000 Subject: 4.03 --- Changes | 1 + Symbols.ev | 1 + configure.ac | 2 +- ev.3 | 765 +++++++++++++++++++++++++++++++++++++---------------------- ev.h | 2 +- 5 files changed, 492 insertions(+), 279 deletions(-) diff --git a/Changes b/Changes index 640be46..53bb646 100644 --- a/Changes +++ b/Changes @@ -13,6 +13,7 @@ Revision history for libev, a high-performance and full-featured event loop. - new (experimental) function: ev_feed_signal. - new (to become default) EVFLAG_NOSIGMASK flag. - new EVBACKEND_MASK symbol. + - updated COMMON IDIOMS SECTION. 4.01 Fri Nov 5 21:51:29 CET 2010 - automake fucked it up, apparently, --add-missing -f is not quite enough diff --git a/Symbols.ev b/Symbols.ev index 8e2465f..7a29a75 100644 --- a/Symbols.ev +++ b/Symbols.ev @@ -19,6 +19,7 @@ ev_embed_sweep ev_embeddable_backends ev_feed_event ev_feed_fd_event +ev_feed_signal ev_feed_signal_event ev_fork_start ev_fork_stop diff --git a/configure.ac b/configure.ac index 20665bb..5a8ea28 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ AC_INIT AC_CONFIG_SRCDIR([ev_epoll.c]) -AM_INIT_AUTOMAKE(libev,4.01) dnl also update ev.h! +AM_INIT_AUTOMAKE(libev,4.03) dnl also update ev.h! AC_CONFIG_HEADERS([config.h]) AM_MAINTAINER_MODE diff --git a/ev.3 b/ev.3 index 7908093..a5c974c 100644 --- a/ev.3 +++ b/ev.3 @@ -124,7 +124,7 @@ .\" ======================================================================== .\" .IX Title "LIBEV 3" -.TH LIBEV 3 "2010-11-03" "libev-4.01" "libev - high performance full featured event loop" +.TH LIBEV 3 "2011-01-11" "libev-4.03" "libev - high performance full featured event loop" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l @@ -423,6 +423,18 @@ Example: This is basically the same thing that libev does internally, too. \& ... \& ev_set_syserr_cb (fatal_error); .Ve +.IP "ev_feed_signal (int signum)" 4 +.IX Item "ev_feed_signal (int signum)" +This function can be used to \*(L"simulate\*(R" a signal receive. It is completely +safe to call this function at any time, from any context, including signal +handlers or random threads. +.Sp +Its main use is to customise signal handling in your process, especially +in the presence of threads. For example, you could block signals +by default in all threads (and specifying \f(CW\*(C`EVFLAG_NOSIGMASK\*(C'\fR when +creating any loops), and in one thread, use \f(CW\*(C`sigwait\*(C'\fR or any other +mechanism to wait for signals, then \*(L"deliver\*(R" them to libev by calling +\&\f(CW\*(C`ev_feed_signal\*(C'\fR. .SH "FUNCTIONS CONTROLLING EVENT LOOPS" .IX Header "FUNCTIONS CONTROLLING EVENT LOOPS" An event loop is described by a \f(CW\*(C`struct ev_loop *\*(C'\fR (the \f(CW\*(C`struct\*(C'\fR is @@ -477,9 +489,9 @@ environment settings to be taken into account: This will create and initialise a new event loop object. If the loop could not be initialised, returns false. .Sp -Note that this function \fIis\fR thread-safe, and one common way to use -libev with threads is indeed to create one loop per thread, and using the -default loop in the \*(L"main\*(R" or \*(L"initial\*(R" thread. +This function is thread-safe, and one common way to use libev with +threads is indeed to create one loop per thread, and using the default +loop in the \*(L"main\*(R" or \*(L"initial\*(R" thread. .Sp The flags argument can be used to specify special behaviour or specific backends to use, and is usually specified as \f(CW0\fR (or \f(CW\*(C`EVFLAG_AUTO\*(C'\fR). @@ -539,6 +551,18 @@ 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. +.ie n .IP """EVFLAG_NOSIGMASK""" 4 +.el .IP "\f(CWEVFLAG_NOSIGMASK\fR" 4 +.IX Item "EVFLAG_NOSIGMASK" +When this flag is specified, then libev will avoid to modify the signal +mask. Specifically, this means you ahve to make sure signals are unblocked +when you want to receive them. +.Sp +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. +.Sp +This flag's behaviour will become the default in future versions of libev. .ie n .IP """EVBACKEND_SELECT"" (value 1, portable select backend)" 4 .el .IP "\f(CWEVBACKEND_SELECT\fR (value 1, portable select backend)" 4 .IX Item "EVBACKEND_SELECT (value 1, portable select backend)" @@ -602,7 +626,9 @@ events to filter out spurious ones, recreating the set when required. Last not least, it also refuses to work with some file descriptors which work perfectly fine with \f(CW\*(C`select\*(C'\fR (files, many character devices...). .Sp -Epoll is truly the train wreck analog among event poll mechanisms. +Epoll is truly the train wreck analog among event poll mechanisms, +a frankenpoll, cobbled together in a hurry, no thought to design or +interaction with others. .Sp While stopping, setting and starting an I/O watcher in the same iteration will result in some caching, there is still a system call per such @@ -678,19 +704,25 @@ immensely. This uses the Solaris 10 event port mechanism. As with everything on Solaris, it's really slow, but it still scales very well (O(active_fds)). .Sp -Please note that Solaris event ports can deliver a lot of spurious -notifications, so you need to use non-blocking I/O or other means to avoid -blocking when no data (or space) is available. -.Sp While this backend scales well, it requires one system call per active file descriptor per loop iteration. For small and medium numbers of file descriptors a \*(L"slow\*(R" \f(CW\*(C`EVBACKEND_SELECT\*(C'\fR or \f(CW\*(C`EVBACKEND_POLL\*(C'\fR backend might perform better. .Sp -On the positive side, with the exception of the spurious readiness -notifications, this backend actually performed fully to specification -in all tests and is fully embeddable, which is a rare feat among the -OS-specific backends (I vastly prefer correctness over speed hacks). +On the positive side, this backend actually performed fully to +specification in all tests and is fully embeddable, which is a rare feat +among the OS-specific backends (I vastly prefer correctness over speed +hacks). +.Sp +On the negative side, the interface is \fIbizarre\fR \- so bizarre that +even sun itself gets it wrong in their code examples: The event polling +function sometimes returning events to the caller even though an error +occurred, but with no indication whether it has done so or not (yes, it's +even documented that way) \- deadly for edge-triggered interfaces where +you absolutely have to know whether an event occurred or not because you +have to re-arm the watcher. +.Sp +Fortunately libev seems to be able to work around these idiocies. .Sp This backend maps \f(CW\*(C`EV_READ\*(C'\fR and \f(CW\*(C`EV_WRITE\*(C'\fR in the same way as \&\f(CW\*(C`EVBACKEND_POLL\*(C'\fR. @@ -701,7 +733,15 @@ Try all backends (even potentially broken ones that wouldn't be tried with \f(CW\*(C`EVFLAG_AUTO\*(C'\fR). Since this is a mask, you can do stuff such as \&\f(CW\*(C`EVBACKEND_ALL & ~EVBACKEND_KQUEUE\*(C'\fR. .Sp -It is definitely not recommended to use this flag. +It is definitely not recommended to use this flag, use whatever +\&\f(CW\*(C`ev_recommended_backends ()\*(C'\fR returns, or simply do not specify a backend +at all. +.ie n .IP """EVBACKEND_MASK""" 4 +.el .IP "\f(CWEVBACKEND_MASK\fR" 4 +.IX Item "EVBACKEND_MASK" +Not a backend at all, but a mask to select all backend bits from a +\&\f(CW\*(C`flags\*(C'\fR value, in case you want to mask out any backends from a flags +value (e.g. when modifying the \f(CW\*(C`LIBEV_FLAGS\*(C'\fR environment variable). .RE .RS 4 .Sp @@ -800,15 +840,16 @@ prepare and check phases. .IP "unsigned int ev_depth (loop)" 4 .IX Item "unsigned int ev_depth (loop)" Returns the number of times \f(CW\*(C`ev_run\*(C'\fR was entered minus the number of -times \f(CW\*(C`ev_run\*(C'\fR was exited, in other words, the recursion depth. +times \f(CW\*(C`ev_run\*(C'\fR was exited normally, in other words, the recursion depth. .Sp Outside \f(CW\*(C`ev_run\*(C'\fR, this number is zero. In a callback, this number is \&\f(CW1\fR, unless \f(CW\*(C`ev_run\*(C'\fR was invoked recursively (or from another thread), in which case it is higher. .Sp -Leaving \f(CW\*(C`ev_run\*(C'\fR abnormally (setjmp/longjmp, cancelling the thread -etc.), doesn't count as \*(L"exit\*(R" \- consider this as a hint to avoid such -ungentleman-like behaviour unless it's really convenient. +Leaving \f(CW\*(C`ev_run\*(C'\fR abnormally (setjmp/longjmp, cancelling the thread, +throwing an exception etc.), doesn't count as \*(L"exit\*(R" \- consider this +as a hint to avoid such ungentleman-like behaviour unless it's really +convenient, in which case it is fully supported. .IP "unsigned int ev_backend (loop)" 4 .IX Item "unsigned int ev_backend (loop)" Returns one of the \f(CW\*(C`EVBACKEND_*\*(C'\fR flags indicating the event backend in @@ -877,6 +918,11 @@ that automatically loops as long as it has to and no longer by virtue of relying on its watchers stopping correctly, that is truly a thing of beauty. .Sp +This function is also \fImostly\fR exception-safe \- you can break out of +a \f(CW\*(C`ev_run\*(C'\fR call by calling \f(CW\*(C`longjmp\*(C'\fR in a callback, throwing a \*(C+ +exception and so on. This does not decrement the \f(CW\*(C`ev_depth\*(C'\fR value, nor +will it clear any outstanding \f(CW\*(C`EVBREAK_ONE\*(C'\fR breaks. +.Sp A flags value of \f(CW\*(C`EVRUN_NOWAIT\*(C'\fR will look for new events, will handle those events and any already outstanding ones, but will not wait and block your process in case there are no events and will return after one @@ -950,9 +996,10 @@ has processed all outstanding events). The \f(CW\*(C`how\*(C'\fR argument must b \&\f(CW\*(C`EVBREAK_ONE\*(C'\fR, which will make the innermost \f(CW\*(C`ev_run\*(C'\fR call return, or \&\f(CW\*(C`EVBREAK_ALL\*(C'\fR, which will make all nested \f(CW\*(C`ev_run\*(C'\fR calls return. .Sp -This \*(L"break state\*(R" will be cleared when entering \f(CW\*(C`ev_run\*(C'\fR again. +This \*(L"break state\*(R" will be cleared on the next call to \f(CW\*(C`ev_run\*(C'\fR. .Sp -It is safe to call \f(CW\*(C`ev_break\*(C'\fR from outside any \f(CW\*(C`ev_run\*(C'\fR calls, too. +It is safe to call \f(CW\*(C`ev_break\*(C'\fR from outside any \f(CW\*(C`ev_run\*(C'\fR calls, too, in +which case it will have no effect. .IP "ev_ref (loop)" 4 .IX Item "ev_ref (loop)" .PD 0 @@ -985,7 +1032,7 @@ running when nothing else is active. \& ev_signal exitsig; \& ev_signal_init (&exitsig, sig_cb, SIGINT); \& ev_signal_start (loop, &exitsig); -\& evf_unref (loop); +\& ev_unref (loop); .Ve .Sp Example: For some weird reason, unregister the above signal handler again. @@ -1109,12 +1156,12 @@ document. .IP "ev_set_userdata (loop, void *data)" 4 .IX Item "ev_set_userdata (loop, void *data)" .PD 0 -.IP "ev_userdata (loop)" 4 -.IX Item "ev_userdata (loop)" +.IP "void *ev_userdata (loop)" 4 +.IX Item "void *ev_userdata (loop)" .PD Set and retrieve a single \f(CW\*(C`void *\*(C'\fR associated with a loop. When \&\f(CW\*(C`ev_set_userdata\*(C'\fR has never been called, then \f(CW\*(C`ev_userdata\*(C'\fR returns -\&\f(CW0.\fR +\&\f(CW0\fR. .Sp These two functions can be used to associate arbitrary data with a loop, and are intended solely for the \f(CW\*(C`invoke_pending_cb\*(C'\fR, \f(CW\*(C`release\*(C'\fR and @@ -1430,78 +1477,9 @@ not started in the first place. .Sp See also \f(CW\*(C`ev_feed_fd_event\*(C'\fR and \f(CW\*(C`ev_feed_signal_event\*(C'\fR for related functions that do not need a watcher. -.SS "\s-1ASSOCIATING\s0 \s-1CUSTOM\s0 \s-1DATA\s0 \s-1WITH\s0 A \s-1WATCHER\s0" -.IX Subsection "ASSOCIATING CUSTOM DATA WITH A WATCHER" -Each watcher has, by default, a member \f(CW\*(C`void *data\*(C'\fR that you can change -and read at any time: libev will completely ignore it. This can be used -to associate arbitrary data with your watcher. If you need more data and -don't want to allocate memory and store a pointer to it in that data -member, you can also \*(L"subclass\*(R" the watcher type and provide your own -data: -.PP -.Vb 7 -\& struct my_io -\& { -\& ev_io io; -\& int otherfd; -\& void *somedata; -\& struct whatever *mostinteresting; -\& }; -\& -\& ... -\& struct my_io w; -\& ev_io_init (&w.io, my_cb, fd, EV_READ); -.Ve -.PP -And since your callback will be called with a pointer to the watcher, you -can cast it back to your own type: -.PP -.Vb 5 -\& static void my_cb (struct ev_loop *loop, ev_io *w_, int revents) -\& { -\& struct my_io *w = (struct my_io *)w_; -\& ... -\& } -.Ve .PP -More interesting and less C\-conformant ways of casting your callback type -instead have been omitted. -.PP -Another common scenario is to use some data structure with multiple -embedded watchers: -.PP -.Vb 6 -\& struct my_biggy -\& { -\& int some_data; -\& ev_timer t1; -\& ev_timer t2; -\& } -.Ve -.PP -In this case getting the pointer to \f(CW\*(C`my_biggy\*(C'\fR is a bit more -complicated: Either you store the address of your \f(CW\*(C`my_biggy\*(C'\fR struct -in the \f(CW\*(C`data\*(C'\fR member of the watcher (for woozies), or you need to use -some pointer arithmetic using \f(CW\*(C`offsetof\*(C'\fR inside your watchers (for real -programmers): -.PP -.Vb 1 -\& #include -\& -\& static void -\& t1_cb (EV_P_ ev_timer *w, int revents) -\& { -\& 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)); -\& } -.Ve +See also the \*(L"\s-1ASSOCIATING\s0 \s-1CUSTOM\s0 \s-1DATA\s0 \s-1WITH\s0 A \s-1WATCHER\s0\*(R" and \*(L"\s-1BUILDING\s0 \s-1YOUR\s0 +\&\s-1OWN\s0 \s-1COMPOSITE\s0 \s-1WATCHERS\s0\*(R" idioms. .SS "\s-1WATCHER\s0 \s-1STATES\s0" .IX Subsection "WATCHER STATES" There are various watcher states mentioned throughout this manual \- @@ -1686,26 +1664,19 @@ 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). .PP -If you cannot use non-blocking mode, then force the use of a -known-to-be-good backend (at the time of this writing, this includes only -\&\f(CW\*(C`EVBACKEND_SELECT\*(C'\fR and \f(CW\*(C`EVBACKEND_POLL\*(C'\fR). The same applies to file -descriptors for which non-blocking operation makes no sense (such as -files) \- libev doesn't guarantee any specific behaviour in that case. -.PP Another thing you have to watch out for is that it is quite easy to -receive \*(L"spurious\*(R" readiness notifications, that is your callback might +receive \*(L"spurious\*(R" readiness notifications, that is, your callback might be called with \f(CW\*(C`EV_READ\*(C'\fR but a subsequent \f(CW\*(C`read\*(C'\fR(2) will actually block -because there is no data. Not only are some backends known to create a -lot of those (for example Solaris ports), 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 \f(CW\*(C`read\*(C'\fR(2) returning -\&\f(CW\*(C`EAGAIN\*(C'\fR is far preferable to a program hanging until some data arrives. +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 \f(CW\*(C`read\*(C'\fR(2) returning \f(CW\*(C`EAGAIN\*(C'\fR is far +preferable to a program hanging until some data arrives. .PP 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 our Xlib example, Xlib already -does this on its own, so its quite safe to use). Some people additionally +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 \f(CW\*(C`SIGALRM\*(C'\fR and an interval timer, just to be sure you won't block indefinitely. .PP @@ -1745,17 +1716,50 @@ There is no workaround possible except not registering events for potentially \f(CW\*(C`dup ()\*(C'\fR'ed file descriptors, or to resort to \&\f(CW\*(C`EVBACKEND_SELECT\*(C'\fR or \f(CW\*(C`EVBACKEND_POLL\*(C'\fR. .PP +\fIThe special problem of files\fR +.IX Subsection "The special problem of files" +.PP +Many people try to use \f(CW\*(C`select\*(C'\fR (or libev) on file descriptors +representing files, and expect it to become ready when their program +doesn't block on disk accesses (which can take a long time on their own). +.PP +However, this cannot ever work in the \*(L"expected\*(R" way \- you get a readiness +notification as soon as the kernel knows whether and how much data is +there, and in the case of open files, that's always the case, so you +always get a readiness notification instantly, and your read (or possibly +write) will still block on the disk I/O. +.PP +Another way to view it is that in the case of sockets, pipes, character +devices and so on, there is another party (the sender) that delivers data +on its own, but in the case of files, there is no such thing: the disk +will not send data on its own, simply because it doesn't know what you +wish to read \- you would first have to request some data. +.PP +Since files are typically not-so-well supported by advanced notification +mechanism, libev tries hard to emulate \s-1POSIX\s0 behaviour with respect +to files, even though you should not use it. The reason for this is +convenience: sometimes you want to watch \s-1STDIN\s0 or \s-1STDOUT\s0, which is +usually a tty, often a pipe, but also sometimes files or special devices +(for example, \f(CW\*(C`epoll\*(C'\fR on Linux works with \fI/dev/random\fR but not with +\&\fI/dev/urandom\fR), and even though the file might better be served with +asynchronous I/O instead of with non-blocking I/O, it is still useful when +it \*(L"just works\*(R" instead of freezing. +.PP +So avoid file descriptors pointing to files when you know it (e.g. use +libeio), but use them when it is convenient, e.g. for \s-1STDIN/STDOUT\s0, or +when you rarely read from a file instead of from a socket, and want to +reuse the same code path. +.PP \fIThe special problem of fork\fR .IX Subsection "The special problem of fork" .PP Some backends (epoll, kqueue) do not support \f(CW\*(C`fork ()\*(C'\fR at all or exhibit useless behaviour. Libev fully supports fork, but needs to be told about -it in the child. +it in the child if you want to continue to use it in the child. .PP -To support fork in your programs, you either have to call -\&\f(CW\*(C`ev_default_fork ()\*(C'\fR or \f(CW\*(C`ev_loop_fork ()\*(C'\fR after a fork in the child, -enable \f(CW\*(C`EVFLAG_FORKCHECK\*(C'\fR, or resort to \f(CW\*(C`EVBACKEND_SELECT\*(C'\fR or -\&\f(CW\*(C`EVBACKEND_POLL\*(C'\fR. +To support fork in your child processes, you have to call \f(CW\*(C`ev_loop_fork +()\*(C'\fR after a fork in the child, enable \f(CW\*(C`EVFLAG_FORKCHECK\*(C'\fR, or resort to +\&\f(CW\*(C`EVBACKEND_SELECT\*(C'\fR or \f(CW\*(C`EVBACKEND_POLL\*(C'\fR. .PP \fIThe special problem of \s-1SIGPIPE\s0\fR .IX Subsection "The special problem of SIGPIPE" @@ -2451,6 +2455,21 @@ So I can't stress this enough: \fIIf you do not reset your signal mask when you expect it to be empty, you have a race condition in your code\fR. This is not a libev-specific thing, this is true for most event libraries. .PP +\fIThe special problem of threads signal handling\fR +.IX Subsection "The special problem of threads signal handling" +.PP +\&\s-1POSIX\s0 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. +.PP +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 \f(CW\*(C`EVFLAG_NOSIGMASK\*(C'\fR when creating +loops. Then designate one thread as \*(L"signal receiver thread\*(R" which handles +these signals. You can pass on any signals that libev might be interested +in by calling \f(CW\*(C`ev_feed_signal\*(C'\fR. +.PP \fIWatcher-Specific Functions and Data Members\fR .IX Subsection "Watcher-Specific Functions and Data Members" .IP "ev_signal_init (ev_signal *, callback, int signum)" 4 @@ -3302,7 +3321,10 @@ it by calling \f(CW\*(C`ev_async_send\*(C'\fR, which is thread\- and signal safe This functionality is very similar to \f(CW\*(C`ev_signal\*(C'\fR watchers, as signals, too, are asynchronous in nature, and signals, too, will be compressed (i.e. the number of callback invocations may be less than the number of -\&\f(CW\*(C`ev_async_sent\*(C'\fR calls). +\&\f(CW\*(C`ev_async_sent\*(C'\fR calls). In fact, you could use signal watchers as a kind +of \*(L"global async watchers\*(R" by using a watcher on an otherwise unused +signal, and \f(CW\*(C`ev_feed_signal\*(C'\fR to signal this watcher from another thread, +even without knowing which loop owns the signal. .PP Unlike \f(CW\*(C`ev_signal\*(C'\fR watchers, \f(CW\*(C`ev_async\*(C'\fR works with any event loop, not just the default loop. @@ -3475,13 +3497,353 @@ Feed an event on the given fd, as if a file descriptor backend detected the given events it. .IP "ev_feed_signal_event (loop, int signum)" 4 .IX Item "ev_feed_signal_event (loop, int signum)" -Feed an event as if the given signal occurred (\f(CW\*(C`loop\*(C'\fR must be the default -loop!). +Feed an event as if the given signal occurred. See also \f(CW\*(C`ev_feed_signal\*(C'\fR, +which is async-safe. +.SH "COMMON OR USEFUL IDIOMS (OR BOTH)" +.IX Header "COMMON OR USEFUL IDIOMS (OR BOTH)" +This section explains some common idioms that are not immediately +obvious. Note that examples are sprinkled over the whole manual, and this +section only contains stuff that wouldn't fit anywhere else. +.SS "\s-1ASSOCIATING\s0 \s-1CUSTOM\s0 \s-1DATA\s0 \s-1WITH\s0 A \s-1WATCHER\s0" +.IX Subsection "ASSOCIATING CUSTOM DATA WITH A WATCHER" +Each watcher has, by default, a \f(CW\*(C`void *data\*(C'\fR member that you can read +or modify at any time: libev will completely ignore it. This can be used +to associate arbitrary data with your watcher. If you need more data and +don't want to allocate memory separately and store a pointer to it in that +data member, you can also \*(L"subclass\*(R" the watcher type and provide your own +data: +.PP +.Vb 7 +\& struct my_io +\& { +\& ev_io io; +\& int otherfd; +\& void *somedata; +\& struct whatever *mostinteresting; +\& }; +\& +\& ... +\& struct my_io w; +\& ev_io_init (&w.io, my_cb, fd, EV_READ); +.Ve +.PP +And since your callback will be called with a pointer to the watcher, you +can cast it back to your own type: +.PP +.Vb 5 +\& static void my_cb (struct ev_loop *loop, ev_io *w_, int revents) +\& { +\& struct my_io *w = (struct my_io *)w_; +\& ... +\& } +.Ve +.PP +More interesting and less C\-conformant ways of casting your callback +function type instead have been omitted. +.SS "\s-1BUILDING\s0 \s-1YOUR\s0 \s-1OWN\s0 \s-1COMPOSITE\s0 \s-1WATCHERS\s0" +.IX Subsection "BUILDING YOUR OWN COMPOSITE WATCHERS" +Another common scenario is to use some data structure with multiple +embedded watchers, in effect creating your own watcher that combines +multiple libev event sources into one \*(L"super-watcher\*(R": +.PP +.Vb 6 +\& struct my_biggy +\& { +\& int some_data; +\& ev_timer t1; +\& ev_timer t2; +\& } +.Ve +.PP +In this case getting the pointer to \f(CW\*(C`my_biggy\*(C'\fR is a bit more +complicated: Either you store the address of your \f(CW\*(C`my_biggy\*(C'\fR struct in +the \f(CW\*(C`data\*(C'\fR member of the watcher (for woozies or \*(C+ coders), or you need +to use some pointer arithmetic using \f(CW\*(C`offsetof\*(C'\fR inside your watchers (for +real programmers): +.PP +.Vb 1 +\& #include +\& +\& static void +\& t1_cb (EV_P_ ev_timer *w, int revents) +\& { +\& 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)); +\& } +.Ve +.SS "\s-1MODEL/NESTED\s0 \s-1EVENT\s0 \s-1LOOP\s0 \s-1INVOCATIONS\s0 \s-1AND\s0 \s-1EXIT\s0 \s-1CONDITIONS\s0" +.IX Subsection "MODEL/NESTED EVENT LOOP INVOCATIONS AND EXIT CONDITIONS" +Often (especially in \s-1GUI\s0 toolkits) there are places where you have +\&\fImodal\fR interaction, which is most easily implemented by recursively +invoking \f(CW\*(C`ev_run\*(C'\fR. +.PP +This brings the problem of exiting \- a callback might want to finish the +main \f(CW\*(C`ev_run\*(C'\fR call, but not the nested one (e.g. user clicked \*(L"Quit\*(R", but +a modal \*(L"Are you sure?\*(R" dialog is still waiting), or just the nested one +and not the main one (e.g. user clocked \*(L"Ok\*(R" in a modal dialog), or some +other combination: In these cases, \f(CW\*(C`ev_break\*(C'\fR will not work alone. +.PP +The solution is to maintain \*(L"break this loop\*(R" variable for each \f(CW\*(C`ev_run\*(C'\fR +invocation, and use a loop around \f(CW\*(C`ev_run\*(C'\fR until the condition is +triggered, using \f(CW\*(C`EVRUN_ONCE\*(C'\fR: +.PP +.Vb 2 +\& // main loop +\& int exit_main_loop = 0; +\& +\& while (!exit_main_loop) +\& ev_run (EV_DEFAULT_ EVRUN_ONCE); +\& +\& // in a model watcher +\& int exit_nested_loop = 0; +\& +\& while (!exit_nested_loop) +\& ev_run (EV_A_ EVRUN_ONCE); +.Ve +.PP +To exit from any of these loops, just set the corresponding exit variable: +.PP +.Vb 2 +\& // 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; +.Ve +.SS "\s-1THREAD\s0 \s-1LOCKING\s0 \s-1EXAMPLE\s0" +.IX Subsection "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. +.PP +For a real-world example, see the \f(CW\*(C`EV::Loop::Async\*(C'\fR perl module, +which uses exactly this technique (which is suited for many high-level +languages). +.PP +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. +.PP +First, you need to associate some data with the event loop: +.PP +.Vb 6 +\& typedef struct { +\& mutex_t lock; /* global loop lock */ +\& ev_async async_w; +\& thread_t tid; +\& cond_t invoke_cv; +\& } 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); +\& +\& pthread_mutex_init (&u\->lock, 0); +\& pthread_cond_init (&u\->invoke_cv, 0); +\& +\& // now associate this with the loop +\& ev_set_userdata (EV_A_ u); +\& ev_set_invoke_pending_cb (EV_A_ l_invoke); +\& ev_set_loop_release_cb (EV_A_ l_release, l_acquire); +\& +\& // then create the thread running ev_loop +\& pthread_create (&u\->tid, 0, l_run, EV_A); +\& } +.Ve +.PP +The callback for the \f(CW\*(C`ev_async\*(C'\fR watcher does nothing: the watcher is used +solely to wake up the event loop so it takes notice of any new watchers +that might have been added: +.PP +.Vb 5 +\& static void +\& async_cb (EV_P_ ev_async *w, int revents) +\& { +\& // just used for the side effects +\& } +.Ve +.PP +The \f(CW\*(C`l_release\*(C'\fR and \f(CW\*(C`l_acquire\*(C'\fR callbacks simply unlock/lock the mutex +protecting the loop data, respectively. +.PP +.Vb 6 +\& static void +\& l_release (EV_P) +\& { +\& userdata *u = ev_userdata (EV_A); +\& pthread_mutex_unlock (&u\->lock); +\& } +\& +\& static void +\& l_acquire (EV_P) +\& { +\& userdata *u = ev_userdata (EV_A); +\& pthread_mutex_lock (&u\->lock); +\& } +.Ve +.PP +The event loop thread first acquires the mutex, and then jumps straight +into \f(CW\*(C`ev_run\*(C'\fR: +.PP +.Vb 4 +\& void * +\& l_run (void *thr_arg) +\& { +\& struct ev_loop *loop = (struct ev_loop *)thr_arg; +\& +\& l_acquire (EV_A); +\& pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0); +\& ev_run (EV_A_ 0); +\& l_release (EV_A); +\& +\& return 0; +\& } +.Ve +.PP +Instead of invoking all pending watchers, the \f(CW\*(C`l_invoke\*(C'\fR callback will +signal the main thread via some unspecified mechanism (signals? pipe +writes? \f(CW\*(C`Async::Interrupt\*(C'\fR?) and then waits until all pending watchers +have been called (in a while loop because a) spurious wakeups are possible +and b) skipping inter-thread-communication when there are no pending +watchers is very beneficial): +.PP +.Vb 4 +\& static void +\& l_invoke (EV_P) +\& { +\& userdata *u = ev_userdata (EV_A); +\& +\& while (ev_pending_count (EV_A)) +\& { +\& wake_up_other_thread_in_some_magic_or_not_so_magic_way (); +\& pthread_cond_wait (&u\->invoke_cv, &u\->lock); +\& } +\& } +.Ve +.PP +Now, whenever the main thread gets told to invoke pending watchers, it +will grab the lock, call \f(CW\*(C`ev_invoke_pending\*(C'\fR and then signal the loop +thread to continue: +.PP +.Vb 4 +\& static void +\& real_invoke_pending (EV_P) +\& { +\& userdata *u = ev_userdata (EV_A); +\& +\& pthread_mutex_lock (&u\->lock); +\& ev_invoke_pending (EV_A); +\& pthread_cond_signal (&u\->invoke_cv); +\& pthread_mutex_unlock (&u\->lock); +\& } +.Ve +.PP +Whenever you want to start/stop a watcher or do other modifications to an +event loop, you will now have to lock: +.PP +.Vb 2 +\& ev_timer timeout_watcher; +\& userdata *u = ev_userdata (EV_A); +\& +\& ev_timer_init (&timeout_watcher, timeout_cb, 5.5, 0.); +\& +\& pthread_mutex_lock (&u\->lock); +\& ev_timer_start (EV_A_ &timeout_watcher); +\& ev_async_send (EV_A_ &u\->async_w); +\& pthread_mutex_unlock (&u\->lock); +.Ve +.PP +Note that sending the \f(CW\*(C`ev_async\*(C'\fR watcher is required because otherwise +an event loop currently blocking in the kernel will have no knowledge +about the newly added timer. By waking up the loop it will pick up any new +watchers in the next event loop iteration. +.SS "\s-1THREADS\s0, \s-1COROUTINES\s0, \s-1CONTINUATIONS\s0, \s-1QUEUES\s0... \s-1INSTEAD\s0 \s-1OF\s0 \s-1CALLBACKS\s0" +.IX Subsection "THREADS, COROUTINES, CONTINUATIONS, QUEUES... INSTEAD OF CALLBACKS" +While the overhead of a callback that e.g. schedules a thread is small, it +is still an overhead. If you embed libev, and your main usage is with some +kind of threads or coroutines, you might want to customise libev so that +doesn't need callbacks anymore. +.PP +Imagine you have coroutines that you can switch to using a function +\&\f(CW\*(C`switch_to (coro)\*(C'\fR, that libev runs in a coroutine called \f(CW\*(C`libev_coro\*(C'\fR +and that due to some magic, the currently active coroutine is stored in a +global called \f(CW\*(C`current_coro\*(C'\fR. Then you can build your own \*(L"wait for libev +event\*(R" primitive by changing \f(CW\*(C`EV_CB_DECLARE\*(C'\fR and \f(CW\*(C`EV_CB_INVOKE\*(C'\fR (note +the differing \f(CW\*(C`;\*(C'\fR conventions): +.PP +.Vb 2 +\& #define EV_CB_DECLARE(type) struct my_coro *cb; +\& #define EV_CB_INVOKE(watcher) switch_to ((watcher)\->cb) +.Ve +.PP +That means instead of having a C callback function, you store the +coroutine to switch to in each watcher, and instead of having libev call +your callback, you instead have it switch to that coroutine. +.PP +A coroutine might now wait for an event with a function called +\&\f(CW\*(C`wait_for_event\*(C'\fR. (the watcher needs to be started, as always, but it doesn't +matter when, or whether the watcher is active or not when this function is +called): +.PP +.Vb 6 +\& void +\& wait_for_event (ev_watcher *w) +\& { +\& ev_cb_set (w) = current_coro; +\& switch_to (libev_coro); +\& } +.Ve +.PP +That basically suspends the coroutine inside \f(CW\*(C`wait_for_event\*(C'\fR and +continues the libev coroutine, which, when appropriate, switches back to +this or any other coroutine. I am sure if you sue this your own :) +.PP +You can do similar tricks if you have, say, threads with an event queue \- +instead of storing a coroutine, you store the queue object and instead of +switching to a coroutine, you push the watcher onto the queue and notify +any waiters. +.PP +To embed libev, see \s-1EMBEDDING\s0, but in short, it's easiest to create two +files, \fImy_ev.h\fR and \fImy_ev.c\fR that include the respective libev files: +.PP +.Vb 4 +\& // my_ev.h +\& #define EV_CB_DECLARE(type) struct my_coro *cb; +\& #define EV_CB_INVOKE(watcher) switch_to ((watcher)\->cb); +\& #include "../libev/ev.h" +\& +\& // my_ev.c +\& #define EV_H "my_ev.h" +\& #include "../libev/ev.c" +.Ve +.PP +And then use \fImy_ev.h\fR when you would normally use \fIev.h\fR, and compile +\&\fImy_ev.c\fR into your project. When properly specifying include paths, you +can even use \fIev.h\fR as header file name directly. .SH "LIBEVENT EMULATION" .IX Header "LIBEVENT EMULATION" Libev offers a compatibility emulation layer for libevent. It cannot emulate the internals of libevent, so here are some usage hints: .IP "\(bu" 4 +Only the libevent\-1.4.1\-beta \s-1API\s0 is being emulated. +.Sp +This was the newest libevent version available when libev was implemented, +and is still mostly unchanged in 2010. +.IP "\(bu" 4 Use it by including , as usual. .IP "\(bu" 4 The following members are fully supported: ev_base, ev_callback, @@ -3496,7 +3858,7 @@ will fail and all watchers will have the same priority, even though there is an ev_pri field. .IP "\(bu" 4 In libevent, the last base created gets the signals, in libev, the -first base created (== the default loop) gets the signals. +base that registered the signal gets the signals. .IP "\(bu" 4 Other members are not supported. .IP "\(bu" 4 @@ -3524,11 +3886,11 @@ classes add (compared to plain C\-style watchers) is the event loop pointer that the watcher is associated with (or no additional members at all if you disable \f(CW\*(C`EV_MULTIPLICITY\*(C'\fR when embedding libev). .PP -Currently, functions, and static and non-static member functions can be -used as callbacks. Other types should be easy to add as long as they only -need one additional pointer for context. If you need support for other -types of functors please contact the author (preferably after implementing -it). +Currently, functions, static and non-static member functions and classes +with \f(CW\*(C`operator ()\*(C'\fR can be used as callbacks. Other types should be easy +to add as long as they only need one additional pointer for context. If +you need support for other types of functors please contact the author +(preferably after implementing it). .PP Here is a list of things available in the \f(CW\*(C`ev\*(C'\fR namespace: .ie n .IP """ev::READ"", ""ev::WRITE"" etc." 4 @@ -4376,8 +4738,8 @@ And a \fIev_cpp.C\fR implementation file that contains libev proper and is compi \& #include "ev_cpp.h" \& #include "ev.c" .Ve -.SH "INTERACTION WITH OTHER PROGRAMS OR LIBRARIES" -.IX Header "INTERACTION WITH OTHER PROGRAMS OR LIBRARIES" +.SH "INTERACTION WITH OTHER PROGRAMS, LIBRARIES OR THE ENVIRONMENT" +.IX Header "INTERACTION WITH OTHER PROGRAMS, LIBRARIES OR THE ENVIRONMENT" .SS "\s-1THREADS\s0 \s-1AND\s0 \s-1COROUTINES\s0" .IX Subsection "THREADS AND COROUTINES" \fI\s-1THREADS\s0\fR @@ -4434,158 +4796,7 @@ work in the default loop by registering the signal watcher with the default loop and triggering an \f(CW\*(C`ev_async\*(C'\fR watcher from the default loop watcher callback into the event loop interested in the signal. .PP -\s-1THREAD\s0 \s-1LOCKING\s0 \s-1EXAMPLE\s0 -.IX Subsection "THREAD LOCKING EXAMPLE" -.PP -Here is a fictitious example of how to run an event loop in a different -thread than where callbacks are being invoked and watchers are -created/added/removed. -.PP -For a real-world example, see the \f(CW\*(C`EV::Loop::Async\*(C'\fR perl module, -which uses exactly this technique (which is suited for many high-level -languages). -.PP -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. -.PP -First, you need to associate some data with the event loop: -.PP -.Vb 6 -\& typedef struct { -\& mutex_t lock; /* global loop lock */ -\& ev_async async_w; -\& thread_t tid; -\& cond_t invoke_cv; -\& } 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); -\& -\& pthread_mutex_init (&u\->lock, 0); -\& pthread_cond_init (&u\->invoke_cv, 0); -\& -\& // now associate this with the loop -\& ev_set_userdata (EV_A_ u); -\& ev_set_invoke_pending_cb (EV_A_ l_invoke); -\& ev_set_loop_release_cb (EV_A_ l_release, l_acquire); -\& -\& // then create the thread running ev_loop -\& pthread_create (&u\->tid, 0, l_run, EV_A); -\& } -.Ve -.PP -The callback for the \f(CW\*(C`ev_async\*(C'\fR watcher does nothing: the watcher is used -solely to wake up the event loop so it takes notice of any new watchers -that might have been added: -.PP -.Vb 5 -\& static void -\& async_cb (EV_P_ ev_async *w, int revents) -\& { -\& // just used for the side effects -\& } -.Ve -.PP -The \f(CW\*(C`l_release\*(C'\fR and \f(CW\*(C`l_acquire\*(C'\fR callbacks simply unlock/lock the mutex -protecting the loop data, respectively. -.PP -.Vb 6 -\& static void -\& l_release (EV_P) -\& { -\& userdata *u = ev_userdata (EV_A); -\& pthread_mutex_unlock (&u\->lock); -\& } -\& -\& static void -\& l_acquire (EV_P) -\& { -\& userdata *u = ev_userdata (EV_A); -\& pthread_mutex_lock (&u\->lock); -\& } -.Ve -.PP -The event loop thread first acquires the mutex, and then jumps straight -into \f(CW\*(C`ev_run\*(C'\fR: -.PP -.Vb 4 -\& void * -\& l_run (void *thr_arg) -\& { -\& struct ev_loop *loop = (struct ev_loop *)thr_arg; -\& -\& l_acquire (EV_A); -\& pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0); -\& ev_run (EV_A_ 0); -\& l_release (EV_A); -\& -\& return 0; -\& } -.Ve -.PP -Instead of invoking all pending watchers, the \f(CW\*(C`l_invoke\*(C'\fR callback will -signal the main thread via some unspecified mechanism (signals? pipe -writes? \f(CW\*(C`Async::Interrupt\*(C'\fR?) and then waits until all pending watchers -have been called (in a while loop because a) spurious wakeups are possible -and b) skipping inter-thread-communication when there are no pending -watchers is very beneficial): -.PP -.Vb 4 -\& static void -\& l_invoke (EV_P) -\& { -\& userdata *u = ev_userdata (EV_A); -\& -\& while (ev_pending_count (EV_A)) -\& { -\& wake_up_other_thread_in_some_magic_or_not_so_magic_way (); -\& pthread_cond_wait (&u\->invoke_cv, &u\->lock); -\& } -\& } -.Ve -.PP -Now, whenever the main thread gets told to invoke pending watchers, it -will grab the lock, call \f(CW\*(C`ev_invoke_pending\*(C'\fR and then signal the loop -thread to continue: -.PP -.Vb 4 -\& static void -\& real_invoke_pending (EV_P) -\& { -\& userdata *u = ev_userdata (EV_A); -\& -\& pthread_mutex_lock (&u\->lock); -\& ev_invoke_pending (EV_A); -\& pthread_cond_signal (&u\->invoke_cv); -\& pthread_mutex_unlock (&u\->lock); -\& } -.Ve -.PP -Whenever you want to start/stop a watcher or do other modifications to an -event loop, you will now have to lock: -.PP -.Vb 2 -\& ev_timer timeout_watcher; -\& userdata *u = ev_userdata (EV_A); -\& -\& ev_timer_init (&timeout_watcher, timeout_cb, 5.5, 0.); -\& -\& pthread_mutex_lock (&u\->lock); -\& ev_timer_start (EV_A_ &timeout_watcher); -\& ev_async_send (EV_A_ &u\->async_w); -\& pthread_mutex_unlock (&u\->lock); -.Ve -.PP -Note that sending the \f(CW\*(C`ev_async\*(C'\fR watcher is required because otherwise -an event loop currently blocking in the kernel will have no knowledge -about the newly added timer. By waking up the loop it will pick up any new -watchers in the next event loop iteration. +See also \*(L"\s-1THREAD\s0 \s-1LOCKING\s0 \s-1EXAMPLE\s0\*(R". .PP \fI\s-1COROUTINES\s0\fR .IX Subsection "COROUTINES" diff --git a/ev.h b/ev.h index 75017f3..9edf656 100644 --- a/ev.h +++ b/ev.h @@ -193,7 +193,7 @@ struct ev_loop; /*****************************************************************************/ #define EV_VERSION_MAJOR 4 -#define EV_VERSION_MINOR 1 +#define EV_VERSION_MINOR 3 /* eventmask, revents, events... */ enum { -- cgit v1.2.3