Merge pull request #1909 from esdrubal/reflection
[mono.git] / mono / metadata / threadpool-ms-io-poll.c
1
2 #define POLL_NEVENTS 1024
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         guint i;
20
21         poll_fds_size = 1;
22         poll_fds_capacity = POLL_NEVENTS;
23         poll_fds = g_new0 (mono_pollfd, poll_fds_capacity);
24
25         POLL_INIT_FD (poll_fds, wakeup_pipe_fd, MONO_POLLIN);
26         for (i = 1; i < poll_fds_capacity; ++i)
27                 POLL_INIT_FD (poll_fds + i, -1, 0);
28
29         return TRUE;
30 }
31
32 static void
33 poll_cleanup (void)
34 {
35         g_free (poll_fds);
36 }
37
38 static inline gint
39 poll_mark_bad_fds (mono_pollfd *poll_fds, gint poll_fds_size)
40 {
41         gint i;
42         gint ret;
43         gint ready = 0;
44         mono_pollfd *poll_fd;
45
46         for (i = 0; i < poll_fds_size; i++) {
47                 poll_fd = poll_fds + i;
48                 if (poll_fd->fd == -1)
49                         continue;
50
51                 ret = mono_poll (poll_fd, 1, 0);
52                 if (ret == 1)
53                         ready++;
54                 if (ret == -1) {
55 #if !defined(HOST_WIN32)
56                         if (errno == EBADF)
57 #else
58                         if (WSAGetLastError () == WSAEBADF)
59 #endif
60                         {
61                                 poll_fd->revents |= MONO_POLLNVAL;
62                                 ready++;
63                         }
64                 }
65         }
66
67         return ready;
68 }
69
70 static void
71 poll_register_fd (gint fd, gint events, gboolean is_new)
72 {
73         gboolean found = FALSE;
74         gint j, k;
75
76         for (j = 1; j < poll_fds_size; ++j) {
77                 mono_pollfd *poll_fd = poll_fds + j;
78                 if (poll_fd->fd == fd) {
79                         found = TRUE;
80                         break;
81                 }
82         }
83
84         if (events == 0) {
85                 if (found)
86                         POLL_INIT_FD (poll_fds + j, -1, 0);
87                 return;
88         }
89
90         if (!found) {
91                 for (j = 1; j < poll_fds_capacity; ++j) {
92                         mono_pollfd *poll_fd = poll_fds + j;
93                         if (poll_fd->fd == -1)
94                                 break;
95                 }
96         }
97
98         if (j == poll_fds_capacity) {
99                 poll_fds_capacity += POLL_NEVENTS;
100                 poll_fds = g_renew (mono_pollfd, poll_fds, poll_fds_capacity);
101                 for (k = j; k < poll_fds_capacity; ++k)
102                         POLL_INIT_FD (poll_fds + k, -1, 0);
103         }
104
105         POLL_INIT_FD (poll_fds + j, fd, events);
106
107         if (j >= poll_fds_size)
108                 poll_fds_size = j + 1;
109 }
110
111 static gint
112 poll_event_wait (void)
113 {
114         gint ready;
115
116         ready = mono_poll (poll_fds, poll_fds_size, -1);
117         if (ready == -1) {
118                 /*
119                  * Apart from EINTR, we only check EBADF, for the rest:
120                  *  EINVAL: mono_poll() 'protects' us from descriptor
121                  *      numbers above the limit if using select() by marking
122                  *      then as MONO_POLLERR.  If a system poll() is being
123                  *      used, the number of descriptor we're passing will not
124                  *      be over sysconf(_SC_OPEN_MAX), as the error would have
125                  *      happened when opening.
126                  *
127                  *  EFAULT: we own the memory pointed by pfds.
128                  *  ENOMEM: we're doomed anyway
129                  *
130                  */
131 #if !defined(HOST_WIN32)
132                 switch (errno)
133 #else
134                 switch (WSAGetLastError ())
135 #endif
136                 {
137 #if !defined(HOST_WIN32)
138                 case EINTR:
139 #else
140                 case WSAEINTR:
141 #endif
142                         mono_thread_internal_check_for_interruption_critical (mono_thread_internal_current ());
143                         ready = 0;
144                         break;
145 #if !defined(HOST_WIN32)
146                 case EBADF:
147 #else
148                 case WSAEBADF:
149 #endif
150                         ready = poll_mark_bad_fds (poll_fds, poll_fds_size);
151                         break;
152                 default:
153 #if !defined(HOST_WIN32)
154                         g_warning ("poll_event_wait: mono_poll () failed, error (%d) %s", errno, g_strerror (errno));
155 #else
156                         g_warning ("poll_event_wait: mono_poll () failed, error (%d)\n", WSAGetLastError ());
157 #endif
158                         break;
159                 }
160         }
161
162         return ready;
163 }
164
165 static gint
166 poll_event_get_fd_at (gint i, gint *events)
167 {
168         g_assert (events);
169
170         *events = ((poll_fds [i].revents & (MONO_POLLIN | MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)) ? MONO_POLLIN : 0)
171                     | ((poll_fds [i].revents & (MONO_POLLOUT | MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)) ? MONO_POLLOUT : 0);
172
173         /* if nothing happened on the fd, then just return
174          * an invalid fd number so it is discarded */
175         return poll_fds [i].revents == 0 ? -1 : poll_fds [i].fd;
176 }
177
178 static gint
179 poll_event_get_fd_max (void)
180 {
181         return poll_fds_size;
182 }
183
184 static ThreadPoolIOBackend backend_poll = {
185         .init = poll_init,
186         .cleanup = poll_cleanup,
187         .register_fd = poll_register_fd,
188         .event_wait = poll_event_wait,
189         .event_get_fd_max = poll_event_get_fd_max,
190         .event_get_fd_at = poll_event_get_fd_at,
191 };