aboutsummaryrefslogtreecommitdiff
path: root/src/lib/eventloop.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/eventloop.c')
-rw-r--r--src/lib/eventloop.c348
1 files changed, 0 insertions, 348 deletions
diff --git a/src/lib/eventloop.c b/src/lib/eventloop.c
index 84ad3974..5dc971c1 100644
--- a/src/lib/eventloop.c
+++ b/src/lib/eventloop.c
@@ -36,11 +36,7 @@
36 * For non-Windows OSes, that is. For Windows it's always 64, because 36 * For non-Windows OSes, that is. For Windows it's always 64, because
37 * that's the limit anyway. 37 * that's the limit anyway.
38 */ 38 */
39#ifdef WINDOWS
40#define INITIAL_POLL_ARRAY_SIZE 64
41#else
42#define INITIAL_POLL_ARRAY_SIZE 30 39#define INITIAL_POLL_ARRAY_SIZE 30
43#endif
44 40
45/** 41/**
46 * Main context for our event loop. 42 * Main context for our event loop.
@@ -118,60 +114,6 @@ struct GNUNET_GTK_MainLoop
118 */ 114 */
119 int argc; 115 int argc;
120 116
121#if WINDOWS
122 /**
123 * Array to hold pipe handles during a select() call
124 */
125 struct GNUNET_DISK_FileHandle **read_array;
126
127 /**
128 * Allocated length of read_array
129 */
130 int read_array_length;
131
132 /**
133 * Event to fire when a socket is ready for reading
134 */
135 HANDLE hEventRead;
136
137 /**
138 * Event to fire when a socket is ready for writing
139 */
140 HANDLE hEventWrite;
141
142 /**
143 * Event to fire when a socket had an error
144 */
145 HANDLE hEventException;
146
147 /**
148 * Event that is permanently enabled and is used to signal a pipe
149 * that is ready for writing (asynchronous pipes are always writable)
150 */
151 HANDLE hEventPipeWrite;
152
153 /**
154 * Event that is permanently enabled and is used to signal a pipe
155 * that is ready for reading (used to wake up early on a pipe that
156 * is known to be readable)
157 */
158 HANDLE hEventReadReady;
159
160 /**
161 * A list to hold file handles that are ready for reading
162 */
163 struct GNUNET_CONTAINER_SList *handles_read;
164
165 /**
166 * A list to hold file handles that are ready for writing
167 */
168 struct GNUNET_CONTAINER_SList *handles_write;
169
170 /**
171 * A list to hold file handles that are broken
172 */
173 struct GNUNET_CONTAINER_SList *handles_except;
174#endif
175}; 117};
176 118
177 119
@@ -365,295 +307,6 @@ keepalive_task (void *cls)
365} 307}
366 308
367 309
368#ifdef WINDOWS
369/**
370 * FIXME.
371 */
372struct _select_params_gtk
373{
374 /**
375 * Read set.
376 */
377 struct GNUNET_NETWORK_FDSet *rfds;
378
379 /**
380 * Write set.
381 */
382 struct GNUNET_NETWORK_FDSet *wfds;
383
384 /**
385 * Except set.
386 */
387 struct GNUNET_NETWORK_FDSet *efds;
388
389 /**
390 * Timeout for select().
391 */
392 struct GNUNET_TIME_Relative timeout;
393
394 /**
395 * FIXME.
396 */
397 HANDLE event_to_that_wakes_us_up;
398
399 /**
400 * FIXME.
401 */
402 HANDLE event_to_signal_we_woke_up;
403
404 /**
405 * FIXME.
406 */
407 HANDLE event_to_wait_for_a_job;
408
409 /**
410 * Set to return value from select.
411 */
412 int status;
413};
414
415static unsigned __stdcall _gnunet_selector_thread (void *p)
416{
417 struct _select_params_gtk *sp = p;
418
419 while (1)
420 {
421 WaitForSingleObject (sp->event_to_wait_for_a_job, INFINITE);
422 ResetEvent (sp->event_to_wait_for_a_job);
423 sp->status =
424 GNUNET_NETWORK_socket_select (sp->rfds, sp->wfds, sp->efds, sp->timeout);
425 SetEvent (sp->event_to_signal_we_woke_up);
426 }
427 return 0;
428}
429
430
431static int
432handle_gui_events (struct GNUNET_GTK_MainLoop *ml,
433 gint max_priority,
434 gint need_gfds)
435{
436 /* Take care of GUI events.
437 * Dispatching the events here will eventually crash the scheduler, must do this
438 * from within a task (currently we're not in a task, but in a select() call, remember)
439 * Startup reason is used to pass the scheduler sanity check.
440 */
441 if (NULL == ml->gmc)
442 return GNUNET_NO;
443 if (g_main_context_check (ml->gmc,
444 max_priority,
445 ml->cached_poll_array,
446 need_gfds))
447 {
448 GNUNET_SCHEDULER_add_with_reason_and_priority (&dispatch_gtk_task,
449 ml,
450 GNUNET_SCHEDULER_REASON_STARTUP,
451 GNUNET_SCHEDULER_PRIORITY_UI);
452 return GNUNET_YES;
453 }
454 return GNUNET_NO;
455}
456
457
458/**
459 * Replacement for the GNUnet scheduler's "select" that integrates the
460 * Gtk event loop. We run g_poll() in the main thread and run
461 * GNUnet's own select() in a separate thread in parallel.
462 * Then we process the Gtk events (by adding a task to do so to the GNUnet
463 * scheduler), and, if applicable, return the GNUnet-scheduler events back
464 * to GNUnet.
465 *
466 * @param cls the 'struct GNUNET_GTK_MainLoop'
467 * @param rfds set of sockets to be checked for readability
468 * @param wfds set of sockets to be checked for writability
469 * @param efds set of sockets to be checked for exceptions
470 * @param timeout relative value when to return
471 * @return number of selected sockets, GNUNET_SYSERR on error
472 */
473static int
474gnunet_gtk_select (void *cls,
475 struct GNUNET_NETWORK_FDSet *rfds,
476 struct GNUNET_NETWORK_FDSet *wfds,
477 struct GNUNET_NETWORK_FDSet *efds,
478 const struct GNUNET_TIME_Relative timeout)
479{
480 struct GNUNET_GTK_MainLoop *ml = cls;
481 int gnunet_select_result;
482 struct GNUNET_TIME_Relative timeout_from_delay;
483 gint delay;
484 gint need_gfds;
485 gint max_priority;
486 gint g_poll_result;
487 DWORD wait_result;
488
489 static struct GNUNET_NETWORK_FDSet *standin_rfds;
490 static HANDLE wakeup_event_for_gnunet;
491 static HANDLE gnunet_woke_up_event;
492 static HANDLE gnunet_selector_thread_job_event;
493 static struct GNUNET_DISK_FileHandle *wakeup_event_for_gnunet_fh;
494 static struct _select_params_gtk *sp;
495
496 /* To be safe, we do g_poll in the main thread (MSDN does mention
497 * something about message queue being per-thread, and g_poll does
498 * wait for messages), unless glib main loop is not running,
499 * in which case we just use gnunet select right here.
500 */
501 static HANDLE gnunet_select_subthread;
502
503 static gsize initialized = 0;
504
505 if (ml->gml == NULL || TRUE != g_main_loop_is_running (ml->gml))
506 return GNUNET_NETWORK_socket_select (rfds, wfds, efds, timeout);
507
508 if (g_once_init_enter (&initialized))
509 {
510 wakeup_event_for_gnunet = CreateEvent (NULL, TRUE, FALSE, NULL);
511 gnunet_woke_up_event = CreateEvent (NULL, TRUE, FALSE, NULL);
512 standin_rfds = GNUNET_NETWORK_fdset_create ();
513 wakeup_event_for_gnunet_fh =
514 GNUNET_DISK_get_handle_from_w32_handle (wakeup_event_for_gnunet);
515 gnunet_selector_thread_job_event = CreateEvent (NULL, TRUE, FALSE, NULL);
516 sp = GNUNET_new (struct _select_params_gtk);
517
518 sp->event_to_signal_we_woke_up = gnunet_woke_up_event;
519 sp->event_to_that_wakes_us_up = wakeup_event_for_gnunet;
520 sp->event_to_wait_for_a_job = gnunet_selector_thread_job_event;
521
522 gnunet_select_subthread =
523 (HANDLE) _beginthreadex (NULL, 0, _gnunet_selector_thread, sp, 0, NULL);
524
525 g_once_init_leave (&initialized, 1);
526 }
527
528 if (wakeup_event_for_gnunet == NULL || gnunet_woke_up_event == NULL ||
529 gnunet_select_subthread == NULL || wakeup_event_for_gnunet_fh == NULL ||
530 gnunet_selector_thread_job_event == NULL)
531 {
532 GNUNET_break (0);
533 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
534 "%s",
535 _ ("Failed to initialize GNUnet-GTK select\n"));
536 return GNUNET_SYSERR;
537 }
538
539 timeout_from_delay = GNUNET_TIME_UNIT_ZERO;
540 /* Optimization hack: assume that at least one of the fds
541 * is not NULL and not empty.
542 */
543 gnunet_select_result =
544 GNUNET_NETWORK_socket_select (rfds, wfds, efds, timeout_from_delay);
545 if (gnunet_select_result < 0)
546 return gnunet_select_result;
547
548 if (ml->cached_poll_array_size == 0)
549 resize_cached_poll_array (ml, INITIAL_POLL_ARRAY_SIZE);
550
551 delay = INT_MAX;
552 need_gfds = -1;
553 if (NULL != ml->gmc)
554 {
555 g_main_context_prepare (ml->gmc, &max_priority);
556 need_gfds = g_main_context_query (ml->gmc,
557 max_priority,
558 &delay,
559 ml->cached_poll_array,
560 ml->cached_poll_array_size);
561 if (ml->cached_poll_array_size < need_gfds + 1)
562 {
563 GNUNET_break (0);
564 GNUNET_log (
565 GNUNET_ERROR_TYPE_ERROR,
566 _ ("Ran out of handle space - g_poll() needs %d handles, has %d!\n"),
567 need_gfds + 1,
568 ml->cached_poll_array_size);
569 return GNUNET_SYSERR;
570 }
571 }
572 if (timeout.rel_value_us != GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
573 {
574 if (delay >= 0)
575 delay = GNUNET_MIN (timeout.rel_value_us /
576 GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us,
577 delay);
578 else
579 delay = timeout.rel_value_us / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us;
580 }
581
582 g_poll_result = g_poll (ml->cached_poll_array, need_gfds, 0);
583 if (g_poll_result < 0)
584 {
585 GNUNET_break (0);
586 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
587 "g_poll() returned %d\n",
588 g_poll_result);
589 return GNUNET_SYSERR;
590 }
591 g_poll_result =
592 (GNUNET_YES == handle_gui_events (ml, max_priority, need_gfds)) ? 1 : 0;
593
594 if ((gnunet_select_result > 0) || (g_poll_result > 0) || (delay == 0))
595 {
596 return gnunet_select_result + g_poll_result;
597 }
598
599 if (rfds == NULL)
600 rfds = standin_rfds;
601
602 ResetEvent (wakeup_event_for_gnunet);
603 ResetEvent (gnunet_woke_up_event);
604
605 GNUNET_NETWORK_fdset_handle_set_first (rfds, wakeup_event_for_gnunet_fh);
606
607 sp->status = 0;
608 /* Optimization hack: assume that at least one of the fds
609 * is not NULL and not empty.
610 */
611 sp->rfds = rfds;
612 sp->wfds = wfds;
613 sp->efds = efds;
614
615 sp->timeout =
616 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, delay);
617 ml->cached_poll_array[need_gfds].fd = (intptr_t) gnunet_woke_up_event;
618 ml->cached_poll_array[need_gfds].events = G_IO_IN;
619
620 /* Wakes up the gnunet selector thread */
621 SetEvent (gnunet_selector_thread_job_event);
622
623 /* During this call, if gnunet select threads wakes up first,
624 * it will set gnunet_woke_up_event, waking us up.
625 */
626 g_poll_result = g_poll (ml->cached_poll_array, need_gfds + 1, delay);
627
628 SetEvent (wakeup_event_for_gnunet);
629
630 wait_result = WaitForSingleObject (gnunet_woke_up_event, INFINITE);
631 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
632 "Finished waiting for the gnunet select thread: %lu %d\n",
633 wait_result,
634 sp->status);
635
636 g_poll_result =
637 (GNUNET_YES == handle_gui_events (ml, max_priority, need_gfds)) ? 1 : 0;
638
639 if (-1 == sp->status)
640 {
641 return GNUNET_SYSERR;
642 }
643
644 if (GNUNET_NETWORK_fdset_handle_isset (rfds, wakeup_event_for_gnunet_fh))
645 sp->status -= 1;
646
647 if (-1 == sp->status)
648 {
649 GNUNET_break (0);
650 }
651
652 return sp->status + g_poll_result;
653}
654
655#else
656
657#ifndef FD_COPY 310#ifndef FD_COPY
658#define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set))) 311#define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set)))
659#endif 312#endif
@@ -823,7 +476,6 @@ gnunet_gtk_select (void *cls,
823 return result; 476 return result;
824} 477}
825 478
826#endif
827 479
828/** 480/**
829 * Actual main function run right after GNUnet's scheduler 481 * Actual main function run right after GNUnet's scheduler