Merge pull request #1909 from esdrubal/reflection
[mono.git] / mono / metadata / threadpool-ms-io-kqueue.c
1
2 #if defined(HAVE_KQUEUE)
3
4 #include <sys/types.h>
5 #include <sys/event.h>
6 #include <sys/time.h>
7
8 #if defined(HOST_WIN32)
9 /* We assume that kqueue is not available on windows */
10 #error
11 #endif
12
13 #define KQUEUE_NEVENTS 128
14
15 static gint kqueue_fd;
16 static struct kevent *kqueue_events;
17
18 static gboolean
19 kqueue_init (gint wakeup_pipe_fd)
20 {
21         struct kevent event;
22
23         kqueue_fd = kqueue ();
24         if (kqueue_fd == -1) {
25                 g_warning ("kqueue_init: kqueue () failed, error (%d) %s", errno, g_strerror (errno));
26                 return FALSE;
27         }
28
29         EV_SET (&event, wakeup_pipe_fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
30         if (kevent (kqueue_fd, &event, 1, NULL, 0, NULL) == -1) {
31                 g_warning ("kqueue_init: kevent () failed, error (%d) %s", errno, g_strerror (errno));
32                 close (kqueue_fd);
33                 return FALSE;
34         }
35
36         kqueue_events = g_new0 (struct kevent, KQUEUE_NEVENTS);
37
38         return TRUE;
39 }
40
41 static void
42 kqueue_cleanup (void)
43 {
44         g_free (kqueue_events);
45         close (kqueue_fd);
46 }
47
48 static void
49 kqueue_register_fd (gint fd, gint events, gboolean is_new)
50 {
51         struct kevent event;
52
53         if (events == 0)
54                 return;
55
56         if ((events & MONO_POLLIN) != 0)
57                 EV_SET (&event, fd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, 0);
58         if ((events & MONO_POLLOUT) != 0)
59                 EV_SET (&event, fd, EVFILT_WRITE, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, 0);
60
61         if (kevent (kqueue_fd, &event, 1, NULL, 0, NULL) == -1)
62                 g_warning ("kqueue_register_fd: kevent(update) failed, error (%d) %s", errno, g_strerror (errno));
63 }
64
65 static gint
66 kqueue_event_wait (void)
67 {
68         gint ready;
69
70         ready = kevent (kqueue_fd, NULL, 0, kqueue_events, KQUEUE_NEVENTS, NULL);
71         if (ready == -1) {
72                 switch (errno) {
73                 case EINTR:
74                         mono_thread_internal_check_for_interruption_critical (mono_thread_internal_current ());
75                         ready = 0;
76                         break;
77                 default:
78                         g_warning ("kqueue_event_wait: kevent () failed, error (%d) %s", errno, g_strerror (errno));
79                         break;
80                 }
81         }
82
83         return ready;
84 }
85
86 static gint
87 kqueue_event_get_fd_at (gint i, gint *events)
88 {
89         g_assert (events);
90
91         *events = ((kqueue_events [i].filter == EVFILT_READ || (kqueue_events [i].flags & EV_ERROR) != 0) ? MONO_POLLIN : 0)
92                     | ((kqueue_events [i].filter == EVFILT_WRITE || (kqueue_events [i].flags & EV_ERROR) != 0) ? MONO_POLLOUT : 0);
93
94         return kqueue_events [i].ident;
95 }
96
97 static gint
98 kqueue_event_get_fd_max (void)
99 {
100         return KQUEUE_NEVENTS;
101 }
102
103 static ThreadPoolIOBackend backend_kqueue = {
104         .init = kqueue_init,
105         .cleanup = kqueue_cleanup,
106         .register_fd = kqueue_register_fd,
107         .event_wait = kqueue_event_wait,
108         .event_get_fd_max = kqueue_event_get_fd_max,
109         .event_get_fd_at = kqueue_event_get_fd_at,
110 };
111
112 #endif