Merge pull request #2003 from esdrubal/seq_test_fix2
[mono.git] / mono / metadata / threadpool-ms-io-poll.c
1
2 #if defined(HAVE_POLL)
3
4 #if defined(HAVE_POLL_H)
5 #include <poll.h>
6 #elif defined(HAVE_SYS_POLL_H)
7 #include <sys/poll.h>
8 #endif
9
10 typedef struct pollfd mono_pollfd;
11
12 #elif defined(HOST_WIN32)
13
14 #include "mswsock.h"
15
16 typedef WSAPOLLFD mono_pollfd;
17
18 #else
19 /* poll is not defined */
20 #error
21 #endif
22
23 static mono_pollfd *poll_fds;
24 static guint poll_fds_capacity;
25 static guint poll_fds_size;
26
27 static inline void
28 POLL_INIT_FD (mono_pollfd *poll_fd, gint fd, gint events)
29 {
30         poll_fd->fd = fd;
31         poll_fd->events = events;
32         poll_fd->revents = 0;
33 }
34
35 static gboolean
36 poll_init (gint wakeup_pipe_fd)
37 {
38         gint i;
39
40         poll_fds_size = wakeup_pipe_fd + 1;
41         poll_fds_capacity = 64;
42
43         while (wakeup_pipe_fd >= poll_fds_capacity)
44                 poll_fds_capacity *= 4;
45
46         poll_fds = g_new0 (mono_pollfd, poll_fds_capacity);
47
48         for (i = 0; i < wakeup_pipe_fd; ++i)
49                 POLL_INIT_FD (&poll_fds [i], -1, 0);
50
51         POLL_INIT_FD (&poll_fds [wakeup_pipe_fd], wakeup_pipe_fd, POLLIN);
52
53         return TRUE;
54 }
55
56 static void
57 poll_cleanup (void)
58 {
59         g_free (poll_fds);
60 }
61
62 static void
63 poll_register_fd (gint fd, gint events, gboolean is_new)
64 {
65         gint i;
66         mono_pollfd *poll_fd;
67
68         g_assert (fd >= 0);
69         g_assert (poll_fds_size <= poll_fds_capacity);
70
71         if (fd >= poll_fds_capacity) {
72                 do {
73                         poll_fds_capacity *= 4;
74                 } while (fd >= poll_fds_capacity);
75
76                 poll_fds = g_renew (mono_pollfd, poll_fds, poll_fds_capacity);
77         }
78
79         if (fd >= poll_fds_size) {
80                 for (i = poll_fds_size; i <= fd; ++i)
81                         POLL_INIT_FD (&poll_fds [i], -1, 0);
82
83                 poll_fds_size = fd + 1;
84         }
85
86         poll_fd = &poll_fds [fd];
87
88         if (poll_fd->fd != -1) {
89                 g_assert (poll_fd->fd == fd);
90                 g_assert (!is_new);
91         }
92
93         POLL_INIT_FD (poll_fd, fd, ((events & EVENT_IN) ? POLLIN : 0) | ((events & EVENT_OUT) ? POLLOUT : 0));
94 }
95
96 static void
97 poll_remove_fd (gint fd)
98 {
99         mono_pollfd *poll_fd;
100
101         g_assert (fd >= 0);
102
103         g_assert (fd < poll_fds_size);
104         poll_fd = &poll_fds [fd];
105
106         g_assert (poll_fd->fd == fd);
107         POLL_INIT_FD (poll_fd, -1, 0);
108 }
109
110 static gint
111 poll_event_wait (void (*callback) (gint fd, gint events, gpointer user_data), gpointer user_data)
112 {
113         gint i, ready;
114
115         for (i = 0; i < poll_fds_size; ++i)
116                 poll_fds [i].revents = 0;
117
118         mono_gc_set_skip_thread (TRUE);
119
120 #if !defined(HOST_WIN32)
121         ready = poll (poll_fds, poll_fds_size, -1);
122 #else
123         ready = WSAPoll(poll_fds, poll_fds_size, -1);
124         if (ready == SOCKET_ERROR)
125                 ready = -1;
126 #endif
127
128         mono_gc_set_skip_thread (FALSE);
129
130         if (ready == -1) {
131                 /*
132                  * Apart from EINTR, we only check EBADF, for the rest:
133                  *  EINVAL: mono_poll() 'protects' us from descriptor
134                  *      numbers above the limit if using select() by marking
135                  *      then as POLLERR.  If a system poll() is being
136                  *      used, the number of descriptor we're passing will not
137                  *      be over sysconf(_SC_OPEN_MAX), as the error would have
138                  *      happened when opening.
139                  *
140                  *  EFAULT: we own the memory pointed by pfds.
141                  *  ENOMEM: we're doomed anyway
142                  *
143                  */
144 #if !defined(HOST_WIN32)
145                 switch (errno)
146 #else
147                 switch (WSAGetLastError ())
148 #endif
149                 {
150 #if !defined(HOST_WIN32)
151                 case EINTR:
152 #else
153                 case WSAEINTR:
154 #endif
155                 {
156                         mono_thread_internal_check_for_interruption_critical (mono_thread_internal_current ());
157                         ready = 0;
158                         break;
159                 }
160                 default:
161 #if !defined(HOST_WIN32)
162                         g_error ("poll_event_wait: mono_poll () failed, error (%d) %s", errno, g_strerror (errno));
163 #else
164                         g_error ("poll_event_wait: mono_poll () failed, error (%d)\n", WSAGetLastError ());
165 #endif
166                         break;
167                 }
168         }
169
170         if (ready == -1)
171                 return -1;
172
173         for (i = 0; i < poll_fds_size; ++i) {
174                 gint fd, events = 0;
175
176                 if (poll_fds [i].fd == -1)
177                         continue;
178                 if (poll_fds [i].revents == 0)
179                         continue;
180
181                 fd = poll_fds [i].fd;
182                 if (poll_fds [i].revents & (POLLIN | POLLERR | POLLHUP | POLLNVAL))
183                         events |= EVENT_IN;
184                 if (poll_fds [i].revents & (POLLOUT | POLLERR | POLLHUP | POLLNVAL))
185                         events |= EVENT_OUT;
186
187                 callback (fd, events, user_data);
188
189                 if (--ready == 0)
190                         break;
191         }
192
193         return 0;
194 }
195
196 static ThreadPoolIOBackend backend_poll = {
197         .init = poll_init,
198         .cleanup = poll_cleanup,
199         .register_fd = poll_register_fd,
200         .remove_fd = poll_remove_fd,
201         .event_wait = poll_event_wait,
202 };