Merge pull request #3213 from henricm/fix-for-win-securestring-to-bstr
[mono.git] / mono / metadata / threadpool-ms-io-poll.c
1
2 #include "utils/mono-poll.h"
3
4 static mono_pollfd *poll_fds;
5 static guint poll_fds_capacity;
6 static guint poll_fds_size;
7
8 static inline void
9 POLL_INIT_FD (mono_pollfd *poll_fd, gint fd, gint events)
10 {
11         poll_fd->fd = fd;
12         poll_fd->events = events;
13         poll_fd->revents = 0;
14 }
15
16 static gboolean
17 poll_init (gint wakeup_pipe_fd)
18 {
19         g_assert (wakeup_pipe_fd >= 0);
20
21         poll_fds_size = 1;
22         poll_fds_capacity = 64;
23
24         poll_fds = g_new0 (mono_pollfd, poll_fds_capacity);
25
26         POLL_INIT_FD (&poll_fds [0], wakeup_pipe_fd, MONO_POLLIN);
27
28         return TRUE;
29 }
30
31 static void
32 poll_register_fd (gint fd, gint events, gboolean is_new)
33 {
34         gint i;
35         gint poll_event;
36
37         g_assert (fd >= 0);
38         g_assert (poll_fds_size <= poll_fds_capacity);
39
40         g_assert ((events & ~(EVENT_IN | EVENT_OUT)) == 0);
41
42         poll_event = 0;
43         if (events & EVENT_IN)
44                 poll_event |= MONO_POLLIN;
45         if (events & EVENT_OUT)
46                 poll_event |= MONO_POLLOUT;
47
48         for (i = 0; i < poll_fds_size; ++i) {
49                 if (poll_fds [i].fd == fd) {
50                         g_assert (!is_new);
51                         POLL_INIT_FD (&poll_fds [i], fd, poll_event);
52                         return;
53                 }
54         }
55
56         g_assert (is_new);
57
58         for (i = 0; i < poll_fds_size; ++i) {
59                 if (poll_fds [i].fd == -1) {
60                         POLL_INIT_FD (&poll_fds [i], fd, poll_event);
61                         return;
62                 }
63         }
64
65         poll_fds_size += 1;
66
67         if (poll_fds_size > poll_fds_capacity) {
68                 poll_fds_capacity *= 2;
69                 g_assert (poll_fds_size <= poll_fds_capacity);
70
71                 poll_fds = (mono_pollfd *)g_renew (mono_pollfd, poll_fds, poll_fds_capacity);
72         }
73
74         POLL_INIT_FD (&poll_fds [poll_fds_size - 1], fd, poll_event);
75 }
76
77 static void
78 poll_remove_fd (gint fd)
79 {
80         gint i;
81
82         g_assert (fd >= 0);
83
84         for (i = 0; i < poll_fds_size; ++i) {
85                 if (poll_fds [i].fd == fd) {
86                         POLL_INIT_FD (&poll_fds [i], -1, 0);
87                         break;
88                 }
89         }
90
91         /* if we don't find the fd in poll_fds,
92          * it means we try to delete it twice */
93         g_assert (i < poll_fds_size);
94
95         /* if we find it again, it means we added
96          * it twice */
97         for (; i < poll_fds_size; ++i)
98                 g_assert (poll_fds [i].fd != fd);
99
100         /* reduce the value of poll_fds_size so we
101          * do not keep it too big */
102         while (poll_fds_size > 1 && poll_fds [poll_fds_size - 1].fd == -1)
103                 poll_fds_size -= 1;
104 }
105
106 static inline gint
107 poll_mark_bad_fds (mono_pollfd *poll_fds, gint poll_fds_size)
108 {
109         gint i, ready = 0;
110
111         for (i = 0; i < poll_fds_size; i++) {
112                 if (poll_fds [i].fd == -1)
113                         continue;
114
115                 switch (mono_poll (&poll_fds [i], 1, 0)) {
116                 case 1:
117                         ready++;
118                         break;
119                 case -1:
120 #if !defined(HOST_WIN32)
121                         if (errno == EBADF)
122 #else
123                         if (WSAGetLastError () == WSAEBADF)
124 #endif
125                         {
126                                 poll_fds [i].revents |= MONO_POLLNVAL;
127                                 ready++;
128                         }
129                         break;
130                 }
131         }
132
133         return ready;
134 }
135
136 static gint
137 poll_event_wait (void (*callback) (gint fd, gint events, gpointer user_data), gpointer user_data)
138 {
139         gint i, ready;
140
141         for (i = 0; i < poll_fds_size; ++i)
142                 poll_fds [i].revents = 0;
143
144         mono_gc_set_skip_thread (TRUE);
145
146         MONO_ENTER_GC_SAFE;
147         ready = mono_poll (poll_fds, poll_fds_size, -1);
148         MONO_EXIT_GC_SAFE;
149
150         mono_gc_set_skip_thread (FALSE);
151
152         if (ready == -1) {
153                 /*
154                  * Apart from EINTR, we only check EBADF, for the rest:
155                  *  EINVAL: mono_poll() 'protects' us from descriptor
156                  *      numbers above the limit if using select() by marking
157                  *      then as POLLERR.  If a system poll() is being
158                  *      used, the number of descriptor we're passing will not
159                  *      be over sysconf(_SC_OPEN_MAX), as the error would have
160                  *      happened when opening.
161                  *
162                  *  EFAULT: we own the memory pointed by pfds.
163                  *  ENOMEM: we're doomed anyway
164                  *
165                  */
166 #if !defined(HOST_WIN32)
167                 switch (errno)
168 #else
169                 switch (WSAGetLastError ())
170 #endif
171                 {
172 #if !defined(HOST_WIN32)
173                 case EINTR:
174 #else
175                 case WSAEINTR:
176 #endif
177                 {
178                         mono_thread_internal_check_for_interruption_critical (mono_thread_internal_current ());
179                         ready = 0;
180                         break;
181                 }
182 #if !defined(HOST_WIN32)
183                 case EBADF:
184 #else
185                 case WSAEBADF:
186 #endif
187                 {
188                         ready = poll_mark_bad_fds (poll_fds, poll_fds_size);
189                         break;
190                 }
191                 default:
192 #if !defined(HOST_WIN32)
193                         g_error ("poll_event_wait: mono_poll () failed, error (%d) %s", errno, g_strerror (errno));
194 #else
195                         g_error ("poll_event_wait: mono_poll () failed, error (%d)\n", WSAGetLastError ());
196 #endif
197                         break;
198                 }
199         }
200
201         if (ready == -1)
202                 return -1;
203         if (ready == 0)
204                 return 0;
205
206         g_assert (ready > 0);
207
208         for (i = 0; i < poll_fds_size; ++i) {
209                 gint fd, events = 0;
210
211                 if (poll_fds [i].fd == -1)
212                         continue;
213                 if (poll_fds [i].revents == 0)
214                         continue;
215
216                 fd = poll_fds [i].fd;
217                 if (poll_fds [i].revents & (MONO_POLLIN | MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL))
218                         events |= EVENT_IN;
219                 if (poll_fds [i].revents & (MONO_POLLOUT | MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL))
220                         events |= EVENT_OUT;
221                 if (poll_fds [i].revents & (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL))
222                         events |= EVENT_ERR;
223
224                 callback (fd, events, user_data);
225
226                 if (--ready == 0)
227                         break;
228         }
229
230         return 0;
231 }
232
233 static ThreadPoolIOBackend backend_poll = {
234         .init = poll_init,
235         .register_fd = poll_register_fd,
236         .remove_fd = poll_remove_fd,
237         .event_wait = poll_event_wait,
238 };