aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorlurchi <lurchi@strangeplace.net>2017-08-08 18:35:53 +0200
committerlurchi <lurchi@strangeplace.net>2017-08-08 18:35:57 +0200
commit6a1cd49f753ee946599266d0265afdd9ba20e68e (patch)
tree5166fdbe3230b697716bde47c4e59ed4811c3551 /src
parentb60af34ef8ec413af4eea572ce211ab03a79ca17 (diff)
downloadgnunet-6a1cd49f753ee946599266d0265afdd9ba20e68e.tar.gz
gnunet-6a1cd49f753ee946599266d0265afdd9ba20e68e.zip
separate the select driver's fd sets from the driver-internal fdsets
Diffstat (limited to 'src')
-rw-r--r--src/include/gnunet_scheduler_lib.h2
-rw-r--r--src/util/scheduler.c849
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 */
362const struct GNUNET_SCHEDULER_Driver * 362struct GNUNET_SCHEDULER_Driver *
363GNUNET_SCHEDULER_driver_select (void); 363GNUNET_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
219struct 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 */
234struct 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 */
339static void *scheduler_select_cls; 357static void *scheduler_select_cls;
340 358
359/**
360 * Scheduler handle used for the driver functions
361 */
362static 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 */
381void getNextPendingTimeout(struct GNUNET_TIME_Relative *timeout) 402struct GNUNET_TIME_Absolute
403get_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
400static void
401update_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 */
443static int
444set_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 */
470static int
471is_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 */
524static void
525check_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 */
636static void
637run_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 */
705static struct GNUNET_DISK_PipeHandle *shutdown_pipe_handle; 522static 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 */
769static int 586//static int
770check_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
795int 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
930GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_TaskCallback task, 626GNUNET_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
1032int scheduler_multi_function_call(struct GNUNET_SCHEDULER_Task *t, int (*driver_func)()) 742int 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
760void
761shutdown_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 */
1357struct GNUNET_SCHEDULER_Task * 1090struct GNUNET_SCHEDULER_Task *
1358GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_TaskCallback task, 1091GNUNET_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 */
1377struct GNUNET_SCHEDULER_Task * 1110struct GNUNET_SCHEDULER_Task *
1378GNUNET_SCHEDULER_add_shutdown (GNUNET_SCHEDULER_TaskCallback task, 1111GNUNET_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 */
1863void 1598void
1864GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task, 1599GNUNET_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,
1905int 1647int
1906GNUNET_SCHEDULER_run_from_driver (struct GNUNET_SCHEDULER_Handle *sh) 1648GNUNET_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 */
2013int 1757int
2014GNUNET_SCHEDULER_run_with_driver (const struct GNUNET_SCHEDULER_Driver *driver, 1758GNUNET_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
2112int 1856int
2113select_add(void *cls, 1857select_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
2121int 1900int
2122select_del(void *cls, 1901select_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
2130int 1957int
2131select_loop(void *cls, 1958select_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
2139select_set_wakeup(void *cls, 2102select_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 */
2151const struct GNUNET_SCHEDULER_Driver * 2117struct GNUNET_SCHEDULER_Driver *
2152GNUNET_SCHEDULER_driver_select () 2118GNUNET_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