Display more debugging info when epoll fails
[mono.git] / mono / metadata / tpool-epoll.c
1 /*
2  * tpool-epoll.c: epoll related stuff
3  *
4  * Authors:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *   Gonzalo Paniagua Javier (gonzalo@ximian.com)
7  *
8  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9  * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
10  */
11
12 struct _tp_epoll_data {
13         int epollfd;
14 };
15
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);
20
21 static gpointer
22 tp_epoll_init (SocketIOData *data)
23 {
24         tp_epoll_data *result;
25
26         result = g_new0 (tp_epoll_data, 1);
27 #ifdef EPOLL_CLOEXEC
28         result->epollfd = epoll_create1 (EPOLL_CLOEXEC);
29 #else
30         result->epollfd = epoll_create (256); /* The number does not really matter */
31         fcntl (result->epollfd, F_SETFD, FD_CLOEXEC);
32 #endif
33         if (result->epollfd == -1) {
34                 int err = errno;
35                 if (g_getenv ("MONO_DEBUG")) {
36 #ifdef EPOLL_CLOEXEC
37                         g_message ("epoll_create1(EPOLL_CLOEXEC) failed: %d %s", err, g_strerror (err));
38 #else
39                         g_message ("epoll_create(256) failed: %d %s", err, g_strerror (err));
40 #endif
41                 }
42
43                 return NULL;
44         }
45
46         data->shutdown = tp_epoll_shutdown;
47         data->modify = tp_epoll_modify;
48         data->wait = tp_epoll_wait;
49         return result;
50 }
51
52 static void
53 tp_epoll_modify (gpointer event_data, int fd, int operation, int events, gboolean is_new)
54 {
55         tp_epoll_data *data = event_data;
56         struct epoll_event evt;
57         int epoll_op;
58
59         evt.data.fd = fd;
60         if ((events & MONO_POLLIN) != 0)
61                 evt.events |= EPOLLIN;
62         if ((events & MONO_POLLOUT) != 0)
63                 evt.events |= EPOLLOUT;
64
65         epoll_op = (is_new) ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
66         if (epoll_ctl (data->epollfd, epoll_op, fd, &evt) == -1) {
67                 int err = errno;
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));
72                         }
73                 }
74         }
75 }
76
77 static void
78 tp_epoll_shutdown (gpointer event_data)
79 {
80         tp_epoll_data *data = event_data;
81
82         close (data->epollfd);
83         g_free (data);
84 }
85
86 #define EPOLL_ERRORS (EPOLLERR | EPOLLHUP)
87 #define EPOLL_NEVENTS   128
88 static void
89 tp_epoll_wait (gpointer p)
90 {
91         SocketIOData *socket_io_data;
92         int epollfd;
93         MonoInternalThread *thread;
94         struct epoll_event *events, *evt;
95         int ready = 0, i;
96         gpointer async_results [EPOLL_NEVENTS * 2]; // * 2 because each loop can add up to 2 results here
97         gint nresults;
98         tp_epoll_data *data;
99
100         socket_io_data = p;
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);
105
106         while (1) {
107                 do {
108                         if (ready == -1) {
109                                 if (THREAD_WANTS_A_BREAK (thread))
110                                         mono_thread_interruption_checkpoint ();
111                         }
112                         ready = epoll_wait (epollfd, events, EPOLL_NEVENTS, -1);
113                 } while (ready == -1 && errno == EINTR);
114
115                 if (ready == -1) {
116                         int err = errno;
117                         g_free (events);
118                         if (err != EBADF)
119                                 g_warning ("epoll_wait: %d %s", err, g_strerror (err));
120
121                         return;
122                 }
123
124                 EnterCriticalSection (&socket_io_data->io_lock);
125                 if (socket_io_data->inited == 3) {
126                         g_free (events);
127                         LeaveCriticalSection (&socket_io_data->io_lock);
128                         return; /* cleanup called */
129                 }
130
131                 nresults = 0;
132                 for (i = 0; i < ready; i++) {
133                         int fd;
134                         MonoMList *list;
135                         MonoObject *ares;
136
137                         evt = &events [i];
138                         fd = evt->data.fd;
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);
142                                 if (ares != NULL)
143                                         async_results [nresults++] = ares;
144                         }
145
146                         if (list != NULL && (evt->events & (EPOLLOUT | EPOLL_ERRORS)) != 0) {
147                                 ares = get_io_event (&list, MONO_POLLOUT);
148                                 if (ares != NULL)
149                                         async_results [nresults++] = ares;
150                         }
151
152                         if (list != NULL) {
153                                 int p;
154
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) {
161                                                 int err = errno;
162                                                 g_message ("epoll(ADD): %d %s", err, g_strerror (err));
163                                         }
164                                 }
165                         } else {
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);
168                         }
169                 }
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);
173         }
174 }
175 #undef EPOLL_NEVENTS
176 #undef EPOLL_ERRORS