diff options
-rw-r--r-- | src/include/gnunet_scheduler_lib.h | 2 | ||||
-rw-r--r-- | src/util/scheduler.c | 849 |
2 files changed, 407 insertions, 444 deletions
diff --git a/src/include/gnunet_scheduler_lib.h b/src/include/gnunet_scheduler_lib.h index 837a23ba5..68a5ac534 100644 --- a/src/include/gnunet_scheduler_lib.h +++ b/src/include/gnunet_scheduler_lib.h | |||
@@ -359,7 +359,7 @@ GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, | |||
359 | * | 359 | * |
360 | * @return NULL on error | 360 | * @return NULL on error |
361 | */ | 361 | */ |
362 | const struct GNUNET_SCHEDULER_Driver * | 362 | struct GNUNET_SCHEDULER_Driver * |
363 | GNUNET_SCHEDULER_driver_select (void); | 363 | GNUNET_SCHEDULER_driver_select (void); |
364 | 364 | ||
365 | 365 | ||
diff --git a/src/util/scheduler.c b/src/util/scheduler.c index 42309c199..7cd42dcea 100644 --- a/src/util/scheduler.c +++ b/src/util/scheduler.c | |||
@@ -89,12 +89,6 @@ struct GNUNET_SCHEDULER_Handle | |||
89 | * @deprecated | 89 | * @deprecated |
90 | */ | 90 | */ |
91 | struct GNUNET_NETWORK_FDSet *ws; | 91 | struct GNUNET_NETWORK_FDSet *ws; |
92 | |||
93 | /** | ||
94 | * Driver we used for the event loop. | ||
95 | */ | ||
96 | const struct GNUNET_SCHEDULER_Driver *driver; | ||
97 | |||
98 | }; | 92 | }; |
99 | 93 | ||
100 | 94 | ||
@@ -124,11 +118,6 @@ struct GNUNET_SCHEDULER_Task | |||
124 | void *callback_cls; | 118 | void *callback_cls; |
125 | 119 | ||
126 | /** | 120 | /** |
127 | * Handle to the scheduler's state. | ||
128 | */ | ||
129 | const struct GNUNET_SCHEDULER_Handle *sh; | ||
130 | |||
131 | /** | ||
132 | * Set of file descriptors this task is waiting | 121 | * Set of file descriptors this task is waiting |
133 | * for for reading. Once ready, this is updated | 122 | * for for reading. Once ready, this is updated |
134 | * to reflect the set of file descriptors ready | 123 | * to reflect the set of file descriptors ready |
@@ -224,9 +213,38 @@ struct GNUNET_SCHEDULER_Task | |||
224 | int num_backtrace_strings; | 213 | int num_backtrace_strings; |
225 | #endif | 214 | #endif |
226 | 215 | ||
216 | }; | ||
217 | |||
218 | |||
219 | struct Scheduled | ||
220 | { | ||
221 | struct Scheduled *prev; | ||
222 | |||
223 | struct Scheduled *next; | ||
224 | |||
225 | struct GNUNET_SCHEDULER_Task *task; | ||
227 | 226 | ||
227 | struct GNUNET_SCHEDULER_FdInfo *fdi; | ||
228 | }; | 228 | }; |
229 | 229 | ||
230 | |||
231 | /** | ||
232 | * Driver context used by GNUNET_SCHEDULER_run | ||
233 | */ | ||
234 | struct DriverContext | ||
235 | { | ||
236 | struct Scheduled *scheduled_in_head; | ||
237 | |||
238 | struct Scheduled *scheduled_in_tail; | ||
239 | |||
240 | struct Scheduled *scheduled_out_head; | ||
241 | |||
242 | struct Scheduled *scheduled_out_tail; | ||
243 | |||
244 | struct GNUNET_TIME_Relative timeout; | ||
245 | }; | ||
246 | |||
247 | |||
230 | /** | 248 | /** |
231 | * The driver used for the event loop. Will be handed over to | 249 | * The driver used for the event loop. Will be handed over to |
232 | * the scheduler in #GNUNET_SCHEDULER_run_from_driver(), peristed | 250 | * the scheduler in #GNUNET_SCHEDULER_run_from_driver(), peristed |
@@ -338,6 +356,11 @@ static struct GNUNET_SCHEDULER_TaskContext tc; | |||
338 | */ | 356 | */ |
339 | static void *scheduler_select_cls; | 357 | static void *scheduler_select_cls; |
340 | 358 | ||
359 | /** | ||
360 | * Scheduler handle used for the driver functions | ||
361 | */ | ||
362 | static struct GNUNET_SCHEDULER_Handle sh; | ||
363 | |||
341 | 364 | ||
342 | /** | 365 | /** |
343 | * Sets the select function to use in the scheduler (scheduler_select). | 366 | * Sets the select function to use in the scheduler (scheduler_select). |
@@ -372,127 +395,44 @@ check_priority (enum GNUNET_SCHEDULER_Priority p) | |||
372 | 395 | ||
373 | 396 | ||
374 | /** | 397 | /** |
375 | * Update all sets and timeout for select. | 398 | * chooses the nearest timeout from all pending tasks, to be used |
376 | * | 399 | * to tell the driver the next wakeup time (using its set_wakeup |
377 | * @param rs read-set, set to all FDs we would like to read (updated) | 400 | * callback) |
378 | * @param ws write-set, set to all FDs we would like to write (updated) | ||
379 | * @param timeout next timeout (updated) | ||
380 | */ | 401 | */ |
381 | void getNextPendingTimeout(struct GNUNET_TIME_Relative *timeout) | 402 | struct GNUNET_TIME_Absolute |
403 | get_timeout () | ||
382 | { | 404 | { |
383 | |||
384 | struct GNUNET_SCHEDULER_Task *pos; | 405 | struct GNUNET_SCHEDULER_Task *pos; |
385 | struct GNUNET_TIME_Absolute now; | 406 | struct GNUNET_TIME_Absolute now; |
386 | struct GNUNET_TIME_Relative to; | 407 | struct GNUNET_TIME_Absolute timeout; |
387 | 408 | ||
388 | now = GNUNET_TIME_absolute_get (); | ||
389 | pos = pending_timeout_head; | 409 | pos = pending_timeout_head; |
410 | now = GNUNET_TIME_absolute_get (); | ||
411 | timeout = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
390 | if (NULL != pos) | 412 | if (NULL != pos) |
391 | { | 413 | { |
392 | to = GNUNET_TIME_absolute_get_difference (now, pos->timeout); | ||
393 | if (timeout->rel_value_us > to.rel_value_us) | ||
394 | *timeout = to; | ||
395 | if (0 != pos->reason) | 414 | if (0 != pos->reason) |
396 | *timeout = GNUNET_TIME_UNIT_ZERO; | 415 | { |
416 | timeout = now; | ||
417 | } | ||
418 | else | ||
419 | { | ||
420 | timeout = pos->timeout; | ||
421 | } | ||
397 | } | 422 | } |
398 | } | ||
399 | |||
400 | static void | ||
401 | update_sets (struct GNUNET_NETWORK_FDSet *rs, | ||
402 | struct GNUNET_NETWORK_FDSet *ws, | ||
403 | struct GNUNET_TIME_Relative *timeout) | ||
404 | { | ||
405 | struct GNUNET_SCHEDULER_Task *pos; | ||
406 | struct GNUNET_TIME_Absolute now; | ||
407 | struct GNUNET_TIME_Relative to; | ||
408 | |||
409 | now = GNUNET_TIME_absolute_get (); | ||
410 | |||
411 | getNextPendingTimeout(timeout); | ||
412 | for (pos = pending_head; NULL != pos; pos = pos->next) | 423 | for (pos = pending_head; NULL != pos; pos = pos->next) |
413 | { | 424 | { |
414 | if (pos->timeout.abs_value_us != GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us) | 425 | if (0 != pos->reason) |
415 | { | 426 | { |
416 | to = GNUNET_TIME_absolute_get_difference (now, pos->timeout); | 427 | timeout = now; |
417 | if (timeout->rel_value_us > to.rel_value_us) | 428 | } |
418 | *timeout = to; | 429 | else if ((pos->timeout.abs_value_us != GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us) && |
430 | (timeout.abs_value_us > pos->timeout.abs_value_us)) | ||
431 | { | ||
432 | timeout = pos->timeout; | ||
419 | } | 433 | } |
420 | if (-1 != pos->read_fd) | ||
421 | GNUNET_NETWORK_fdset_set_native (rs, pos->read_fd); | ||
422 | if (-1 != pos->write_fd) | ||
423 | GNUNET_NETWORK_fdset_set_native (ws, pos->write_fd); | ||
424 | if (NULL != pos->read_set) | ||
425 | GNUNET_NETWORK_fdset_add (rs, pos->read_set); | ||
426 | if (NULL != pos->write_set) | ||
427 | GNUNET_NETWORK_fdset_add (ws, pos->write_set); | ||
428 | if (0 != pos->reason) | ||
429 | *timeout = GNUNET_TIME_UNIT_ZERO; | ||
430 | } | ||
431 | } | ||
432 | |||
433 | |||
434 | /** | ||
435 | * Check if the ready set overlaps with the set we want to have ready. | ||
436 | * If so, update the want set (set all FDs that are ready). If not, | ||
437 | * return #GNUNET_NO. | ||
438 | * | ||
439 | * @param ready set that is ready | ||
440 | * @param want set that we want to be ready | ||
441 | * @return #GNUNET_YES if there was some overlap | ||
442 | */ | ||
443 | static int | ||
444 | set_overlaps (const struct GNUNET_NETWORK_FDSet *ready, | ||
445 | struct GNUNET_NETWORK_FDSet *want) | ||
446 | { | ||
447 | if ((NULL == want) || (NULL == ready)) | ||
448 | return GNUNET_NO; | ||
449 | if (GNUNET_NETWORK_fdset_overlap (ready, want)) | ||
450 | { | ||
451 | /* copy all over (yes, there maybe unrelated bits, | ||
452 | * but this should not hurt well-written clients) */ | ||
453 | GNUNET_NETWORK_fdset_copy (want, ready); | ||
454 | return GNUNET_YES; | ||
455 | } | 434 | } |
456 | return GNUNET_NO; | 435 | return timeout; |
457 | } | ||
458 | |||
459 | |||
460 | /** | ||
461 | * Check if the given task is eligible to run now. | ||
462 | * Also set the reason why it is eligible. | ||
463 | * | ||
464 | * @param task task to check if it is ready | ||
465 | * @param now the current time | ||
466 | * @param rs set of FDs ready for reading | ||
467 | * @param ws set of FDs ready for writing | ||
468 | * @return #GNUNET_YES if we can run it, #GNUNET_NO if not. | ||
469 | */ | ||
470 | static int | ||
471 | is_ready (struct GNUNET_SCHEDULER_Task *task, | ||
472 | struct GNUNET_TIME_Absolute now, | ||
473 | const struct GNUNET_NETWORK_FDSet *rs, | ||
474 | const struct GNUNET_NETWORK_FDSet *ws) | ||
475 | { | ||
476 | enum GNUNET_SCHEDULER_Reason reason; | ||
477 | |||
478 | reason = task->reason; | ||
479 | if (now.abs_value_us >= task->timeout.abs_value_us) | ||
480 | reason |= GNUNET_SCHEDULER_REASON_TIMEOUT; | ||
481 | if ((0 == (reason & GNUNET_SCHEDULER_REASON_READ_READY)) && | ||
482 | (((task->read_fd != -1) && | ||
483 | (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (rs, task->read_fd))) || | ||
484 | (set_overlaps (rs, task->read_set)))) | ||
485 | reason |= GNUNET_SCHEDULER_REASON_READ_READY; | ||
486 | if ((0 == (reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) && | ||
487 | (((task->write_fd != -1) && | ||
488 | (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (ws, task->write_fd))) | ||
489 | || (set_overlaps (ws, task->write_set)))) | ||
490 | reason |= GNUNET_SCHEDULER_REASON_WRITE_READY; | ||
491 | if (0 == reason) | ||
492 | return GNUNET_NO; /* not ready */ | ||
493 | reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE; | ||
494 | task->reason = reason; | ||
495 | return GNUNET_YES; | ||
496 | } | 436 | } |
497 | 437 | ||
498 | 438 | ||
@@ -515,53 +455,6 @@ queue_ready_task (struct GNUNET_SCHEDULER_Task *task) | |||
515 | 455 | ||
516 | 456 | ||
517 | /** | 457 | /** |
518 | * Check which tasks are ready and move them | ||
519 | * to the respective ready queue. | ||
520 | * | ||
521 | * @param rs FDs ready for reading | ||
522 | * @param ws FDs ready for writing | ||
523 | */ | ||
524 | static void | ||
525 | check_ready (const struct GNUNET_NETWORK_FDSet *rs, | ||
526 | const struct GNUNET_NETWORK_FDSet *ws) | ||
527 | { | ||
528 | struct GNUNET_SCHEDULER_Task *pos; | ||
529 | struct GNUNET_SCHEDULER_Task *next; | ||
530 | struct GNUNET_TIME_Absolute now; | ||
531 | |||
532 | now = GNUNET_TIME_absolute_get (); | ||
533 | while (NULL != (pos = pending_timeout_head)) | ||
534 | { | ||
535 | if (now.abs_value_us >= pos->timeout.abs_value_us) | ||
536 | pos->reason |= GNUNET_SCHEDULER_REASON_TIMEOUT; | ||
537 | if (0 == pos->reason) | ||
538 | break; | ||
539 | scheduler_driver->set_wakeup (scheduler_driver->cls, | ||
540 | pending_timeout_head->timeout); | ||
541 | GNUNET_CONTAINER_DLL_remove (pending_timeout_head, | ||
542 | pending_timeout_tail, | ||
543 | pos); | ||
544 | if (pending_timeout_last == pos) | ||
545 | pending_timeout_last = NULL; | ||
546 | queue_ready_task (pos); | ||
547 | } | ||
548 | pos = pending_head; | ||
549 | while (NULL != pos) | ||
550 | { | ||
551 | next = pos->next; | ||
552 | if (GNUNET_YES == is_ready (pos, now, rs, ws)) | ||
553 | { | ||
554 | GNUNET_CONTAINER_DLL_remove (pending_head, | ||
555 | pending_tail, | ||
556 | pos); | ||
557 | queue_ready_task (pos); | ||
558 | } | ||
559 | pos = next; | ||
560 | } | ||
561 | } | ||
562 | |||
563 | |||
564 | /** | ||
565 | * Request the shutdown of a scheduler. Marks all tasks | 458 | * Request the shutdown of a scheduler. Marks all tasks |
566 | * awaiting shutdown as ready. Note that tasks | 459 | * awaiting shutdown as ready. Note that tasks |
567 | * scheduled with #GNUNET_SCHEDULER_add_shutdown() AFTER this call | 460 | * scheduled with #GNUNET_SCHEDULER_add_shutdown() AFTER this call |
@@ -614,7 +507,7 @@ dump_backtrace (struct GNUNET_SCHEDULER_Task *t) | |||
614 | unsigned int i; | 507 | unsigned int i; |
615 | 508 | ||
616 | for (i = 0; i < t->num_backtrace_strings; i++) | 509 | for (i = 0; i < t->num_backtrace_strings; i++) |
617 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 510 | LOG (GNUNET_ERROR_TYPE_WARNING, |
618 | "Task %p trace %u: %s\n", | 511 | "Task %p trace %u: %s\n", |
619 | t, | 512 | t, |
620 | i, | 513 | i, |
@@ -624,82 +517,6 @@ dump_backtrace (struct GNUNET_SCHEDULER_Task *t) | |||
624 | 517 | ||
625 | 518 | ||
626 | /** | 519 | /** |
627 | * Run at least one task in the highest-priority queue that is not | ||
628 | * empty. Keep running tasks until we are either no longer running | ||
629 | * "URGENT" tasks or until we have at least one "pending" task (which | ||
630 | * may become ready, hence we should select on it). Naturally, if | ||
631 | * there are no more ready tasks, we also return. | ||
632 | * | ||
633 | * @param rs FDs ready for reading | ||
634 | * @param ws FDs ready for writing | ||
635 | */ | ||
636 | static void | ||
637 | run_ready (struct GNUNET_NETWORK_FDSet *rs, | ||
638 | struct GNUNET_NETWORK_FDSet *ws) | ||
639 | { | ||
640 | enum GNUNET_SCHEDULER_Priority p; | ||
641 | struct GNUNET_SCHEDULER_Task *pos; | ||
642 | |||
643 | max_priority_added = GNUNET_SCHEDULER_PRIORITY_KEEP; | ||
644 | do | ||
645 | { | ||
646 | if (0 == ready_count) | ||
647 | return; | ||
648 | GNUNET_assert (NULL == ready_head[GNUNET_SCHEDULER_PRIORITY_KEEP]); | ||
649 | /* yes, p>0 is correct, 0 is "KEEP" which should | ||
650 | * always be an empty queue (see assertion)! */ | ||
651 | for (p = GNUNET_SCHEDULER_PRIORITY_COUNT - 1; p > 0; p--) | ||
652 | { | ||
653 | pos = ready_head[p]; | ||
654 | if (NULL != pos) | ||
655 | break; | ||
656 | } | ||
657 | GNUNET_assert (NULL != pos); /* ready_count wrong? */ | ||
658 | GNUNET_CONTAINER_DLL_remove (ready_head[p], | ||
659 | ready_tail[p], | ||
660 | pos); | ||
661 | ready_count--; | ||
662 | current_priority = pos->priority; | ||
663 | current_lifeness = pos->lifeness; | ||
664 | active_task = pos; | ||
665 | #if PROFILE_DELAYS | ||
666 | if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value_us > | ||
667 | DELAY_THRESHOLD.rel_value_us) | ||
668 | { | ||
669 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
670 | "Task %p took %s to be scheduled\n", | ||
671 | pos, | ||
672 | GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->start_time), | ||
673 | GNUNET_YES)); | ||
674 | } | ||
675 | #endif | ||
676 | tc.reason = pos->reason; | ||
677 | tc.read_ready = (NULL == pos->read_set) ? rs : pos->read_set; | ||
678 | if ((-1 != pos->read_fd) && | ||
679 | (0 != (pos->reason & GNUNET_SCHEDULER_REASON_READ_READY))) | ||
680 | GNUNET_NETWORK_fdset_set_native (rs, pos->read_fd); | ||
681 | tc.write_ready = (NULL == pos->write_set) ? ws : pos->write_set; | ||
682 | if ((-1 != pos->write_fd) && | ||
683 | (0 != (pos->reason & GNUNET_SCHEDULER_REASON_WRITE_READY))) | ||
684 | GNUNET_NETWORK_fdset_set_native (ws, pos->write_fd); | ||
685 | if ((0 != (tc.reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) && | ||
686 | (-1 != pos->write_fd) && | ||
687 | (!GNUNET_NETWORK_fdset_test_native (ws, pos->write_fd))) | ||
688 | GNUNET_assert (0); // added to ready in previous select loop! | ||
689 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
690 | "Running task: %p\n", | ||
691 | pos); | ||
692 | pos->callback (pos->callback_cls); | ||
693 | dump_backtrace (pos); | ||
694 | active_task = NULL; | ||
695 | destroy_task (pos); | ||
696 | tasks_run++; | ||
697 | } | ||
698 | while ((NULL == pending_head) || (p >= max_priority_added)); | ||
699 | } | ||
700 | |||
701 | |||
702 | /** | ||
703 | * Pipe used to communicate shutdown via signal. | 520 | * Pipe used to communicate shutdown via signal. |
704 | */ | 521 | */ |
705 | static struct GNUNET_DISK_PipeHandle *shutdown_pipe_handle; | 522 | static struct GNUNET_DISK_PipeHandle *shutdown_pipe_handle; |
@@ -766,152 +583,31 @@ sighandler_shutdown () | |||
766 | * @return #GNUNET_OK to continue the main loop, | 583 | * @return #GNUNET_OK to continue the main loop, |
767 | * #GNUNET_NO to exit | 584 | * #GNUNET_NO to exit |
768 | */ | 585 | */ |
769 | static int | 586 | //static int |
770 | check_lifeness () | 587 | //check_lifeness () |
771 | { | 588 | //{ |
772 | struct GNUNET_SCHEDULER_Task *t; | 589 | // struct GNUNET_SCHEDULER_Task *t; |
773 | 590 | // | |
774 | if (ready_count > 0) | 591 | // if (ready_count > 0) |
775 | return GNUNET_OK; | 592 | // return GNUNET_OK; |
776 | for (t = pending_head; NULL != t; t = t->next) | 593 | // for (t = pending_head; NULL != t; t = t->next) |
777 | if (t->lifeness == GNUNET_YES) | 594 | // if (t->lifeness == GNUNET_YES) |
778 | return GNUNET_OK; | 595 | // return GNUNET_OK; |
779 | for (t = shutdown_head; NULL != t; t = t->next) | 596 | // for (t = shutdown_head; NULL != t; t = t->next) |
780 | if (t->lifeness == GNUNET_YES) | 597 | // if (t->lifeness == GNUNET_YES) |
781 | return GNUNET_OK; | 598 | // return GNUNET_OK; |
782 | for (t = pending_timeout_head; NULL != t; t = t->next) | 599 | // for (t = pending_timeout_head; NULL != t; t = t->next) |
783 | if (t->lifeness == GNUNET_YES) | 600 | // if (t->lifeness == GNUNET_YES) |
784 | return GNUNET_OK; | 601 | // return GNUNET_OK; |
785 | if (NULL != shutdown_head) | 602 | // if (NULL != shutdown_head) |
786 | { | 603 | // { |
787 | GNUNET_SCHEDULER_shutdown (); | 604 | // GNUNET_SCHEDULER_shutdown (); |
788 | return GNUNET_OK; | 605 | // return GNUNET_OK; |
789 | } | 606 | // } |
790 | return GNUNET_NO; | 607 | // return GNUNET_NO; |
791 | } | 608 | //} |
792 | |||
793 | 609 | ||
794 | 610 | ||
795 | int while_live(struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws) | ||
796 | { | ||
797 | int ret; | ||
798 | unsigned int busy_wait_warning; | ||
799 | unsigned long long last_tr; | ||
800 | const struct GNUNET_DISK_FileHandle *pr; | ||
801 | char c; | ||
802 | struct GNUNET_TIME_Relative timeout; | ||
803 | |||
804 | busy_wait_warning = 0; | ||
805 | pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle, | ||
806 | GNUNET_DISK_PIPE_END_READ); | ||
807 | GNUNET_assert (NULL != pr); | ||
808 | last_tr = 0; | ||
809 | |||
810 | while (GNUNET_OK == check_lifeness ()) | ||
811 | { | ||
812 | GNUNET_NETWORK_fdset_zero (rs); | ||
813 | GNUNET_NETWORK_fdset_zero (ws); | ||
814 | timeout = GNUNET_TIME_UNIT_FOREVER_REL; | ||
815 | update_sets (rs, ws, &timeout); | ||
816 | GNUNET_NETWORK_fdset_handle_set (rs, pr); | ||
817 | if (ready_count > 0) | ||
818 | { | ||
819 | /* no blocking, more work already ready! */ | ||
820 | timeout = GNUNET_TIME_UNIT_ZERO; | ||
821 | } | ||
822 | if (NULL == scheduler_select) | ||
823 | ret = GNUNET_NETWORK_socket_select (rs, | ||
824 | ws, | ||
825 | NULL, | ||
826 | timeout); | ||
827 | else | ||
828 | ret = scheduler_select (scheduler_select_cls, | ||
829 | rs, | ||
830 | ws, | ||
831 | NULL, | ||
832 | timeout); | ||
833 | if (ret == GNUNET_SYSERR) | ||
834 | { | ||
835 | if (errno == EINTR) | ||
836 | continue; | ||
837 | |||
838 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "select"); | ||
839 | #ifndef MINGW | ||
840 | #if USE_LSOF | ||
841 | char lsof[512]; | ||
842 | |||
843 | snprintf (lsof, sizeof (lsof), "lsof -p %d", getpid ()); | ||
844 | (void) close (1); | ||
845 | (void) dup2 (2, 1); | ||
846 | if (0 != system (lsof)) | ||
847 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, | ||
848 | "system"); | ||
849 | #endif | ||
850 | #endif | ||
851 | #if DEBUG_FDS | ||
852 | struct GNUNET_SCHEDULER_Task *t; | ||
853 | |||
854 | for (t = pending_head; NULL != t; t = t->next) | ||
855 | { | ||
856 | if (-1 != t->read_fd) | ||
857 | { | ||
858 | int flags = fcntl (t->read_fd, F_GETFD); | ||
859 | if ((flags == -1) && (errno == EBADF)) | ||
860 | { | ||
861 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
862 | "Got invalid file descriptor %d!\n", | ||
863 | t->read_fd); | ||
864 | dump_backtrace (t); | ||
865 | } | ||
866 | } | ||
867 | if (-1 != t->write_fd) | ||
868 | { | ||
869 | int flags = fcntl (t->write_fd, F_GETFD); | ||
870 | if ((flags == -1) && (errno == EBADF)) | ||
871 | { | ||
872 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
873 | "Got invalid file descriptor %d!\n", | ||
874 | t->write_fd); | ||
875 | dump_backtrace (t); | ||
876 | } | ||
877 | } | ||
878 | } | ||
879 | #endif | ||
880 | GNUNET_assert (0); | ||
881 | break; | ||
882 | } | ||
883 | |||
884 | if ( (0 == ret) && | ||
885 | (0 == timeout.rel_value_us) && | ||
886 | (busy_wait_warning > 16) ) | ||
887 | { | ||
888 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
889 | "Looks like we're busy waiting...\n"); | ||
890 | short_wait (100); /* mitigate */ | ||
891 | } | ||
892 | check_ready (rs, ws); | ||
893 | run_ready (rs, ws); | ||
894 | if (GNUNET_NETWORK_fdset_handle_isset (rs, pr)) | ||
895 | { | ||
896 | /* consume the signal */ | ||
897 | GNUNET_DISK_file_read (pr, &c, sizeof (c)); | ||
898 | /* mark all active tasks as ready due to shutdown */ | ||
899 | GNUNET_SCHEDULER_shutdown (); | ||
900 | } | ||
901 | if (last_tr == tasks_run) | ||
902 | { | ||
903 | short_wait (1); | ||
904 | busy_wait_warning++; | ||
905 | } | ||
906 | else | ||
907 | { | ||
908 | last_tr = tasks_run; | ||
909 | busy_wait_warning = 0; | ||
910 | } | ||
911 | } | ||
912 | return ret; | ||
913 | } | ||
914 | |||
915 | /** | 611 | /** |
916 | * Initialize and run scheduler. This function will return when all | 612 | * Initialize and run scheduler. This function will return when all |
917 | * tasks have completed. On systems with signals, receiving a SIGTERM | 613 | * tasks have completed. On systems with signals, receiving a SIGTERM |
@@ -930,9 +626,19 @@ void | |||
930 | GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_TaskCallback task, | 626 | GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_TaskCallback task, |
931 | void *task_cls) | 627 | void *task_cls) |
932 | { | 628 | { |
933 | 629 | struct GNUNET_SCHEDULER_Driver *driver; | |
934 | GNUNET_SCHEDULER_run_with_driver(GNUNET_SCHEDULER_driver_select (), task, task_cls); | 630 | struct DriverContext context = {.scheduled_in_head = NULL, |
935 | 631 | .scheduled_in_tail = NULL, | |
632 | .scheduled_out_head = NULL, | ||
633 | .scheduled_out_tail = NULL, | ||
634 | .timeout = GNUNET_TIME_UNIT_FOREVER_REL}; | ||
635 | |||
636 | driver = GNUNET_SCHEDULER_driver_select (); | ||
637 | driver->cls = &context; | ||
638 | |||
639 | GNUNET_SCHEDULER_run_with_driver (driver, task, task_cls); | ||
640 | |||
641 | GNUNET_free (driver); | ||
936 | } | 642 | } |
937 | 643 | ||
938 | 644 | ||
@@ -1010,39 +716,63 @@ initFdInfo(struct GNUNET_SCHEDULER_Task *t, | |||
1010 | { | 716 | { |
1011 | struct GNUNET_SCHEDULER_FdInfo read_fdi = { .fd = read_nh, .et = GNUNET_SCHEDULER_ET_IN, .sock = GNUNET_NETWORK_get_fd (read_nh)}; | 717 | struct GNUNET_SCHEDULER_FdInfo read_fdi = { .fd = read_nh, .et = GNUNET_SCHEDULER_ET_IN, .sock = GNUNET_NETWORK_get_fd (read_nh)}; |
1012 | t->fdx = read_fdi; | 718 | t->fdx = read_fdi; |
719 | t->fds = &t->fdx; | ||
1013 | } | 720 | } |
1014 | else if (NULL != write_nh) | 721 | else if (NULL != write_nh) |
1015 | { | 722 | { |
1016 | struct GNUNET_SCHEDULER_FdInfo write_fdi = { .fd = write_nh, .et = GNUNET_SCHEDULER_ET_OUT, .sock = GNUNET_NETWORK_get_fd (write_nh)}; | 723 | struct GNUNET_SCHEDULER_FdInfo write_fdi = { .fd = write_nh, .et = GNUNET_SCHEDULER_ET_OUT, .sock = GNUNET_NETWORK_get_fd (write_nh)}; |
1017 | t->fdx = write_fdi; | 724 | t->fdx = write_fdi; |
725 | t->fds = &t->fdx; | ||
1018 | } | 726 | } |
1019 | else if (NULL != read_fh) | 727 | else if (NULL != read_fh) |
1020 | { | 728 | { |
1021 | struct GNUNET_SCHEDULER_FdInfo read_fdi = { .fh = read_fh, .et = GNUNET_SCHEDULER_ET_IN, .sock = read_fh->fd}; | 729 | struct GNUNET_SCHEDULER_FdInfo read_fdi = { .fh = read_fh, .et = GNUNET_SCHEDULER_ET_IN, .sock = read_fh->fd}; |
1022 | t->fdx = read_fdi; | 730 | t->fdx = read_fdi; |
731 | t->fds = &t->fdx; | ||
1023 | } | 732 | } |
1024 | else if (NULL != write_fh) | 733 | else if (NULL != write_fh) |
1025 | { | 734 | { |
1026 | struct GNUNET_SCHEDULER_FdInfo write_fdi = { .fh = write_fh, .et = GNUNET_SCHEDULER_ET_OUT, .sock = write_fh->fd}; | 735 | struct GNUNET_SCHEDULER_FdInfo write_fdi = { .fh = write_fh, .et = GNUNET_SCHEDULER_ET_OUT, .sock = write_fh->fd}; |
1027 | t->fdx = write_fdi; | 736 | t->fdx = write_fdi; |
737 | t->fds = &t->fdx; | ||
1028 | } | 738 | } |
1029 | } | 739 | } |
1030 | 740 | ||
1031 | 741 | ||
1032 | int scheduler_multi_function_call(struct GNUNET_SCHEDULER_Task *t, int (*driver_func)()) | 742 | int scheduler_multi_function_call(struct GNUNET_SCHEDULER_Task *t, int (*driver_func)()) |
1033 | { | 743 | { |
1034 | if (t->fds_len > 1){ | 744 | if (t->fds_len > 1) |
745 | { | ||
1035 | int success = GNUNET_YES; | 746 | int success = GNUNET_YES; |
1036 | for (int i = 0; i < t->fds_len;i++){ | 747 | for (int i = 0; i < t->fds_len;i++) |
1037 | success = driver_func(scheduler_driver->cls, t , t->fds+i) && success; | 748 | { |
749 | success = driver_func (scheduler_driver->cls, t , t->fds+i) && success; | ||
1038 | } | 750 | } |
1039 | return success; | 751 | return success; |
1040 | }else{ | 752 | } |
1041 | return driver_func(scheduler_driver->cls, t , t->fds); | 753 | else |
754 | { | ||
755 | return driver_func (scheduler_driver->cls, t , t->fds); | ||
1042 | } | 756 | } |
1043 | } | 757 | } |
1044 | 758 | ||
1045 | 759 | ||
760 | void | ||
761 | shutdown_task (void *cls) | ||
762 | { | ||
763 | char c; | ||
764 | const struct GNUNET_DISK_FileHandle *pr; | ||
765 | |||
766 | pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle, | ||
767 | GNUNET_DISK_PIPE_END_READ); | ||
768 | GNUNET_assert (! GNUNET_DISK_handle_invalid (pr)); | ||
769 | /* consume the signal */ | ||
770 | GNUNET_DISK_file_read (pr, &c, sizeof (c)); | ||
771 | /* mark all active tasks as ready due to shutdown */ | ||
772 | GNUNET_SCHEDULER_shutdown (); | ||
773 | } | ||
774 | |||
775 | |||
1046 | /** | 776 | /** |
1047 | * Cancel the task with the specified identifier. | 777 | * Cancel the task with the specified identifier. |
1048 | * The task must not yet have run. | 778 | * The task must not yet have run. |
@@ -1078,7 +808,7 @@ GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Task *task) | |||
1078 | pending_timeout_last = NULL; | 808 | pending_timeout_last = NULL; |
1079 | else | 809 | else |
1080 | scheduler_driver->set_wakeup (scheduler_driver->cls, | 810 | scheduler_driver->set_wakeup (scheduler_driver->cls, |
1081 | pending_timeout_head->timeout); | 811 | get_timeout ()); |
1082 | } | 812 | } |
1083 | if (task == pending_timeout_last) | 813 | if (task == pending_timeout_last) |
1084 | pending_timeout_last = NULL; | 814 | pending_timeout_last = NULL; |
@@ -1099,10 +829,10 @@ GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Task *task) | |||
1099 | task); | 829 | task); |
1100 | ready_count--; | 830 | ready_count--; |
1101 | } | 831 | } |
1102 | ret = task->callback_cls; | 832 | LOG (GNUNET_ERROR_TYPE_WARNING, |
1103 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1104 | "Canceling task %p\n", | 833 | "Canceling task %p\n", |
1105 | task); | 834 | task); |
835 | ret = task->callback_cls; | ||
1106 | destroy_task (task); | 836 | destroy_task (task); |
1107 | return ret; | 837 | return ret; |
1108 | } | 838 | } |
@@ -1161,7 +891,7 @@ GNUNET_SCHEDULER_add_with_reason_and_priority (GNUNET_SCHEDULER_TaskCallback tas | |||
1161 | t->reason = reason; | 891 | t->reason = reason; |
1162 | t->priority = priority; | 892 | t->priority = priority; |
1163 | t->lifeness = current_lifeness; | 893 | t->lifeness = current_lifeness; |
1164 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 894 | LOG (GNUNET_ERROR_TYPE_WARNING, |
1165 | "Adding continuation task %p\n", | 895 | "Adding continuation task %p\n", |
1166 | t); | 896 | t); |
1167 | init_backtrace (t); | 897 | init_backtrace (t); |
@@ -1211,7 +941,8 @@ GNUNET_SCHEDULER_add_at_with_priority (struct GNUNET_TIME_Absolute at, | |||
1211 | GNUNET_CONTAINER_DLL_insert (pending_timeout_head, | 941 | GNUNET_CONTAINER_DLL_insert (pending_timeout_head, |
1212 | pending_timeout_tail, | 942 | pending_timeout_tail, |
1213 | t); | 943 | t); |
1214 | scheduler_driver->set_wakeup(scheduler_driver->cls,pending_timeout_head->timeout); | 944 | scheduler_driver->set_wakeup (scheduler_driver->cls, |
945 | at); | ||
1215 | } | 946 | } |
1216 | else | 947 | else |
1217 | { | 948 | { |
@@ -1236,11 +967,13 @@ GNUNET_SCHEDULER_add_at_with_priority (struct GNUNET_TIME_Absolute at, | |||
1236 | pending_timeout_tail, | 967 | pending_timeout_tail, |
1237 | prev, | 968 | prev, |
1238 | t); | 969 | t); |
970 | scheduler_driver->set_wakeup (scheduler_driver->cls, | ||
971 | get_timeout()); | ||
1239 | } | 972 | } |
1240 | /* finally, update heuristic insertion point to last insertion... */ | 973 | /* finally, update heuristic insertion point to last insertion... */ |
1241 | pending_timeout_last = t; | 974 | pending_timeout_last = t; |
1242 | 975 | ||
1243 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 976 | LOG (GNUNET_ERROR_TYPE_WARNING, |
1244 | "Adding task: %p\n", | 977 | "Adding task: %p\n", |
1245 | t); | 978 | t); |
1246 | init_backtrace (t); | 979 | init_backtrace (t); |
@@ -1356,11 +1089,11 @@ GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay, | |||
1356 | */ | 1089 | */ |
1357 | struct GNUNET_SCHEDULER_Task * | 1090 | struct GNUNET_SCHEDULER_Task * |
1358 | GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_TaskCallback task, | 1091 | GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_TaskCallback task, |
1359 | void *task_cls) | 1092 | void *task_cls) |
1360 | { | 1093 | { |
1361 | return GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_ZERO, | 1094 | return GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_ZERO, |
1362 | task, | 1095 | task, |
1363 | task_cls); | 1096 | task_cls); |
1364 | } | 1097 | } |
1365 | 1098 | ||
1366 | 1099 | ||
@@ -1376,7 +1109,7 @@ GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_TaskCallback task, | |||
1376 | */ | 1109 | */ |
1377 | struct GNUNET_SCHEDULER_Task * | 1110 | struct GNUNET_SCHEDULER_Task * |
1378 | GNUNET_SCHEDULER_add_shutdown (GNUNET_SCHEDULER_TaskCallback task, | 1111 | GNUNET_SCHEDULER_add_shutdown (GNUNET_SCHEDULER_TaskCallback task, |
1379 | void *task_cls) | 1112 | void *task_cls) |
1380 | { | 1113 | { |
1381 | struct GNUNET_SCHEDULER_Task *t; | 1114 | struct GNUNET_SCHEDULER_Task *t; |
1382 | 1115 | ||
@@ -1395,10 +1128,10 @@ GNUNET_SCHEDULER_add_shutdown (GNUNET_SCHEDULER_TaskCallback task, | |||
1395 | t->on_shutdown = GNUNET_YES; | 1128 | t->on_shutdown = GNUNET_YES; |
1396 | t->lifeness = GNUNET_YES; | 1129 | t->lifeness = GNUNET_YES; |
1397 | GNUNET_CONTAINER_DLL_insert (shutdown_head, | 1130 | GNUNET_CONTAINER_DLL_insert (shutdown_head, |
1398 | shutdown_tail, | 1131 | shutdown_tail, |
1399 | t); | 1132 | t); |
1400 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1133 | LOG (GNUNET_ERROR_TYPE_WARNING, |
1401 | "Adding task: %p\n", | 1134 | "Adding shutdown task: %p\n", |
1402 | t); | 1135 | t); |
1403 | init_backtrace (t); | 1136 | init_backtrace (t); |
1404 | return t; | 1137 | return t; |
@@ -1465,8 +1198,6 @@ add_without_sets (struct GNUNET_TIME_Relative delay, | |||
1465 | const struct GNUNET_NETWORK_Handle *write_nh, | 1198 | const struct GNUNET_NETWORK_Handle *write_nh, |
1466 | const struct GNUNET_DISK_FileHandle *read_fh, | 1199 | const struct GNUNET_DISK_FileHandle *read_fh, |
1467 | const struct GNUNET_DISK_FileHandle *write_fh, | 1200 | const struct GNUNET_DISK_FileHandle *write_fh, |
1468 | //int rfd, | ||
1469 | //int wfd, | ||
1470 | GNUNET_SCHEDULER_TaskCallback task, | 1201 | GNUNET_SCHEDULER_TaskCallback task, |
1471 | void *task_cls) | 1202 | void *task_cls) |
1472 | { | 1203 | { |
@@ -1517,6 +1248,8 @@ add_without_sets (struct GNUNET_TIME_Relative delay, | |||
1517 | pending_tail, | 1248 | pending_tail, |
1518 | t); | 1249 | t); |
1519 | scheduler_multi_function_call(t, scheduler_driver->add); | 1250 | scheduler_multi_function_call(t, scheduler_driver->add); |
1251 | scheduler_driver->set_wakeup (scheduler_driver->cls, | ||
1252 | get_timeout ()); | ||
1520 | max_priority_added = GNUNET_MAX (max_priority_added, | 1253 | max_priority_added = GNUNET_MAX (max_priority_added, |
1521 | t->priority); | 1254 | t->priority); |
1522 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1255 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
@@ -1758,7 +1491,7 @@ GNUNET_SCHEDULER_add_file_with_priority (struct GNUNET_TIME_Relative delay, | |||
1758 | return ret; | 1491 | return ret; |
1759 | #else | 1492 | #else |
1760 | GNUNET_assert (on_read || on_write); | 1493 | GNUNET_assert (on_read || on_write); |
1761 | GNUNET_assert(fd->fd >= 0); | 1494 | GNUNET_assert (fd->fd >= 0); |
1762 | return add_without_sets (delay, priority, | 1495 | return add_without_sets (delay, priority, |
1763 | NULL, | 1496 | NULL, |
1764 | NULL, | 1497 | NULL, |
@@ -1840,9 +1573,11 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio, | |||
1840 | pending_tail, | 1573 | pending_tail, |
1841 | t); | 1574 | t); |
1842 | scheduler_multi_function_call(t, scheduler_driver->add); | 1575 | scheduler_multi_function_call(t, scheduler_driver->add); |
1576 | scheduler_driver->set_wakeup (scheduler_driver->cls, | ||
1577 | get_timeout ()); | ||
1843 | max_priority_added = GNUNET_MAX (max_priority_added, | 1578 | max_priority_added = GNUNET_MAX (max_priority_added, |
1844 | t->priority); | 1579 | t->priority); |
1845 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1580 | LOG (GNUNET_ERROR_TYPE_WARNING, |
1846 | "Adding task %p\n", | 1581 | "Adding task %p\n", |
1847 | t); | 1582 | t); |
1848 | init_backtrace (t); | 1583 | init_backtrace (t); |
@@ -1862,11 +1597,15 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio, | |||
1862 | */ | 1597 | */ |
1863 | void | 1598 | void |
1864 | GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task, | 1599 | GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task, |
1865 | enum GNUNET_SCHEDULER_EventType et) | 1600 | enum GNUNET_SCHEDULER_EventType et) |
1866 | { | 1601 | { |
1867 | enum GNUNET_SCHEDULER_Reason reason; | 1602 | enum GNUNET_SCHEDULER_Reason reason; |
1868 | struct GNUNET_TIME_Absolute now; | 1603 | struct GNUNET_TIME_Absolute now; |
1869 | 1604 | ||
1605 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1606 | "task ready: %p\n", | ||
1607 | task); | ||
1608 | |||
1870 | now = GNUNET_TIME_absolute_get (); | 1609 | now = GNUNET_TIME_absolute_get (); |
1871 | reason = task->reason; | 1610 | reason = task->reason; |
1872 | if (now.abs_value_us >= task->timeout.abs_value_us) | 1611 | if (now.abs_value_us >= task->timeout.abs_value_us) |
@@ -1882,6 +1621,9 @@ GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task, | |||
1882 | task->fds = &task->fdx; | 1621 | task->fds = &task->fdx; |
1883 | task->fdx.et = et; | 1622 | task->fdx.et = et; |
1884 | task->fds_len = 1; | 1623 | task->fds_len = 1; |
1624 | GNUNET_CONTAINER_DLL_remove (pending_head, | ||
1625 | pending_tail, | ||
1626 | task); | ||
1885 | queue_ready_task (task); | 1627 | queue_ready_task (task); |
1886 | } | 1628 | } |
1887 | 1629 | ||
@@ -1905,6 +1647,7 @@ GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task, | |||
1905 | int | 1647 | int |
1906 | GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) | 1648 | GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) |
1907 | { | 1649 | { |
1650 | // FIXME: we have to check lifeness here! | ||
1908 | enum GNUNET_SCHEDULER_Priority p; | 1651 | enum GNUNET_SCHEDULER_Priority p; |
1909 | struct GNUNET_SCHEDULER_Task *pos; | 1652 | struct GNUNET_SCHEDULER_Task *pos; |
1910 | struct GNUNET_TIME_Absolute now; | 1653 | struct GNUNET_TIME_Absolute now; |
@@ -1920,7 +1663,6 @@ GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) | |||
1920 | GNUNET_CONTAINER_DLL_remove (pending_timeout_head, | 1663 | GNUNET_CONTAINER_DLL_remove (pending_timeout_head, |
1921 | pending_timeout_tail, | 1664 | pending_timeout_tail, |
1922 | pos); | 1665 | pos); |
1923 | scheduler_driver->set_wakeup(scheduler_driver->cls,pending_timeout_head->timeout); | ||
1924 | if (pending_timeout_last == pos) | 1666 | if (pending_timeout_last == pos) |
1925 | pending_timeout_last = NULL; | 1667 | pending_timeout_last = NULL; |
1926 | queue_ready_task (pos); | 1668 | queue_ready_task (pos); |
@@ -1957,7 +1699,7 @@ GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) | |||
1957 | if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value_us > | 1699 | if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value_us > |
1958 | DELAY_THRESHOLD.rel_value_us) | 1700 | DELAY_THRESHOLD.rel_value_us) |
1959 | { | 1701 | { |
1960 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1702 | LOG (GNUNET_ERROR_TYPE_WARNING, |
1961 | "Task %p took %s to be scheduled\n", | 1703 | "Task %p took %s to be scheduled\n", |
1962 | pos, | 1704 | pos, |
1963 | GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->start_time), | 1705 | GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->start_time), |
@@ -1979,8 +1721,8 @@ GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) | |||
1979 | (0 != (pos->reason & GNUNET_SCHEDULER_REASON_WRITE_READY))) | 1721 | (0 != (pos->reason & GNUNET_SCHEDULER_REASON_WRITE_READY))) |
1980 | GNUNET_NETWORK_fdset_set_native (sh->ws, | 1722 | GNUNET_NETWORK_fdset_set_native (sh->ws, |
1981 | pos->write_fd); | 1723 | pos->write_fd); |
1982 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1724 | LOG (GNUNET_ERROR_TYPE_WARNING, |
1983 | "Running task: %p\n", | 1725 | "Running task from driver: %p\n", |
1984 | pos); | 1726 | pos); |
1985 | pos->callback (pos->callback_cls); | 1727 | pos->callback (pos->callback_cls); |
1986 | active_task = NULL; | 1728 | active_task = NULL; |
@@ -1988,6 +1730,8 @@ GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) | |||
1988 | destroy_task (pos); | 1730 | destroy_task (pos); |
1989 | tasks_run++; | 1731 | tasks_run++; |
1990 | } | 1732 | } |
1733 | scheduler_driver->set_wakeup (scheduler_driver->cls, | ||
1734 | get_timeout ()); | ||
1991 | if (0 == ready_count) | 1735 | if (0 == ready_count) |
1992 | return GNUNET_NO; | 1736 | return GNUNET_NO; |
1993 | return GNUNET_OK; | 1737 | return GNUNET_OK; |
@@ -2012,11 +1756,10 @@ GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) | |||
2012 | */ | 1756 | */ |
2013 | int | 1757 | int |
2014 | GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, | 1758 | GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, |
2015 | GNUNET_SCHEDULER_TaskCallback task, | 1759 | GNUNET_SCHEDULER_TaskCallback task, |
2016 | void *task_cls) | 1760 | void *task_cls) |
2017 | { | 1761 | { |
2018 | int ret; | 1762 | int ret; |
2019 | struct GNUNET_SCHEDULER_Handle sh; | ||
2020 | struct GNUNET_SIGNAL_Context *shc_int; | 1763 | struct GNUNET_SIGNAL_Context *shc_int; |
2021 | struct GNUNET_SIGNAL_Context *shc_term; | 1764 | struct GNUNET_SIGNAL_Context *shc_term; |
2022 | #if (SIGTERM != GNUNET_TERM_SIG) | 1765 | #if (SIGTERM != GNUNET_TERM_SIG) |
@@ -2029,7 +1772,6 @@ GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, | |||
2029 | #endif | 1772 | #endif |
2030 | struct GNUNET_SCHEDULER_Task tsk; | 1773 | struct GNUNET_SCHEDULER_Task tsk; |
2031 | const struct GNUNET_DISK_FileHandle *pr; | 1774 | const struct GNUNET_DISK_FileHandle *pr; |
2032 | scheduler_driver = driver; | ||
2033 | 1775 | ||
2034 | /* general set-up */ | 1776 | /* general set-up */ |
2035 | GNUNET_assert (NULL == active_task); | 1777 | GNUNET_assert (NULL == active_task); |
@@ -2041,11 +1783,11 @@ GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, | |||
2041 | GNUNET_assert (NULL != shutdown_pipe_handle); | 1783 | GNUNET_assert (NULL != shutdown_pipe_handle); |
2042 | pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle, | 1784 | pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle, |
2043 | GNUNET_DISK_PIPE_END_READ); | 1785 | GNUNET_DISK_PIPE_END_READ); |
2044 | GNUNET_assert (NULL != pr); | ||
2045 | my_pid = getpid (); | 1786 | my_pid = getpid (); |
1787 | scheduler_driver = driver; | ||
2046 | 1788 | ||
2047 | /* install signal handlers */ | 1789 | /* install signal handlers */ |
2048 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1790 | LOG (GNUNET_ERROR_TYPE_WARNING, |
2049 | "Registering signal handlers\n"); | 1791 | "Registering signal handlers\n"); |
2050 | shc_int = GNUNET_SIGNAL_handler_install (SIGINT, | 1792 | shc_int = GNUNET_SIGNAL_handler_install (SIGINT, |
2051 | &sighandler_shutdown); | 1793 | &sighandler_shutdown); |
@@ -2071,7 +1813,6 @@ GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, | |||
2071 | 0, | 1813 | 0, |
2072 | sizeof (tsk)); | 1814 | sizeof (tsk)); |
2073 | active_task = &tsk; | 1815 | active_task = &tsk; |
2074 | tsk.sh = &sh; | ||
2075 | GNUNET_SCHEDULER_add_with_reason_and_priority (task, | 1816 | GNUNET_SCHEDULER_add_with_reason_and_priority (task, |
2076 | task_cls, | 1817 | task_cls, |
2077 | GNUNET_SCHEDULER_REASON_STARTUP, | 1818 | GNUNET_SCHEDULER_REASON_STARTUP, |
@@ -2079,17 +1820,19 @@ GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, | |||
2079 | GNUNET_SCHEDULER_add_now_with_lifeness (GNUNET_NO, | 1820 | GNUNET_SCHEDULER_add_now_with_lifeness (GNUNET_NO, |
2080 | &GNUNET_OS_install_parent_control_handler, | 1821 | &GNUNET_OS_install_parent_control_handler, |
2081 | NULL); | 1822 | NULL); |
1823 | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
1824 | pr, | ||
1825 | &shutdown_task, | ||
1826 | NULL); | ||
2082 | active_task = NULL; | 1827 | active_task = NULL; |
2083 | driver->set_wakeup (driver->cls, | ||
2084 | GNUNET_TIME_absolute_get ()); | ||
2085 | |||
2086 | /* begin main event loop */ | 1828 | /* begin main event loop */ |
2087 | sh.rs = GNUNET_NETWORK_fdset_create (); | 1829 | sh.rs = GNUNET_NETWORK_fdset_create (); |
2088 | sh.ws = GNUNET_NETWORK_fdset_create (); | 1830 | sh.ws = GNUNET_NETWORK_fdset_create (); |
2089 | GNUNET_NETWORK_fdset_handle_set (sh.rs, pr); | 1831 | //GNUNET_NETWORK_fdset_handle_set (sh.rs, pr); |
2090 | sh.driver = driver; | ||
2091 | ret = driver->loop (driver->cls, | 1832 | ret = driver->loop (driver->cls, |
2092 | &sh); | 1833 | &sh); |
1834 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1835 | "loop finished!"); | ||
2093 | GNUNET_NETWORK_fdset_destroy (sh.rs); | 1836 | GNUNET_NETWORK_fdset_destroy (sh.rs); |
2094 | GNUNET_NETWORK_fdset_destroy (sh.ws); | 1837 | GNUNET_NETWORK_fdset_destroy (sh.ws); |
2095 | 1838 | ||
@@ -2109,29 +1852,249 @@ GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, | |||
2109 | return ret; | 1852 | return ret; |
2110 | } | 1853 | } |
2111 | 1854 | ||
1855 | |||
2112 | int | 1856 | int |
2113 | select_add(void *cls, | 1857 | select_add (void *cls, |
2114 | struct GNUNET_SCHEDULER_Task *task, | 1858 | struct GNUNET_SCHEDULER_Task *task, |
2115 | struct GNUNET_SCHEDULER_FdInfo *fdi) | 1859 | struct GNUNET_SCHEDULER_FdInfo *fdi) |
2116 | { | 1860 | { |
1861 | struct DriverContext *context = cls; | ||
1862 | GNUNET_assert (NULL != context); | ||
1863 | |||
1864 | if (!((NULL != fdi->fd) ^ (NULL != fdi->fh)) || (0 >= fdi->sock)) | ||
1865 | { | ||
1866 | /* exactly one out of {fd, hf} must be != NULL and the OS handle must be valid */ | ||
1867 | return GNUNET_SYSERR; | ||
1868 | } | ||
1869 | |||
1870 | struct Scheduled *scheduled = GNUNET_new (struct Scheduled); | ||
1871 | scheduled->task = task; | ||
1872 | scheduled->fdi = fdi; | ||
1873 | |||
1874 | switch (fdi->et) | ||
1875 | { | ||
1876 | case GNUNET_SCHEDULER_ET_IN: | ||
1877 | { | ||
1878 | GNUNET_CONTAINER_DLL_insert (context->scheduled_in_head, | ||
1879 | context->scheduled_in_tail, | ||
1880 | scheduled); | ||
1881 | break; | ||
1882 | } | ||
1883 | case GNUNET_SCHEDULER_ET_OUT: | ||
1884 | { | ||
1885 | GNUNET_CONTAINER_DLL_insert (context->scheduled_out_head, | ||
1886 | context->scheduled_out_tail, | ||
1887 | scheduled); | ||
1888 | break; | ||
1889 | } | ||
1890 | default: | ||
1891 | { | ||
1892 | // FIXME: other event types not implemented yet | ||
1893 | GNUNET_assert (0); | ||
1894 | } | ||
1895 | } | ||
2117 | return GNUNET_OK; | 1896 | return GNUNET_OK; |
2118 | } | 1897 | } |
2119 | 1898 | ||
2120 | 1899 | ||
2121 | int | 1900 | int |
2122 | select_del(void *cls, | 1901 | select_del (void *cls, |
2123 | struct GNUNET_SCHEDULER_Task *task, | 1902 | struct GNUNET_SCHEDULER_Task *task, |
2124 | struct GNUNET_SCHEDULER_FdInfo *fdi) | 1903 | struct GNUNET_SCHEDULER_FdInfo *fdi) |
2125 | { | 1904 | { |
2126 | return GNUNET_OK; | 1905 | struct DriverContext *context = cls; |
1906 | GNUNET_assert (NULL != context); | ||
1907 | |||
1908 | int ret = GNUNET_SYSERR; | ||
1909 | struct Scheduled *pos; | ||
1910 | switch (fdi->et) | ||
1911 | { | ||
1912 | case GNUNET_SCHEDULER_ET_IN: | ||
1913 | { | ||
1914 | for (pos = context->scheduled_in_head; NULL != pos; pos = pos->next) | ||
1915 | { | ||
1916 | if (pos->task == task) | ||
1917 | { | ||
1918 | GNUNET_CONTAINER_DLL_remove (context->scheduled_in_head, | ||
1919 | context->scheduled_in_tail, | ||
1920 | pos); | ||
1921 | ret = GNUNET_OK; | ||
1922 | } | ||
1923 | } | ||
1924 | break; | ||
1925 | } | ||
1926 | case GNUNET_SCHEDULER_ET_OUT: | ||
1927 | { | ||
1928 | for (pos = context->scheduled_out_head; NULL != pos; pos = pos->next) | ||
1929 | { | ||
1930 | if (pos->task == task) | ||
1931 | { | ||
1932 | GNUNET_CONTAINER_DLL_remove (context->scheduled_out_head, | ||
1933 | context->scheduled_out_tail, | ||
1934 | pos); | ||
1935 | ret = GNUNET_OK; | ||
1936 | } | ||
1937 | } | ||
1938 | break; | ||
1939 | } | ||
1940 | default: | ||
1941 | { | ||
1942 | // FIXME: other event types not implemented yet | ||
1943 | GNUNET_assert (0); | ||
1944 | } | ||
1945 | } | ||
1946 | return ret; | ||
2127 | } | 1947 | } |
2128 | 1948 | ||
2129 | 1949 | ||
1950 | //int | ||
1951 | //select_loop_condition (const struct DriverContext *context) | ||
1952 | //{ | ||
1953 | // struct GNUNET_TIME_absolute_ | ||
1954 | //} | ||
1955 | |||
1956 | |||
2130 | int | 1957 | int |
2131 | select_loop(void *cls, | 1958 | select_loop (void *cls, |
2132 | struct GNUNET_SCHEDULER_Handle *sh) | 1959 | struct GNUNET_SCHEDULER_Handle *sh) |
2133 | { | 1960 | { |
2134 | return while_live(sh->rs, sh->ws); | 1961 | struct GNUNET_NETWORK_FDSet *rs; |
1962 | struct GNUNET_NETWORK_FDSet *ws; | ||
1963 | struct DriverContext *context; | ||
1964 | int select_result; | ||
1965 | unsigned long long last_tr; | ||
1966 | unsigned int busy_wait_warning; | ||
1967 | |||
1968 | context = cls; | ||
1969 | GNUNET_assert (NULL != context); | ||
1970 | rs = GNUNET_NETWORK_fdset_create (); | ||
1971 | ws = GNUNET_NETWORK_fdset_create (); | ||
1972 | last_tr = 0; | ||
1973 | busy_wait_warning = 0; | ||
1974 | while ((NULL != context->scheduled_in_head) || | ||
1975 | (NULL != context->scheduled_out_head)) | ||
1976 | { | ||
1977 | GNUNET_NETWORK_fdset_zero (rs); | ||
1978 | GNUNET_NETWORK_fdset_zero (ws); | ||
1979 | struct Scheduled *pos; | ||
1980 | for (pos = context->scheduled_in_head; NULL != pos; pos = pos->next) | ||
1981 | { | ||
1982 | GNUNET_NETWORK_fdset_set_native (rs, pos->fdi->sock); | ||
1983 | } | ||
1984 | for (pos = context->scheduled_out_head; NULL != pos; pos = pos->next) | ||
1985 | { | ||
1986 | GNUNET_NETWORK_fdset_set_native (ws, pos->fdi->sock); | ||
1987 | } | ||
1988 | if (ready_count > 0) | ||
1989 | { | ||
1990 | /* no blocking, more work already ready! */ | ||
1991 | context->timeout = GNUNET_TIME_UNIT_ZERO; | ||
1992 | } | ||
1993 | if (NULL == scheduler_select) | ||
1994 | { | ||
1995 | select_result = GNUNET_NETWORK_socket_select (rs, | ||
1996 | ws, | ||
1997 | NULL, | ||
1998 | context->timeout); | ||
1999 | } | ||
2000 | else | ||
2001 | { | ||
2002 | select_result = scheduler_select (scheduler_select_cls, | ||
2003 | rs, | ||
2004 | ws, | ||
2005 | NULL, | ||
2006 | context->timeout); | ||
2007 | } | ||
2008 | if (select_result == GNUNET_SYSERR) | ||
2009 | { | ||
2010 | if (errno == EINTR) | ||
2011 | continue; | ||
2012 | |||
2013 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "select"); | ||
2014 | #ifndef MINGW | ||
2015 | #if USE_LSOF | ||
2016 | char lsof[512]; | ||
2017 | |||
2018 | snprintf (lsof, sizeof (lsof), "lsof -p %d", getpid ()); | ||
2019 | (void) close (1); | ||
2020 | (void) dup2 (2, 1); | ||
2021 | if (0 != system (lsof)) | ||
2022 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, | ||
2023 | "system"); | ||
2024 | #endif | ||
2025 | #endif | ||
2026 | #if DEBUG_FDS | ||
2027 | struct GNUNET_SCHEDULER_Task *t; | ||
2028 | for (t = pending_head; NULL != t; t = t->next) | ||
2029 | { | ||
2030 | if (-1 != t->read_fd) | ||
2031 | { | ||
2032 | int flags = fcntl (t->read_fd, F_GETFD); | ||
2033 | if ((flags == -1) && (errno == EBADF)) | ||
2034 | { | ||
2035 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2036 | "Got invalid file descriptor %d!\n", | ||
2037 | t->read_fd); | ||
2038 | dump_backtrace (t); | ||
2039 | } | ||
2040 | } | ||
2041 | if (-1 != t->write_fd) | ||
2042 | { | ||
2043 | int flags = fcntl (t->write_fd, F_GETFD); | ||
2044 | if ((flags == -1) && (errno == EBADF)) | ||
2045 | { | ||
2046 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2047 | "Got invalid file descriptor %d!\n", | ||
2048 | t->write_fd); | ||
2049 | dump_backtrace (t); | ||
2050 | } | ||
2051 | } | ||
2052 | } | ||
2053 | #endif | ||
2054 | GNUNET_assert (0); | ||
2055 | return GNUNET_SYSERR; | ||
2056 | } | ||
2057 | if ( (0 == select_result) && | ||
2058 | (0 == context->timeout.rel_value_us) && | ||
2059 | (busy_wait_warning > 16) ) | ||
2060 | { | ||
2061 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2062 | "Looks like we're busy waiting...\n"); | ||
2063 | short_wait (100); /* mitigate */ | ||
2064 | } | ||
2065 | for (pos = context->scheduled_in_head; NULL != pos; pos = pos->next) | ||
2066 | { | ||
2067 | if (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (rs, pos->fdi->sock)) | ||
2068 | { | ||
2069 | GNUNET_SCHEDULER_task_ready (pos->task, GNUNET_SCHEDULER_ET_IN); | ||
2070 | GNUNET_CONTAINER_DLL_remove (context->scheduled_in_head, | ||
2071 | context->scheduled_in_tail, | ||
2072 | pos); | ||
2073 | } | ||
2074 | } | ||
2075 | for (pos = context->scheduled_out_head; NULL != pos; pos = pos->next) | ||
2076 | { | ||
2077 | if (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (ws, pos->fdi->sock)) | ||
2078 | { | ||
2079 | GNUNET_SCHEDULER_task_ready (pos->task, GNUNET_SCHEDULER_ET_OUT); | ||
2080 | GNUNET_CONTAINER_DLL_remove (context->scheduled_out_head, | ||
2081 | context->scheduled_out_tail, | ||
2082 | pos); | ||
2083 | } | ||
2084 | } | ||
2085 | GNUNET_SCHEDULER_run_from_driver (sh); | ||
2086 | if (last_tr == tasks_run) | ||
2087 | { | ||
2088 | short_wait (1); | ||
2089 | busy_wait_warning++; | ||
2090 | } | ||
2091 | else | ||
2092 | { | ||
2093 | last_tr = tasks_run; | ||
2094 | busy_wait_warning = 0; | ||
2095 | } | ||
2096 | } | ||
2097 | return GNUNET_OK; | ||
2135 | } | 2098 | } |
2136 | 2099 | ||
2137 | 2100 | ||
@@ -2139,7 +2102,10 @@ void | |||
2139 | select_set_wakeup(void *cls, | 2102 | select_set_wakeup(void *cls, |
2140 | struct GNUNET_TIME_Absolute dt) | 2103 | struct GNUNET_TIME_Absolute dt) |
2141 | { | 2104 | { |
2142 | 2105 | struct DriverContext *context = cls; | |
2106 | GNUNET_assert (NULL != context); | ||
2107 | |||
2108 | context->timeout = GNUNET_TIME_absolute_get_remaining (dt); | ||
2143 | } | 2109 | } |
2144 | 2110 | ||
2145 | 2111 | ||
@@ -2148,12 +2114,10 @@ select_set_wakeup(void *cls, | |||
2148 | * | 2114 | * |
2149 | * @return NULL on error | 2115 | * @return NULL on error |
2150 | */ | 2116 | */ |
2151 | const struct GNUNET_SCHEDULER_Driver * | 2117 | struct GNUNET_SCHEDULER_Driver * |
2152 | GNUNET_SCHEDULER_driver_select () | 2118 | GNUNET_SCHEDULER_driver_select () |
2153 | { | 2119 | { |
2154 | |||
2155 | struct GNUNET_SCHEDULER_Driver *select_driver; | 2120 | struct GNUNET_SCHEDULER_Driver *select_driver; |
2156 | |||
2157 | select_driver = GNUNET_new (struct GNUNET_SCHEDULER_Driver); | 2121 | select_driver = GNUNET_new (struct GNUNET_SCHEDULER_Driver); |
2158 | 2122 | ||
2159 | select_driver->loop = &select_loop; | 2123 | select_driver->loop = &select_loop; |
@@ -2161,7 +2125,6 @@ GNUNET_SCHEDULER_driver_select () | |||
2161 | select_driver->del = &select_del; | 2125 | select_driver->del = &select_del; |
2162 | select_driver->set_wakeup = &select_set_wakeup; | 2126 | select_driver->set_wakeup = &select_set_wakeup; |
2163 | 2127 | ||
2164 | |||
2165 | return select_driver; | 2128 | return select_driver; |
2166 | } | 2129 | } |
2167 | 2130 | ||