diff options
Diffstat (limited to 'src/lib/eventloop.c')
-rw-r--r-- | src/lib/eventloop.c | 348 |
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 | */ | ||
372 | struct _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 | |||
415 | static 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 | |||
431 | static int | ||
432 | handle_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 | */ | ||
473 | static int | ||
474 | gnunet_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 |