2 * tpool-kqueue.c: kqueue related stuff
5 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 * Copyright 2011 Novell, Inc (http://www.novell.com)
10 struct _tp_kqueue_data {
14 typedef struct _tp_kqueue_data tp_kqueue_data;
15 static void tp_kqueue_modify (gpointer p, int fd, int operation, int events, gboolean is_new);
16 static void tp_kqueue_shutdown (gpointer event_data);
17 static void tp_kqueue_wait (gpointer event_data);
20 tp_kqueue_init (SocketIOData *data)
22 tp_kqueue_data *result;
24 result = g_new0 (tp_kqueue_data, 1);
25 result->fd = kqueue ();
29 data->shutdown = tp_kqueue_shutdown;
30 data->modify = tp_kqueue_modify;
31 data->wait = tp_kqueue_wait;
36 kevent_change (int kfd, struct kevent *evt, const char *error_str)
38 if (kevent (kfd, evt, 1, NULL, 0, NULL) == -1) {
40 g_message ("kqueue(%s): %d %s", error_str, err, g_strerror (err));
45 tp_kqueue_modify (gpointer p, int fd, int operation, int events, gboolean is_new)
47 SocketIOData *socket_io_data;
49 tp_kqueue_data *data = socket_io_data->event_data;
52 memset (&evt, 0, sizeof (evt));
53 if ((events & MONO_POLLIN) != 0) {
54 EV_SET (&evt, fd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, 0);
55 kevent_change (data->fd, &evt, "ADD read");
58 if ((events & MONO_POLLOUT) != 0) {
59 EV_SET (&evt, fd, EVFILT_WRITE, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, 0);
60 kevent_change (data->fd, &evt, "ADD write");
62 LeaveCriticalSection (&socket_io_data->io_lock);
66 tp_kqueue_shutdown (gpointer event_data)
68 tp_kqueue_data *data = event_data;
74 #define KQUEUE_NEVENTS 128
76 tp_kqueue_wait (gpointer p)
78 SocketIOData *socket_io_data;
80 struct kevent *events, *evt;
82 gpointer async_results [KQUEUE_NEVENTS * 2]; // * 2 because each loop can add up to 2 results here
87 data = socket_io_data->event_data;
89 events = g_new0 (struct kevent, KQUEUE_NEVENTS);
93 mono_gc_set_skip_thread (TRUE);
97 check_for_interruption_critical ();
99 ready = kevent (kfd, NULL, 0, events, KQUEUE_NEVENTS, NULL);
100 } while (ready == -1 && errno == EINTR);
102 mono_gc_set_skip_thread (FALSE);
108 g_warning ("kevent wait: %d %s", err, g_strerror (err));
113 EnterCriticalSection (&socket_io_data->io_lock);
114 if (socket_io_data->inited == 3) {
116 LeaveCriticalSection (&socket_io_data->io_lock);
117 return; /* cleanup called */
121 for (i = 0; i < ready; i++) {
128 list = mono_g_hash_table_lookup (socket_io_data->sock_to_state, GINT_TO_POINTER (fd));
129 if (list != NULL && (evt->filter == EVFILT_READ || (evt->flags & EV_ERROR) != 0)) {
130 ares = get_io_event (&list, MONO_POLLIN);
132 async_results [nresults++] = ares;
134 if (list != NULL && (evt->filter == EVFILT_WRITE || (evt->flags & EV_ERROR) != 0)) {
135 ares = get_io_event (&list, MONO_POLLOUT);
137 async_results [nresults++] = ares;
143 mono_g_hash_table_replace (socket_io_data->sock_to_state, GINT_TO_POINTER (fd), list);
144 p = get_events_from_list (list);
145 if (evt->filter == EVFILT_READ && (p & MONO_POLLIN) != 0) {
146 EV_SET (evt, fd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, 0);
147 kevent_change (kfd, evt, "READD read");
150 if (evt->filter == EVFILT_WRITE && (p & MONO_POLLOUT) != 0) {
151 EV_SET (evt, fd, EVFILT_WRITE, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, 0);
152 kevent_change (kfd, evt, "READD write");
155 mono_g_hash_table_remove (socket_io_data->sock_to_state, GINT_TO_POINTER (fd));
158 LeaveCriticalSection (&socket_io_data->io_lock);
159 threadpool_append_jobs (&async_io_tp, (MonoObject **) async_results, nresults);
160 mono_gc_bzero (async_results, sizeof (gpointer) * nresults);
163 #undef KQUEUE_NEVENTS