2 * tpool-epoll.c: epoll related stuff
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
12 struct _tp_epoll_data {
16 typedef struct _tp_epoll_data tp_epoll_data;
17 static void tp_epoll_modify (gpointer event_data, int fd, int operation, int events, gboolean is_new);
18 static void tp_epoll_shutdown (gpointer event_data);
19 static void tp_epoll_wait (gpointer event_data);
22 tp_epoll_init (SocketIOData *data)
24 tp_epoll_data *result;
26 result = g_new0 (tp_epoll_data, 1);
28 result->epollfd = epoll_create1 (EPOLL_CLOEXEC);
30 result->epollfd = epoll_create (256); /* The number does not really matter */
31 fcntl (result->epollfd, F_SETFD, FD_CLOEXEC);
33 if (result->epollfd == -1) {
35 if (g_getenv ("MONO_DEBUG")) {
37 g_message ("epoll_create1(EPOLL_CLOEXEC) failed: %d %s", err, g_strerror (err));
39 g_message ("epoll_create(256) failed: %d %s", err, g_strerror (err));
46 data->shutdown = tp_epoll_shutdown;
47 data->modify = tp_epoll_modify;
48 data->wait = tp_epoll_wait;
53 tp_epoll_modify (gpointer event_data, int fd, int operation, int events, gboolean is_new)
55 tp_epoll_data *data = event_data;
56 struct epoll_event evt;
60 if ((events & MONO_POLLIN) != 0)
61 evt.events |= EPOLLIN;
62 if ((events & MONO_POLLOUT) != 0)
63 evt.events |= EPOLLOUT;
65 epoll_op = (is_new) ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
66 if (epoll_ctl (data->epollfd, epoll_op, fd, &evt) == -1) {
68 if (epoll_op == EPOLL_CTL_ADD && err == EEXIST) {
69 epoll_op = EPOLL_CTL_MOD;
70 if (epoll_ctl (data->epollfd, epoll_op, fd, &evt) == -1) {
71 g_message ("epoll_ctl(MOD): %d %s", err, g_strerror (err));
78 tp_epoll_shutdown (gpointer event_data)
80 tp_epoll_data *data = event_data;
82 close (data->epollfd);
86 #define EPOLL_ERRORS (EPOLLERR | EPOLLHUP)
87 #define EPOLL_NEVENTS 128
89 tp_epoll_wait (gpointer p)
91 SocketIOData *socket_io_data;
93 MonoInternalThread *thread;
94 struct epoll_event *events, *evt;
96 gpointer async_results [EPOLL_NEVENTS * 2]; // * 2 because each loop can add up to 2 results here
101 data = socket_io_data->event_data;
102 epollfd = data->epollfd;
103 thread = mono_thread_internal_current ();
104 events = g_new0 (struct epoll_event, EPOLL_NEVENTS);
109 if (THREAD_WANTS_A_BREAK (thread))
110 mono_thread_interruption_checkpoint ();
112 ready = epoll_wait (epollfd, events, EPOLL_NEVENTS, -1);
113 } while (ready == -1 && errno == EINTR);
119 g_warning ("epoll_wait: %d %s", err, g_strerror (err));
124 EnterCriticalSection (&socket_io_data->io_lock);
125 if (socket_io_data->inited == 3) {
127 LeaveCriticalSection (&socket_io_data->io_lock);
128 return; /* cleanup called */
132 for (i = 0; i < ready; i++) {
139 list = mono_g_hash_table_lookup (socket_io_data->sock_to_state, GINT_TO_POINTER (fd));
140 if (list != NULL && (evt->events & (EPOLLIN | EPOLL_ERRORS)) != 0) {
141 ares = get_io_event (&list, MONO_POLLIN);
143 async_results [nresults++] = ares;
146 if (list != NULL && (evt->events & (EPOLLOUT | EPOLL_ERRORS)) != 0) {
147 ares = get_io_event (&list, MONO_POLLOUT);
149 async_results [nresults++] = ares;
155 mono_g_hash_table_replace (socket_io_data->sock_to_state, GINT_TO_POINTER (fd), list);
156 p = get_events_from_list (list);
157 evt->events = (p & MONO_POLLOUT) ? EPOLLOUT : 0;
158 evt->events |= (p & MONO_POLLIN) ? EPOLLIN : 0;
159 if (epoll_ctl (epollfd, EPOLL_CTL_MOD, fd, evt) == -1) {
160 if (epoll_ctl (epollfd, EPOLL_CTL_ADD, fd, evt) == -1) {
162 g_message ("epoll(ADD): %d %s", err, g_strerror (err));
166 mono_g_hash_table_remove (socket_io_data->sock_to_state, GINT_TO_POINTER (fd));
167 epoll_ctl (epollfd, EPOLL_CTL_DEL, fd, evt);
170 LeaveCriticalSection (&socket_io_data->io_lock);
171 threadpool_append_jobs (&async_io_tp, (MonoObject **) async_results, nresults);
172 mono_gc_bzero (async_results, sizeof (gpointer) * nresults);