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)
10 * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
13 struct _tp_epoll_data
{
17 typedef struct _tp_epoll_data tp_epoll_data
;
18 static void tp_epoll_modify (gpointer p
, int fd
, int operation
, int events
, gboolean is_new
);
19 static void tp_epoll_shutdown (gpointer event_data
);
20 static void tp_epoll_wait (gpointer event_data
);
23 tp_epoll_init (SocketIOData
*data
)
25 tp_epoll_data
*result
;
27 result
= g_new0 (tp_epoll_data
, 1);
29 result
->epollfd
= epoll_create1 (EPOLL_CLOEXEC
);
31 result
->epollfd
= epoll_create (256); /* The number does not really matter */
32 fcntl (result
->epollfd
, F_SETFD
, FD_CLOEXEC
);
34 if (result
->epollfd
== -1) {
36 if (g_getenv ("MONO_DEBUG")) {
38 g_message ("epoll_create1(EPOLL_CLOEXEC) failed: %d %s", err
, g_strerror (err
));
40 g_message ("epoll_create(256) failed: %d %s", err
, g_strerror (err
));
47 data
->shutdown
= tp_epoll_shutdown
;
48 data
->modify
= tp_epoll_modify
;
49 data
->wait
= tp_epoll_wait
;
54 tp_epoll_modify (gpointer p
, int fd
, int operation
, int events
, gboolean is_new
)
56 SocketIOData
*socket_io_data
;
58 struct epoll_event evt
;
62 data
= socket_io_data
->event_data
;
64 memset (&evt
, 0, sizeof (evt
));
66 if ((events
& MONO_POLLIN
) != 0)
67 evt
.events
|= EPOLLIN
;
68 if ((events
& MONO_POLLOUT
) != 0)
69 evt
.events
|= EPOLLOUT
;
71 epoll_op
= (is_new
) ? EPOLL_CTL_ADD
: EPOLL_CTL_MOD
;
72 if (epoll_ctl (data
->epollfd
, epoll_op
, fd
, &evt
) == -1) {
74 if (epoll_op
== EPOLL_CTL_ADD
&& err
== EEXIST
) {
75 epoll_op
= EPOLL_CTL_MOD
;
76 if (epoll_ctl (data
->epollfd
, epoll_op
, fd
, &evt
) == -1) {
77 g_message ("epoll_ctl(MOD): %d %s", err
, g_strerror (err
));
81 mono_mutex_unlock (&socket_io_data
->io_lock
);
85 tp_epoll_shutdown (gpointer event_data
)
87 tp_epoll_data
*data
= event_data
;
89 close (data
->epollfd
);
93 #define EPOLL_ERRORS (EPOLLERR | EPOLLHUP)
94 #define EPOLL_NEVENTS 128
96 tp_epoll_wait (gpointer p
)
98 SocketIOData
*socket_io_data
;
100 struct epoll_event
*events
, *evt
;
102 gpointer async_results
[EPOLL_NEVENTS
* 2]; // * 2 because each loop can add up to 2 results here
107 data
= socket_io_data
->event_data
;
108 epollfd
= data
->epollfd
;
109 events
= g_new0 (struct epoll_event
, EPOLL_NEVENTS
);
112 mono_gc_set_skip_thread (TRUE
);
116 check_for_interruption_critical ();
118 ready
= epoll_wait (epollfd
, events
, EPOLL_NEVENTS
, -1);
119 } while (ready
== -1 && errno
== EINTR
);
121 mono_gc_set_skip_thread (FALSE
);
127 g_warning ("epoll_wait: %d %s", err
, g_strerror (err
));
132 mono_mutex_lock (&socket_io_data
->io_lock
);
133 if (socket_io_data
->inited
== 3) {
135 mono_mutex_unlock (&socket_io_data
->io_lock
);
136 return; /* cleanup called */
140 for (i
= 0; i
< ready
; i
++) {
147 list
= mono_g_hash_table_lookup (socket_io_data
->sock_to_state
, GINT_TO_POINTER (fd
));
148 if (list
!= NULL
&& (evt
->events
& (EPOLLIN
| EPOLL_ERRORS
)) != 0) {
149 ares
= get_io_event (&list
, MONO_POLLIN
);
151 async_results
[nresults
++] = ares
;
154 if (list
!= NULL
&& (evt
->events
& (EPOLLOUT
| EPOLL_ERRORS
)) != 0) {
155 ares
= get_io_event (&list
, MONO_POLLOUT
);
157 async_results
[nresults
++] = ares
;
163 mono_g_hash_table_replace (socket_io_data
->sock_to_state
, GINT_TO_POINTER (fd
), list
);
164 p
= get_events_from_list (list
);
165 evt
->events
= (p
& MONO_POLLOUT
) ? EPOLLOUT
: 0;
166 evt
->events
|= (p
& MONO_POLLIN
) ? EPOLLIN
: 0;
167 if (epoll_ctl (epollfd
, EPOLL_CTL_MOD
, fd
, evt
) == -1) {
168 if (epoll_ctl (epollfd
, EPOLL_CTL_ADD
, fd
, evt
) == -1) {
170 g_message ("epoll(ADD): %d %s", err
, g_strerror (err
));
174 mono_g_hash_table_remove (socket_io_data
->sock_to_state
, GINT_TO_POINTER (fd
));
175 epoll_ctl (epollfd
, EPOLL_CTL_DEL
, fd
, evt
);
178 mono_mutex_unlock (&socket_io_data
->io_lock
);
179 threadpool_append_jobs (&async_io_tp
, (MonoObject
**) async_results
, nresults
);
180 mono_gc_bzero_aligned (async_results
, sizeof (gpointer
) * nresults
);