[WinForms] Fix #18506 ActiveTracker, do not propagate message to control when it...
[mono-project.git] / mono / metadata / threadpool-io-poll.c
blobac57194d9d8e8ea90cdc5206d2ee17f9a468a38a
1 /**
2 * \file
3 */
5 #include "utils/mono-poll.h"
7 static mono_pollfd *poll_fds;
8 static guint poll_fds_capacity;
9 static guint poll_fds_size;
11 static void
12 POLL_INIT_FD (mono_pollfd *poll_fd, gint fd, gint events)
14 poll_fd->fd = fd;
15 poll_fd->events = events;
16 poll_fd->revents = 0;
19 static gboolean
20 poll_init (gint wakeup_pipe_fd)
22 g_assert (wakeup_pipe_fd >= 0);
24 poll_fds_size = 1;
25 poll_fds_capacity = 64;
27 poll_fds = g_new0 (mono_pollfd, poll_fds_capacity);
29 POLL_INIT_FD (&poll_fds [0], wakeup_pipe_fd, MONO_POLLIN);
31 return TRUE;
34 static gboolean
35 poll_can_register_fd (int fd)
37 return mono_poll_can_add (poll_fds, poll_fds_size, fd);
40 static void
41 poll_register_fd (gint fd, gint events, gboolean is_new)
43 gint i;
44 gint poll_event;
46 g_assert (fd >= 0);
47 g_assert (poll_fds_size <= poll_fds_capacity);
49 g_assert ((events & ~(EVENT_IN | EVENT_OUT)) == 0);
51 poll_event = 0;
52 if (events & EVENT_IN)
53 poll_event |= MONO_POLLIN;
54 if (events & EVENT_OUT)
55 poll_event |= MONO_POLLOUT;
57 for (i = 0; i < poll_fds_size; ++i) {
58 if (poll_fds [i].fd == fd) {
59 g_assert (!is_new);
60 POLL_INIT_FD (&poll_fds [i], fd, poll_event);
61 return;
65 g_assert (is_new);
67 for (i = 0; i < poll_fds_size; ++i) {
68 if (poll_fds [i].fd == -1) {
69 POLL_INIT_FD (&poll_fds [i], fd, poll_event);
70 return;
74 poll_fds_size += 1;
76 if (poll_fds_size > poll_fds_capacity) {
77 poll_fds_capacity *= 2;
78 g_assert (poll_fds_size <= poll_fds_capacity);
80 poll_fds = (mono_pollfd *)g_renew (mono_pollfd, poll_fds, poll_fds_capacity);
83 POLL_INIT_FD (&poll_fds [poll_fds_size - 1], fd, poll_event);
87 static void
88 poll_remove_fd (gint fd)
90 gint i;
92 g_assert (fd >= 0);
94 for (i = 0; i < poll_fds_size; ++i) {
95 if (poll_fds [i].fd == fd) {
96 POLL_INIT_FD (&poll_fds [i], -1, 0);
97 break;
101 /* if we don't find the fd in poll_fds,
102 * it means we try to delete it twice */
103 g_assert (i < poll_fds_size);
105 /* if we find it again, it means we added
106 * it twice */
107 for (; i < poll_fds_size; ++i)
108 g_assert (poll_fds [i].fd != fd);
110 /* reduce the value of poll_fds_size so we
111 * do not keep it too big */
112 while (poll_fds_size > 1 && poll_fds [poll_fds_size - 1].fd == -1)
113 poll_fds_size -= 1;
116 static gint
117 poll_mark_bad_fds (mono_pollfd *fds, gint size)
119 gint i, ready = 0;
121 for (i = 0; i < size; i++) {
122 if (fds [i].fd == -1)
123 continue;
125 switch (mono_poll (&fds [i], 1, 0)) {
126 case 1:
127 ready++;
128 break;
129 case -1:
130 if (errno == EBADF)
132 fds [i].revents |= MONO_POLLNVAL;
133 ready++;
135 break;
139 return ready;
142 static gint
143 poll_event_wait (void (*callback) (gint fd, gint events, gpointer user_data), gpointer user_data)
145 gint i, ready;
147 for (i = 0; i < poll_fds_size; ++i)
148 poll_fds [i].revents = 0;
150 mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NO_GC);
152 MONO_ENTER_GC_SAFE;
153 ready = mono_poll (poll_fds, poll_fds_size, -1);
154 MONO_EXIT_GC_SAFE;
156 mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NONE);
158 if (ready == -1) {
160 * Apart from EINTR, we only check EBADF, for the rest:
161 * EINVAL: mono_poll() 'protects' us from descriptor
162 * numbers above the limit if using select() by marking
163 * then as POLLERR. If a system poll() is being
164 * used, the number of descriptor we're passing will not
165 * be over sysconf(_SC_OPEN_MAX), as the error would have
166 * happened when opening.
168 * EFAULT: we own the memory pointed by pfds.
169 * ENOMEM: we're doomed anyway
172 switch (errno)
174 case EINTR:
176 ready = 0;
177 break;
179 case EBADF:
181 ready = poll_mark_bad_fds (poll_fds, poll_fds_size);
182 break;
184 default:
185 g_error ("poll_event_wait: mono_poll () failed, error (%d) %s", errno, g_strerror (errno));
186 break;
190 if (ready == -1)
191 return -1;
192 if (ready == 0)
193 return 0;
195 g_assert (ready > 0);
197 for (i = 0; i < poll_fds_size; ++i) {
198 gint fd, events = 0;
200 if (poll_fds [i].fd == -1)
201 continue;
202 if (poll_fds [i].revents == 0)
203 continue;
205 fd = poll_fds [i].fd;
206 if (poll_fds [i].revents & (MONO_POLLIN | MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL))
207 events |= EVENT_IN;
208 if (poll_fds [i].revents & (MONO_POLLOUT | MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL))
209 events |= EVENT_OUT;
210 if (poll_fds [i].revents & (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL))
211 events |= EVENT_ERR;
213 callback (fd, events, user_data);
215 if (--ready == 0)
216 break;
219 return 0;
222 static ThreadPoolIOBackend backend_poll = {
223 poll_init,
224 poll_can_register_fd,
225 poll_register_fd,
226 poll_remove_fd,
227 poll_event_wait,