Change an #ifdef DEBUG to THREAD_DEBUG(). Fixes #676615.
[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                 return NULL;
35
36         data->shutdown = tp_epoll_shutdown;
37         data->modify = tp_epoll_modify;
38         data->wait = tp_epoll_wait;
39         return result;
40 }
41
42 static void
43 tp_epoll_modify (gpointer event_data, int fd, int operation, int events, gboolean is_new)
44 {
45         tp_epoll_data *data = event_data;
46         struct epoll_event evt;
47         int epoll_op;
48
49         evt.data.fd = fd;
50         if ((events & MONO_POLLIN) != 0)
51                 evt.events |= EPOLLIN;
52         if ((events & MONO_POLLOUT) != 0)
53                 evt.events |= EPOLLOUT;
54
55         epoll_op = (is_new) ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
56         if (epoll_ctl (data->epollfd, epoll_op, fd, &evt) == -1) {
57                 int err = errno;
58                 if (epoll_op == EPOLL_CTL_ADD && err == EEXIST) {
59                         epoll_op = EPOLL_CTL_MOD;
60                         if (epoll_ctl (data->epollfd, epoll_op, fd, &evt) == -1) {
61                                 g_message ("epoll_ctl(MOD): %d %s", err, g_strerror (err));
62                         }
63                 }
64         }
65 }
66
67 static void
68 tp_epoll_shutdown (gpointer event_data)
69 {
70         tp_epoll_data *data = event_data;
71
72         close (data->epollfd);
73         g_free (data);
74 }
75
76 #define EPOLL_ERRORS (EPOLLERR | EPOLLHUP)
77 #define EPOLL_NEVENTS   128
78 static void
79 tp_epoll_wait (gpointer p)
80 {
81         SocketIOData *socket_io_data;
82         int epollfd;
83         MonoInternalThread *thread;
84         struct epoll_event *events, *evt;
85         int ready = 0, i;
86         gpointer async_results [EPOLL_NEVENTS * 2]; // * 2 because each loop can add up to 2 results here
87         gint nresults;
88         tp_epoll_data *data;
89
90         socket_io_data = p;
91         data = socket_io_data->event_data;
92         epollfd = data->epollfd;
93         thread = mono_thread_internal_current ();
94         events = g_new0 (struct epoll_event, EPOLL_NEVENTS);
95
96         while (1) {
97                 do {
98                         if (ready == -1) {
99                                 if (THREAD_WANTS_A_BREAK (thread))
100                                         mono_thread_interruption_checkpoint ();
101                         }
102                         ready = epoll_wait (epollfd, events, EPOLL_NEVENTS, -1);
103                 } while (ready == -1 && errno == EINTR);
104
105                 if (ready == -1) {
106                         int err = errno;
107                         g_free (events);
108                         if (err != EBADF)
109                                 g_warning ("epoll_wait: %d %s", err, g_strerror (err));
110
111                         return;
112                 }
113
114                 EnterCriticalSection (&socket_io_data->io_lock);
115                 if (socket_io_data->inited == 3) {
116                         g_free (events);
117                         LeaveCriticalSection (&socket_io_data->io_lock);
118                         return; /* cleanup called */
119                 }
120
121                 nresults = 0;
122                 for (i = 0; i < ready; i++) {
123                         int fd;
124                         MonoMList *list;
125                         MonoObject *ares;
126
127                         evt = &events [i];
128                         fd = evt->data.fd;
129                         list = mono_g_hash_table_lookup (socket_io_data->sock_to_state, GINT_TO_POINTER (fd));
130                         if (list != NULL && (evt->events & (EPOLLIN | EPOLL_ERRORS)) != 0) {
131                                 ares = get_io_event (&list, MONO_POLLIN);
132                                 if (ares != NULL)
133                                         async_results [nresults++] = ares;
134                         }
135
136                         if (list != NULL && (evt->events & (EPOLLOUT | EPOLL_ERRORS)) != 0) {
137                                 ares = get_io_event (&list, MONO_POLLOUT);
138                                 if (ares != NULL)
139                                         async_results [nresults++] = ares;
140                         }
141
142                         if (list != NULL) {
143                                 int p;
144
145                                 mono_g_hash_table_replace (socket_io_data->sock_to_state, GINT_TO_POINTER (fd), list);
146                                 p = get_events_from_list (list);
147                                 evt->events = (p & MONO_POLLOUT) ? EPOLLOUT : 0;
148                                 evt->events |= (p & MONO_POLLIN) ? EPOLLIN : 0;
149                                 if (epoll_ctl (epollfd, EPOLL_CTL_MOD, fd, evt) == -1) {
150                                         if (epoll_ctl (epollfd, EPOLL_CTL_ADD, fd, evt) == -1) {
151                                                 int err = errno;
152                                                 g_message ("epoll(ADD): %d %s", err, g_strerror (err));
153                                         }
154                                 }
155                         } else {
156                                 mono_g_hash_table_remove (socket_io_data->sock_to_state, GINT_TO_POINTER (fd));
157                                 epoll_ctl (epollfd, EPOLL_CTL_DEL, fd, evt);
158                         }
159                 }
160                 LeaveCriticalSection (&socket_io_data->io_lock);
161                 threadpool_append_jobs (&async_io_tp, (MonoObject **) async_results, nresults);
162                 memset (async_results, 0, sizeof (gpointer) * nresults);
163         }
164 }
165 #undef EPOLL_NEVENTS
166 #undef EPOLL_ERRORS