]> git.llucax.com Git - software/ev.d.git/blob - ev/c.d
Move low-level ev bindings to module ev.c.
[software/ev.d.git] / ev / c.d
1 /+
2  + D Programming Language "bindings" to libev
3  + <http://software.schmorp.de/pkg/libev.html>
4  +
5  + Written by Leandro Lucarella (2008).
6  +
7  + Placed under BOLA license <http://auriga.wearlab.de/~alb/bola/> which is
8  + basically public domain.
9  +
10  +/
11
12 module ev.c;
13
14 enum: uint
15 {
16         UNDEF    = 0xFFFFFFFFL, // guaranteed to be invalid
17         NONE     =       0x00L, // no events
18         READ     =       0x01L, // ev_io detected read will not block
19         WRITE    =       0x02L, // ev_io detected write will not block
20         IOFDSET  =       0x80L, // internal use only
21         TIMEOUT  = 0x00000100L, // timer timed out
22         PERIODIC = 0x00000200L, // periodic timer timed out
23         SIGNAL   = 0x00000400L, // signal was received
24         CHILD    = 0x00000800L, // child/pid had status change
25         STAT     = 0x00001000L, // stat data changed
26         IDLE     = 0x00002000L, // event loop is idling
27         PREPARE  = 0x00004000L, // event loop about to poll
28         CHECK    = 0x00008000L, // event loop finished poll
29         EMBED    = 0x00010000L, // embedded event loop needs sweep
30         FORK     = 0x00020000L, // event loop resumed in child
31         ERROR    = 0x80000000L, // sent when an error occurs
32 }
33
34 enum: uint
35 {
36         // bits for ev_default_loop and ev_loop_new
37         // the default
38         AUTO       = 0x00000000UL, // not quite a mask
39         // flag bits
40         NOENV      = 0x01000000UL, // do NOT consult environment
41         FORKCHECK  = 0x02000000UL, // check for a fork in each iteration
42         // method bits to be ored together
43         SELECT     = 0x00000001UL, // about anywhere
44         POLL       = 0x00000002UL, // !win
45         EPOLL      = 0x00000004UL, // linux
46         KQUEUE     = 0x00000008UL, // bsd
47         DEVPOLL    = 0x00000010UL, // solaris 8 / NYI
48         PORT       = 0x00000020UL, // solaris 10
49 }
50
51 enum
52 {
53         NONBLOCK = 1, // do not block/wait
54         ONESHOT  = 2, // block *once* only
55 }
56
57 enum how
58 {
59         CANCEL = 0, // undo unloop
60         ONE    = 1, // unloop once
61         ALL    = 2, // unloop all loops
62 }
63
64
65 extern (C):
66 align (4):
67
68 version (EV_ENABLE_SELECT)
69 {
70 }
71 else
72 {
73         version = EV_PERIODIC_ENABLE;
74         version = EV_STAT_ENABLE;
75         version = EV_IDLE_ENABLE;
76         version = EV_FORK_ENABLE;
77         version = EV_EMBED_ENABLE;
78 }
79
80 alias double ev_tstamp;
81
82 struct ev_loop_t;
83
84 template EV_COMMON()
85 {
86         void* data;
87 }
88
89 template EV_CB_DECLARE(TYPE)
90 {
91         void function (ev_loop_t*, TYPE*, int) cb;
92 }
93
94 template EV_WATCHER(TYPE)
95 {
96         int active;                 // private
97         int pending;                // private
98         int priority;               // private
99         mixin EV_COMMON;            // rw
100         mixin EV_CB_DECLARE!(TYPE); // private
101 }
102
103 template EV_WATCHER_LIST(TYPE)
104 {
105         mixin EV_WATCHER!(TYPE);
106         ev_watcher_list* next;      // private
107 }
108
109 template EV_WATCHER_TIME(TYPE)
110 {
111         mixin EV_WATCHER!(TYPE);
112         ev_tstamp at;               // private
113 }
114
115 struct ev_watcher
116 {
117         mixin EV_WATCHER!(ev_watcher);
118 }
119
120 struct ev_watcher_list
121 {
122         mixin EV_WATCHER_LIST!(ev_watcher_list);
123 }
124
125 struct ev_watcher_time
126 {
127         mixin EV_WATCHER_TIME!(ev_watcher_time);
128 }
129
130 struct ev_io
131 {
132         mixin EV_WATCHER_LIST!(ev_io);
133         int fd;     // ro
134         int events; // ro
135 }
136
137 struct ev_timer
138 {
139         mixin EV_WATCHER_TIME!(ev_timer);
140         ev_tstamp repeat; // rw
141 }
142
143 version (EV_PERIODIC_ENABLE)
144 {
145         struct ev_periodic
146         {
147                 mixin EV_WATCHER_TIME!(ev_periodic);
148                 ev_tstamp offset;                     // rw
149                 ev_tstamp interval;                   // rw
150                 ev_tstamp function(ev_periodic *w,
151                                 ev_tstamp now) reschedule_cb; // rw
152         }
153 }
154
155 struct ev_signal
156 {
157         mixin EV_WATCHER_LIST!(ev_signal);
158         int signum; // ro
159 }
160
161 struct ev_child
162 {
163         mixin EV_WATCHER_LIST!(ev_child);
164         int pid;     // ro
165         int rpid;    // rw, holds the received pid
166         int rstatus; // rw, holds the exit status, use the
167         // macros from sys/wait.h
168 }
169
170 version (EV_STAT_ENABLE)
171 {
172
173         version (Windows) // alias _stati64 ev_statdata;
174         {
175                 pragma (msg, "ev_stat not supported in windows "
176                                 "because I don't know the "
177                                 "layout of _stati64");
178                 static assert(0);
179                 // Maybe this should work?
180                 //static import stat = std.c.windows.stat;
181                 //alias stat.struct_stat ev_statdata;
182         }
183         else // It should be POSIX
184         {
185                 static import stat = std.c.unix.unix;
186                 alias stat.struct_stat ev_statdata;
187         }
188
189         struct ev_stat
190         {
191                 mixin EV_WATCHER_LIST!(ev_stat);
192
193                 ev_timer timer;     // private
194                 ev_tstamp interval; // ro
195                 const char *path;   // ro
196                 ev_statdata prev;   // ro
197                 ev_statdata attr;   // ro
198                 int wd; // wd for inotify, fd for kqueue
199         }
200 }
201
202 version (EV_IDLE_ENABLE)
203 {
204         struct ev_idle
205         {
206                 mixin EV_WATCHER!(ev_idle);
207         }
208 }
209
210 struct ev_prepare
211 {
212         mixin EV_WATCHER!(ev_prepare);
213 }
214
215 struct ev_check
216 {
217         mixin EV_WATCHER!(ev_check);
218 }
219
220 version (EV_FORK_ENABLE)
221 {
222         struct ev_fork
223         {
224                 mixin EV_WATCHER!(ev_fork);
225         }
226 }
227
228 version (EV_EMBED_ENABLE)
229 {
230         struct ev_embed
231         {
232                 mixin EV_WATCHER!(ev_embed);
233                 ev_loop_t* other;     // ro
234                 ev_io io;             // private
235                 ev_prepare prepare;   // private
236                 ev_check check;       // unused
237                 ev_timer timer;       // unused
238                 ev_periodic periodic; // unused
239                 ev_idle idle;         // unused
240                 ev_fork fork;         // unused
241         }
242 }
243
244 int ev_version_major();
245 int ev_version_minor();
246
247 uint ev_supported_backends();
248 uint ev_recommended_backends();
249 uint ev_embeddable_backends();
250
251 ev_tstamp ev_time();
252 void ev_sleep(ev_tstamp delay); // sleep for a while
253
254 // Sets the allocation function to use, works like realloc.
255 // It is used to allocate and free memory.
256 // If it returns zero when memory needs to be allocated, the library
257 // might abort
258 // or take some potentially destructive action.
259 // The default is your system realloc function.
260 void ev_set_allocator(void* function(void* ptr, int size));
261
262 // set the callback function to call on a
263 // retryable syscall error
264 // (such as failed select, poll, epoll_wait)
265 void ev_set_syserr_cb(void* function(char* msg));
266
267 extern ev_loop_t* ev_default_loop_ptr;
268
269 ev_loop_t* ev_default_loop_init(uint flags);
270
271 // create and destroy alternative loops that don't handle signals
272 ev_loop_t* ev_loop_new(uint flags);
273 void ev_loop_destroy(ev_loop_t*);
274 void ev_loop_fork(ev_loop_t*);
275
276 ev_tstamp ev_now(ev_loop_t*);
277 void ev_default_destroy();
278 void ev_default_fork();
279 uint ev_backend(ev_loop_t*);
280 uint ev_loop_count(ev_loop_t*);
281 void ev_loop(ev_loop_t*, int flags);
282 void ev_unloop(ev_loop_t*, how);
283 void ev_set_io_collect_interval(ev_loop_t*, ev_tstamp interval);
284 void ev_set_timeout_collect_interval(ev_loop_t*, ev_tstamp interval);
285 void ev_ref(ev_loop_t*);
286 void ev_unref(ev_loop_t*);
287 void ev_once(ev_loop_t*, int fd, int events, ev_tstamp timeout,
288                 void function(int revents, void* arg), void* arg);
289
290 void ev_feed_event(ev_loop_t*, void *w, int revents);
291 void ev_feed_fd_event(ev_loop_t*, int fd, int revents);
292 void ev_feed_signal_event (ev_loop_t*, int signum);
293 void ev_invoke(ev_loop_t*, void *w, int revents);
294 int  ev_clear_pending(ev_loop_t*, void *w);
295
296 void ev_io_start(ev_loop_t*, ev_io *w);
297 void ev_io_stop(ev_loop_t*, ev_io *w);
298
299 void ev_timer_start(ev_loop_t*, ev_timer *w);
300 void ev_timer_stop(ev_loop_t*, ev_timer *w);
301 void ev_timer_again(ev_loop_t*, ev_timer *w);
302
303 version (EV_PERIODIC_ENABLE)
304 {
305         void ev_periodic_start(ev_loop_t*, ev_periodic *w);
306         void ev_periodic_stop(ev_loop_t*, ev_periodic *w);
307         void ev_periodic_again(ev_loop_t*, ev_periodic *w);
308 }
309
310 void ev_signal_start(ev_loop_t*, ev_signal *w);
311 void ev_signal_stop(ev_loop_t*, ev_signal *w);
312
313 /* only supported in the default loop */
314 void ev_child_start(ev_loop_t*, ev_child *w);
315 void ev_child_stop(ev_loop_t*, ev_child *w);
316
317 version (EV_STAT_ENABLE)
318 {
319         void ev_stat_start(ev_loop_t*, ev_stat *w);
320         void ev_stat_stop(ev_loop_t*, ev_stat *w);
321         void ev_stat_stat(ev_loop_t*, ev_stat *w);
322 }
323
324 version (EV_IDLE_ENABLE)
325 {
326         void ev_idle_start(ev_loop_t*, ev_idle *w);
327         void ev_idle_stop(ev_loop_t*, ev_idle *w);
328 }
329
330 void ev_prepare_start(ev_loop_t*, ev_prepare *w);
331 void ev_prepare_stop(ev_loop_t*, ev_prepare *w);
332
333 void ev_check_start(ev_loop_t*, ev_check *w);
334 void ev_check_stop(ev_loop_t*, ev_check *w);
335
336 version (EV_FORK_ENABLE)
337 {
338         void ev_fork_start(ev_loop_t*, ev_fork *w);
339         void ev_fork_stop(ev_loop_t*, ev_fork *w);
340 }
341
342 version (EV_EMBED_ENABLE)
343 {
344         // only supported when loop to be embedded is in fact embeddable
345         void ev_embed_start(ev_loop_t*, ev_embed *w);
346         void ev_embed_stop(ev_loop_t*, ev_embed *w);
347         void ev_embed_sweep(ev_loop_t*, ev_embed *w);
348 }
349
350 bool ev_is_pending(TYPE)(TYPE* w)
351 {
352         return w.pending;
353 }
354
355 bool ev_is_active(TYPE)(TYPE* w)
356 {
357         return w.active;
358 }
359
360 int ev_priority(TYPE)(TYPE* w)
361 {
362         return w.priority;
363 }
364
365 void function(ev_loop_t*, TYPE*, int) ev_cb(TYPE)(TYPE* w)
366 {
367         return w.cb;
368 }
369
370 void ev_set_priority(TYPE)(TYPE* w, int pri)
371 {
372         w.priority = pri;
373 }
374
375 void ev_set_cb(TYPE)(TYPE* w,
376                 void function(ev_loop_t*, TYPE*, int) cb)
377 {
378         w.cb = cb;
379 }
380
381 void ev_init(TYPE)(TYPE* w,
382                 void function(ev_loop_t*, TYPE*, int) cb)
383 {
384         w.active = 0;
385         w.pending = 0;
386         w.priority = 0;
387         ev_set_cb(w, cb);
388 }
389
390 void ev_io_set(ev_io* w, int fd, int events)
391 {
392         w.fd = fd;
393         w.events = events | IOFDSET;
394 }
395
396 void ev_timer_set(ev_timer* w, ev_tstamp after, ev_tstamp repeat)
397 {
398         w.at = after;
399         w.repeat = repeat;
400 }
401
402 void ev_periodic_set(ev_periodic* w, ev_tstamp ofs, ev_tstamp ival,
403                 ev_tstamp function(ev_periodic *w, ev_tstamp now) res)
404 {
405         w.offset = ofs;
406         w.interval = ival;
407         w.reschedule_cb = res;
408 }
409
410 void ev_signal_set(ev_signal* w, int signum)
411 {
412         w.signum = signum;
413 }
414
415 void ev_child_set(ev_child* w, int pid)
416 {
417         w.pid = pid;
418 }
419
420 void ev_stat_set(ev_stat* w, char* path, ev_tstamp interval)
421 {
422         w.path = path;
423         w.interval = interval;
424         w.wd = -2;
425 }
426
427 void ev_idle_set(ev_idle* w)
428 {
429 }
430
431 void ev_prepare_set(ev_prepare* w)
432 {
433 }
434
435 void ev_check_set(ev_check* w)
436 {
437 }
438
439 void ev_embed_set(ev_embed* w, ev_loop_t* other)
440 {
441         w.other = other;
442 }
443
444 void ev_fork_set(ev_fork* w)
445 {
446 }
447
448 void ev_io_init(ev_io* w, void function(ev_loop_t*, ev_io*, int) cb, int fd,
449                 int events)
450 {
451         ev_init(w, cb);
452         ev_io_set(w, fd, events);
453 }
454
455 void ev_timer_init(ev_timer* w, void function(ev_loop_t*, ev_timer*, int) cb,
456                 ev_tstamp after, ev_tstamp repeat)
457 {
458         ev_init(w, cb);
459         ev_timer_set(w, after, repeat);
460 }
461
462 void ev_periodic_init(ev_periodic* w,
463                 void function(ev_loop_t*, ev_periodic*, int) cb,
464                 ev_tstamp ofs, ev_tstamp ival,
465                 ev_tstamp function(ev_periodic *w, ev_tstamp now) res)
466 {
467         ev_init(w, cb);
468         ev_periodic_set(w, ofs, ival, res);
469 }
470
471 void ev_signal_init(ev_signal* w, void function(ev_loop_t*, ev_signal*, int) cb,
472                 int signum)
473 {
474         ev_init(w, cb);
475         ev_signal_set(w, signum);
476 }
477
478 void ev_child_init(ev_child* w, void function(ev_loop_t*, ev_child*, int) cb,
479                 int pid)
480 {
481         ev_init(w, cb);
482         ev_child_set(w, pid);
483 }
484
485 void ev_stat_init(ev_stat* w, void function(ev_loop_t*, ev_stat*, int) cb,
486                 char* path, ev_tstamp interval)
487 {
488         ev_init(w, cb);
489         ev_stat_set(w, path, interval);
490 }
491
492 void ev_idle_init(ev_idle* w, void function(ev_loop_t*, ev_idle*, int) cb)
493 {
494         ev_init(w, cb);
495         ev_idle_set(w);
496 }
497
498 void ev_prepare_init(ev_prepare* w,
499                 void function(ev_loop_t*, ev_prepare*, int) cb)
500 {
501         ev_init(w, cb);
502         ev_prepare_set(w);
503 }
504
505 void ev_check_init(ev_check* w, void function(ev_loop_t*, ev_check*, int) cb)
506 {
507         ev_init(w, cb);
508         ev_check_set(w);
509 }
510
511 void ev_embed_init(ev_embed* w, void function(ev_loop_t*, ev_embed*, int) cb,
512                 ev_loop_t* other)
513 {
514         ev_init(w, cb);
515         ev_embed_set(w, other);
516 }
517
518 void ev_fork_init(ev_fork* w, void function(ev_loop_t*, ev_fork*, int) cb)
519 {
520         ev_init(w, cb);
521         ev_fork_set(w);
522 }
523
524 ev_loop_t* ev_default_loop(uint flags = AUTO)
525 {
526         if (!ev_default_loop_ptr)
527                 ev_default_loop_init(flags);
528         return ev_default_loop_ptr;
529 }
530
531 version (UnitTest):
532 extern (D):
533 import stdio = std.stdio;
534 import stdlib = std.c.stdlib;
535 import str = std.string;
536 import unix = std.c.unix.unix;
537 import proc = std.c.process;
538 enum { SIGINT = 2 }
539 const STAT_FILE = "/tmp/libev-stat-test-file";
540 const TEST_TEXT = "hello";
541 bool prepare_done = false;
542 bool check_done = false;
543 bool idle_done = false;
544 bool timer_done = false;
545 bool io_done = false;
546 bool stat_done = false;
547 bool child_done = false;
548 bool signal_done = false;
549 bool eio_done = false;
550 int child_pid = -1;
551 unittest
552 {
553         stdio.writefln("Unittesting...");
554         extern (C) static void cbprepare(ev_loop_t* loop, ev_prepare* w, int revents)
555         {
556                 stdio.writefln("ev_prepare");
557                 assert (!prepare_done);
558                 assert (!check_done);
559                 assert (!idle_done);
560                 assert (!timer_done);
561                 assert (!io_done);
562                 assert (!stat_done);
563                 assert (!child_done);
564                 assert (!signal_done);
565                 assert (!eio_done);
566                 prepare_done = true;
567                 ev_prepare_stop(loop, w);
568         }
569         extern (C) static void cbcheck(ev_loop_t* loop, ev_check* w, int revents)
570         {
571                 stdio.writefln("ev_check");
572                 assert (prepare_done);
573                 assert (!check_done);
574                 assert (!idle_done);
575                 assert (!timer_done);
576                 assert (!io_done);
577                 assert (!stat_done);
578                 assert (!child_done);
579                 assert (!signal_done);
580                 assert (!eio_done);
581                 check_done = true;
582                 ev_check_stop(loop, w);
583         }
584         extern (C) static void cbidle(ev_loop_t* loop, ev_idle* w, int revents)
585         {
586                 stdio.writefln("ev_idle");
587                 assert (prepare_done);
588                 assert (check_done);
589                 assert (!idle_done);
590                 assert (!timer_done);
591                 assert (!io_done);
592                 assert (!stat_done);
593                 assert (!child_done);
594                 assert (!signal_done);
595                 assert (!eio_done);
596                 idle_done = true;
597                 ev_idle_stop(loop, w);
598         }
599         extern (C) static void cbtimer(ev_loop_t* loop, ev_timer* w,
600                         int revents)
601         {
602                 stdio.writefln("ev_timer");
603                 assert (prepare_done);
604                 assert (check_done);
605                 assert (idle_done);
606                 assert (!timer_done);
607                 assert (!io_done);
608                 assert (!stat_done);
609                 assert (!child_done);
610                 assert (!signal_done);
611                 assert (!eio_done);
612                 timer_done = true;
613                 ev_timer_stop(loop, w);
614                 stdio.writefln("\tfiring ev_io");
615                 stdio.writefln("\t\topening pipe for writing...");
616                 int pipe_fd = *cast (int*) w.data;
617                 stdio.writefln("\t\twriting '%s' to pipe...", TEST_TEXT);
618                 int n = unix.write(pipe_fd, cast (void*) TEST_TEXT,
619                                 TEST_TEXT.length);
620                 assert (n == TEST_TEXT.length);
621         }
622         extern (C) static void cbio(ev_loop_t* loop, ev_io* w, int revents)
623         {
624                 stdio.writefln("ev_io");
625                 assert (prepare_done);
626                 assert (check_done);
627                 assert (idle_done);
628                 assert (timer_done);
629                 assert (!io_done);
630                 assert (!stat_done);
631                 assert (!child_done);
632                 assert (!signal_done);
633                 assert (!eio_done);
634                 io_done = true;
635                 ev_io_stop(loop, w);
636                 char[TEST_TEXT.length] buffer;
637                 stdio.writefln("\treading %d bytes from pipe...",
638                                 buffer.length);
639                 int n = unix.read(w.fd, cast (void*) buffer, buffer.length);
640                 assert (n == TEST_TEXT.length);
641                 assert (buffer.dup == TEST_TEXT.dup);
642                 stdio.writefln("\tread '%s'", buffer);
643                 stdio.writefln("\tfiring ev_stat");
644                 stdio.writefln("\t\topening file '%s'", STAT_FILE);
645                 int fd = unix.open(str.toStringz(STAT_FILE),
646                                 unix.O_WRONLY | unix.O_TRUNC | unix.O_CREAT);
647                 assert (fd != -1);
648                 stdio.writefln("\t\tfd: %d", fd);
649                 n = unix.write(fd, cast (void*) TEST_TEXT,
650                                 TEST_TEXT.length);
651                 assert (n == TEST_TEXT.length);
652                 unix.close(fd);
653         }
654         extern (C) static void cbstat(ev_loop_t* loop, ev_stat* w, int revents)
655         {
656                 stdio.writefln("ev_stat");
657                 assert (prepare_done);
658                 assert (check_done);
659                 assert (idle_done);
660                 assert (timer_done);
661                 assert (io_done);
662                 assert (!stat_done);
663                 assert (!child_done);
664                 assert (!signal_done);
665                 assert (!eio_done);
666                 stat_done = true;
667                 ev_stat_stop(loop, w);
668                 static void print_stat(ev_statdata* s)
669                 {
670                         stdio.writefln("\t\t\tinode: ", s.st_ino);
671                         stdio.writefln("\t\t\tmode: ", s.st_mode);
672                         stdio.writefln("\t\t\tlinks: ", s.st_nlink);
673                         stdio.writefln("\t\t\tuid: ", s.st_uid);
674                         stdio.writefln("\t\t\tgid: ", s.st_gid);
675                         stdio.writefln("\t\t\tsize: ", s.st_size);
676                         stdio.writefln("\t\t\tatime: ", s.st_atime);
677                         stdio.writefln("\t\t\tmtime: ", s.st_mtime);
678                         stdio.writefln("\t\t\tctime: ", s.st_ctime);
679                 }
680                 if (w.attr.st_nlink)
681                 {
682                         stdio.writefln("\tfile '%s' changed", str.toString(w.path));
683                         stdio.writefln("\t\tprevios state:");
684                         print_stat(&w.prev);
685                         stdio.writefln("\t\tcurrent state:");
686                         print_stat(&w.attr);
687                 }
688                 else
689                 {
690                         stdio.writefln("\tfile '%s' does not exist!",
691                                         str.toString(w.path));
692                         stdio.writefln("\t\tprevios state:");
693                         print_stat(&w.prev);
694                 }
695                 stdio.writefln("\tfiring ev_fork...");
696                 stdio.writefln("\t\tforking...");
697                 auto pid = unix.fork();
698                 assert (pid != -1);
699                 if (pid)
700                 {
701                         child_pid = pid;
702                         stdio.writefln("\t\tev_stat: in parent, child pid: ", pid);
703                 }
704                 else
705                 {
706                         stdio.writefln("\t\tev_stat: in child, calling "
707                                         "ev_default_fork...");
708                         ev_default_fork();
709                 }
710         }
711         extern (C) static void cbchild(ev_loop_t* loop, ev_child* w, int revents)
712         {
713                 stdio.writefln("ev_child");
714                 assert (prepare_done);
715                 assert (check_done);
716                 assert (idle_done);
717                 assert (timer_done);
718                 assert (io_done);
719                 assert (stat_done);
720                 assert (!child_done);
721                 assert (!signal_done);
722                 assert (!eio_done);
723                 child_done = true;
724                 ev_child_stop(loop, w);
725                 static ubyte WEXITSTATUS(int s)
726                 {
727                         return cast(ubyte)((s & 0xff00) >> 8);
728                 }
729                 static ubyte WTERMSIG(int s)
730                 {
731                         return cast(ubyte)(s & 0x7f);
732                 }
733                 static bool WIFEXITED(int s)
734                 {
735                         return WTERMSIG(s) == 0;
736                 }
737                 static bool WIFSIGNALED(int s)
738                 {
739                         return cast(byte)(((s & 0x7f) + 1) >> 1) > 0;
740                 }
741                 static bool WCOREDUMP(int s)
742                 {
743                         return cast(bool)(s & 0x80);
744                 }
745                 stdio.writefln("\tthe child with pid %d exited with status "
746                                 "%d", w.rpid, w.rstatus);
747                 assert (child_pid == w.rpid);
748                 if (WIFEXITED(w.rstatus))
749                         stdio.writefln("\tchild exited normally with code ",
750                                         WEXITSTATUS(w.rstatus));
751                 if (WIFSIGNALED(w.rstatus))
752                 {
753                         stdio.writefln("\tchild exited with signal ",
754                                         WTERMSIG(w.rstatus));
755                         if (WCOREDUMP(w.rstatus))
756                                 stdio.writefln("\tchild produced a core dump");
757                 }
758                 assert (WIFEXITED(w.rstatus) && WEXITSTATUS(w.rstatus) == 5);
759                 stdio.writefln("\tfiring ev_signal");
760                 stdio.writefln("\t\tsending signal 2 (SIGINT)");
761                 unix.kill(proc.getpid(), SIGINT);
762         }
763         extern (C) static void cbfork(ev_loop_t* loop, ev_fork* w, int revents)
764         {
765                 stdio.writefln("ev_fork");
766                 assert (prepare_done);
767                 assert (check_done);
768                 assert (idle_done);
769                 assert (timer_done);
770                 assert (io_done);
771                 assert (stat_done);
772                 assert (!child_done);
773                 assert (!signal_done);
774                 assert (!eio_done);
775                 ev_fork_stop(loop, w);
776                 stdio.writefln("\texiting the child program with return "
777                                 "code 5");
778                 stdlib.exit(5);
779         }
780         extern (C) static void cbsignal(ev_loop_t* loop, ev_signal* w,
781                         int revents)
782         {
783                 stdio.writefln("ev_signal");
784                 assert (prepare_done);
785                 assert (check_done);
786                 assert (idle_done);
787                 assert (timer_done);
788                 assert (io_done);
789                 assert (stat_done);
790                 assert (child_done);
791                 assert (!signal_done);
792                 assert (!eio_done);
793                 signal_done = true;
794                 ev_signal_stop(loop, w);
795                 stdio.writefln("\tfiring embeded ev_io...");
796                 stdio.writefln("\t\topening pipe for writing...");
797                 int pipe_fd = *cast(int*)w.data;
798                 stdio.writefln("\t\twriting '%s' to pipe...", TEST_TEXT);
799                 int n = unix.write(pipe_fd, cast(void*)TEST_TEXT,
800                                 TEST_TEXT.length);
801                 assert (n == TEST_TEXT.length);
802         }
803         extern (C) static void ecbio(ev_loop_t* loop, ev_io* w, int revents)
804         {
805                 stdio.writefln("embeded ev_io");
806                 assert (prepare_done);
807                 assert (check_done);
808                 assert (idle_done);
809                 assert (timer_done);
810                 assert (io_done);
811                 assert (stat_done);
812                 assert (child_done);
813                 assert (signal_done);
814                 assert (!eio_done);
815                 eio_done = true;
816                 //ev_io_stop(loop, w);
817                 char[TEST_TEXT.length] buffer;
818                 stdio.writefln("\treading %d bytes from pipe...",
819                                 buffer.length);
820                 int n = unix.read(w.fd, cast (void*) buffer, buffer.length);
821                 assert (n == TEST_TEXT.length);
822                 assert (buffer.dup == TEST_TEXT.dup);
823                 stdio.writefln("\tread '%s'", buffer);
824                 stdio.writefln("\tstoping the loop");
825                 ev_unloop(loop, how.ONE);
826         }
827         extern (C) static void cbembed(ev_loop_t* loop, ev_embed* w, int revents)
828         {
829                 stdio.writefln("ev_embed");
830                 stdio.writefln("\tsweeping embeded loop...");
831                 ev_embed_sweep(w.other, w);
832                 //ev_embed_stop(loop, w);
833         }
834
835         auto loop = ev_default_loop(0);
836
837         ev_io wio;
838         ev_io ewio;
839         ev_timer wtimer;
840         ev_signal wsignal;
841         ev_child wchild;
842         ev_stat wstat;
843         ev_idle widle;
844         ev_prepare wprepare;
845         ev_check wcheck;
846         ev_fork wfork;
847         ev_embed wembed;
848
849         ev_loop_t* eloop = ev_embeddable_backends() & ev_recommended_backends()
850                 ? ev_loop_new(ev_embeddable_backends () &
851                                 ev_recommended_backends ())
852                 : null;
853
854         if (eloop)
855         {
856                 stdio.writefln("Initializing embeded loop");
857                 ev_embed_init(&wembed, &cbembed, eloop);
858                 ev_embed_start(loop, &wembed);
859         }
860         else
861         {
862                 stdio.writefln("No embeded loop, using the default");
863                 eloop = loop;
864         }
865
866         int[2] epipe;
867         {
868                 int ret = unix.pipe(epipe);
869                 assert (ret == 0);
870         }
871         ev_io_init(&ewio, &ecbio, epipe[0], READ);
872         ev_io_start(eloop, &ewio);
873
874         int[2] pipe;
875         {
876                 int ret = unix.pipe(pipe);
877                 assert (ret == 0);
878         }
879
880         ev_io_init(&wio, &cbio, pipe[0], READ);
881         ev_io_start(loop, &wio);
882
883         ev_timer_init(&wtimer, &cbtimer, 1.5, 0.);
884         wtimer.data = &pipe[1]; // write fd
885         ev_timer_start(loop, &wtimer);
886
887         ev_signal_init(&wsignal, &cbsignal, SIGINT);
888         wsignal.data = &epipe[1]; // write fd
889         ev_signal_start(loop, &wsignal);
890
891         ev_child_init(&wchild, &cbchild, 0 /* trace any PID */);
892         ev_child_start(loop, &wchild);
893
894         ev_stat_init(&wstat, &cbstat, str.toStringz(STAT_FILE), 0 /* auto */);
895         ev_stat_start(loop, &wstat);
896
897         ev_idle_init(&widle, &cbidle);
898         ev_idle_start(loop, &widle);
899
900         ev_prepare_init(&wprepare, &cbprepare);
901         ev_prepare_start(loop, &wprepare);
902
903         ev_check_init(&wcheck, &cbcheck);
904         ev_check_start(loop, &wcheck);
905
906         ev_fork_init(&wfork, &cbfork);
907         ev_fork_start(loop, &wfork);
908
909         ev_loop(loop, 0);
910
911         assert (prepare_done);
912         assert (check_done);
913         assert (idle_done);
914         assert (timer_done);
915         assert (io_done);
916         assert (stat_done);
917         assert (child_done);
918         assert (signal_done);
919         assert (eio_done);
920
921         stdio.writefln("Unittesting done!");
922
923 }
924