aboutsummaryrefslogtreecommitdiff
path: root/src/util/scheduler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/scheduler.c')
-rw-r--r--src/util/scheduler.c621
1 files changed, 291 insertions, 330 deletions
diff --git a/src/util/scheduler.c b/src/util/scheduler.c
index 87a107dba..ec45889ea 100644
--- a/src/util/scheduler.c
+++ b/src/util/scheduler.c
@@ -71,19 +71,24 @@
71 71
72 72
73/** 73/**
74 * Linked list of pending tasks. 74 * Entry in list of pending tasks.
75 */ 75 */
76struct Task 76struct GNUNET_SCHEDULER_Task
77{ 77{
78 /** 78 /**
79 * This is a linked list. 79 * This is a linked list.
80 */ 80 */
81 struct Task *next; 81 struct GNUNET_SCHEDULER_Task *next;
82
83 /**
84 * This is a linked list.
85 */
86 struct GNUNET_SCHEDULER_Task *prev;
82 87
83 /** 88 /**
84 * Function to run when ready. 89 * Function to run when ready.
85 */ 90 */
86 GNUNET_SCHEDULER_Task callback; 91 GNUNET_SCHEDULER_TaskCallback callback;
87 92
88 /** 93 /**
89 * Closure for the @e callback. 94 * Closure for the @e callback.
@@ -106,13 +111,8 @@ struct Task
106 struct GNUNET_NETWORK_FDSet *write_set; 111 struct GNUNET_NETWORK_FDSet *write_set;
107 112
108 /** 113 /**
109 * Unique task identifier.
110 */
111 GNUNET_SCHEDULER_TaskIdentifier id;
112
113 /**
114 * Absolute timeout value for the task, or 114 * Absolute timeout value for the task, or
115 * GNUNET_TIME_UNIT_FOREVER_ABS for "no timeout". 115 * #GNUNET_TIME_UNIT_FOREVER_ABS for "no timeout".
116 */ 116 */
117 struct GNUNET_TIME_Absolute timeout; 117 struct GNUNET_TIME_Absolute timeout;
118 118
@@ -169,9 +169,14 @@ struct Task
169 169
170 170
171/** 171/**
172 * List of tasks waiting for an event. 172 * Head of list of tasks waiting for an event.
173 */
174static struct GNUNET_SCHEDULER_Task *pending_head;
175
176/**
177 * Tail of list of tasks waiting for an event.
173 */ 178 */
174static struct Task *pending; 179static struct GNUNET_SCHEDULER_Task *pending_tail;
175 180
176/** 181/**
177 * List of tasks waiting ONLY for a timeout event. 182 * List of tasks waiting ONLY for a timeout event.
@@ -180,31 +185,37 @@ static struct Task *pending;
180 * building select sets (we just look at the head 185 * building select sets (we just look at the head
181 * to determine the respective timeout ONCE). 186 * to determine the respective timeout ONCE).
182 */ 187 */
183static struct Task *pending_timeout; 188static struct GNUNET_SCHEDULER_Task *pending_timeout_head;
189
190/**
191 * List of tasks waiting ONLY for a timeout event.
192 * Sorted by timeout (earliest first). Used so that
193 * we do not traverse the list of these tasks when
194 * building select sets (we just look at the head
195 * to determine the respective timeout ONCE).
196 */
197static struct GNUNET_SCHEDULER_Task *pending_timeout_tail;
184 198
185/** 199/**
186 * Last inserted task waiting ONLY for a timeout event. 200 * Last inserted task waiting ONLY for a timeout event.
187 * Used to (heuristically) speed up insertion. 201 * Used to (heuristically) speed up insertion.
188 */ 202 */
189static struct Task *pending_timeout_last; 203static struct GNUNET_SCHEDULER_Task *pending_timeout_last;
190 204
191/** 205/**
192 * ID of the task that is running right now. 206 * ID of the task that is running right now.
193 */ 207 */
194static struct Task *active_task; 208static struct GNUNET_SCHEDULER_Task *active_task;
195 209
196/** 210/**
197 * List of tasks ready to run right now, 211 * Head of list of tasks ready to run right now, grouped by importance.
198 * grouped by importance.
199 */ 212 */
200static struct Task *ready[GNUNET_SCHEDULER_PRIORITY_COUNT]; 213static struct GNUNET_SCHEDULER_Task *ready_head[GNUNET_SCHEDULER_PRIORITY_COUNT];
201 214
202/** 215/**
203 * Identity of the last task queued. Incremented for each task to 216 * Tail of list of tasks ready to run right now, grouped by importance.
204 * generate a unique task ID (it is virtually impossible to start
205 * more than 2^64 tasks during the lifetime of a process).
206 */ 217 */
207static GNUNET_SCHEDULER_TaskIdentifier last_id; 218static struct GNUNET_SCHEDULER_Task *ready_tail[GNUNET_SCHEDULER_PRIORITY_COUNT];
208 219
209/** 220/**
210 * Number of tasks on the ready list. 221 * Number of tasks on the ready list.
@@ -240,10 +251,11 @@ static int current_lifeness;
240static GNUNET_SCHEDULER_select scheduler_select; 251static GNUNET_SCHEDULER_select scheduler_select;
241 252
242/** 253/**
243 * Closure for 'scheduler_select'. 254 * Closure for #scheduler_select.
244 */ 255 */
245static void *scheduler_select_cls; 256static void *scheduler_select_cls;
246 257
258
247/** 259/**
248 * Sets the select function to use in the scheduler (scheduler_select). 260 * Sets the select function to use in the scheduler (scheduler_select).
249 * 261 *
@@ -284,25 +296,25 @@ check_priority (enum GNUNET_SCHEDULER_Priority p)
284 * @param timeout next timeout (updated) 296 * @param timeout next timeout (updated)
285 */ 297 */
286static void 298static void
287update_sets (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws, 299update_sets (struct GNUNET_NETWORK_FDSet *rs,
300 struct GNUNET_NETWORK_FDSet *ws,
288 struct GNUNET_TIME_Relative *timeout) 301 struct GNUNET_TIME_Relative *timeout)
289{ 302{
290 struct Task *pos; 303 struct GNUNET_SCHEDULER_Task *pos;
291 struct GNUNET_TIME_Absolute now; 304 struct GNUNET_TIME_Absolute now;
292 struct GNUNET_TIME_Relative to; 305 struct GNUNET_TIME_Relative to;
293 306
294 now = GNUNET_TIME_absolute_get (); 307 now = GNUNET_TIME_absolute_get ();
295 pos = pending_timeout; 308 pos = pending_timeout_head;
296 if (NULL != pos) 309 if (NULL != pos)
297 { 310 {
298 to = GNUNET_TIME_absolute_get_difference (now, pos->timeout); 311 to = GNUNET_TIME_absolute_get_difference (now, pos->timeout);
299 if (timeout->rel_value_us > to.rel_value_us) 312 if (timeout->rel_value_us > to.rel_value_us)
300 *timeout = to; 313 *timeout = to;
301 if (pos->reason != 0) 314 if (0 != pos->reason)
302 *timeout = GNUNET_TIME_UNIT_ZERO; 315 *timeout = GNUNET_TIME_UNIT_ZERO;
303 } 316 }
304 pos = pending; 317 for (pos = pending_head; NULL != pos; pos = pos->next)
305 while (NULL != pos)
306 { 318 {
307 if (pos->timeout.abs_value_us != GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us) 319 if (pos->timeout.abs_value_us != GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us)
308 { 320 {
@@ -320,7 +332,6 @@ update_sets (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws,
320 GNUNET_NETWORK_fdset_add (ws, pos->write_set); 332 GNUNET_NETWORK_fdset_add (ws, pos->write_set);
321 if (0 != pos->reason) 333 if (0 != pos->reason)
322 *timeout = GNUNET_TIME_UNIT_ZERO; 334 *timeout = GNUNET_TIME_UNIT_ZERO;
323 pos = pos->next;
324 } 335 }
325} 336}
326 337
@@ -328,11 +339,11 @@ update_sets (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws,
328/** 339/**
329 * Check if the ready set overlaps with the set we want to have ready. 340 * Check if the ready set overlaps with the set we want to have ready.
330 * If so, update the want set (set all FDs that are ready). If not, 341 * If so, update the want set (set all FDs that are ready). If not,
331 * return GNUNET_NO. 342 * return #GNUNET_NO.
332 * 343 *
333 * @param ready set that is ready 344 * @param ready set that is ready
334 * @param want set that we want to be ready 345 * @param want set that we want to be ready
335 * @return GNUNET_YES if there was some overlap 346 * @return #GNUNET_YES if there was some overlap
336 */ 347 */
337static int 348static int
338set_overlaps (const struct GNUNET_NETWORK_FDSet *ready, 349set_overlaps (const struct GNUNET_NETWORK_FDSet *ready,
@@ -362,7 +373,8 @@ set_overlaps (const struct GNUNET_NETWORK_FDSet *ready,
362 * @return #GNUNET_YES if we can run it, #GNUNET_NO if not. 373 * @return #GNUNET_YES if we can run it, #GNUNET_NO if not.
363 */ 374 */
364static int 375static int
365is_ready (struct Task *task, struct GNUNET_TIME_Absolute now, 376is_ready (struct GNUNET_SCHEDULER_Task *task,
377 struct GNUNET_TIME_Absolute now,
366 const struct GNUNET_NETWORK_FDSet *rs, 378 const struct GNUNET_NETWORK_FDSet *rs,
367 const struct GNUNET_NETWORK_FDSet *ws) 379 const struct GNUNET_NETWORK_FDSet *ws)
368{ 380{
@@ -395,14 +407,15 @@ is_ready (struct Task *task, struct GNUNET_TIME_Absolute now,
395 * @param task task ready for execution 407 * @param task task ready for execution
396 */ 408 */
397static void 409static void
398queue_ready_task (struct Task *task) 410queue_ready_task (struct GNUNET_SCHEDULER_Task *task)
399{ 411{
400 enum GNUNET_SCHEDULER_Priority p = task->priority; 412 enum GNUNET_SCHEDULER_Priority p = check_priority (task->priority);
401 413
402 if (0 != (task->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) 414 if (0 != (task->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
403 p = GNUNET_SCHEDULER_PRIORITY_SHUTDOWN; 415 p = GNUNET_SCHEDULER_PRIORITY_SHUTDOWN;
404 task->next = ready[check_priority (p)]; 416 GNUNET_CONTAINER_DLL_insert (ready_head[p],
405 ready[check_priority (p)] = task; 417 ready_tail[p],
418 task);
406 ready_count++; 419 ready_count++;
407} 420}
408 421
@@ -418,45 +431,35 @@ static void
418check_ready (const struct GNUNET_NETWORK_FDSet *rs, 431check_ready (const struct GNUNET_NETWORK_FDSet *rs,
419 const struct GNUNET_NETWORK_FDSet *ws) 432 const struct GNUNET_NETWORK_FDSet *ws)
420{ 433{
421 struct Task *pos; 434 struct GNUNET_SCHEDULER_Task *pos;
422 struct Task *prev; 435 struct GNUNET_SCHEDULER_Task *next;
423 struct Task *next;
424 struct GNUNET_TIME_Absolute now; 436 struct GNUNET_TIME_Absolute now;
425 437
426 now = GNUNET_TIME_absolute_get (); 438 now = GNUNET_TIME_absolute_get ();
427 prev = NULL; 439 while (NULL != (pos = pending_timeout_head))
428 pos = pending_timeout;
429 while (NULL != pos)
430 { 440 {
431 next = pos->next;
432 if (now.abs_value_us >= pos->timeout.abs_value_us) 441 if (now.abs_value_us >= pos->timeout.abs_value_us)
433 pos->reason |= GNUNET_SCHEDULER_REASON_TIMEOUT; 442 pos->reason |= GNUNET_SCHEDULER_REASON_TIMEOUT;
434 if (0 == pos->reason) 443 if (0 == pos->reason)
435 break; 444 break;
436 pending_timeout = next; 445 GNUNET_CONTAINER_DLL_remove (pending_timeout_head,
446 pending_timeout_tail,
447 pos);
437 if (pending_timeout_last == pos) 448 if (pending_timeout_last == pos)
438 pending_timeout_last = NULL; 449 pending_timeout_last = NULL;
439 queue_ready_task (pos); 450 queue_ready_task (pos);
440 pos = next;
441 } 451 }
442 pos = pending; 452 pos = pending_head;
443 while (NULL != pos) 453 while (NULL != pos)
444 { 454 {
445 LOG (GNUNET_ERROR_TYPE_DEBUG,
446 "Checking readiness of task: %llu / %p\n",
447 pos->id, pos->callback_cls);
448 next = pos->next; 455 next = pos->next;
449 if (GNUNET_YES == is_ready (pos, now, rs, ws)) 456 if (GNUNET_YES == is_ready (pos, now, rs, ws))
450 { 457 {
451 if (NULL == prev) 458 GNUNET_CONTAINER_DLL_remove (pending_head,
452 pending = next; 459 pending_tail,
453 else 460 pos);
454 prev->next = next;
455 queue_ready_task (pos); 461 queue_ready_task (pos);
456 pos = next;
457 continue;
458 } 462 }
459 prev = pos;
460 pos = next; 463 pos = next;
461 } 464 }
462} 465}
@@ -468,43 +471,24 @@ check_ready (const struct GNUNET_NETWORK_FDSet *rs,
468 * cause all tasks to run (as soon as possible, respecting 471 * cause all tasks to run (as soon as possible, respecting
469 * priorities and prerequisite tasks). Note that tasks 472 * priorities and prerequisite tasks). Note that tasks
470 * scheduled AFTER this call may still be delayed arbitrarily. 473 * scheduled AFTER this call may still be delayed arbitrarily.
474 *
475 * Note that we don't move the tasks into the ready queue yet;
476 * check_ready() will do that later, possibly adding additional
477 * readiness-factors
471 */ 478 */
472void 479void
473GNUNET_SCHEDULER_shutdown () 480GNUNET_SCHEDULER_shutdown ()
474{ 481{
475 struct Task *pos; 482 struct GNUNET_SCHEDULER_Task *pos;
476 int i; 483 int i;
477 484
478 pos = pending_timeout; 485 for (pos = pending_timeout_head; NULL != pos; pos = pos->next)
479 while (NULL != pos)
480 {
481 pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN; 486 pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN;
482 /* we don't move the task into the ready queue yet; check_ready 487 for (pos = pending_head; NULL != pos; pos = pos->next)
483 * will do that later, possibly adding additional
484 * readiness-factors */
485 pos = pos->next;
486 }
487 pos = pending;
488 while (NULL != pos)
489 {
490 pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN; 488 pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN;
491 /* we don't move the task into the ready queue yet; check_ready
492 * will do that later, possibly adding additional
493 * readiness-factors */
494 pos = pos->next;
495 }
496 for (i = 0; i < GNUNET_SCHEDULER_PRIORITY_COUNT; i++) 489 for (i = 0; i < GNUNET_SCHEDULER_PRIORITY_COUNT; i++)
497 { 490 for (pos = ready_head[i]; NULL != pos; pos = pos->next)
498 pos = ready[i];
499 while (NULL != pos)
500 {
501 pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN; 491 pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN;
502 /* we don't move the task into the ready queue yet; check_ready
503 * will do that later, possibly adding additional
504 * readiness-factors */
505 pos = pos->next;
506 }
507 }
508} 492}
509 493
510 494
@@ -514,7 +498,7 @@ GNUNET_SCHEDULER_shutdown ()
514 * @param t task to destroy 498 * @param t task to destroy
515 */ 499 */
516static void 500static void
517destroy_task (struct Task *t) 501destroy_task (struct GNUNET_SCHEDULER_Task *t)
518{ 502{
519 if (NULL != t->read_set) 503 if (NULL != t->read_set)
520 GNUNET_NETWORK_fdset_destroy (t->read_set); 504 GNUNET_NETWORK_fdset_destroy (t->read_set);
@@ -542,7 +526,7 @@ run_ready (struct GNUNET_NETWORK_FDSet *rs,
542 struct GNUNET_NETWORK_FDSet *ws) 526 struct GNUNET_NETWORK_FDSet *ws)
543{ 527{
544 enum GNUNET_SCHEDULER_Priority p; 528 enum GNUNET_SCHEDULER_Priority p;
545 struct Task *pos; 529 struct GNUNET_SCHEDULER_Task *pos;
546 struct GNUNET_SCHEDULER_TaskContext tc; 530 struct GNUNET_SCHEDULER_TaskContext tc;
547 531
548 max_priority_added = GNUNET_SCHEDULER_PRIORITY_KEEP; 532 max_priority_added = GNUNET_SCHEDULER_PRIORITY_KEEP;
@@ -550,17 +534,19 @@ run_ready (struct GNUNET_NETWORK_FDSet *rs,
550 { 534 {
551 if (0 == ready_count) 535 if (0 == ready_count)
552 return; 536 return;
553 GNUNET_assert (ready[GNUNET_SCHEDULER_PRIORITY_KEEP] == NULL); 537 GNUNET_assert (NULL == ready_head[GNUNET_SCHEDULER_PRIORITY_KEEP]);
554 /* yes, p>0 is correct, 0 is "KEEP" which should 538 /* yes, p>0 is correct, 0 is "KEEP" which should
555 * always be an empty queue (see assertion)! */ 539 * always be an empty queue (see assertion)! */
556 for (p = GNUNET_SCHEDULER_PRIORITY_COUNT - 1; p > 0; p--) 540 for (p = GNUNET_SCHEDULER_PRIORITY_COUNT - 1; p > 0; p--)
557 { 541 {
558 pos = ready[p]; 542 pos = ready_head[p];
559 if (NULL != pos) 543 if (NULL != pos)
560 break; 544 break;
561 } 545 }
562 GNUNET_assert (NULL != pos); /* ready_count wrong? */ 546 GNUNET_assert (NULL != pos); /* ready_count wrong? */
563 ready[p] = pos->next; 547 GNUNET_CONTAINER_DLL_remove (ready_head[p],
548 ready_tail[p],
549 pos);
564 ready_count--; 550 ready_count--;
565 current_priority = pos->priority; 551 current_priority = pos->priority;
566 current_lifeness = pos->lifeness; 552 current_lifeness = pos->lifeness;
@@ -570,35 +556,35 @@ run_ready (struct GNUNET_NETWORK_FDSet *rs,
570 DELAY_THRESHOLD.rel_value_us) 556 DELAY_THRESHOLD.rel_value_us)
571 { 557 {
572 LOG (GNUNET_ERROR_TYPE_DEBUG, 558 LOG (GNUNET_ERROR_TYPE_DEBUG,
573 "Task %llu took %s to be scheduled\n", 559 "Task %p took %s to be scheduled\n",
574 (unsigned long long) pos->id, 560 pos,
575 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->start_time), 561 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (pos->start_time),
576 GNUNET_YES)); 562 GNUNET_YES));
577 } 563 }
578#endif 564#endif
579 tc.reason = pos->reason; 565 tc.reason = pos->reason;
580 tc.read_ready = (pos->read_set == NULL) ? rs : pos->read_set; 566 tc.read_ready = (NULL == pos->read_set) ? rs : pos->read_set;
581 if ((pos->read_fd != -1) && 567 if ((-1 != pos->read_fd) &&
582 (0 != (pos->reason & GNUNET_SCHEDULER_REASON_READ_READY))) 568 (0 != (pos->reason & GNUNET_SCHEDULER_REASON_READ_READY)))
583 GNUNET_NETWORK_fdset_set_native (rs, pos->read_fd); 569 GNUNET_NETWORK_fdset_set_native (rs, pos->read_fd);
584 tc.write_ready = (pos->write_set == NULL) ? ws : pos->write_set; 570 tc.write_ready = (NULL == pos->write_set) ? ws : pos->write_set;
585 if ((pos->write_fd != -1) && 571 if ((-1 != pos->write_fd) &&
586 (0 != (pos->reason & GNUNET_SCHEDULER_REASON_WRITE_READY))) 572 (0 != (pos->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)))
587 GNUNET_NETWORK_fdset_set_native (ws, pos->write_fd); 573 GNUNET_NETWORK_fdset_set_native (ws, pos->write_fd);
588 if (((tc.reason & GNUNET_SCHEDULER_REASON_WRITE_READY) != 0) && 574 if ((0 != (tc.reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) &&
589 (pos->write_fd != -1) && 575 (-1 != pos->write_fd) &&
590 (!GNUNET_NETWORK_fdset_test_native (ws, pos->write_fd))) 576 (!GNUNET_NETWORK_fdset_test_native (ws, pos->write_fd)))
591 GNUNET_abort (); // added to ready in previous select loop! 577 GNUNET_abort (); // added to ready in previous select loop!
592 LOG (GNUNET_ERROR_TYPE_DEBUG, 578 LOG (GNUNET_ERROR_TYPE_DEBUG,
593 "Running task: %llu / %p\n", pos->id, 579 "Running task: %p\n",
594 pos->callback_cls); 580 pos);
595 pos->callback (pos->callback_cls, &tc); 581 pos->callback (pos->callback_cls, &tc);
596#if EXECINFO 582#if EXECINFO
597 int i; 583 unsigned int i;
598 584
599 for (i = 0; i < pos->num_backtrace_strings; i++) 585 for (i = 0; i < pos->num_backtrace_strings; i++)
600 LOG (GNUNET_ERROR_TYPE_ERROR, 586 LOG (GNUNET_ERROR_TYPE_ERROR,
601 "Task %llu trace %d: %s\n", 587 "Task %llu trace %u: %s\n",
602 pos->id, 588 pos->id,
603 i, 589 i,
604 pos->backtrace_strings[i]); 590 pos->backtrace_strings[i]);
@@ -607,9 +593,10 @@ run_ready (struct GNUNET_NETWORK_FDSet *rs,
607 destroy_task (pos); 593 destroy_task (pos);
608 tasks_run++; 594 tasks_run++;
609 } 595 }
610 while ((NULL == pending) || (p >= max_priority_added)); 596 while ((NULL == pending_head) || (p >= max_priority_added));
611} 597}
612 598
599
613/** 600/**
614 * Pipe used to communicate shutdown via signal. 601 * Pipe used to communicate shutdown via signal.
615 */ 602 */
@@ -680,17 +667,17 @@ sighandler_shutdown ()
680static int 667static int
681check_lifeness () 668check_lifeness ()
682{ 669{
683 struct Task *t; 670 struct GNUNET_SCHEDULER_Task *t;
684 671
685 if (ready_count > 0) 672 if (ready_count > 0)
686 return GNUNET_OK; 673 return GNUNET_OK;
687 for (t = pending; NULL != t; t = t->next) 674 for (t = pending_head; NULL != t; t = t->next)
688 if (t->lifeness == GNUNET_YES) 675 if (t->lifeness == GNUNET_YES)
689 return GNUNET_OK; 676 return GNUNET_OK;
690 for (t = pending_timeout; NULL != t; t = t->next) 677 for (t = pending_timeout_head; NULL != t; t = t->next)
691 if (t->lifeness == GNUNET_YES) 678 if (t->lifeness == GNUNET_YES)
692 return GNUNET_OK; 679 return GNUNET_OK;
693 if ((NULL != pending) || (NULL != pending_timeout)) 680 if ((NULL != pending_head) || (NULL != pending_timeout_head))
694 { 681 {
695 GNUNET_SCHEDULER_shutdown (); 682 GNUNET_SCHEDULER_shutdown ();
696 return GNUNET_OK; 683 return GNUNET_OK;
@@ -714,7 +701,8 @@ check_lifeness ()
714 * @param task_cls closure of @a task 701 * @param task_cls closure of @a task
715 */ 702 */
716void 703void
717GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls) 704GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_TaskCallback task,
705 void *task_cls)
718{ 706{
719 struct GNUNET_NETWORK_FDSet *rs; 707 struct GNUNET_NETWORK_FDSet *rs;
720 struct GNUNET_NETWORK_FDSet *ws; 708 struct GNUNET_NETWORK_FDSet *ws;
@@ -740,13 +728,17 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
740 rs = GNUNET_NETWORK_fdset_create (); 728 rs = GNUNET_NETWORK_fdset_create ();
741 ws = GNUNET_NETWORK_fdset_create (); 729 ws = GNUNET_NETWORK_fdset_create ();
742 GNUNET_assert (NULL == shutdown_pipe_handle); 730 GNUNET_assert (NULL == shutdown_pipe_handle);
743 shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO); 731 shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO,
732 GNUNET_NO,
733 GNUNET_NO,
734 GNUNET_NO);
744 GNUNET_assert (NULL != shutdown_pipe_handle); 735 GNUNET_assert (NULL != shutdown_pipe_handle);
745 pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle, 736 pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle,
746 GNUNET_DISK_PIPE_END_READ); 737 GNUNET_DISK_PIPE_END_READ);
747 GNUNET_assert (pr != NULL); 738 GNUNET_assert (NULL != pr);
748 my_pid = getpid (); 739 my_pid = getpid ();
749 LOG (GNUNET_ERROR_TYPE_DEBUG, "Registering signal handlers\n"); 740 LOG (GNUNET_ERROR_TYPE_DEBUG,
741 "Registering signal handlers\n");
750 shc_int = GNUNET_SIGNAL_handler_install (SIGINT, &sighandler_shutdown); 742 shc_int = GNUNET_SIGNAL_handler_install (SIGINT, &sighandler_shutdown);
751 shc_term = GNUNET_SIGNAL_handler_install (SIGTERM, &sighandler_shutdown); 743 shc_term = GNUNET_SIGNAL_handler_install (SIGTERM, &sighandler_shutdown);
752#if (SIGTERM != GNUNET_TERM_SIG) 744#if (SIGTERM != GNUNET_TERM_SIG)
@@ -759,7 +751,8 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
759#endif 751#endif
760 current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT; 752 current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT;
761 current_lifeness = GNUNET_YES; 753 current_lifeness = GNUNET_YES;
762 GNUNET_SCHEDULER_add_continuation (task, task_cls, 754 GNUNET_SCHEDULER_add_continuation (task,
755 task_cls,
763 GNUNET_SCHEDULER_REASON_STARTUP); 756 GNUNET_SCHEDULER_REASON_STARTUP);
764 active_task = (void *) (long) -1; /* force passing of sanity check */ 757 active_task = (void *) (long) -1; /* force passing of sanity check */
765 GNUNET_SCHEDULER_add_now_with_lifeness (GNUNET_NO, 758 GNUNET_SCHEDULER_add_now_with_lifeness (GNUNET_NO,
@@ -860,7 +853,7 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
860enum GNUNET_SCHEDULER_Reason 853enum GNUNET_SCHEDULER_Reason
861GNUNET_SCHEDULER_get_reason () 854GNUNET_SCHEDULER_get_reason ()
862{ 855{
863 GNUNET_assert (active_task != NULL); 856 GNUNET_assert (NULL != active_task);
864 return active_task->reason; 857 return active_task->reason;
865} 858}
866 859
@@ -877,21 +870,17 @@ GNUNET_SCHEDULER_get_reason ()
877unsigned int 870unsigned int
878GNUNET_SCHEDULER_get_load (enum GNUNET_SCHEDULER_Priority p) 871GNUNET_SCHEDULER_get_load (enum GNUNET_SCHEDULER_Priority p)
879{ 872{
880 struct Task *pos; 873 struct GNUNET_SCHEDULER_Task *pos;
881 unsigned int ret; 874 unsigned int ret;
882 875
883 GNUNET_assert (active_task != NULL); 876 GNUNET_assert (NULL != active_task);
884 if (p == GNUNET_SCHEDULER_PRIORITY_COUNT) 877 if (p == GNUNET_SCHEDULER_PRIORITY_COUNT)
885 return ready_count; 878 return ready_count;
886 if (p == GNUNET_SCHEDULER_PRIORITY_KEEP) 879 if (p == GNUNET_SCHEDULER_PRIORITY_KEEP)
887 p = current_priority; 880 p = current_priority;
888 ret = 0; 881 ret = 0;
889 pos = ready[check_priority (p)]; 882 for (pos = ready_head[check_priority (p)]; NULL != pos; pos = pos->next)
890 while (NULL != pos)
891 {
892 pos = pos->next;
893 ret++; 883 ret++;
894 }
895 return ret; 884 return ret;
896} 885}
897 886
@@ -904,92 +893,45 @@ GNUNET_SCHEDULER_get_load (enum GNUNET_SCHEDULER_Priority p)
904 * @return original closure of the task 893 * @return original closure of the task
905 */ 894 */
906void * 895void *
907GNUNET_SCHEDULER_cancel (GNUNET_SCHEDULER_TaskIdentifier task) 896GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Task *task)
908{ 897{
909 struct Task *t;
910 struct Task *prev;
911 enum GNUNET_SCHEDULER_Priority p; 898 enum GNUNET_SCHEDULER_Priority p;
912 int to;
913 void *ret; 899 void *ret;
914 900
915 GNUNET_assert (NULL != active_task); 901 GNUNET_assert (NULL != active_task);
916 to = 0; 902 if (GNUNET_SCHEDULER_REASON_NONE == task->reason)
917 prev = NULL;
918 t = pending;
919 while (NULL != t)
920 {
921 if (t->id == task)
922 break;
923 prev = t;
924 t = t->next;
925 }
926 if (NULL == t)
927 {
928 prev = NULL;
929 to = 1;
930 t = pending_timeout;
931 while (t != NULL)
932 {
933 if (t->id == task)
934 break;
935 prev = t;
936 t = t->next;
937 }
938 if (pending_timeout_last == t)
939 pending_timeout_last = NULL;
940 }
941 p = 0;
942 while (NULL == t)
943 {
944 p++;
945 if (p >= GNUNET_SCHEDULER_PRIORITY_COUNT)
946 {
947 LOG (GNUNET_ERROR_TYPE_ERROR,
948 _("Attempt to cancel dead task %llu!\n"),
949 (unsigned long long) task);
950 GNUNET_assert (0);
951 }
952 prev = NULL;
953 t = ready[p];
954 while (NULL != t)
955 {
956 if (t->id == task)
957 {
958 ready_count--;
959 break;
960 }
961 prev = t;
962 t = t->next;
963 }
964 }
965 if (NULL == prev)
966 { 903 {
967 if (0 == p) 904 if ( (-1 == task->read_fd) &&
905 (-1 == task->write_fd) &&
906 (NULL == task->read_set) &&
907 (NULL == task->write_set) )
968 { 908 {
969 if (0 == to) 909 GNUNET_CONTAINER_DLL_remove (pending_timeout_head,
970 { 910 pending_timeout_tail,
971 pending = t->next; 911 task);
972 } 912 if (task == pending_timeout_last)
973 else 913 pending_timeout_last = NULL;
974 {
975 pending_timeout = t->next;
976 }
977 } 914 }
978 else 915 else
979 { 916 {
980 ready[p] = t->next; 917 GNUNET_CONTAINER_DLL_remove (pending_head,
918 pending_tail,
919 task);
981 } 920 }
982 } 921 }
983 else 922 else
984 { 923 {
985 prev->next = t->next; 924 p = check_priority (task->priority);
925 GNUNET_CONTAINER_DLL_remove (ready_head[p],
926 ready_tail[p],
927 task);
928 ready_count--;
986 } 929 }
987 ret = t->callback_cls; 930 ret = task->callback_cls;
988 LOG (GNUNET_ERROR_TYPE_DEBUG, 931 LOG (GNUNET_ERROR_TYPE_DEBUG,
989 "Canceling task: %llu / %p\n", 932 "Canceling task %p\n",
990 task, 933 task);
991 t->callback_cls); 934 destroy_task (task);
992 destroy_task (t);
993 return ret; 935 return ret;
994} 936}
995 937
@@ -1005,11 +947,12 @@ GNUNET_SCHEDULER_cancel (GNUNET_SCHEDULER_TaskIdentifier task)
1005 * @param priority priority to use for the task 947 * @param priority priority to use for the task
1006 */ 948 */
1007void 949void
1008GNUNET_SCHEDULER_add_continuation_with_priority (GNUNET_SCHEDULER_Task task, void *task_cls, 950GNUNET_SCHEDULER_add_continuation_with_priority (GNUNET_SCHEDULER_TaskCallback task,
951 void *task_cls,
1009 enum GNUNET_SCHEDULER_Reason reason, 952 enum GNUNET_SCHEDULER_Reason reason,
1010 enum GNUNET_SCHEDULER_Priority priority) 953 enum GNUNET_SCHEDULER_Priority priority)
1011{ 954{
1012 struct Task *t; 955 struct GNUNET_SCHEDULER_Task *t;
1013 956
1014#if EXECINFO 957#if EXECINFO
1015 void *backtrace_array[50]; 958 void *backtrace_array[50];
@@ -1018,7 +961,7 @@ GNUNET_SCHEDULER_add_continuation_with_priority (GNUNET_SCHEDULER_Task task, voi
1018 GNUNET_assert (NULL != task); 961 GNUNET_assert (NULL != task);
1019 GNUNET_assert ((NULL != active_task) || 962 GNUNET_assert ((NULL != active_task) ||
1020 (GNUNET_SCHEDULER_REASON_STARTUP == reason)); 963 (GNUNET_SCHEDULER_REASON_STARTUP == reason));
1021 t = GNUNET_new (struct Task); 964 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1022#if EXECINFO 965#if EXECINFO
1023 t->num_backtrace_strings = backtrace (backtrace_array, 50); 966 t->num_backtrace_strings = backtrace (backtrace_array, 50);
1024 t->backtrace_strings = 967 t->backtrace_strings =
@@ -1028,7 +971,6 @@ GNUNET_SCHEDULER_add_continuation_with_priority (GNUNET_SCHEDULER_Task task, voi
1028 t->write_fd = -1; 971 t->write_fd = -1;
1029 t->callback = task; 972 t->callback = task;
1030 t->callback_cls = task_cls; 973 t->callback_cls = task_cls;
1031 t->id = ++last_id;
1032#if PROFILE_DELAYS 974#if PROFILE_DELAYS
1033 t->start_time = GNUNET_TIME_absolute_get (); 975 t->start_time = GNUNET_TIME_absolute_get ();
1034#endif 976#endif
@@ -1036,9 +978,8 @@ GNUNET_SCHEDULER_add_continuation_with_priority (GNUNET_SCHEDULER_Task task, voi
1036 t->priority = priority; 978 t->priority = priority;
1037 t->lifeness = current_lifeness; 979 t->lifeness = current_lifeness;
1038 LOG (GNUNET_ERROR_TYPE_DEBUG, 980 LOG (GNUNET_ERROR_TYPE_DEBUG,
1039 "Adding continuation task: %llu / %p\n", 981 "Adding continuation task %p\n",
1040 t->id, 982 t);
1041 t->callback_cls);
1042 queue_ready_task (t); 983 queue_ready_task (t);
1043} 984}
1044 985
@@ -1053,7 +994,7 @@ GNUNET_SCHEDULER_add_continuation_with_priority (GNUNET_SCHEDULER_Task task, voi
1053 * @param reason reason for task invocation 994 * @param reason reason for task invocation
1054 */ 995 */
1055void 996void
1056GNUNET_SCHEDULER_add_continuation (GNUNET_SCHEDULER_Task task, void *task_cls, 997GNUNET_SCHEDULER_add_continuation (GNUNET_SCHEDULER_TaskCallback task, void *task_cls,
1057 enum GNUNET_SCHEDULER_Reason reason) 998 enum GNUNET_SCHEDULER_Reason reason)
1058{ 999{
1059 GNUNET_SCHEDULER_add_continuation_with_priority (task, task_cls, 1000 GNUNET_SCHEDULER_add_continuation_with_priority (task, task_cls,
@@ -1063,26 +1004,6 @@ GNUNET_SCHEDULER_add_continuation (GNUNET_SCHEDULER_Task task, void *task_cls,
1063 1004
1064 1005
1065/** 1006/**
1066 * Schedule a new task to be run with a specified priority.
1067 *
1068 * @param prio how important is the new task?
1069 * @param task main function of the task
1070 * @param task_cls closure of @a task
1071 * @return unique task identifier for the job
1072 * only valid until @a task is started!
1073 */
1074GNUNET_SCHEDULER_TaskIdentifier
1075GNUNET_SCHEDULER_add_with_priority (enum GNUNET_SCHEDULER_Priority prio,
1076 GNUNET_SCHEDULER_Task task, void *task_cls)
1077{
1078 return GNUNET_SCHEDULER_add_select (prio,
1079 GNUNET_TIME_UNIT_ZERO, NULL, NULL, task,
1080 task_cls);
1081}
1082
1083
1084
1085/**
1086 * Schedule a new task to be run with a specified delay. The task 1007 * Schedule a new task to be run with a specified delay. The task
1087 * will be scheduled for execution once the delay has expired. 1008 * will be scheduled for execution once the delay has expired.
1088 * 1009 *
@@ -1094,14 +1015,15 @@ GNUNET_SCHEDULER_add_with_priority (enum GNUNET_SCHEDULER_Priority prio,
1094 * @return unique task identifier for the job 1015 * @return unique task identifier for the job
1095 * only valid until @a task is started! 1016 * only valid until @a task is started!
1096 */ 1017 */
1097GNUNET_SCHEDULER_TaskIdentifier 1018struct GNUNET_SCHEDULER_Task *
1098GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay, 1019GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay,
1099 enum GNUNET_SCHEDULER_Priority priority, 1020 enum GNUNET_SCHEDULER_Priority priority,
1100 GNUNET_SCHEDULER_Task task, void *task_cls) 1021 GNUNET_SCHEDULER_TaskCallback task,
1022 void *task_cls)
1101{ 1023{
1102 struct Task *t; 1024 struct GNUNET_SCHEDULER_Task *t;
1103 struct Task *pos; 1025 struct GNUNET_SCHEDULER_Task *pos;
1104 struct Task *prev; 1026 struct GNUNET_SCHEDULER_Task *prev;
1105 1027
1106#if EXECINFO 1028#if EXECINFO
1107 void *backtrace_array[MAX_TRACE_DEPTH]; 1029 void *backtrace_array[MAX_TRACE_DEPTH];
@@ -1109,7 +1031,7 @@ GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay,
1109 1031
1110 GNUNET_assert (NULL != active_task); 1032 GNUNET_assert (NULL != active_task);
1111 GNUNET_assert (NULL != task); 1033 GNUNET_assert (NULL != task);
1112 t = GNUNET_new (struct Task); 1034 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1113 t->callback = task; 1035 t->callback = task;
1114 t->callback_cls = task_cls; 1036 t->callback_cls = task_cls;
1115#if EXECINFO 1037#if EXECINFO
@@ -1119,7 +1041,6 @@ GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay,
1119#endif 1041#endif
1120 t->read_fd = -1; 1042 t->read_fd = -1;
1121 t->write_fd = -1; 1043 t->write_fd = -1;
1122 t->id = ++last_id;
1123#if PROFILE_DELAYS 1044#if PROFILE_DELAYS
1124 t->start_time = GNUNET_TIME_absolute_get (); 1045 t->start_time = GNUNET_TIME_absolute_get ();
1125#endif 1046#endif
@@ -1128,44 +1049,74 @@ GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay,
1128 t->lifeness = current_lifeness; 1049 t->lifeness = current_lifeness;
1129 /* try tail first (optimization in case we are 1050 /* try tail first (optimization in case we are
1130 * appending to a long list of tasks with timeouts) */ 1051 * appending to a long list of tasks with timeouts) */
1131 prev = pending_timeout_last; 1052 if (0 == delay.rel_value_us)
1132 if (prev != NULL)
1133 { 1053 {
1134 if (prev->timeout.abs_value_us > t->timeout.abs_value_us) 1054 GNUNET_CONTAINER_DLL_insert (pending_timeout_head,
1135 prev = NULL; 1055 pending_timeout_tail,
1136 else 1056 t);
1137 pos = prev->next; /* heuristic success! */
1138 }
1139 if (prev == NULL)
1140 {
1141 /* heuristic failed, do traversal of timeout list */
1142 pos = pending_timeout;
1143 } 1057 }
1144 while ((pos != NULL) && 1058 else
1145 ((pos->timeout.abs_value_us <= t->timeout.abs_value_us) ||
1146 (0 != pos->reason)))
1147 { 1059 {
1148 prev = pos; 1060 /* first move from heuristic start backwards to before start time */
1149 pos = pos->next; 1061 prev = pending_timeout_last;
1062 while ( (NULL != prev) &&
1063 (prev->timeout.abs_value_us > t->timeout.abs_value_us) )
1064 prev = prev->prev;
1065 /* now, move from heuristic start (or head of list) forward to insertion point */
1066 if (NULL == prev)
1067 pos = pending_timeout_head;
1068 else
1069 pos = prev->next;
1070 while ( (NULL != pos) &&
1071 ( (pos->timeout.abs_value_us <= t->timeout.abs_value_us) ||
1072 (0 != pos->reason) ) )
1073 {
1074 prev = pos;
1075 pos = pos->next;
1076 }
1077 GNUNET_CONTAINER_DLL_insert_after (pending_timeout_head,
1078 pending_timeout_tail,
1079 prev,
1080 t);
1081 /* finally, update heuristic insertion point to last insertion... */
1082 pending_timeout_last = t;
1150 } 1083 }
1151 if (prev == NULL)
1152 pending_timeout = t;
1153 else
1154 prev->next = t;
1155 t->next = pos;
1156 /* hyper-optimization... */
1157 pending_timeout_last = t;
1158 1084
1159 LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id, 1085 LOG (GNUNET_ERROR_TYPE_DEBUG,
1160 t->callback_cls); 1086 "Adding task: %p\n",
1087 t);
1161#if EXECINFO 1088#if EXECINFO
1162 int i; 1089 unsigned int i;
1163 1090
1164 for (i = 0; i < t->num_backtrace_strings; i++) 1091 for (i = 0; i < t->num_backtrace_strings; i++)
1165 LOG (GNUNET_ERROR_TYPE_DEBUG, "Task %llu trace %d: %s\n", t->id, i, 1092 LOG (GNUNET_ERROR_TYPE_DEBUG,
1093 "Task %p trace %d: %s\n",
1094 t,
1095 i,
1166 t->backtrace_strings[i]); 1096 t->backtrace_strings[i]);
1167#endif 1097#endif
1168 return t->id; 1098 return t;
1099}
1100
1101
1102/**
1103 * Schedule a new task to be run with a specified priority.
1104 *
1105 * @param prio how important is the new task?
1106 * @param task main function of the task
1107 * @param task_cls closure of @a task
1108 * @return unique task identifier for the job
1109 * only valid until @a task is started!
1110 */
1111struct GNUNET_SCHEDULER_Task *
1112GNUNET_SCHEDULER_add_with_priority (enum GNUNET_SCHEDULER_Priority prio,
1113 GNUNET_SCHEDULER_TaskCallback task,
1114 void *task_cls)
1115{
1116 return GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_UNIT_ZERO,
1117 prio,
1118 task,
1119 task_cls);
1169} 1120}
1170 1121
1171 1122
@@ -1181,9 +1132,9 @@ GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay,
1181 * @return unique task identifier for the job 1132 * @return unique task identifier for the job
1182 * only valid until "task" is started! 1133 * only valid until "task" is started!
1183 */ 1134 */
1184GNUNET_SCHEDULER_TaskIdentifier 1135struct GNUNET_SCHEDULER_Task *
1185GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay, 1136GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay,
1186 GNUNET_SCHEDULER_Task task, void *task_cls) 1137 GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
1187{ 1138{
1188 return GNUNET_SCHEDULER_add_delayed_with_priority (delay, 1139 return GNUNET_SCHEDULER_add_delayed_with_priority (delay,
1189 GNUNET_SCHEDULER_PRIORITY_DEFAULT, 1140 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
@@ -1206,8 +1157,8 @@ GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay,
1206 * @return unique task identifier for the job 1157 * @return unique task identifier for the job
1207 * only valid until "task" is started! 1158 * only valid until "task" is started!
1208 */ 1159 */
1209GNUNET_SCHEDULER_TaskIdentifier 1160struct GNUNET_SCHEDULER_Task *
1210GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_Task task, void *task_cls) 1161GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
1211{ 1162{
1212 return GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_ZERO, task, task_cls); 1163 return GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_ZERO, task, task_cls);
1213} 1164}
@@ -1227,19 +1178,15 @@ GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_Task task, void *task_cls)
1227 * @return unique task identifier for the job 1178 * @return unique task identifier for the job
1228 * only valid until @a task is started! 1179 * only valid until @a task is started!
1229 */ 1180 */
1230GNUNET_SCHEDULER_TaskIdentifier 1181struct GNUNET_SCHEDULER_Task *
1231GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness, 1182GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness,
1232 GNUNET_SCHEDULER_Task task, 1183 GNUNET_SCHEDULER_TaskCallback task,
1233 void *task_cls) 1184 void *task_cls)
1234{ 1185{
1235 GNUNET_SCHEDULER_TaskIdentifier ret; 1186 struct GNUNET_SCHEDULER_Task *ret;
1236 1187
1237 ret = 1188 ret = GNUNET_SCHEDULER_add_now (task, task_cls);
1238 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, 1189 ret->lifeness = lifeness;
1239 GNUNET_TIME_UNIT_ZERO, NULL, NULL, task,
1240 task_cls);
1241 GNUNET_assert (pending->id == ret);
1242 pending->lifeness = lifeness;
1243 return ret; 1190 return ret;
1244} 1191}
1245 1192
@@ -1269,16 +1216,18 @@ GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness,
1269 * @param task main function of the task 1216 * @param task main function of the task
1270 * @param task_cls closure of @a task 1217 * @param task_cls closure of @a task
1271 * @return unique task identifier for the job 1218 * @return unique task identifier for the job
1272 * only valid until "task" is started! 1219 * only valid until @a task is started!
1273 */ 1220 */
1274#ifndef MINGW 1221#ifndef MINGW
1275static GNUNET_SCHEDULER_TaskIdentifier 1222static struct GNUNET_SCHEDULER_Task *
1276add_without_sets (struct GNUNET_TIME_Relative delay, 1223add_without_sets (struct GNUNET_TIME_Relative delay,
1277 enum GNUNET_SCHEDULER_Priority priority, 1224 enum GNUNET_SCHEDULER_Priority priority,
1278 int rfd, int wfd, 1225 int rfd,
1279 GNUNET_SCHEDULER_Task task, void *task_cls) 1226 int wfd,
1227 GNUNET_SCHEDULER_TaskCallback task,
1228 void *task_cls)
1280{ 1229{
1281 struct Task *t; 1230 struct GNUNET_SCHEDULER_Task *t;
1282 1231
1283#if EXECINFO 1232#if EXECINFO
1284 void *backtrace_array[MAX_TRACE_DEPTH]; 1233 void *backtrace_array[MAX_TRACE_DEPTH];
@@ -1286,7 +1235,7 @@ add_without_sets (struct GNUNET_TIME_Relative delay,
1286 1235
1287 GNUNET_assert (NULL != active_task); 1236 GNUNET_assert (NULL != active_task);
1288 GNUNET_assert (NULL != task); 1237 GNUNET_assert (NULL != task);
1289 t = GNUNET_new (struct Task); 1238 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1290 t->callback = task; 1239 t->callback = task;
1291 t->callback_cls = task_cls; 1240 t->callback_cls = task_cls;
1292#if EXECINFO 1241#if EXECINFO
@@ -1339,36 +1288,35 @@ add_without_sets (struct GNUNET_TIME_Relative delay,
1339 t->read_fd = rfd; 1288 t->read_fd = rfd;
1340 GNUNET_assert (wfd >= -1); 1289 GNUNET_assert (wfd >= -1);
1341 t->write_fd = wfd; 1290 t->write_fd = wfd;
1342 t->id = ++last_id;
1343#if PROFILE_DELAYS 1291#if PROFILE_DELAYS
1344 t->start_time = GNUNET_TIME_absolute_get (); 1292 t->start_time = GNUNET_TIME_absolute_get ();
1345#endif 1293#endif
1346 t->timeout = GNUNET_TIME_relative_to_absolute (delay); 1294 t->timeout = GNUNET_TIME_relative_to_absolute (delay);
1347 t->priority = check_priority ((priority == GNUNET_SCHEDULER_PRIORITY_KEEP) ? current_priority : priority); 1295 t->priority = check_priority ((priority == GNUNET_SCHEDULER_PRIORITY_KEEP) ? current_priority : priority);
1348 t->lifeness = current_lifeness; 1296 t->lifeness = current_lifeness;
1349 t->next = pending; 1297 GNUNET_CONTAINER_DLL_insert (pending_head,
1350 pending = t; 1298 pending_tail,
1351 max_priority_added = GNUNET_MAX (max_priority_added, t->priority); 1299 t);
1300 max_priority_added = GNUNET_MAX (max_priority_added,
1301 t->priority);
1352 LOG (GNUNET_ERROR_TYPE_DEBUG, 1302 LOG (GNUNET_ERROR_TYPE_DEBUG,
1353 "Adding task: %llu / %p\n", 1303 "Adding task %p\n",
1354 t->id, 1304 t);
1355 t->callback_cls);
1356#if EXECINFO 1305#if EXECINFO
1357 int i; 1306 unsigned int i;
1358 1307
1359 for (i = 0; i < t->num_backtrace_strings; i++) 1308 for (i = 0; i < t->num_backtrace_strings; i++)
1360 LOG (GNUNET_ERROR_TYPE_DEBUG, 1309 LOG (GNUNET_ERROR_TYPE_DEBUG,
1361 "Task %llu trace %d: %s\n", 1310 "Task %p trace %d: %s\n",
1362 t->id, 1311 t,
1363 i, 1312 i,
1364 t->backtrace_strings[i]); 1313 t->backtrace_strings[i]);
1365#endif 1314#endif
1366 return t->id; 1315 return t;
1367} 1316}
1368#endif 1317#endif
1369 1318
1370 1319
1371
1372/** 1320/**
1373 * Schedule a new task to be run with a specified delay or when the 1321 * Schedule a new task to be run with a specified delay or when the
1374 * specified file descriptor is ready for reading. The delay can be 1322 * specified file descriptor is ready for reading. The delay can be
@@ -1384,10 +1332,11 @@ add_without_sets (struct GNUNET_TIME_Relative delay,
1384 * @return unique task identifier for the job 1332 * @return unique task identifier for the job
1385 * only valid until @a task is started! 1333 * only valid until @a task is started!
1386 */ 1334 */
1387GNUNET_SCHEDULER_TaskIdentifier 1335struct GNUNET_SCHEDULER_Task *
1388GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay, 1336GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay,
1389 struct GNUNET_NETWORK_Handle *rfd, 1337 struct GNUNET_NETWORK_Handle *rfd,
1390 GNUNET_SCHEDULER_Task task, void *task_cls) 1338 GNUNET_SCHEDULER_TaskCallback task,
1339 void *task_cls)
1391{ 1340{
1392 return GNUNET_SCHEDULER_add_read_net_with_priority (delay, 1341 return GNUNET_SCHEDULER_add_read_net_with_priority (delay,
1393 GNUNET_SCHEDULER_PRIORITY_DEFAULT, 1342 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
@@ -1412,16 +1361,18 @@ GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay,
1412 * @return unique task identifier for the job 1361 * @return unique task identifier for the job
1413 * only valid until @a task is started! 1362 * only valid until @a task is started!
1414 */ 1363 */
1415GNUNET_SCHEDULER_TaskIdentifier 1364struct GNUNET_SCHEDULER_Task *
1416GNUNET_SCHEDULER_add_read_net_with_priority (struct GNUNET_TIME_Relative delay, 1365GNUNET_SCHEDULER_add_read_net_with_priority (struct GNUNET_TIME_Relative delay,
1417 enum GNUNET_SCHEDULER_Priority priority, 1366 enum GNUNET_SCHEDULER_Priority priority,
1418 struct GNUNET_NETWORK_Handle *rfd, 1367 struct GNUNET_NETWORK_Handle *rfd,
1419 GNUNET_SCHEDULER_Task task, void *task_cls) 1368 GNUNET_SCHEDULER_TaskCallback task,
1369 void *task_cls)
1420{ 1370{
1421 return GNUNET_SCHEDULER_add_net_with_priority ( 1371 return GNUNET_SCHEDULER_add_net_with_priority (delay, priority,
1422 delay, priority, 1372 rfd,
1423 rfd, GNUNET_YES, GNUNET_NO, 1373 GNUNET_YES,
1424 task, task_cls); 1374 GNUNET_NO,
1375 task, task_cls);
1425} 1376}
1426 1377
1427 1378
@@ -1441,15 +1392,17 @@ GNUNET_SCHEDULER_add_read_net_with_priority (struct GNUNET_TIME_Relative delay,
1441 * @return unique task identifier for the job 1392 * @return unique task identifier for the job
1442 * only valid until @a task is started! 1393 * only valid until @a task is started!
1443 */ 1394 */
1444GNUNET_SCHEDULER_TaskIdentifier 1395struct GNUNET_SCHEDULER_Task *
1445GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay, 1396GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay,
1446 struct GNUNET_NETWORK_Handle *wfd, 1397 struct GNUNET_NETWORK_Handle *wfd,
1447 GNUNET_SCHEDULER_Task task, void *task_cls) 1398 GNUNET_SCHEDULER_TaskCallback task,
1399 void *task_cls)
1448{ 1400{
1449 return GNUNET_SCHEDULER_add_net_with_priority ( 1401 return GNUNET_SCHEDULER_add_net_with_priority (delay,
1450 delay, GNUNET_SCHEDULER_PRIORITY_DEFAULT, 1402 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1451 wfd, GNUNET_NO, GNUNET_YES, 1403 wfd,
1452 task, task_cls); 1404 GNUNET_NO, GNUNET_YES,
1405 task, task_cls);
1453} 1406}
1454 1407
1455/** 1408/**
@@ -1460,7 +1413,7 @@ GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay,
1460 * socket operation is ready. 1413 * socket operation is ready.
1461 * 1414 *
1462 * @param delay when should this operation time out? Use 1415 * @param delay when should this operation time out? Use
1463 * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" 1416 * #GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown"
1464 * @param priority priority of the task 1417 * @param priority priority of the task
1465 * @param fd file-descriptor 1418 * @param fd file-descriptor
1466 * @param on_read whether to poll the file-descriptor for readability 1419 * @param on_read whether to poll the file-descriptor for readability
@@ -1470,18 +1423,20 @@ GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay,
1470 * @return unique task identifier for the job 1423 * @return unique task identifier for the job
1471 * only valid until "task" is started! 1424 * only valid until "task" is started!
1472 */ 1425 */
1473GNUNET_SCHEDULER_TaskIdentifier 1426struct GNUNET_SCHEDULER_Task *
1474GNUNET_SCHEDULER_add_net_with_priority (struct GNUNET_TIME_Relative delay, 1427GNUNET_SCHEDULER_add_net_with_priority (struct GNUNET_TIME_Relative delay,
1475 enum GNUNET_SCHEDULER_Priority priority, 1428 enum GNUNET_SCHEDULER_Priority priority,
1476 struct GNUNET_NETWORK_Handle *fd, 1429 struct GNUNET_NETWORK_Handle *fd,
1477 int on_read, int on_write, 1430 int on_read,
1478 GNUNET_SCHEDULER_Task task, void *task_cls) 1431 int on_write,
1432 GNUNET_SCHEDULER_TaskCallback task,
1433 void *task_cls)
1479{ 1434{
1480#if MINGW 1435#if MINGW
1481 struct GNUNET_NETWORK_FDSet *s; 1436 struct GNUNET_NETWORK_FDSet *s;
1482 GNUNET_SCHEDULER_TaskIdentifier ret; 1437 struct GNUNET_SCHEDULER_Task * ret;
1483 1438
1484 GNUNET_assert (fd != NULL); 1439 GNUNET_assert (NULL != fd);
1485 s = GNUNET_NETWORK_fdset_create (); 1440 s = GNUNET_NETWORK_fdset_create ();
1486 GNUNET_NETWORK_fdset_set (s, fd); 1441 GNUNET_NETWORK_fdset_set (s, fd);
1487 ret = GNUNET_SCHEDULER_add_select ( 1442 ret = GNUNET_SCHEDULER_add_select (
@@ -1493,11 +1448,10 @@ GNUNET_SCHEDULER_add_net_with_priority (struct GNUNET_TIME_Relative delay,
1493 return ret; 1448 return ret;
1494#else 1449#else
1495 GNUNET_assert (GNUNET_NETWORK_get_fd (fd) >= 0); 1450 GNUNET_assert (GNUNET_NETWORK_get_fd (fd) >= 0);
1496 return add_without_sets ( 1451 return add_without_sets (delay, priority,
1497 delay, priority, 1452 on_read ? GNUNET_NETWORK_get_fd (fd) : -1,
1498 on_read ? GNUNET_NETWORK_get_fd (fd) : -1, 1453 on_write ? GNUNET_NETWORK_get_fd (fd) : -1,
1499 on_write ? GNUNET_NETWORK_get_fd (fd) : -1, 1454 task, task_cls);
1500 task, task_cls);
1501#endif 1455#endif
1502} 1456}
1503 1457
@@ -1517,10 +1471,10 @@ GNUNET_SCHEDULER_add_net_with_priority (struct GNUNET_TIME_Relative delay,
1517 * @return unique task identifier for the job 1471 * @return unique task identifier for the job
1518 * only valid until @a task is started! 1472 * only valid until @a task is started!
1519 */ 1473 */
1520GNUNET_SCHEDULER_TaskIdentifier 1474struct GNUNET_SCHEDULER_Task *
1521GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay, 1475GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay,
1522 const struct GNUNET_DISK_FileHandle *rfd, 1476 const struct GNUNET_DISK_FileHandle *rfd,
1523 GNUNET_SCHEDULER_Task task, void *task_cls) 1477 GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
1524{ 1478{
1525 return GNUNET_SCHEDULER_add_file_with_priority ( 1479 return GNUNET_SCHEDULER_add_file_with_priority (
1526 delay, GNUNET_SCHEDULER_PRIORITY_DEFAULT, 1480 delay, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
@@ -1544,10 +1498,10 @@ GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay,
1544 * @return unique task identifier for the job 1498 * @return unique task identifier for the job
1545 * only valid until @a task is started! 1499 * only valid until @a task is started!
1546 */ 1500 */
1547GNUNET_SCHEDULER_TaskIdentifier 1501struct GNUNET_SCHEDULER_Task *
1548GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay, 1502GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay,
1549 const struct GNUNET_DISK_FileHandle *wfd, 1503 const struct GNUNET_DISK_FileHandle *wfd,
1550 GNUNET_SCHEDULER_Task task, void *task_cls) 1504 GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
1551{ 1505{
1552 return GNUNET_SCHEDULER_add_file_with_priority ( 1506 return GNUNET_SCHEDULER_add_file_with_priority (
1553 delay, GNUNET_SCHEDULER_PRIORITY_DEFAULT, 1507 delay, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
@@ -1574,18 +1528,18 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay,
1574 * @return unique task identifier for the job 1528 * @return unique task identifier for the job
1575 * only valid until @a task is started! 1529 * only valid until @a task is started!
1576 */ 1530 */
1577GNUNET_SCHEDULER_TaskIdentifier 1531struct GNUNET_SCHEDULER_Task *
1578GNUNET_SCHEDULER_add_file_with_priority (struct GNUNET_TIME_Relative delay, 1532GNUNET_SCHEDULER_add_file_with_priority (struct GNUNET_TIME_Relative delay,
1579 enum GNUNET_SCHEDULER_Priority priority, 1533 enum GNUNET_SCHEDULER_Priority priority,
1580 const struct GNUNET_DISK_FileHandle *fd, 1534 const struct GNUNET_DISK_FileHandle *fd,
1581 int on_read, int on_write, 1535 int on_read, int on_write,
1582 GNUNET_SCHEDULER_Task task, void *task_cls) 1536 GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
1583{ 1537{
1584#if MINGW 1538#if MINGW
1585 struct GNUNET_NETWORK_FDSet *s; 1539 struct GNUNET_NETWORK_FDSet *s;
1586 GNUNET_SCHEDULER_TaskIdentifier ret; 1540 struct GNUNET_SCHEDULER_Task * ret;
1587 1541
1588 GNUNET_assert (fd != NULL); 1542 GNUNET_assert (NULL != fd);
1589 s = GNUNET_NETWORK_fdset_create (); 1543 s = GNUNET_NETWORK_fdset_create ();
1590 GNUNET_NETWORK_fdset_handle_set (s, fd); 1544 GNUNET_NETWORK_fdset_handle_set (s, fd);
1591 ret = GNUNET_SCHEDULER_add_select ( 1545 ret = GNUNET_SCHEDULER_add_select (
@@ -1636,21 +1590,28 @@ GNUNET_SCHEDULER_add_file_with_priority (struct GNUNET_TIME_Relative delay,
1636 * @return unique task identifier for the job 1590 * @return unique task identifier for the job
1637 * only valid until @a task is started! 1591 * only valid until @a task is started!
1638 */ 1592 */
1639GNUNET_SCHEDULER_TaskIdentifier 1593struct GNUNET_SCHEDULER_Task *
1640GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio, 1594GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio,
1641 struct GNUNET_TIME_Relative delay, 1595 struct GNUNET_TIME_Relative delay,
1642 const struct GNUNET_NETWORK_FDSet *rs, 1596 const struct GNUNET_NETWORK_FDSet *rs,
1643 const struct GNUNET_NETWORK_FDSet *ws, 1597 const struct GNUNET_NETWORK_FDSet *ws,
1644 GNUNET_SCHEDULER_Task task, void *task_cls) 1598 GNUNET_SCHEDULER_TaskCallback task,
1599 void *task_cls)
1645{ 1600{
1646 struct Task *t; 1601 struct GNUNET_SCHEDULER_Task *t;
1647#if EXECINFO 1602#if EXECINFO
1648 void *backtrace_array[MAX_TRACE_DEPTH]; 1603 void *backtrace_array[MAX_TRACE_DEPTH];
1649#endif 1604#endif
1650 1605
1606 if ( (NULL == rs) &&
1607 (NULL == ws) )
1608 return GNUNET_SCHEDULER_add_delayed_with_priority (delay,
1609 prio,
1610 task,
1611 task_cls);
1651 GNUNET_assert (NULL != active_task); 1612 GNUNET_assert (NULL != active_task);
1652 GNUNET_assert (NULL != task); 1613 GNUNET_assert (NULL != task);
1653 t = GNUNET_new (struct Task); 1614 t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
1654 t->callback = task; 1615 t->callback = task;
1655 t->callback_cls = task_cls; 1616 t->callback_cls = task_cls;
1656#if EXECINFO 1617#if EXECINFO
@@ -1670,7 +1631,6 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio,
1670 t->write_set = GNUNET_NETWORK_fdset_create (); 1631 t->write_set = GNUNET_NETWORK_fdset_create ();
1671 GNUNET_NETWORK_fdset_copy (t->write_set, ws); 1632 GNUNET_NETWORK_fdset_copy (t->write_set, ws);
1672 } 1633 }
1673 t->id = ++last_id;
1674#if PROFILE_DELAYS 1634#if PROFILE_DELAYS
1675 t->start_time = GNUNET_TIME_absolute_get (); 1635 t->start_time = GNUNET_TIME_absolute_get ();
1676#endif 1636#endif
@@ -1680,23 +1640,24 @@ GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio,
1680 GNUNET_SCHEDULER_PRIORITY_KEEP) ? current_priority : 1640 GNUNET_SCHEDULER_PRIORITY_KEEP) ? current_priority :
1681 prio); 1641 prio);
1682 t->lifeness = current_lifeness; 1642 t->lifeness = current_lifeness;
1683 t->next = pending; 1643 GNUNET_CONTAINER_DLL_insert (pending_head,
1684 pending = t; 1644 pending_tail,
1645 t);
1685 max_priority_added = GNUNET_MAX (max_priority_added, t->priority); 1646 max_priority_added = GNUNET_MAX (max_priority_added, t->priority);
1686 LOG (GNUNET_ERROR_TYPE_DEBUG, 1647 LOG (GNUNET_ERROR_TYPE_DEBUG,
1687 "Adding task: %llu / %p\n", 1648 "Adding task %p\n",
1688 t->id, 1649 t);
1689 t->callback_cls);
1690#if EXECINFO 1650#if EXECINFO
1691 int i; 1651 int i;
1692 1652
1693 for (i = 0; i < t->num_backtrace_strings; i++) 1653 for (i = 0; i < t->num_backtrace_strings; i++)
1694 LOG (GNUNET_ERROR_TYPE_DEBUG, 1654 LOG (GNUNET_ERROR_TYPE_DEBUG,
1695 "Task %llu trace %d: %s\n", 1655 "Task p trace %d: %s\n",
1696 t->id, i, 1656 t,
1657 i,
1697 t->backtrace_strings[i]); 1658 t->backtrace_strings[i]);
1698#endif 1659#endif
1699 return t->id; 1660 return t;
1700} 1661}
1701 1662
1702/* end of scheduler.c */ 1663/* end of scheduler.c */