[2020-02] Fix leak in assembly-specific dllmap lookups (#21053)
[mono-project.git] / mono / metadata / threadpool-io-kqueue.c
blob6dd81968745e7ae2df629d9055eb8fb8bd04b1c0
1 /**
2 * \file
3 */
5 #if defined(HAVE_KQUEUE)
7 #include <sys/types.h>
8 #include <sys/event.h>
9 #include <sys/time.h>
11 #if defined(HOST_WIN32)
12 /* We assume that kqueue is not available on windows */
13 #error
14 #endif
16 #define KQUEUE_NEVENTS 128
18 static gint kqueue_fd;
19 static struct kevent *kqueue_events;
21 static gint
22 KQUEUE_INIT_FD (gint fd, gint events, gint flags)
24 struct kevent event;
25 EV_SET (&event, fd, events, flags, 0, 0, 0);
26 return kevent (kqueue_fd, &event, 1, NULL, 0, NULL);
29 static gboolean
30 kqueue_init (gint wakeup_pipe_fd)
32 kqueue_fd = kqueue ();
33 if (kqueue_fd == -1) {
34 g_error ("kqueue_init: kqueue () failed, error (%d) %s", errno, g_strerror (errno));
35 return FALSE;
38 if (KQUEUE_INIT_FD (wakeup_pipe_fd, EVFILT_READ, EV_ADD | EV_ENABLE) == -1) {
39 g_error ("kqueue_init: kevent () failed, error (%d) %s", errno, g_strerror (errno));
40 close (kqueue_fd);
41 return FALSE;
44 kqueue_events = g_new0 (struct kevent, KQUEUE_NEVENTS);
46 return TRUE;
49 static gboolean
50 kqueue_can_register_fd (int fd)
52 return TRUE;
55 static void
56 kqueue_register_fd (gint fd, gint events, gboolean is_new)
58 if (events & EVENT_IN) {
59 if (KQUEUE_INIT_FD (fd, EVFILT_READ, EV_ADD | EV_ENABLE) == -1)
60 g_error ("kqueue_register_fd: kevent(read,enable) failed, error (%d) %s", errno, g_strerror (errno));
61 } else {
62 if (KQUEUE_INIT_FD (fd, EVFILT_READ, EV_ADD | EV_DISABLE) == -1)
63 g_error ("kqueue_register_fd: kevent(read,disable) failed, error (%d) %s", errno, g_strerror (errno));
65 if (events & EVENT_OUT) {
66 if (KQUEUE_INIT_FD (fd, EVFILT_WRITE, EV_ADD | EV_ENABLE) == -1)
67 g_error ("kqueue_register_fd: kevent(write,enable) failed, error (%d) %s", errno, g_strerror (errno));
68 } else {
69 if (KQUEUE_INIT_FD (fd, EVFILT_WRITE, EV_ADD | EV_DISABLE) == -1)
70 g_error ("kqueue_register_fd: kevent(write,disable) failed, error (%d) %s", errno, g_strerror (errno));
72 return;
75 static void
76 kqueue_remove_fd (gint fd)
78 /* FIXME: a race between closing and adding operation in the Socket managed code trigger a ENOENT error */
79 if (KQUEUE_INIT_FD (fd, EVFILT_READ, EV_DELETE) == -1)
80 g_error ("kqueue_register_fd: kevent(read,delete) failed, error (%d) %s", errno, g_strerror (errno));
81 if (KQUEUE_INIT_FD (fd, EVFILT_WRITE, EV_DELETE) == -1)
82 g_error ("kqueue_register_fd: kevent(write,delete) failed, error (%d) %s", errno, g_strerror (errno));
85 static gint
86 kqueue_event_wait (void (*callback) (gint fd, gint events, gpointer user_data), gpointer user_data)
88 gint i, ready;
90 memset (kqueue_events, 0, sizeof (struct kevent) * KQUEUE_NEVENTS);
92 mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NO_GC);
94 MONO_ENTER_GC_SAFE;
95 ready = kevent (kqueue_fd, NULL, 0, kqueue_events, KQUEUE_NEVENTS, NULL);
96 MONO_EXIT_GC_SAFE;
98 mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NONE);
100 if (ready == -1) {
101 switch (errno) {
102 case EINTR:
103 ready = 0;
104 break;
105 default:
106 g_error ("kqueue_event_wait: kevent () failed, error (%d) %s", errno, g_strerror (errno));
107 break;
111 if (ready == -1)
112 return -1;
114 for (i = 0; i < ready; ++i) {
115 gint fd, events = 0;
117 fd = kqueue_events [i].ident;
118 if (kqueue_events [i].filter == EVFILT_READ || (kqueue_events [i].flags & EV_ERROR) != 0)
119 events |= EVENT_IN;
120 if (kqueue_events [i].filter == EVFILT_WRITE || (kqueue_events [i].flags & EV_ERROR) != 0)
121 events |= EVENT_OUT;
123 callback (fd, events, user_data);
126 return 0;
129 static ThreadPoolIOBackend backend_kqueue = {
130 .init = kqueue_init,
131 .can_register_fd = kqueue_can_register_fd,
132 .register_fd = kqueue_register_fd,
133 .remove_fd = kqueue_remove_fd,
134 .event_wait = kqueue_event_wait,
137 #endif