]> git.llucax.com Git - software/ev.d.git/blob - ev/c.d
3efcb678a76f47bd4bb6bcad755833c426b99be6
[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 extern (C):
15 align (4):
16
17 enum: uint
18 {
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
35 }
36
37 enum: uint
38 {
39         // bits for ev_default_loop and ev_loop_new
40         // the default
41         EVFLAG_AUTO       = 0x00000000UL, // not quite a mask
42         // flag bits
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
52 }
53
54 enum
55 {
56         EVLOOP_NONBLOCK = 1, // do not block/wait
57         EVLOOP_ONESHOT  = 2, // block *once* only
58 }
59
60 enum
61 {
62         EVUNLOOP_CANCEL = 0, // undo unloop
63         EVUNLOOP_ONE    = 1, // unloop once
64         EVUNLOOP_ALL    = 2, // unloop all loops
65 }
66
67 version (EV_ENABLE_SELECT)
68 {
69 }
70 else
71 {
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;
77 }
78
79 alias double ev_tstamp;
80
81 struct ev_loop_t;
82
83 template EV_COMMON()
84 {
85         void* data;
86 }
87
88 template EV_CB_DECLARE(TYPE)
89 {
90         void function (ev_loop_t*, TYPE*, int) cb;
91 }
92
93 template EV_WATCHER(TYPE)
94 {
95         int active;                 // private
96         int pending;                // private
97         int priority;               // private
98         mixin EV_COMMON;            // rw
99         mixin EV_CB_DECLARE!(TYPE); // private
100 }
101
102 template EV_WATCHER_LIST(TYPE)
103 {
104         mixin EV_WATCHER!(TYPE);
105         ev_watcher_list* next;      // private
106 }
107
108 template EV_WATCHER_TIME(TYPE)
109 {
110         mixin EV_WATCHER!(TYPE);
111         ev_tstamp at;               // private
112 }
113
114 struct ev_watcher
115 {
116         mixin EV_WATCHER!(ev_watcher);
117 }
118
119 struct ev_watcher_list
120 {
121         mixin EV_WATCHER_LIST!(ev_watcher_list);
122 }
123
124 struct ev_watcher_time
125 {
126         mixin EV_WATCHER_TIME!(ev_watcher_time);
127 }
128
129 struct ev_io
130 {
131         mixin EV_WATCHER_LIST!(ev_io);
132         int fd;     // ro
133         int events; // ro
134 }
135
136 struct ev_timer
137 {
138         mixin EV_WATCHER_TIME!(ev_timer);
139         ev_tstamp repeat; // rw
140 }
141
142 version (EV_PERIODIC_ENABLE)
143 {
144         struct ev_periodic
145         {
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
151         }
152 }
153
154 struct ev_signal
155 {
156         mixin EV_WATCHER_LIST!(ev_signal);
157         int signum; // ro
158 }
159
160 struct ev_child
161 {
162         mixin EV_WATCHER_LIST!(ev_child);
163         int pid;     // ro
164         int rpid;    // rw, holds the received pid
165         int rstatus; // rw, holds the exit status, use the
166         // macros from sys/wait.h
167 }
168
169 version (EV_STAT_ENABLE)
170 {
171
172         version (Windows) // alias _stati64 ev_statdata;
173         {
174                 pragma (msg, "ev_stat not supported in windows "
175                                 "because I don't know the "
176                                 "layout of _stati64");
177                 static assert(0);
178                 // Maybe this should work?
179                 //static import stat = std.c.windows.stat;
180                 //alias stat.struct_stat ev_statdata;
181         }
182         else // It should be POSIX
183         {
184                 static import stat = std.c.unix.unix;
185                 alias stat.struct_stat ev_statdata;
186         }
187
188         struct ev_stat
189         {
190                 mixin EV_WATCHER_LIST!(ev_stat);
191
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
198         }
199 }
200
201 version (EV_IDLE_ENABLE)
202 {
203         struct ev_idle
204         {
205                 mixin EV_WATCHER!(ev_idle);
206         }
207 }
208
209 struct ev_prepare
210 {
211         mixin EV_WATCHER!(ev_prepare);
212 }
213
214 struct ev_check
215 {
216         mixin EV_WATCHER!(ev_check);
217 }
218
219 version (EV_FORK_ENABLE)
220 {
221         struct ev_fork
222         {
223                 mixin EV_WATCHER!(ev_fork);
224         }
225 }
226
227 version (EV_EMBED_ENABLE)
228 {
229         struct ev_embed
230         {
231                 mixin EV_WATCHER!(ev_embed);
232                 ev_loop_t* other;     // ro
233                 ev_io io;             // private
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
240         }
241 }
242
243 int ev_version_major();
244 int ev_version_minor();
245
246 uint ev_supported_backends();
247 uint ev_recommended_backends();
248 uint ev_embeddable_backends();
249
250 ev_tstamp ev_time();
251 void ev_sleep(ev_tstamp delay); // sleep for a while
252
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
256 // might abort
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));
260
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));
265
266 extern ev_loop_t* ev_default_loop_ptr;
267
268 ev_loop_t* ev_default_loop_init(uint flags);
269
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*);
274
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);
288
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);
294
295 void ev_io_start(ev_loop_t*, ev_io *w);
296 void ev_io_stop(ev_loop_t*, ev_io *w);
297
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);
301
302 version (EV_PERIODIC_ENABLE)
303 {
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);
307 }
308
309 void ev_signal_start(ev_loop_t*, ev_signal *w);
310 void ev_signal_stop(ev_loop_t*, ev_signal *w);
311
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);
315
316 version (EV_STAT_ENABLE)
317 {
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);
321 }
322
323 version (EV_IDLE_ENABLE)
324 {
325         void ev_idle_start(ev_loop_t*, ev_idle *w);
326         void ev_idle_stop(ev_loop_t*, ev_idle *w);
327 }
328
329 void ev_prepare_start(ev_loop_t*, ev_prepare *w);
330 void ev_prepare_stop(ev_loop_t*, ev_prepare *w);
331
332 void ev_check_start(ev_loop_t*, ev_check *w);
333 void ev_check_stop(ev_loop_t*, ev_check *w);
334
335 version (EV_FORK_ENABLE)
336 {
337         void ev_fork_start(ev_loop_t*, ev_fork *w);
338         void ev_fork_stop(ev_loop_t*, ev_fork *w);
339 }
340
341 version (EV_EMBED_ENABLE)
342 {
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);
347 }
348
349 bool ev_is_pending(TYPE)(TYPE* w)
350 {
351         return w.pending;
352 }
353
354 bool ev_is_active(TYPE)(TYPE* w)
355 {
356         return w.active;
357 }
358
359 int ev_priority(TYPE)(TYPE* w)
360 {
361         return w.priority;
362 }
363
364 void function(ev_loop_t*, TYPE*, int) ev_cb(TYPE)(TYPE* w)
365 {
366         return w.cb;
367 }
368
369 void ev_set_priority(TYPE)(TYPE* w, int pri)
370 {
371         w.priority = pri;
372 }
373
374 void ev_set_cb(TYPE)(TYPE* w,
375                 void function(ev_loop_t*, TYPE*, int) cb)
376 {
377         w.cb = cb;
378 }
379
380 void ev_init(TYPE)(TYPE* w,
381                 void function(ev_loop_t*, TYPE*, int) cb)
382 {
383         w.active = 0;
384         w.pending = 0;
385         w.priority = 0;
386         ev_set_cb(w, cb);
387 }
388
389 void ev_io_set(ev_io* w, int fd, int events)
390 {
391         w.fd = fd;
392         w.events = events | EV_IOFDSET;
393 }
394
395 void ev_timer_set(ev_timer* w, ev_tstamp after, ev_tstamp repeat)
396 {
397         w.at = after;
398         w.repeat = repeat;
399 }
400
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)
403 {
404         w.offset = ofs;
405         w.interval = ival;
406         w.reschedule_cb = res;
407 }
408
409 void ev_signal_set(ev_signal* w, int signum)
410 {
411         w.signum = signum;
412 }
413
414 void ev_child_set(ev_child* w, int pid)
415 {
416         w.pid = pid;
417 }
418
419 void ev_stat_set(ev_stat* w, char* path, ev_tstamp interval)
420 {
421         w.path = path;
422         w.interval = interval;
423         w.wd = -2;
424 }
425
426 void ev_idle_set(ev_idle* w)
427 {
428 }
429
430 void ev_prepare_set(ev_prepare* w)
431 {
432 }
433
434 void ev_check_set(ev_check* w)
435 {
436 }
437
438 void ev_embed_set(ev_embed* w, ev_loop_t* other)
439 {
440         w.other = other;
441 }
442
443 void ev_fork_set(ev_fork* w)
444 {
445 }
446
447 void ev_io_init(ev_io* w, void function(ev_loop_t*, ev_io*, int) cb, int fd,
448                 int events)
449 {
450         ev_init(w, cb);
451         ev_io_set(w, fd, events);
452 }
453
454 void ev_timer_init(ev_timer* w, void function(ev_loop_t*, ev_timer*, int) cb,
455                 ev_tstamp after, ev_tstamp repeat)
456 {
457         ev_init(w, cb);
458         ev_timer_set(w, after, repeat);
459 }
460
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)
465 {
466         ev_init(w, cb);
467         ev_periodic_set(w, ofs, ival, res);
468 }
469
470 void ev_signal_init(ev_signal* w, void function(ev_loop_t*, ev_signal*, int) cb,
471                 int signum)
472 {
473         ev_init(w, cb);
474         ev_signal_set(w, signum);
475 }
476
477 void ev_child_init(ev_child* w, void function(ev_loop_t*, ev_child*, int) cb,
478                 int pid)
479 {
480         ev_init(w, cb);
481         ev_child_set(w, pid);
482 }
483
484 void ev_stat_init(ev_stat* w, void function(ev_loop_t*, ev_stat*, int) cb,
485                 char* path, ev_tstamp interval)
486 {
487         ev_init(w, cb);
488         ev_stat_set(w, path, interval);
489 }
490
491 void ev_idle_init(ev_idle* w, void function(ev_loop_t*, ev_idle*, int) cb)
492 {
493         ev_init(w, cb);
494         ev_idle_set(w);
495 }
496
497 void ev_prepare_init(ev_prepare* w,
498                 void function(ev_loop_t*, ev_prepare*, int) cb)
499 {
500         ev_init(w, cb);
501         ev_prepare_set(w);
502 }
503
504 void ev_check_init(ev_check* w, void function(ev_loop_t*, ev_check*, int) cb)
505 {
506         ev_init(w, cb);
507         ev_check_set(w);
508 }
509
510 void ev_embed_init(ev_embed* w, void function(ev_loop_t*, ev_embed*, int) cb,
511                 ev_loop_t* other)
512 {
513         ev_init(w, cb);
514         ev_embed_set(w, other);
515 }
516
517 void ev_fork_init(ev_fork* w, void function(ev_loop_t*, ev_fork*, int) cb)
518 {
519         ev_init(w, cb);
520         ev_fork_set(w);
521 }
522
523 ev_loop_t* ev_default_loop(uint flags = EVFLAG_AUTO)
524 {
525         if (!ev_default_loop_ptr)
526                 ev_default_loop_init(flags);
527         return ev_default_loop_ptr;
528 }
529
530 version (UnitTest):
531 extern (D):
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;
537 enum { SIGINT = 2 }
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;
549 int child_pid = -1;
550 unittest
551 {
552         stdio.writefln("Unittesting...");
553         extern (C) static void cbprepare(ev_loop_t* loop, ev_prepare* w, int revents)
554         {
555                 stdio.writefln("ev_prepare");
556                 assert (!prepare_done);
557                 assert (!check_done);
558                 assert (!idle_done);
559                 assert (!timer_done);
560                 assert (!io_done);
561                 assert (!stat_done);
562                 assert (!child_done);
563                 assert (!signal_done);
564                 assert (!eio_done);
565                 prepare_done = true;
566                 ev_prepare_stop(loop, w);
567         }
568         extern (C) static void cbcheck(ev_loop_t* loop, ev_check* w, int revents)
569         {
570                 stdio.writefln("ev_check");
571                 assert (prepare_done);
572                 assert (!check_done);
573                 assert (!idle_done);
574                 assert (!timer_done);
575                 assert (!io_done);
576                 assert (!stat_done);
577                 assert (!child_done);
578                 assert (!signal_done);
579                 assert (!eio_done);
580                 check_done = true;
581                 ev_check_stop(loop, w);
582         }
583         extern (C) static void cbidle(ev_loop_t* loop, ev_idle* w, int revents)
584         {
585                 stdio.writefln("ev_idle");
586                 assert (prepare_done);
587                 assert (check_done);
588                 assert (!idle_done);
589                 assert (!timer_done);
590                 assert (!io_done);
591                 assert (!stat_done);
592                 assert (!child_done);
593                 assert (!signal_done);
594                 assert (!eio_done);
595                 idle_done = true;
596                 ev_idle_stop(loop, w);
597         }
598         extern (C) static void cbtimer(ev_loop_t* loop, ev_timer* w,
599                         int revents)
600         {
601                 stdio.writefln("ev_timer");
602                 assert (prepare_done);
603                 assert (check_done);
604                 assert (idle_done);
605                 assert (!timer_done);
606                 assert (!io_done);
607                 assert (!stat_done);
608                 assert (!child_done);
609                 assert (!signal_done);
610                 assert (!eio_done);
611                 timer_done = true;
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,
618                                 TEST_TEXT.length);
619                 assert (n == TEST_TEXT.length);
620         }
621         extern (C) static void cbio(ev_loop_t* loop, ev_io* w, int revents)
622         {
623                 stdio.writefln("ev_io");
624                 assert (prepare_done);
625                 assert (check_done);
626                 assert (idle_done);
627                 assert (timer_done);
628                 assert (!io_done);
629                 assert (!stat_done);
630                 assert (!child_done);
631                 assert (!signal_done);
632                 assert (!eio_done);
633                 io_done = true;
634                 ev_io_stop(loop, w);
635                 char[TEST_TEXT.length] buffer;
636                 stdio.writefln("\treading %d bytes from pipe...",
637                                 buffer.length);
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);
646                 assert (fd != -1);
647                 stdio.writefln("\t\tfd: %d", fd);
648                 n = unix.write(fd, cast (void*) TEST_TEXT,
649                                 TEST_TEXT.length);
650                 assert (n == TEST_TEXT.length);
651                 unix.close(fd);
652         }
653         extern (C) static void cbstat(ev_loop_t* loop, ev_stat* w, int revents)
654         {
655                 stdio.writefln("ev_stat");
656                 assert (prepare_done);
657                 assert (check_done);
658                 assert (idle_done);
659                 assert (timer_done);
660                 assert (io_done);
661                 assert (!stat_done);
662                 assert (!child_done);
663                 assert (!signal_done);
664                 assert (!eio_done);
665                 stat_done = true;
666                 ev_stat_stop(loop, w);
667                 static void print_stat(ev_statdata* s)
668                 {
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);
678                 }
679                 if (w.attr.st_nlink)
680                 {
681                         stdio.writefln("\tfile '%s' changed", str.toString(w.path));
682                         stdio.writefln("\t\tprevios state:");
683                         print_stat(&w.prev);
684                         stdio.writefln("\t\tcurrent state:");
685                         print_stat(&w.attr);
686                 }
687                 else
688                 {
689                         stdio.writefln("\tfile '%s' does not exist!",
690                                         str.toString(w.path));
691                         stdio.writefln("\t\tprevios state:");
692                         print_stat(&w.prev);
693                 }
694                 stdio.writefln("\tfiring ev_fork...");
695                 stdio.writefln("\t\tforking...");
696                 auto pid = unix.fork();
697                 assert (pid != -1);
698                 if (pid)
699                 {
700                         child_pid = pid;
701                         stdio.writefln("\t\tev_stat: in parent, child pid: ", pid);
702                 }
703                 else
704                 {
705                         stdio.writefln("\t\tev_stat: in child, calling "
706                                         "ev_default_fork...");
707                         ev_default_fork();
708                 }
709         }
710         extern (C) static void cbchild(ev_loop_t* loop, ev_child* w, int revents)
711         {
712                 stdio.writefln("ev_child");
713                 assert (prepare_done);
714                 assert (check_done);
715                 assert (idle_done);
716                 assert (timer_done);
717                 assert (io_done);
718                 assert (stat_done);
719                 assert (!child_done);
720                 assert (!signal_done);
721                 assert (!eio_done);
722                 child_done = true;
723                 ev_child_stop(loop, w);
724                 static ubyte WEXITSTATUS(int s)
725                 {
726                         return cast(ubyte)((s & 0xff00) >> 8);
727                 }
728                 static ubyte WTERMSIG(int s)
729                 {
730                         return cast(ubyte)(s & 0x7f);
731                 }
732                 static bool WIFEXITED(int s)
733                 {
734                         return WTERMSIG(s) == 0;
735                 }
736                 static bool WIFSIGNALED(int s)
737                 {
738                         return cast(byte)(((s & 0x7f) + 1) >> 1) > 0;
739                 }
740                 static bool WCOREDUMP(int s)
741                 {
742                         return cast(bool)(s & 0x80);
743                 }
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))
751                 {
752                         stdio.writefln("\tchild exited with signal ",
753                                         WTERMSIG(w.rstatus));
754                         if (WCOREDUMP(w.rstatus))
755                                 stdio.writefln("\tchild produced a core dump");
756                 }
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);
761         }
762         extern (C) static void cbfork(ev_loop_t* loop, ev_fork* w, int revents)
763         {
764                 stdio.writefln("ev_fork");
765                 assert (prepare_done);
766                 assert (check_done);
767                 assert (idle_done);
768                 assert (timer_done);
769                 assert (io_done);
770                 assert (stat_done);
771                 assert (!child_done);
772                 assert (!signal_done);
773                 assert (!eio_done);
774                 ev_fork_stop(loop, w);
775                 stdio.writefln("\texiting the child program with return "
776                                 "code 5");
777                 stdlib.exit(5);
778         }
779         extern (C) static void cbsignal(ev_loop_t* loop, ev_signal* w,
780                         int revents)
781         {
782                 stdio.writefln("ev_signal");
783                 assert (prepare_done);
784                 assert (check_done);
785                 assert (idle_done);
786                 assert (timer_done);
787                 assert (io_done);
788                 assert (stat_done);
789                 assert (child_done);
790                 assert (!signal_done);
791                 assert (!eio_done);
792                 signal_done = true;
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,
799                                 TEST_TEXT.length);
800                 assert (n == TEST_TEXT.length);
801         }
802         extern (C) static void ecbio(ev_loop_t* loop, ev_io* w, int revents)
803         {
804                 stdio.writefln("embeded ev_io");
805                 assert (prepare_done);
806                 assert (check_done);
807                 assert (idle_done);
808                 assert (timer_done);
809                 assert (io_done);
810                 assert (stat_done);
811                 assert (child_done);
812                 assert (signal_done);
813                 assert (!eio_done);
814                 eio_done = true;
815                 //ev_io_stop(loop, w);
816                 char[TEST_TEXT.length] buffer;
817                 stdio.writefln("\treading %d bytes from pipe...",
818                                 buffer.length);
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);
825         }
826         extern (C) static void cbembed(ev_loop_t* loop, ev_embed* w, int revents)
827         {
828                 stdio.writefln("ev_embed");
829                 stdio.writefln("\tsweeping embeded loop...");
830                 ev_embed_sweep(w.other, w);
831                 //ev_embed_stop(loop, w);
832         }
833
834         auto loop = ev_default_loop(0);
835
836         ev_io wio;
837         ev_io ewio;
838         ev_timer wtimer;
839         ev_signal wsignal;
840         ev_child wchild;
841         ev_stat wstat;
842         ev_idle widle;
843         ev_prepare wprepare;
844         ev_check wcheck;
845         ev_fork wfork;
846         ev_embed wembed;
847
848         ev_loop_t* eloop = ev_embeddable_backends() & ev_recommended_backends()
849                 ? ev_loop_new(ev_embeddable_backends () &
850                                 ev_recommended_backends ())
851                 : null;
852
853         if (eloop)
854         {
855                 stdio.writefln("Initializing embeded loop");
856                 ev_embed_init(&wembed, &cbembed, eloop);
857                 ev_embed_start(loop, &wembed);
858         }
859         else
860         {
861                 stdio.writefln("No embeded loop, using the default");
862                 eloop = loop;
863         }
864
865         int[2] epipe;
866         {
867                 int ret = unix.pipe(epipe);
868                 assert (ret == 0);
869         }
870         ev_io_init(&ewio, &ecbio, epipe[0], EV_READ);
871         ev_io_start(eloop, &ewio);
872
873         int[2] pipe;
874         {
875                 int ret = unix.pipe(pipe);
876                 assert (ret == 0);
877         }
878
879         ev_io_init(&wio, &cbio, pipe[0], EV_READ);
880         ev_io_start(loop, &wio);
881
882         ev_timer_init(&wtimer, &cbtimer, 1.5, 0.);
883         wtimer.data = &pipe[1]; // write fd
884         ev_timer_start(loop, &wtimer);
885
886         ev_signal_init(&wsignal, &cbsignal, SIGINT);
887         wsignal.data = &epipe[1]; // write fd
888         ev_signal_start(loop, &wsignal);
889
890         ev_child_init(&wchild, &cbchild, 0 /* trace any PID */);
891         ev_child_start(loop, &wchild);
892
893         ev_stat_init(&wstat, &cbstat, str.toStringz(STAT_FILE), 0 /* auto */);
894         ev_stat_start(loop, &wstat);
895
896         ev_idle_init(&widle, &cbidle);
897         ev_idle_start(loop, &widle);
898
899         ev_prepare_init(&wprepare, &cbprepare);
900         ev_prepare_start(loop, &wprepare);
901
902         ev_check_init(&wcheck, &cbcheck);
903         ev_check_start(loop, &wcheck);
904
905         ev_fork_init(&wfork, &cbfork);
906         ev_fork_start(loop, &wfork);
907
908         ev_loop(loop, 0);
909
910         assert (prepare_done);
911         assert (check_done);
912         assert (idle_done);
913         assert (timer_done);
914         assert (io_done);
915         assert (stat_done);
916         assert (child_done);
917         assert (signal_done);
918         assert (eio_done);
919
920         stdio.writefln("Unittesting done!");
921
922 }
923