2 + D Programming Language "bindings" to libev
3 + <http://software.schmorp.de/pkg/libev.html>
5 + Written by Leandro Lucarella (2008).
7 + Placed under BOLA license <http://auriga.wearlab.de/~alb/bola/> which is
8 + basically public domain.
19 EV_UNDEF = 0xFFFFFFFFL, // guaranteed to be invalid
20 EV_NONE = 0x00L, // no events
21 EV_READ = 0x01L, // ev_io detected read will not block
22 EV_WRITE = 0x02L, // ev_io detected write will not block
23 EV_IOFDSET = 0x80L, // internal use only
24 EV_TIMEOUT = 0x00000100L, // timer timed out
25 EV_PERIODIC = 0x00000200L, // periodic timer timed out
26 EV_SIGNAL = 0x00000400L, // signal was received
27 EV_CHILD = 0x00000800L, // child/pid had status change
28 EV_STAT = 0x00001000L, // stat data changed
29 EV_IDLE = 0x00002000L, // event loop is idling
30 EV_PREPARE = 0x00004000L, // event loop about to poll
31 EV_CHECK = 0x00008000L, // event loop finished poll
32 EV_EMBED = 0x00010000L, // embedded event loop needs sweep
33 EV_FORK = 0x00020000L, // event loop resumed in child
34 EV_ERROR = 0x80000000L, // sent when an error occurs
39 // bits for ev_default_loop and ev_loop_new
41 EVFLAG_AUTO = 0x00000000UL, // not quite a mask
43 EVFLAG_NOENV = 0x01000000UL, // do NOT consult environment
44 EVFLAG_FORKCHECK = 0x02000000UL, // check for a fork in each iteration
45 // method bits to be ored together
46 EVBACKEND_SELECT = 0x00000001UL, // about anywhere
47 EVBACKEND_POLL = 0x00000002UL, // !win
48 EVBACKEND_EPOLL = 0x00000004UL, // linux
49 EVBACKEND_KQUEUE = 0x00000008UL, // bsd
50 EVBACKEND_DEVPOLL = 0x00000010UL, // solaris 8 / NYI
51 EVBACKEND_PORT = 0x00000020UL, // solaris 10
56 EVLOOP_NONBLOCK = 1, // do not block/wait
57 EVLOOP_ONESHOT = 2, // block *once* only
62 EVUNLOOP_CANCEL = 0, // undo unloop
63 EVUNLOOP_ONE = 1, // unloop once
64 EVUNLOOP_ALL = 2, // unloop all loops
67 version (EV_ENABLE_SELECT)
72 version = EV_PERIODIC_ENABLE;
73 version = EV_STAT_ENABLE;
74 version = EV_IDLE_ENABLE;
75 version = EV_FORK_ENABLE;
76 version = EV_EMBED_ENABLE;
79 alias double ev_tstamp;
88 template EV_CB_DECLARE(TYPE)
90 void function (ev_loop_t*, TYPE*, int) cb;
93 template EV_WATCHER(TYPE)
95 int active; // private
96 int pending; // private
97 int priority; // private
98 mixin EV_COMMON; // rw
99 mixin EV_CB_DECLARE!(TYPE); // private
102 template EV_WATCHER_LIST(TYPE)
104 mixin EV_WATCHER!(TYPE);
105 ev_watcher_list* next; // private
108 template EV_WATCHER_TIME(TYPE)
110 mixin EV_WATCHER!(TYPE);
111 ev_tstamp at; // private
116 mixin EV_WATCHER!(ev_watcher);
119 struct ev_watcher_list
121 mixin EV_WATCHER_LIST!(ev_watcher_list);
124 struct ev_watcher_time
126 mixin EV_WATCHER_TIME!(ev_watcher_time);
131 mixin EV_WATCHER_LIST!(ev_io);
138 mixin EV_WATCHER_TIME!(ev_timer);
139 ev_tstamp repeat; // rw
142 version (EV_PERIODIC_ENABLE)
146 mixin EV_WATCHER_TIME!(ev_periodic);
147 ev_tstamp offset; // rw
148 ev_tstamp interval; // rw
149 ev_tstamp function(ev_periodic *w,
150 ev_tstamp now) reschedule_cb; // rw
156 mixin EV_WATCHER_LIST!(ev_signal);
162 mixin EV_WATCHER_LIST!(ev_child);
164 int rpid; // rw, holds the received pid
165 int rstatus; // rw, holds the exit status, use the
166 // macros from sys/wait.h
169 version (EV_STAT_ENABLE)
172 version (Windows) // alias _stati64 ev_statdata;
174 pragma (msg, "ev_stat not supported in windows "
175 "because I don't know the "
176 "layout of _stati64");
178 // Maybe this should work?
179 //static import stat = std.c.windows.stat;
180 //alias stat.struct_stat ev_statdata;
182 else // It should be POSIX
184 static import stat = std.c.unix.unix;
185 alias stat.struct_stat ev_statdata;
190 mixin EV_WATCHER_LIST!(ev_stat);
192 ev_timer timer; // private
193 ev_tstamp interval; // ro
194 const char *path; // ro
195 ev_statdata prev; // ro
196 ev_statdata attr; // ro
197 int wd; // wd for inotify, fd for kqueue
201 version (EV_IDLE_ENABLE)
205 mixin EV_WATCHER!(ev_idle);
211 mixin EV_WATCHER!(ev_prepare);
216 mixin EV_WATCHER!(ev_check);
219 version (EV_FORK_ENABLE)
223 mixin EV_WATCHER!(ev_fork);
227 version (EV_EMBED_ENABLE)
231 mixin EV_WATCHER!(ev_embed);
232 ev_loop_t* other; // ro
234 ev_prepare prepare; // private
235 ev_check check; // unused
236 ev_timer timer; // unused
237 ev_periodic periodic; // unused
238 ev_idle idle; // unused
239 ev_fork fork; // unused
243 int ev_version_major();
244 int ev_version_minor();
246 uint ev_supported_backends();
247 uint ev_recommended_backends();
248 uint ev_embeddable_backends();
251 void ev_sleep(ev_tstamp delay); // sleep for a while
253 // Sets the allocation function to use, works like realloc.
254 // It is used to allocate and free memory.
255 // If it returns zero when memory needs to be allocated, the library
257 // or take some potentially destructive action.
258 // The default is your system realloc function.
259 void ev_set_allocator(void* function(void* ptr, int size));
261 // set the callback function to call on a
262 // retryable syscall error
263 // (such as failed select, poll, epoll_wait)
264 void ev_set_syserr_cb(void function(char* msg));
266 extern ev_loop_t* ev_default_loop_ptr;
268 ev_loop_t* ev_default_loop_init(uint flags);
270 // create and destroy alternative loops that don't handle signals
271 ev_loop_t* ev_loop_new(uint flags);
272 void ev_loop_destroy(ev_loop_t*);
273 void ev_loop_fork(ev_loop_t*);
275 ev_tstamp ev_now(ev_loop_t*);
276 void ev_default_destroy();
277 void ev_default_fork();
278 uint ev_backend(ev_loop_t*);
279 uint ev_loop_count(ev_loop_t*);
280 void ev_loop(ev_loop_t*, int flags);
281 void ev_unloop(ev_loop_t*, int);
282 void ev_set_io_collect_interval(ev_loop_t*, ev_tstamp interval);
283 void ev_set_timeout_collect_interval(ev_loop_t*, ev_tstamp interval);
284 void ev_ref(ev_loop_t*);
285 void ev_unref(ev_loop_t*);
286 void ev_once(ev_loop_t*, int fd, int events, ev_tstamp timeout,
287 void function(int revents, void* arg), void* arg);
289 void ev_feed_event(ev_loop_t*, void *w, int revents);
290 void ev_feed_fd_event(ev_loop_t*, int fd, int revents);
291 void ev_feed_signal_event (ev_loop_t*, int signum);
292 void ev_invoke(ev_loop_t*, void *w, int revents);
293 int ev_clear_pending(ev_loop_t*, void *w);
295 void ev_io_start(ev_loop_t*, ev_io *w);
296 void ev_io_stop(ev_loop_t*, ev_io *w);
298 void ev_timer_start(ev_loop_t*, ev_timer *w);
299 void ev_timer_stop(ev_loop_t*, ev_timer *w);
300 void ev_timer_again(ev_loop_t*, ev_timer *w);
302 version (EV_PERIODIC_ENABLE)
304 void ev_periodic_start(ev_loop_t*, ev_periodic *w);
305 void ev_periodic_stop(ev_loop_t*, ev_periodic *w);
306 void ev_periodic_again(ev_loop_t*, ev_periodic *w);
309 void ev_signal_start(ev_loop_t*, ev_signal *w);
310 void ev_signal_stop(ev_loop_t*, ev_signal *w);
312 /* only supported in the default loop */
313 void ev_child_start(ev_loop_t*, ev_child *w);
314 void ev_child_stop(ev_loop_t*, ev_child *w);
316 version (EV_STAT_ENABLE)
318 void ev_stat_start(ev_loop_t*, ev_stat *w);
319 void ev_stat_stop(ev_loop_t*, ev_stat *w);
320 void ev_stat_stat(ev_loop_t*, ev_stat *w);
323 version (EV_IDLE_ENABLE)
325 void ev_idle_start(ev_loop_t*, ev_idle *w);
326 void ev_idle_stop(ev_loop_t*, ev_idle *w);
329 void ev_prepare_start(ev_loop_t*, ev_prepare *w);
330 void ev_prepare_stop(ev_loop_t*, ev_prepare *w);
332 void ev_check_start(ev_loop_t*, ev_check *w);
333 void ev_check_stop(ev_loop_t*, ev_check *w);
335 version (EV_FORK_ENABLE)
337 void ev_fork_start(ev_loop_t*, ev_fork *w);
338 void ev_fork_stop(ev_loop_t*, ev_fork *w);
341 version (EV_EMBED_ENABLE)
343 // only supported when loop to be embedded is in fact embeddable
344 void ev_embed_start(ev_loop_t*, ev_embed *w);
345 void ev_embed_stop(ev_loop_t*, ev_embed *w);
346 void ev_embed_sweep(ev_loop_t*, ev_embed *w);
349 bool ev_is_pending(TYPE)(TYPE* w)
351 return cast (bool) w.pending;
354 bool ev_is_active(TYPE)(TYPE* w)
356 return cast (bool) w.active;
359 int ev_priority(TYPE)(TYPE* w)
361 return cast (bool) w.priority;
364 void function(ev_loop_t*, TYPE*, int) ev_cb(TYPE)(TYPE* w)
369 void ev_set_priority(TYPE)(TYPE* w, int pri)
374 void ev_set_cb(TYPE)(TYPE* w,
375 void function(ev_loop_t*, TYPE*, int) cb)
380 void ev_init(TYPE)(TYPE* w,
381 void function(ev_loop_t*, TYPE*, int) cb)
389 void ev_io_set(ev_io* w, int fd, int events)
392 w.events = events | EV_IOFDSET;
395 void ev_timer_set(ev_timer* w, ev_tstamp after, ev_tstamp repeat)
401 void ev_periodic_set(ev_periodic* w, ev_tstamp ofs, ev_tstamp ival,
402 ev_tstamp function(ev_periodic *w, ev_tstamp now) res)
406 w.reschedule_cb = res;
409 void ev_signal_set(ev_signal* w, int signum)
414 void ev_child_set(ev_child* w, int pid)
419 void ev_stat_set(ev_stat* w, char* path, ev_tstamp interval)
422 w.interval = interval;
426 void ev_idle_set(ev_idle* w)
430 void ev_prepare_set(ev_prepare* w)
434 void ev_check_set(ev_check* w)
438 void ev_embed_set(ev_embed* w, ev_loop_t* other)
443 void ev_fork_set(ev_fork* w)
447 void ev_io_init(ev_io* w, void function(ev_loop_t*, ev_io*, int) cb, int fd,
451 ev_io_set(w, fd, events);
454 void ev_timer_init(ev_timer* w, void function(ev_loop_t*, ev_timer*, int) cb,
455 ev_tstamp after, ev_tstamp repeat)
458 ev_timer_set(w, after, repeat);
461 void ev_periodic_init(ev_periodic* w,
462 void function(ev_loop_t*, ev_periodic*, int) cb,
463 ev_tstamp ofs, ev_tstamp ival,
464 ev_tstamp function(ev_periodic *w, ev_tstamp now) res)
467 ev_periodic_set(w, ofs, ival, res);
470 void ev_signal_init(ev_signal* w, void function(ev_loop_t*, ev_signal*, int) cb,
474 ev_signal_set(w, signum);
477 void ev_child_init(ev_child* w, void function(ev_loop_t*, ev_child*, int) cb,
481 ev_child_set(w, pid);
484 void ev_stat_init(ev_stat* w, void function(ev_loop_t*, ev_stat*, int) cb,
485 char* path, ev_tstamp interval)
488 ev_stat_set(w, path, interval);
491 void ev_idle_init(ev_idle* w, void function(ev_loop_t*, ev_idle*, int) cb)
497 void ev_prepare_init(ev_prepare* w,
498 void function(ev_loop_t*, ev_prepare*, int) cb)
504 void ev_check_init(ev_check* w, void function(ev_loop_t*, ev_check*, int) cb)
510 void ev_embed_init(ev_embed* w, void function(ev_loop_t*, ev_embed*, int) cb,
514 ev_embed_set(w, other);
517 void ev_fork_init(ev_fork* w, void function(ev_loop_t*, ev_fork*, int) cb)
523 ev_loop_t* ev_default_loop(uint flags = EVFLAG_AUTO)
525 if (!ev_default_loop_ptr)
526 ev_default_loop_init(flags);
527 return ev_default_loop_ptr;
532 import stdio = std.stdio;
533 import stdlib = std.c.stdlib;
534 import str = std.string;
535 import unix = std.c.unix.unix;
536 import proc = std.c.process;
538 const STAT_FILE = "/tmp/libev-stat-test-file";
539 const TEST_TEXT = "hello";
540 bool prepare_done = false;
541 bool check_done = false;
542 bool idle_done = false;
543 bool timer_done = false;
544 bool io_done = false;
545 bool stat_done = false;
546 bool child_done = false;
547 bool signal_done = false;
548 bool eio_done = false;
552 stdio.writefln("Unittesting...");
553 extern (C) static void cbprepare(ev_loop_t* loop, ev_prepare* w, int revents)
555 stdio.writefln("ev_prepare");
556 assert (!prepare_done);
557 assert (!check_done);
559 assert (!timer_done);
562 assert (!child_done);
563 assert (!signal_done);
566 ev_prepare_stop(loop, w);
568 extern (C) static void cbcheck(ev_loop_t* loop, ev_check* w, int revents)
570 stdio.writefln("ev_check");
571 assert (prepare_done);
572 assert (!check_done);
574 assert (!timer_done);
577 assert (!child_done);
578 assert (!signal_done);
581 ev_check_stop(loop, w);
583 extern (C) static void cbidle(ev_loop_t* loop, ev_idle* w, int revents)
585 stdio.writefln("ev_idle");
586 assert (prepare_done);
589 assert (!timer_done);
592 assert (!child_done);
593 assert (!signal_done);
596 ev_idle_stop(loop, w);
598 extern (C) static void cbtimer(ev_loop_t* loop, ev_timer* w,
601 stdio.writefln("ev_timer");
602 assert (prepare_done);
605 assert (!timer_done);
608 assert (!child_done);
609 assert (!signal_done);
612 ev_timer_stop(loop, w);
613 stdio.writefln("\tfiring ev_io");
614 stdio.writefln("\t\topening pipe for writing...");
615 int pipe_fd = *cast (int*) w.data;
616 stdio.writefln("\t\twriting '%s' to pipe...", TEST_TEXT);
617 int n = unix.write(pipe_fd, cast (void*) TEST_TEXT,
619 assert (n == TEST_TEXT.length);
621 extern (C) static void cbio(ev_loop_t* loop, ev_io* w, int revents)
623 stdio.writefln("ev_io");
624 assert (prepare_done);
630 assert (!child_done);
631 assert (!signal_done);
635 char[TEST_TEXT.length] buffer;
636 stdio.writefln("\treading %d bytes from pipe...",
638 int n = unix.read(w.fd, cast (void*) buffer, buffer.length);
639 assert (n == TEST_TEXT.length);
640 assert (buffer.dup == TEST_TEXT.dup);
641 stdio.writefln("\tread '%s'", buffer);
642 stdio.writefln("\tfiring ev_stat");
643 stdio.writefln("\t\topening file '%s'", STAT_FILE);
644 int fd = unix.open(str.toStringz(STAT_FILE),
645 unix.O_WRONLY | unix.O_TRUNC | unix.O_CREAT);
647 stdio.writefln("\t\tfd: %d", fd);
648 n = unix.write(fd, cast (void*) TEST_TEXT,
650 assert (n == TEST_TEXT.length);
653 extern (C) static void cbstat(ev_loop_t* loop, ev_stat* w, int revents)
655 stdio.writefln("ev_stat");
656 assert (prepare_done);
662 assert (!child_done);
663 assert (!signal_done);
666 ev_stat_stop(loop, w);
667 static void print_stat(ev_statdata* s)
669 stdio.writefln("\t\t\tinode: ", s.st_ino);
670 stdio.writefln("\t\t\tmode: ", s.st_mode);
671 stdio.writefln("\t\t\tlinks: ", s.st_nlink);
672 stdio.writefln("\t\t\tuid: ", s.st_uid);
673 stdio.writefln("\t\t\tgid: ", s.st_gid);
674 stdio.writefln("\t\t\tsize: ", s.st_size);
675 stdio.writefln("\t\t\tatime: ", s.st_atime);
676 stdio.writefln("\t\t\tmtime: ", s.st_mtime);
677 stdio.writefln("\t\t\tctime: ", s.st_ctime);
681 stdio.writefln("\tfile '%s' changed", str.toString(w.path));
682 stdio.writefln("\t\tprevios state:");
684 stdio.writefln("\t\tcurrent state:");
689 stdio.writefln("\tfile '%s' does not exist!",
690 str.toString(w.path));
691 stdio.writefln("\t\tprevios state:");
694 stdio.writefln("\tfiring ev_fork...");
695 stdio.writefln("\t\tforking...");
696 auto pid = unix.fork();
701 stdio.writefln("\t\tev_stat: in parent, child pid: ", pid);
705 stdio.writefln("\t\tev_stat: in child, calling "
706 "ev_default_fork...");
710 extern (C) static void cbchild(ev_loop_t* loop, ev_child* w, int revents)
712 stdio.writefln("ev_child");
713 assert (prepare_done);
719 assert (!child_done);
720 assert (!signal_done);
723 ev_child_stop(loop, w);
724 static ubyte WEXITSTATUS(int s)
726 return cast(ubyte)((s & 0xff00) >> 8);
728 static ubyte WTERMSIG(int s)
730 return cast(ubyte)(s & 0x7f);
732 static bool WIFEXITED(int s)
734 return WTERMSIG(s) == 0;
736 static bool WIFSIGNALED(int s)
738 return cast(byte)(((s & 0x7f) + 1) >> 1) > 0;
740 static bool WCOREDUMP(int s)
742 return cast(bool)(s & 0x80);
744 stdio.writefln("\tthe child with pid %d exited with status "
745 "%d", w.rpid, w.rstatus);
746 assert (child_pid == w.rpid);
747 if (WIFEXITED(w.rstatus))
748 stdio.writefln("\tchild exited normally with code ",
749 WEXITSTATUS(w.rstatus));
750 if (WIFSIGNALED(w.rstatus))
752 stdio.writefln("\tchild exited with signal ",
753 WTERMSIG(w.rstatus));
754 if (WCOREDUMP(w.rstatus))
755 stdio.writefln("\tchild produced a core dump");
757 assert (WIFEXITED(w.rstatus) && WEXITSTATUS(w.rstatus) == 5);
758 stdio.writefln("\tfiring ev_signal");
759 stdio.writefln("\t\tsending signal 2 (SIGINT)");
760 unix.kill(proc.getpid(), SIGINT);
762 extern (C) static void cbfork(ev_loop_t* loop, ev_fork* w, int revents)
764 stdio.writefln("ev_fork");
765 assert (prepare_done);
771 assert (!child_done);
772 assert (!signal_done);
774 ev_fork_stop(loop, w);
775 stdio.writefln("\texiting the child program with return "
779 extern (C) static void cbsignal(ev_loop_t* loop, ev_signal* w,
782 stdio.writefln("ev_signal");
783 assert (prepare_done);
790 assert (!signal_done);
793 ev_signal_stop(loop, w);
794 stdio.writefln("\tfiring embeded ev_io...");
795 stdio.writefln("\t\topening pipe for writing...");
796 int pipe_fd = *cast(int*)w.data;
797 stdio.writefln("\t\twriting '%s' to pipe...", TEST_TEXT);
798 int n = unix.write(pipe_fd, cast(void*)TEST_TEXT,
800 assert (n == TEST_TEXT.length);
802 extern (C) static void ecbio(ev_loop_t* loop, ev_io* w, int revents)
804 stdio.writefln("embeded ev_io");
805 assert (prepare_done);
812 assert (signal_done);
815 //ev_io_stop(loop, w);
816 char[TEST_TEXT.length] buffer;
817 stdio.writefln("\treading %d bytes from pipe...",
819 int n = unix.read(w.fd, cast (void*) buffer, buffer.length);
820 assert (n == TEST_TEXT.length);
821 assert (buffer.dup == TEST_TEXT.dup);
822 stdio.writefln("\tread '%s'", buffer);
823 stdio.writefln("\tstoping the loop");
824 ev_unloop(loop, EVUNLOOP_ONE);
826 extern (C) static void cbembed(ev_loop_t* loop, ev_embed* w, int revents)
828 stdio.writefln("ev_embed");
829 stdio.writefln("\tsweeping embeded loop...");
830 ev_embed_sweep(w.other, w);
831 //ev_embed_stop(loop, w);
834 auto loop = ev_default_loop(0);
848 ev_loop_t* eloop = ev_embeddable_backends() & ev_recommended_backends()
849 ? ev_loop_new(ev_embeddable_backends () &
850 ev_recommended_backends ())
855 stdio.writefln("Initializing embeded loop");
856 ev_embed_init(&wembed, &cbembed, eloop);
857 ev_embed_start(loop, &wembed);
861 stdio.writefln("No embeded loop, using the default");
867 int ret = unix.pipe(epipe);
870 ev_io_init(&ewio, &ecbio, epipe[0], EV_READ);
871 ev_io_start(eloop, &ewio);
875 int ret = unix.pipe(pipe);
879 ev_io_init(&wio, &cbio, pipe[0], EV_READ);
880 ev_io_start(loop, &wio);
882 ev_timer_init(&wtimer, &cbtimer, 1.5, 0.);
883 wtimer.data = &pipe[1]; // write fd
884 ev_timer_start(loop, &wtimer);
886 ev_signal_init(&wsignal, &cbsignal, SIGINT);
887 wsignal.data = &epipe[1]; // write fd
888 ev_signal_start(loop, &wsignal);
890 ev_child_init(&wchild, &cbchild, 0 /* trace any PID */);
891 ev_child_start(loop, &wchild);
893 ev_stat_init(&wstat, &cbstat, str.toStringz(STAT_FILE), 0 /* auto */);
894 ev_stat_start(loop, &wstat);
896 ev_idle_init(&widle, &cbidle);
897 ev_idle_start(loop, &widle);
899 ev_prepare_init(&wprepare, &cbprepare);
900 ev_prepare_start(loop, &wprepare);
902 ev_check_init(&wcheck, &cbcheck);
903 ev_check_start(loop, &wcheck);
905 ev_fork_init(&wfork, &cbfork);
906 ev_fork_start(loop, &wfork);
910 assert (prepare_done);
917 assert (signal_done);
920 stdio.writefln("Unittesting done!");