2 * tpool-poll.c: poll related stuff
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
15 #include <mono/metadata/mono-ptr-array.h>
16 #include <mono/metadata/threadpool.h>
17 #include <mono/metadata/threadpool-internals.h>
18 #include <mono/utils/mono-semaphore.h>
19 #include <mono/utils/mono-poll.h>
21 #define INIT_POLLFD(a, b, c) {(a)->fd = b; (a)->events = c; (a)->revents = 0;}
22 struct _tp_poll_data {
28 typedef struct _tp_poll_data tp_poll_data;
30 static void tp_poll_shutdown (gpointer event_data);
31 static void tp_poll_modify (gpointer p, int fd, int operation, int events, gboolean is_new);
32 static void tp_poll_wait (gpointer p);
35 tp_poll_init (SocketIOData *data)
39 struct sockaddr_in client;
40 struct sockaddr_in server;
45 result = g_new0 (tp_poll_data, 1);
47 if (pipe (result->pipe) != 0) {
53 srv = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
54 g_assert (srv != INVALID_SOCKET);
55 result->pipe [1] = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
56 g_assert (result->pipe [1] != INVALID_SOCKET);
58 server.sin_family = AF_INET;
59 server.sin_addr.s_addr = inet_addr ("127.0.0.1");
61 if (bind (srv, (SOCKADDR *) &server, sizeof (struct sockaddr_in))) {
62 g_print ("%d\n", WSAGetLastError ());
66 len = sizeof (server);
67 getsockname (srv, (SOCKADDR *) &server, &len);
69 if (connect ((SOCKET) result->pipe [1], (SOCKADDR *) &server, sizeof (server)) == SOCKET_ERROR) {
70 g_print ("%d\n", WSAGetLastError ());
73 len = sizeof (client);
74 result->pipe [0] = accept (srv, (SOCKADDR *) &client, &len);
75 g_assert (result->pipe [0] != INVALID_SOCKET);
78 MONO_SEM_INIT (&result->new_sem, 1);
79 data->shutdown = tp_poll_shutdown;
80 data->modify = tp_poll_modify;
81 data->wait = tp_poll_wait;
86 tp_poll_modify (gpointer p, int fd, int operation, int events, gboolean is_new)
88 SocketIOData *socket_io_data;
91 int unused G_GNUC_UNUSED;
94 data = socket_io_data->event_data;
96 mono_mutex_unlock (&socket_io_data->io_lock);
98 MONO_SEM_WAIT (&data->new_sem);
99 INIT_POLLFD (&data->newpfd, GPOINTER_TO_INT (fd), events);
100 *msg = (char) operation;
102 unused = write (data->pipe [1], msg, 1);
104 unused = send ((SOCKET) data->pipe [1], msg, 1, 0);
109 tp_poll_shutdown (gpointer event_data)
111 tp_poll_data *data = event_data;
114 closesocket (data->pipe [0]);
115 closesocket (data->pipe [1]);
117 if (data->pipe [0] > -1)
118 close (data->pipe [0]);
119 if (data->pipe [1] > -1)
120 close (data->pipe [1]);
124 MONO_SEM_DESTROY (&data->new_sem);
128 mark_bad_fds (mono_pollfd *pfds, int nfds)
134 for (i = 0; i < nfds; i++) {
139 ret = mono_poll (pfd, 1, 0);
140 if (ret == -1 && errno == EBADF) {
141 pfd->revents |= MONO_POLLNVAL;
143 } else if (ret == 1) {
152 tp_poll_wait (gpointer p)
154 #if MONO_SMALL_CONFIG
155 #define INITIAL_POLLFD_SIZE 128
157 #define INITIAL_POLLFD_SIZE 1024
159 #define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
161 #ifdef DISABLE_SOCKETS
162 #define socket_io_cleanup(x)
169 SocketIOData *socket_io_data = p;
170 MonoPtrArray async_results;
173 data = socket_io_data->event_data;
174 allocated = INITIAL_POLLFD_SIZE;
175 pfds = g_new0 (mono_pollfd, allocated);
176 mono_ptr_array_init (async_results, allocated * 2);
177 INIT_POLLFD (pfds, data->pipe [0], MONO_POLLIN);
178 for (i = 1; i < allocated; i++)
179 INIT_POLLFD (&pfds [i], -1, 0);
188 mono_gc_set_skip_thread (TRUE);
192 check_for_interruption_critical ();
195 nsock = mono_poll (pfds, maxfd, -1);
196 } while (nsock == -1 && errno == EINTR);
198 mono_gc_set_skip_thread (FALSE);
201 * Apart from EINTR, we only check EBADF, for the rest:
202 * EINVAL: mono_poll() 'protects' us from descriptor
203 * numbers above the limit if using select() by marking
204 * then as MONO_POLLERR. If a system poll() is being
205 * used, the number of descriptor we're passing will not
206 * be over sysconf(_SC_OPEN_MAX), as the error would have
207 * happened when opening.
209 * EFAULT: we own the memory pointed by pfds.
210 * ENOMEM: we're doomed anyway
214 if (nsock == -1 && errno == EBADF) {
215 pfds->revents = 0; /* Just in case... */
216 nsock = mark_bad_fds (pfds, maxfd);
219 if ((pfds->revents & POLL_ERRORS) != 0) {
220 /* We're supposed to die now, as the pipe has been closed */
222 mono_ptr_array_destroy (async_results);
223 socket_io_cleanup (socket_io_data);
227 /* Got a new socket */
228 if ((pfds->revents & MONO_POLLIN) != 0) {
230 gboolean found = FALSE;
232 for (i = 1; i < allocated; i++) {
234 if (pfd->fd == data->newpfd.fd) {
241 for (i = 1; i < allocated; i++) {
248 if (i == allocated) {
253 allocated = allocated * 2;
254 pfds = g_renew (mono_pollfd, oldfd, allocated);
256 for (; i < allocated; i++)
257 INIT_POLLFD (&pfds [i], -1, 0);
258 //async_results = g_renew (gpointer, async_results, allocated * 2);
261 nread = read (data->pipe [0], one, 1);
263 nread = recv ((SOCKET) data->pipe [0], one, 1, 0);
267 mono_ptr_array_destroy (async_results);
268 return; /* we're closed */
271 INIT_POLLFD (&pfds [i], data->newpfd.fd, data->newpfd.events);
272 memset (&data->newpfd, 0, sizeof (mono_pollfd));
273 MONO_SEM_POST (&data->new_sem);
282 mono_mutex_lock (&socket_io_data->io_lock);
283 if (socket_io_data->inited == 3) {
285 mono_ptr_array_destroy (async_results);
286 mono_mutex_unlock (&socket_io_data->io_lock);
287 return; /* cleanup called */
291 mono_ptr_array_clear (async_results);
293 for (i = 1; i < maxfd && nsock > 0; i++) {
295 if (pfd->fd == -1 || pfd->revents == 0)
299 list = mono_g_hash_table_lookup (socket_io_data->sock_to_state, GINT_TO_POINTER (pfd->fd));
300 if (list != NULL && (pfd->revents & (MONO_POLLIN | POLL_ERRORS)) != 0) {
301 ares = get_io_event (&list, MONO_POLLIN);
303 mono_ptr_array_append (async_results, ares);
308 if (list != NULL && (pfd->revents & (MONO_POLLOUT | POLL_ERRORS)) != 0) {
309 ares = get_io_event (&list, MONO_POLLOUT);
311 mono_ptr_array_append (async_results, ares);
317 mono_g_hash_table_replace (socket_io_data->sock_to_state, GINT_TO_POINTER (pfd->fd), list);
318 pfd->events = get_events_from_list (list);
320 mono_g_hash_table_remove (socket_io_data->sock_to_state, GINT_TO_POINTER (pfd->fd));
326 mono_mutex_unlock (&socket_io_data->io_lock);
327 threadpool_append_async_io_jobs ((MonoObject **) async_results.data, nresults);
328 mono_ptr_array_clear (async_results);