aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2011-08-15 09:18:27 +0000
committerChristian Grothoff <christian@grothoff.org>2011-08-15 09:18:27 +0000
commitee499cde2f179375c1f897564a16100052388cd3 (patch)
tree1eedc65143cb963a11477ce7da169b742d58e197
parent9901656e38b2849d5588a585312984e3e84dbe73 (diff)
downloadgnunet-gtk-ee499cde2f179375c1f897564a16100052388cd3.tar.gz
gnunet-gtk-ee499cde2f179375c1f897564a16100052388cd3.zip
LRN: scheduler compatible select on top of g_poll for improved W32 portability
-rw-r--r--src/gnunet-gtk.c667
1 files changed, 559 insertions, 108 deletions
diff --git a/src/gnunet-gtk.c b/src/gnunet-gtk.c
index fc5916f0..0784432a 100644
--- a/src/gnunet-gtk.c
+++ b/src/gnunet-gtk.c
@@ -138,8 +138,551 @@ struct MainContext
138 */ 138 */
139 gint max_priority; 139 gint max_priority;
140 140
141#if WINDOWS
142 /**
143 * Array to hold pipe handles during a select() call
144 */
145 struct GNUNET_DISK_FileHandle **read_array;
146
147 /**
148 * Allocated length of read_array
149 */
150 int read_array_length;
151
152 /**
153 * Event to fire when a socket is ready for reading
154 */
155 HANDLE hEventRead;
156
157 /**
158 * Event to fire when a socket is ready for writing
159 */
160 HANDLE hEventWrite;
161
162 /**
163 * Event to fire when a socket had an error
164 */
165 HANDLE hEventException;
166
167 /**
168 * Event that is permanently enabled and is used to signal a pipe
169 * that is ready for writing (asynchronous pipes are always writable)
170 */
171 HANDLE hEventPipeWrite;
172
173 /**
174 * Event that is permanently enabled and is used to signal a pipe
175 * that is ready for reading (used to wake up early on a pipe that
176 * is known to be readable)
177 */
178 HANDLE hEventReadReady;
179
180 /**
181 * A list to hold file handles that are ready for reading
182 */
183 struct GNUNET_CONTAINER_SList *handles_read;
184
185 /**
186 * A list to hold file handles that are ready for writing
187 */
188 struct GNUNET_CONTAINER_SList *handles_write;
189
190 /**
191 * A list to hold file handles that are broken
192 */
193 struct GNUNET_CONTAINER_SList *handles_except;
194#endif
141}; 195};
142 196
197static void
198gnunet_gtk_dispatch_task (void *cls,
199 const struct GNUNET_SCHEDULER_TaskContext *tc)
200{
201 struct MainContext *mc = (struct MainContext *) cls;
202 g_main_context_dispatch (mc->gmc);
203}
204
205#ifndef FD_COPY
206#define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set)))
207#endif
208
209int
210gnunet_gtk_select (void *cls,
211 struct GNUNET_NETWORK_FDSet *rfds,
212 struct GNUNET_NETWORK_FDSet *wfds,
213 struct GNUNET_NETWORK_FDSet *efds,
214 const struct GNUNET_TIME_Relative timeout)
215{
216 struct MainContext *mc = (struct MainContext *) cls;
217 int max_nfds;
218 gint poll_result;
219
220 GPollFD *gfds;
221 gint delay;
222
223 guint i;
224 guint fd_counter = 0;
225
226 guint allocated_nfds, need_gfds;
227
228 fd_set aread, awrite, aexcept;
229
230#if WINDOWS
231 int always_ready_write_fd = -1;
232 int sock_read = 0, sock_write = 0, sock_err = 0, socks = 0;
233
234 int pre_ret = 0;
235 int select_ret = 0;
236 int result = 0;
237
238 int read_handles = 0;
239 DWORD waitstatus;
240#endif
241
242 FD_ZERO (&aread);
243 FD_ZERO (&awrite);
244 FD_ZERO (&aexcept);
245 if (rfds)
246 FD_COPY (&rfds->sds, &aread);
247 if (wfds)
248 FD_COPY (&wfds->sds, &awrite);
249 if (efds)
250 FD_COPY (&efds->sds, &aexcept);
251
252#if WINDOWS
253 ResetEvent (mc->hEventRead);
254 ResetEvent (mc->hEventWrite);
255 ResetEvent (mc->hEventException);
256
257 GNUNET_CONTAINER_slist_clear (mc->handles_read);
258 GNUNET_CONTAINER_slist_clear (mc->handles_write);
259 GNUNET_CONTAINER_slist_clear (mc->handles_except);
260#endif
261
262 if (TRUE != g_main_loop_is_running (mc->gml))
263 return GNUNET_NETWORK_socket_select (rfds, wfds, efds, timeout);
264
265 if (rfds != NULL)
266 max_nfds = rfds->nsds;
267 else
268 max_nfds = -1;
269 if (wfds != NULL && max_nfds < wfds->nsds)
270 max_nfds = wfds->nsds;
271 if (efds != NULL && max_nfds < efds->nsds)
272 max_nfds = efds->nsds;
273
274 allocated_nfds = mc->cached_poll_array_size;
275 gfds = mc->cached_poll_array;
276 if (allocated_nfds == 0)
277 {
278 /* TODO: get some statistics, find the maximum number of fds ever
279 * polled during normal gnunet-gtk operation, and set this to that number.
280 */
281 mc->cached_poll_array = gfds = g_new (GPollFD, 30);
282 mc->cached_poll_array_size = allocated_nfds = 30;
283 }
284
285 while (1)
286 {
287 fd_counter = 0;
288#if !WINDOWS
289 gboolean need_realloc = FALSE;
290 for (i = 0; !need_realloc && i < max_nfds; i += 1)
291 {
292 int isset[3];
293 isset[0] = FD_ISSET (i, &rfds->sds);
294 isset[1] = FD_ISSET (i, &wfds->sds);
295 isset[2] = FD_ISSET (i, &efds->sds);
296 if (!isset[0] && !isset[1] && !isset[2])
297 continue;
298 if (fd_counter >= allocated_nfds)
299 {
300 need_realloc = TRUE;
301 break;
302 }
303 gfds[fd_counter].fd = i;
304 gfds[fd_counter].events = (isset[0] ? G_IO_IN | G_IO_HUP | G_IO_ERR : 0)
305 | (isset[1] ? G_IO_OUT | G_IO_ERR : 0) | (issed[2] ? G_IO_ERR : 0);
306 fd_counter += 1;
307 }
308 if (need_realloc)
309 {
310 mc->cached_poll_array = fds = g_renew (GPollFD, fds, mc->cached_poll_array_size * 2);
311 mc->cached_poll_array_size = allocated_nfds = nfds;
312 fd_counter = 0;
313 need_realloc = FALSE;
314 }
315 else
316 break;
317#else
318 struct GNUNET_CONTAINER_SList_Iterator *t;
319 /* We might overshoot a little, but that won't hurt very much */
320 int need_nfds = (rfds->sds.fd_count + rfds->sds.fd_count + rfds->sds.fd_count > 0 ? 3 : 0)
321 + (rfds == NULL ? 0 : GNUNET_CONTAINER_slist_count (rfds->handles))
322 + (wfds == NULL ? 0 : 1)
323 + 1;
324 if (need_nfds >= allocated_nfds)
325 {
326 /* Since there are also gmainloop's own fds, just need_nfds won't be
327 * enough, so make it twice as long.
328 */
329 mc->cached_poll_array = gfds = g_renew (GPollFD, gfds, need_nfds * 2);
330 mc->cached_poll_array_size = allocated_nfds = need_nfds * 2;
331 }
332 if (mc->read_array_length < GNUNET_CONTAINER_slist_count (rfds->handles))
333 {
334 mc->read_array = GNUNET_realloc (mc->read_array, GNUNET_CONTAINER_slist_count (rfds->handles) * sizeof (struct GNUNET_DISK_FileHandle *));
335 mc->read_array_length = GNUNET_CONTAINER_slist_count (rfds->handles);
336 }
337 if (rfds != NULL)
338 {
339 for (t = GNUNET_CONTAINER_slist_begin (rfds->handles), i = 0;
340 GNUNET_CONTAINER_slist_end (t) != GNUNET_YES;
341 GNUNET_CONTAINER_slist_next (t), i += 1)
342 {
343 struct GNUNET_DISK_FileHandle *fh;
344 fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (t, NULL);
345 if (fh->type == GNUNET_PIPE)
346 {
347 if (!ReadFile (fh->h, NULL, 0, NULL, fh->oOverlapRead))
348 {
349 DWORD error_code = GetLastError();
350 if (error_code == ERROR_IO_PENDING)
351 {
352#if DEBUG_NETWORK
353 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding the pipe's 0x%x overlapped event to the array as %d\n", fh->h, nhandles);
354#endif
355 gfds[fd_counter].fd = (intptr_t) fh->oOverlapRead->hEvent;
356 /* On W32 .events makes no sense - g_poll will just OR its
357 * contents into .revents when the .fd event fires.
358 * So we'll use it in the way that suits us the best.
359 */
360 gfds[fd_counter].events = G_IO_IN;
361 fd_counter += 1;
362 mc->read_array[read_handles] = fh;
363 read_handles += 1;
364 }
365 else
366 {
367 gfds[fd_counter].fd = (intptr_t) mc->hEventReadReady;
368 gfds[fd_counter].events = G_IO_HUP;
369 fd_counter += 1;
370 mc->read_array[read_handles] = fh;
371 read_handles += 1;
372 }
373 }
374 else
375 {
376#if DEBUG_NETWORK
377 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding the read ready event to the array as %d\n", nhandles);
378#endif
379 gfds[fd_counter].fd = (intptr_t) mc->hEventReadReady;
380 gfds[fd_counter].events = G_IO_IN;
381 fd_counter += 1;
382 mc->read_array[read_handles] = fh;
383 read_handles += 1;
384 }
385 }
386 else
387 {
388 GNUNET_CONTAINER_slist_add (mc->handles_read,
389 GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
390 fh, sizeof (struct GNUNET_DISK_FileHandle));
391 pre_ret += 1;
392 }
393 }
394 }
395 if (wfds != NULL && GNUNET_CONTAINER_slist_count (wfds->handles) > 0)
396 {
397 gfds[fd_counter].fd = (intptr_t) mc->hEventPipeWrite;
398 gfds[fd_counter].events = G_IO_OUT;
399 always_ready_write_fd = fd_counter;
400 fd_counter += 1;
401 }
402 if (efds != NULL)
403 {
404 for (t = GNUNET_CONTAINER_slist_begin (efds->handles), i = 0;
405 GNUNET_CONTAINER_slist_end (t) != GNUNET_YES;
406 GNUNET_CONTAINER_slist_next (t), i += 1)
407 {
408 struct GNUNET_DISK_FileHandle *fh;
409 DWORD dwBytes;
410 fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (t, NULL);
411 if (fh->type == GNUNET_PIPE)
412 {
413 if (!PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
414 {
415 GNUNET_CONTAINER_slist_add (mc->handles_except,
416 GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
417 fh, sizeof (struct GNUNET_DISK_FileHandle));
418 pre_ret += 1;
419 }
420 }
421 }
422 }
423 GNUNET_CONTAINER_slist_iter_destroy (t);
424
425 if (rfds != NULL && rfds->sds.fd_count > 0)
426 {
427#if DEBUG_NETWORK
428 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding the socket read event to the array as %d\n", fd_counter);
429#endif
430 gfds[fd_counter].fd = (intptr_t) mc->hEventRead;
431 gfds[fd_counter].events = G_IO_IN;
432 for (i = 0; i < rfds->sds.fd_count; i++)
433 WSAEventSelect (rfds->sds.fd_array[i], mc->hEventRead, FD_ACCEPT | FD_READ | FD_CLOSE);
434 fd_counter += 1;
435 sock_read = rfds->sds.fd_count;
436 }
437 if (wfds != NULL && wfds->sds.fd_count > 0)
438 {
439 int wakeup = 0;
440#if DEBUG_NETWORK
441 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding the socket write event to the array as %d\n", fd_counter);
442#endif
443 gfds[fd_counter].fd = (intptr_t) mc->hEventWrite;
444 gfds[fd_counter].events = G_IO_OUT;
445 for (i = 0; i < wfds->sds.fd_count; i++)
446 {
447 DWORD error;
448 int status;
449 status = send (wfds->sds.fd_array[i], NULL, 0, 0);
450 error = GetLastError ();
451#if DEBUG_NETWORK
452 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pre-send to the socket %d returned %d (%u)\n", i, status, error);
453#endif
454 if (status == 0 || (error != WSAEWOULDBLOCK && error != WSAENOTCONN))
455 wakeup = 1;
456 WSAEventSelect (wfds->sds.fd_array[i], mc->hEventWrite, FD_WRITE | FD_CONNECT | FD_CLOSE);
457 }
458 if (wakeup)
459 SetEvent (mc->hEventWrite);
460 fd_counter += 1;
461 sock_write = wfds->sds.fd_count;
462 }
463 if (efds != NULL && efds->sds.fd_count > 0)
464 {
465#if DEBUG_NETWORK
466 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding the socket error event to the array as %d\n", fd_counter);
467#endif
468 gfds[fd_counter].fd = (intptr_t) mc->hEventException;
469 gfds[fd_counter].events = G_IO_ERR;
470 for (i = 0; i < efds->sds.fd_count; i++)
471 WSAEventSelect (efds->sds.fd_array[i], mc->hEventException, FD_OOB | FD_CLOSE);
472 fd_counter += 1;
473 sock_err = efds->sds.fd_count;
474 }
475 break;
476 }
477 socks = sock_read + sock_write + sock_err;
478#endif
479
480 g_main_context_prepare (mc->gmc, &mc->max_priority);
481 while (allocated_nfds < (need_gfds = g_main_context_query (mc->gmc,
482 mc->max_priority, &delay, &gfds[fd_counter], allocated_nfds - fd_counter)))
483 {
484 mc->cached_poll_array = gfds = g_renew (GPollFD, gfds, allocated_nfds - fd_counter + need_gfds);
485 mc->cached_poll_array_size = allocated_nfds = allocated_nfds - fd_counter + need_gfds;
486 }
487 mc->poll_array_active = fd_counter + need_gfds;
488
489 if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
490 {
491 if (delay >= 0)
492 delay = MIN(timeout.rel_value / GNUNET_TIME_UNIT_MILLISECONDS.rel_value, delay);
493 else
494 delay = timeout.rel_value / GNUNET_TIME_UNIT_MILLISECONDS.rel_value;
495 }
496
497 if (pre_ret > 0)
498 {
499#if DEBUG_NETWORK
500 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pre_ret is %d, setting delay to 0\n", pre_ret);
501#endif
502 delay = 0;
503 }
504
505#if DEBUG_NETWORK
506 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "We have %d of our FDs and %d of GMC ones, going to wait %6dms\n", fd_counter, need_gfds, delay);
507#endif
508
509 poll_result = g_poll (gfds, fd_counter + need_gfds, delay);
510
511#if DEBUG_NETWORK
512 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "g_poll returned : %d\n", poll_result);
513#endif
514
515 /* Take care of GUI events.
516 * Dispatching the events here will eventually crash the scheduler, must do this
517 * from within a task (currently we're not in a task, but in a select() call, remember)
518 * Startup reason is used to pass the scheduler sanity check.
519 */
520 if (TRUE == g_main_context_check (mc->gmc, mc->max_priority, &gfds[fd_counter], need_gfds))
521 GNUNET_SCHEDULER_add_continuation (gnunet_gtk_dispatch_task, mc, GNUNET_SCHEDULER_REASON_STARTUP);
522
523#if !WINDOWS
524 if (rfds)
525 FD_ZERO (rfds);
526 if (wfds)
527 FD_ZERO (wfds);
528 if (efds)
529 FD_ZERO (efds);
530 for (i = 0; i < fd_counter; i++)
531 {
532 int set[3];
533 if (set[0] = FD_ISSET (gfds[i].fd, &aread))
534 FD_SET (gfds[i].fd, rfds->sds);
535 if (set[1] = FD_ISSET (gfds[i].fd, &awrite))
536 FD_SET (gfds[i].fd, wfds->sds);
537 if (set[2] = FD_ISSET (gfds[i].fd, &aexcept))
538 FD_SET (gfds[i].fd, efds->sds);
539 if (set[0] || set[1] || set[2])
540 result += 1;
541 }
542#else
543 if (socks > 0)
544 {
545 struct timeval tvslice;
546 tvslice.tv_sec = 0;
547 tvslice.tv_usec = 0;
548 select_ret = select (max_nfds, &aread, &awrite, &aexcept, &tvslice);
549 if (select_ret == -1)
550 select_ret = 0;
551#if DEBUG_NETWORK
552 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "select() returned %d\n", select_ret);
553#endif
554 }
555 if (always_ready_write_fd >= 0 && gfds[always_ready_write_fd].revents & G_IO_OUT)
556 {
557 GNUNET_CONTAINER_slist_append (mc->handles_write, wfds->handles);
558 result += GNUNET_CONTAINER_slist_count (mc->handles_write);
559#if DEBUG_NETWORK
560 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added write pipe\n");
561#endif
562 }
563 for (i = 0; i < read_handles; i++)
564 {
565 DWORD error;
566 BOOL bret;
567 if (!(gfds[i].revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)))
568 continue;
569 SetLastError (0);
570 waitstatus = 0;
571 bret = PeekNamedPipe (mc->read_array[i]->h, NULL, 0, NULL, &waitstatus, NULL);
572 error = GetLastError ();
573#if DEBUG_NETWORK
574 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peek at read pipe %d (0x%x) returned %d (%d bytes available) GLE %u\n", i, mc->read_array[i]->h, bret, waitstatus, error);
575#endif
576 if (bret == 0 || (gfds[i].revents & G_IO_ERR))
577 {
578 if (efds != NULL)
579 {
580 struct GNUNET_CONTAINER_SList_Iterator *t;
581 for (t = GNUNET_CONTAINER_slist_begin (efds->handles), i = 0;
582 GNUNET_CONTAINER_slist_end (t) != GNUNET_YES;
583 GNUNET_CONTAINER_slist_next (t), i += 1)
584 {
585 struct GNUNET_DISK_FileHandle *fh;
586 fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (t, NULL);
587 if (fh == mc->read_array[i])
588 {
589 GNUNET_CONTAINER_slist_add (mc->handles_except,
590 GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
591 fh, sizeof (struct GNUNET_DISK_FileHandle));
592 break;
593 }
594 }
595 GNUNET_CONTAINER_slist_iter_destroy (t);
596 }
597 }
598 else if (waitstatus <= 0)
599 continue;
600 GNUNET_CONTAINER_slist_add (mc->handles_read,
601 GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
602 mc->read_array[i], sizeof (struct GNUNET_DISK_FileHandle));
603 result += 1;
604#if DEBUG_NETWORK
605 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added read Pipe 0x%x (0x%x)\n", mc->read_array[i], mc->read_array[i]->h);
606#endif
607 }
608 waitstatus = WaitForSingleObject (mc->hEventWrite, 0);
609#if DEBUG_NETWORK
610 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Wait for the write event returned %d\n", waitstatus);
611#endif
612 if (waitstatus == WAIT_OBJECT_0)
613 {
614 for (i = 0; i < wfds->sds.fd_count; i++)
615 {
616 DWORD error;
617 int status;
618 int so_error = 0;
619 int sizeof_so_error = sizeof (so_error);
620 int gso_result = getsockopt (wfds->sds.fd_array[i], SOL_SOCKET, SO_ERROR, (char *) &so_error, &sizeof_so_error);
621 status = send (wfds->sds.fd_array[i], NULL, 0, 0);
622 error = GetLastError ();
623#if DEBUG_NETWORK
624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "send to the socket %d returned %d (%u)\n", i, status, error);
625#endif
626 if (status == 0
627 || (error != WSAEWOULDBLOCK && error != WSAENOTCONN)
628 || (status == -1 && gso_result == 0 && error == WSAENOTCONN && so_error == WSAECONNREFUSED))
629 {
630 FD_SET (wfds->sds.fd_array[i], &awrite);
631 result += 1;
632 }
633 }
634 }
635 if (rfds)
636 {
637 struct GNUNET_CONTAINER_SList_Iterator *t;
638 for (i = 0; i < rfds->sds.fd_count; i++)
639 WSAEventSelect (rfds->sds.fd_array[i], mc->hEventRead, 0);
640 for (t = GNUNET_CONTAINER_slist_begin (rfds->handles);
641 GNUNET_CONTAINER_slist_end (t) != GNUNET_YES;
642 GNUNET_CONTAINER_slist_next (t))
643 {
644 struct GNUNET_DISK_FileHandle *fh;
645 fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (t, NULL);
646 if (fh->type == GNUNET_PIPE)
647 CancelIo (fh->h);
648 }
649 GNUNET_CONTAINER_slist_iter_destroy (t);
650 GNUNET_NETWORK_fdset_zero (rfds);
651 if (select_ret != -1 && socks > 0)
652 GNUNET_NETWORK_fdset_copy_native (rfds, &aread, select_ret);
653 GNUNET_CONTAINER_slist_append (rfds->handles, mc->handles_read);
654 }
655 if (wfds)
656 {
657 for (i = 0; i < wfds->sds.fd_count; i++)
658 WSAEventSelect (wfds->sds.fd_array[i], mc->hEventWrite, 0);
659 GNUNET_NETWORK_fdset_zero (wfds);
660 if (select_ret != -1 && socks > 0)
661 GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, select_ret);
662 GNUNET_CONTAINER_slist_append (wfds->handles, mc->handles_write);
663 }
664 if (efds)
665 {
666 for (i = 0; i < efds->sds.fd_count; i++)
667 WSAEventSelect (efds->sds.fd_array[i], mc->hEventException, 0);
668 GNUNET_NETWORK_fdset_zero (efds);
669 if (select_ret != -1 && socks > 0)
670 GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, select_ret);
671 GNUNET_CONTAINER_slist_append (efds->handles, mc->handles_except);
672 result += GNUNET_CONTAINER_slist_count (mc->handles_except);
673 }
674 if (fd_counter > 0)
675 /* This is not accurate (select_ret counts write-ready sockets,
676 * and result does as well. Anything out there actually cares
677 * about this?
678 */
679 return select_ret + result;
680 else
681 return 0;
682#endif
683 return result;
684}
685
143 686
144/** 687/**
145 * Get the name of the directory where all of our package 688 * Get the name of the directory where all of our package
@@ -178,112 +721,6 @@ free_context (struct MainContext *context)
178 GNUNET_free (context); 721 GNUNET_free (context);
179} 722}
180 723
181
182/**
183 * Run GTK tasks that are ready.
184 *
185 * @param cls the 'struct MainContext'
186 * @param tc task context
187 */
188static void
189run_ready (void *cls,
190 const struct GNUNET_SCHEDULER_TaskContext *tc);
191
192
193/**
194 * Schedule the main GTK Event loop with the GNUnet scheduler.
195 *
196 * @param cls the 'struct MainContext'
197 * @param tc task context
198 */
199static void
200schedule_main_loop (void *cls,
201 const struct GNUNET_SCHEDULER_TaskContext *tc)
202{
203 struct MainContext *mc = cls;
204 struct GNUNET_TIME_Relative delay;
205 gint timeout;
206 gint nfds;
207 GPollFD *fds;
208 guint allocated_nfds;
209
210 if ( (tc != NULL) &&
211 (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) )
212 {
213 g_main_loop_quit (mc->gml);
214 GNUNET_SCHEDULER_add_now (&schedule_main_loop,
215 mc);
216 return;
217 }
218 if (TRUE != g_main_loop_is_running (mc->gml))
219 return;
220 g_main_context_prepare (mc->gmc, &mc->max_priority);
221 allocated_nfds = mc->cached_poll_array_size;
222 fds = mc->cached_poll_array;
223 while ((nfds = g_main_context_query (mc->gmc, mc->max_priority,
224 &timeout, fds,
225 allocated_nfds)) > allocated_nfds)
226 {
227 g_free (fds);
228 mc->cached_poll_array_size = allocated_nfds = nfds;
229 mc->cached_poll_array = fds = g_new (GPollFD, nfds);
230 }
231 mc->poll_array_active = nfds;
232 delay.rel_value = (uint64_t) timeout;
233 GNUNET_NETWORK_fdset_zero (mc->rs);
234 GNUNET_NETWORK_fdset_zero (mc->ws);
235 while (nfds > 0)
236 {
237 nfds--;
238#ifdef __MINGW32__
239 /* TODO: maybe #ifdef WINDOWS? -ndurner */
240 if (fds[nfds].events & (G_IO_IN | G_IO_HUP | G_IO_ERR))
241 GNUNET_NETWORK_fdset_set_native_w32_handle (mc->rs, (HANDLE) fds[nfds].fd);
242 if (fds[nfds].events & (G_IO_OUT | G_IO_ERR))
243 GNUNET_NETWORK_fdset_set_native_w32_handle (mc->ws, (HANDLE) fds[nfds].fd);
244#else
245 if (fds[nfds].events & (G_IO_IN | G_IO_HUP | G_IO_ERR))
246 GNUNET_NETWORK_fdset_set_native (mc->rs, fds[nfds].fd);
247 if (fds[nfds].events & (G_IO_OUT | G_IO_ERR))
248 GNUNET_NETWORK_fdset_set_native (mc->ws, fds[nfds].fd);
249#endif
250 }
251 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_UI,
252 GNUNET_SCHEDULER_NO_TASK,
253 delay,
254 mc->rs,
255 mc->ws,
256 &run_ready,
257 mc);
258}
259
260
261/**
262 * Run GTK tasks that are ready.
263 *
264 * @param cls the 'struct MainContext'
265 * @param tc task context
266 */
267static void
268run_ready (void *cls,
269 const struct GNUNET_SCHEDULER_TaskContext *tc)
270{
271 struct MainContext *mc = cls;
272
273 g_poll (mc->cached_poll_array,
274 mc->poll_array_active,
275 0);
276 if (TRUE ==
277 g_main_context_check (mc->gmc,
278 mc->max_priority,
279 mc->cached_poll_array,
280 mc->poll_array_active))
281 g_main_context_dispatch (mc->gmc);
282 GNUNET_SCHEDULER_add_now (&schedule_main_loop,
283 mc);
284}
285
286
287/** 724/**
288 * Main context (global so we can free it on exit and use 725 * Main context (global so we can free it on exit and use
289 * it for termination). 726 * it for termination).
@@ -562,6 +999,21 @@ run (void *cls,
562 if (mc->builder == NULL) 999 if (mc->builder == NULL)
563 return; 1000 return;
564 1001
1002#if WINDOWS
1003 mc->hEventRead = CreateEvent (NULL, TRUE, FALSE, NULL);
1004 mc->hEventReadReady = CreateEvent (NULL, TRUE, TRUE, NULL);
1005 mc->hEventWrite = CreateEvent (NULL, TRUE, FALSE, NULL);
1006 mc->hEventException = CreateEvent (NULL, TRUE, FALSE, NULL);
1007
1008 mc->hEventPipeWrite = CreateEvent (NULL, TRUE, TRUE, NULL);
1009
1010 mc->handles_read = GNUNET_CONTAINER_slist_create ();
1011 mc->handles_write = GNUNET_CONTAINER_slist_create ();
1012 mc->handles_except = GNUNET_CONTAINER_slist_create ();
1013 mc->read_array = NULL;
1014 mc->read_array_length = 0;
1015#endif
1016
565 /* setup tray icon */ 1017 /* setup tray icon */
566 tray_icon = create_tray_icon(); 1018 tray_icon = create_tray_icon();
567 1019
@@ -618,7 +1070,7 @@ run (void *cls,
618 } 1070 }
619 /* start the event loop */ 1071 /* start the event loop */
620 GNUNET_assert (TRUE == g_main_context_acquire (mc->gmc)); 1072 GNUNET_assert (TRUE == g_main_context_acquire (mc->gmc));
621 schedule_main_loop (mc, NULL); 1073 GNUNET_SCHEDULER_set_select (gnunet_gtk_select, mc);
622} 1074}
623 1075
624 1076
@@ -634,7 +1086,6 @@ GNUNET_GTK_get_main_window_object (const char *name)
634 return gtk_builder_get_object (mc->builder, name); 1086 return gtk_builder_get_object (mc->builder, name);
635} 1087}
636 1088
637
638int 1089int
639main (int argc, char *const *argv) 1090main (int argc, char *const *argv)
640{ 1091{