2 #include "simdag/simdag.h"
3 #include "xbt/sysdep.h"
6 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(sd_task,sd,
7 "Logging specific to SimDag (task)");
9 static void __SD_task_remove_dependencies(SD_task_t task);
10 static void __SD_task_destroy_scheduling_data(SD_task_t task);
13 * \brief Creates a new task.
15 * \param name the name of the task (can be \c NULL)
16 * \param data the user data you want to associate with the task (can be \c NULL)
17 * \param amount amount of the task
18 * \return the new task
19 * \see SD_task_destroy()
21 SD_task_t SD_task_create(const char *name, void *data, double amount) {
26 task = xbt_new(s_SD_task_t, 1);
28 /* general information */
29 task->data = data; /* user data */
31 task->name = xbt_strdup(name);
35 task->state_hookup.prev = NULL;
36 task->state_hookup.next = NULL;
37 task->state_set = sd_global->not_scheduled_task_set;
38 task->state = SD_NOT_SCHEDULED;
39 xbt_swag_insert(task, task->state_set);
41 task->amount = amount;
42 task->remains = amount;
43 task->start_time = -1.0;
44 task->finish_time = -1.0;
45 task->surf_action = NULL;
46 task->watch_points = 0;
47 task->state_changed = 0;
50 task->tasks_before = xbt_dynar_new(sizeof(SD_dependency_t), NULL);
51 task->tasks_after = xbt_dynar_new(sizeof(SD_dependency_t), NULL);
53 /* scheduling parameters */
54 task->workstation_nb = 0;
55 task->workstation_list = NULL;
56 task->computation_amount = NULL;
57 task->communication_amount = NULL;
60 sd_global->task_number++;
66 * \brief Returns the user data of a task
69 * \return the user data associated with this task (can be \c NULL)
70 * \see SD_task_set_data()
72 void* SD_task_get_data(SD_task_t task) {
74 xbt_assert0(task != NULL, "Invalid parameter");
79 * \brief Sets the user data of a task
81 * The new data can be \c NULL. The old data should have been freed first
82 * if it was not \c NULL.
85 * \param data the new data you want to associate with this task
86 * \see SD_task_get_data()
88 void SD_task_set_data(SD_task_t task, void *data) {
90 xbt_assert0(task != NULL, "Invalid parameter");
95 * \brief Returns the state of a task
98 * \return the current \ref e_SD_task_state_t "state" of this task:
99 * #SD_NOT_SCHEDULED, #SD_SCHEDULED, #SD_READY, #SD_RUNNING, #SD_DONE or #SD_FAILED
100 * \see e_SD_task_state_t
102 e_SD_task_state_t SD_task_get_state(SD_task_t task) {
103 SD_CHECK_INIT_DONE();
104 xbt_assert0(task != NULL, "Invalid parameter");
108 /* Changes the state of a task. Updates the swags and the flag sd_global->watch_point_reached.
110 void __SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state) {
111 xbt_swag_remove(task, task->state_set);
113 case SD_NOT_SCHEDULED:
114 task->state_set = sd_global->not_scheduled_task_set;
117 task->state_set = sd_global->scheduled_task_set;
120 task->state_set = sd_global->ready_task_set;
123 task->state_set = sd_global->in_fifo_task_set;
126 task->state_set = sd_global->running_task_set;
127 task->start_time = surf_workstation_resource->common_public->
128 action_get_start_time(task->surf_action);
131 task->state_set = sd_global->done_task_set;
132 task->finish_time = surf_workstation_resource->common_public->
133 action_get_finish_time(task->surf_action);
137 task->state_set = sd_global->failed_task_set;
140 xbt_assert0(0, "Invalid state");
142 xbt_swag_insert(task, task->state_set);
143 task->state = new_state;
145 if (task->watch_points & new_state) {
146 INFO1("Watch point reached with task '%s'!", SD_task_get_name(task));
147 sd_global->watch_point_reached = 1;
148 SD_task_unwatch(task, new_state); /* remove the watch point */
153 * \brief Returns the name of a task
156 * \return the name of this task (can be \c NULL)
158 const char* SD_task_get_name(SD_task_t task) {
159 SD_CHECK_INIT_DONE();
160 xbt_assert0(task != NULL, "Invalid parameter");
165 * \brief Returns the total amount of a task
168 * \return the total amount of this task
169 * \see SD_task_get_remaining_amount()
171 double SD_task_get_amount(SD_task_t task) {
172 SD_CHECK_INIT_DONE();
173 xbt_assert0(task != NULL, "Invalid parameter");
178 * \brief Returns the remaining amount of a task
181 * \return the remaining amount of this task
182 * \see SD_task_get_amount()
184 double SD_task_get_remaining_amount(SD_task_t task) {
185 SD_CHECK_INIT_DONE();
186 xbt_assert0(task != NULL, "Invalid parameter");
188 if (task->surf_action)
189 return task->surf_action->remains;
191 return task->remains;
194 /* temporary function for debbuging */
195 static void __SD_print_dependencies(SD_task_t task) {
199 SD_dependency_t dependency;
201 INFO1("The following tasks must be executed before %s:", SD_task_get_name(task));
202 dynar = task->tasks_before;
203 length = xbt_dynar_length(dynar);
206 for (i = 0; i < length; i++) {
207 xbt_dynar_get_cpy(dynar, i, &dependency);
208 INFO1(" %s", SD_task_get_name(dependency->src));
211 INFO1("The following tasks must be executed after %s:", SD_task_get_name(task));
213 dynar = task->tasks_after;
214 length = xbt_dynar_length(dynar);
215 for (i = 0; i < length; i++) {
216 xbt_dynar_get_cpy(dynar, i, &dependency);
217 INFO1(" %s", SD_task_get_name(dependency->dst));
219 INFO0("----------------------------");
222 /* Destroys a dependency between two tasks.
224 static void __SD_task_dependency_destroy(void *dependency) {
225 if (((SD_dependency_t) dependency)->name != NULL)
226 xbt_free(((SD_dependency_t) dependency)->name);
227 xbt_free(dependency);
231 * \brief Adds a dependency between two tasks
233 * \a dst will depend on \a src, ie \a dst will not start before \a src is finished.
234 * Their \ref e_SD_task_state_t "state" must be #SD_NOT_SCHEDULED, #SD_SCHEDULED or #SD_READY.
236 * \param name the name of the new dependency (can be \c NULL)
237 * \param data the user data you want to associate with this dependency (can be \c NULL)
238 * \param src the task which must be executed first
239 * \param dst the task you want to make depend on \a src
240 * \see SD_task_dependency_remove()
242 void SD_task_dependency_add(const char *name, void *data, SD_task_t src, SD_task_t dst) {
247 SD_dependency_t dependency;
249 SD_CHECK_INIT_DONE();
250 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
252 dynar = src->tasks_after;
253 length = xbt_dynar_length(dynar);
258 THROW1(arg_error, 0, "Cannot add a dependency between task '%s' and itself",
259 SD_task_get_name(src));
261 if (!__SD_task_is_not_scheduled(src) && !__SD_task_is_scheduled_or_ready(src))
262 THROW1(arg_error, 0, "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULED or SD_READY", SD_task_get_name(src));
264 if (!__SD_task_is_not_scheduled(dst) && !__SD_task_is_scheduled_or_ready(dst))
265 THROW1(arg_error, 0, "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULED or SD_READY", SD_task_get_name(dst));
267 DEBUG2("SD_task_dependency_add: src = %s, dst = %s", SD_task_get_name(src), SD_task_get_name(dst));
268 for (i = 0; i < length && !found; i++) {
269 xbt_dynar_get_cpy(dynar, i, &dependency);
270 found = (dependency->dst == dst);
271 DEBUG2("Dependency %d: dependency->dst = %s", i, SD_task_get_name(dependency->dst));
275 THROW2(arg_error, 0, "A dependency already exists between task '%s' and task '%s'",
276 SD_task_get_name(src), SD_task_get_name(dst));
278 dependency = xbt_new(s_SD_dependency_t, 1);
281 dependency->name = xbt_strdup(name);
283 dependency->name = NULL;
285 dependency->data = data;
286 dependency->src = src;
287 dependency->dst = dst;
289 /* src must be executed before dst */
290 xbt_dynar_push(src->tasks_after, &dependency);
291 xbt_dynar_push(dst->tasks_before, &dependency);
293 /* if the task was ready, then dst->tasks_before is not empty anymore,
294 so we must go back to state SD_SCHEDULED */
295 if (__SD_task_is_ready(dst)) {
296 DEBUG1("SD_task_dependency_add: %s was ready and becomes scheduled!", SD_task_get_name(dst));
297 __SD_task_set_state(dst, SD_SCHEDULED);
300 /* __SD_print_dependencies(src);
301 __SD_print_dependencies(dst); */
305 * \brief Indacates whether there is a dependency between two tasks.
308 * \param dst a task depending on \a src
310 int SD_task_dependency_exists(SD_task_t src, SD_task_t dst) {
314 SD_dependency_t dependency;
316 SD_CHECK_INIT_DONE();
317 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
319 dynar = src->tasks_after;
320 length = xbt_dynar_length(dynar);
322 for (i = 0; i < length; i++) {
323 xbt_dynar_get_cpy(dynar, i, &dependency);
324 if (dependency->dst == dst) return 1;
330 * \brief Remove a dependency between two tasks
333 * \param dst a task depending on \a src
334 * \see SD_task_dependency_add()
336 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst) {
342 SD_dependency_t dependency;
344 SD_CHECK_INIT_DONE();
345 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
347 /* remove the dependency from src->tasks_after */
348 dynar = src->tasks_after;
349 length = xbt_dynar_length(dynar);
351 for (i = 0; i < length && !found; i++) {
352 xbt_dynar_get_cpy(dynar, i, &dependency);
353 if (dependency->dst == dst) {
354 xbt_dynar_remove_at(dynar, i, NULL);
360 "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
361 SD_task_get_name(src), SD_task_get_name(dst), SD_task_get_name(dst), SD_task_get_name(src));
363 /* remove the dependency from dst->tasks_before */
364 dynar = dst->tasks_before;
365 length = xbt_dynar_length(dynar);
368 for (i = 0; i < length && !found; i++) {
369 xbt_dynar_get_cpy(dynar, i, &dependency);
370 if (dependency->src == src) {
371 xbt_dynar_remove_at(dynar, i, NULL);
372 __SD_task_dependency_destroy(dependency);
376 /* should never happen... */
377 xbt_assert4(found, "SimDag error: task '%s' is a successor of '%s' but task '%s' is not a predecessor of task '%s'",
378 SD_task_get_name(dst), SD_task_get_name(src), SD_task_get_name(src), SD_task_get_name(dst));
380 /* if the task was scheduled and dst->tasks_before is empty now, we can make it ready */
381 if (xbt_dynar_length(dst->tasks_before) == 0 && __SD_task_is_scheduled(dst))
382 __SD_task_set_state(dst, SD_READY);
384 /* __SD_print_dependencies(src);
385 __SD_print_dependencies(dst);*/
389 * \brief Returns the user data associated with a dependency between two tasks
392 * \param dst a task depending on \a src
393 * \return the user data associated with this dependency (can be \c NULL)
394 * \see SD_task_dependency_add()
396 void *SD_task_dependency_get_data(SD_task_t src, SD_task_t dst) {
402 SD_dependency_t dependency;
405 SD_CHECK_INIT_DONE();
406 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
408 dynar = src->tasks_after;
409 length = xbt_dynar_length(dynar);
411 for (i = 0; i < length && !found; i++) {
412 xbt_dynar_get_cpy(dynar, i, &dependency);
413 found = (dependency->dst == dst);
416 THROW2(arg_error, 0, "No dependency found between task '%s' and '%s'", SD_task_get_name(src), SD_task_get_name(dst));
417 return dependency->data;
420 /* temporary function for debugging */
421 static void __SD_print_watch_points(SD_task_t task) {
422 static const int state_masks[] = {SD_SCHEDULED, SD_RUNNING, SD_READY, SD_DONE, SD_FAILED};
423 static const char* state_names[] = {"scheduled", "running", "ready", "done", "failed"};
426 INFO2("Task '%s' watch points (%x): ", SD_task_get_name(task), task->watch_points);
429 for (i = 0; i < 5; i++) {
430 if (task->watch_points & state_masks[i])
431 INFO1("%s ", state_names[i]);
436 * \brief Adds a watch point to a task
438 * SD_simulate() will stop as soon as the \ref e_SD_task_state_t "state" of this
439 * task becomes the one given in argument. The
440 * watch point is then automatically removed.
443 * \param state the \ref e_SD_task_state_t "state" you want to watch
444 * (cannot be #SD_NOT_SCHEDULED)
445 * \see SD_task_unwatch()
447 void SD_task_watch(SD_task_t task, e_SD_task_state_t state) {
448 SD_CHECK_INIT_DONE();
449 xbt_assert0(task != NULL, "Invalid parameter");
451 if (state & SD_NOT_SCHEDULED)
452 THROW0(arg_error, 0, "Cannot add a watch point for state SD_NOT_SCHEDULED");
454 task->watch_points = task->watch_points | state;
455 /* __SD_print_watch_points(task);*/
459 * \brief Removes a watch point from a task
462 * \param state the \ref e_SD_task_state_t "state" you no longer want to watch
463 * \see SD_task_watch()
465 void SD_task_unwatch(SD_task_t task, e_SD_task_state_t state) {
466 SD_CHECK_INIT_DONE();
467 xbt_assert0(task != NULL, "Invalid parameter");
468 xbt_assert0(state != SD_NOT_SCHEDULED,
469 "SimDag error: Cannot have a watch point for state SD_NOT_SCHEDULED");
471 task->watch_points = task->watch_points & ~state;
472 /* __SD_print_watch_points(task);*/
476 * \brief Returns an approximative estimation of the execution time of a task.
478 * The estimation is very approximative because the value returned is the time
479 * the task would take if it was executed now and if it was the only task.
481 * \param task the task to evaluate
482 * \param workstation_nb number of workstations on which the task would be executed
483 * \param workstation_list the workstations on which the task would be executed
484 * \param computation_amount computation amount for each workstation
485 * \param communication_amount communication amount between each pair of workstations
486 * \param rate task execution speed rate
489 double SD_task_get_execution_time(SD_task_t task,
491 const SD_workstation_t *workstation_list,
492 const double *computation_amount,
493 const double *communication_amount,
495 double time, max_time = 0.0;
497 SD_CHECK_INIT_DONE();
498 xbt_assert0(task != NULL && workstation_nb > 0 && workstation_list != NULL &&
499 computation_amount != NULL && communication_amount != NULL,
500 "Invalid parameter");
502 /* the task execution time is the maximum execution time of the parallel tasks */
504 for (i = 0; i < workstation_nb; i++) {
505 time = SD_workstation_get_computation_time(workstation_list[i], computation_amount[i]);
507 for (j = 0; j < workstation_nb; j++) {
508 time += SD_route_get_communication_time(workstation_list[i], workstation_list[j],
509 communication_amount[i * workstation_nb + j]);
512 if (time > max_time) {
516 return max_time * SD_task_get_amount(task);
520 * \brief Schedules a task
522 * The task state must be #SD_NOT_SCHEDULED.
523 * Once scheduled, a task will be executed as soon as possible in SD_simulate(),
524 * i.e. when its dependencies are satisfied.
526 * \param task the task you want to schedule
527 * \param workstation_nb number of workstations on which the task will be executed
528 * \param workstation_list the workstations on which the task will be executed
529 * \param computation_amount computation amount for each workstation
530 * \param communication_amount communication amount between each pair of workstations
531 * \param rate task execution speed rate
532 * \see SD_task_unschedule()
534 void SD_task_schedule(SD_task_t task, int workstation_nb,
535 const SD_workstation_t *workstation_list, const double *computation_amount,
536 const double *communication_amount, double rate) {
538 int communication_nb;
540 SD_CHECK_INIT_DONE();
541 xbt_assert0(task != NULL, "Invalid parameter");
542 xbt_assert0(workstation_nb > 0, "workstation_nb must be positive");
544 if (!__SD_task_is_not_scheduled(task))
545 THROW1(arg_error, 0, "Task '%s' has already been scheduled", SD_task_get_name(task));
547 task->workstation_nb = workstation_nb;
550 task->computation_amount = xbt_new(double, workstation_nb);
551 memcpy(task->computation_amount, computation_amount, sizeof(double) * workstation_nb);
553 communication_nb = workstation_nb * workstation_nb;
554 task->communication_amount = xbt_new(double, communication_nb);
555 memcpy(task->communication_amount, communication_amount, sizeof(double) * communication_nb);
557 task->workstation_list = xbt_new(SD_workstation_t, workstation_nb);
558 memcpy(task->workstation_list, workstation_list, sizeof(SD_workstation_t) * workstation_nb);
560 /* update the task state */
561 if (xbt_dynar_length(task->tasks_before) == 0)
562 __SD_task_set_state(task, SD_READY);
564 __SD_task_set_state(task, SD_SCHEDULED);
568 * \brief Unschedules a task
570 * The task state must be #SD_SCHEDULED, #SD_READY, #SD_RUNNING or #SD_FAILED.
571 * If you call this function, the task state becomes #SD_NOT_SCHEDULED.
572 * Call SD_task_schedule() to schedule it again.
574 * \param task the task you want to unschedule
575 * \see SD_task_schedule()
577 void SD_task_unschedule(SD_task_t task) {
578 SD_CHECK_INIT_DONE();
579 xbt_assert0(task != NULL, "Invalid parameter");
581 if (task->state_set != sd_global->scheduled_task_set &&
582 task->state_set != sd_global->ready_task_set &&
583 task->state_set != sd_global->running_task_set &&
584 task->state_set != sd_global->failed_task_set)
585 THROW1(arg_error, 0, "Task %s: the state must be SD_SCHEDULED, SD_READY, SD_RUNNING or SD_FAILED",
586 SD_task_get_name(task));
588 if (__SD_task_is_scheduled_or_ready(task)) /* if the task is scheduled or ready */
589 __SD_task_destroy_scheduling_data(task);
591 if (__SD_task_is_running(task)) /* the task should become SD_FAILED */
592 surf_workstation_resource->common_public->action_cancel(task->surf_action);
594 __SD_task_set_state(task, SD_NOT_SCHEDULED);
595 task->remains = task->amount;
596 task->start_time = -1.0;
599 /* Destroys the data memorised by SD_task_schedule. Task state must be SD_SCHEDULED or SD_READY.
601 static void __SD_task_destroy_scheduling_data(SD_task_t task) {
602 SD_CHECK_INIT_DONE();
603 if (!__SD_task_is_scheduled_or_ready(task) && !__SD_task_is_in_fifo(task))
604 THROW1(arg_error, 0, "Task '%s' must be SD_SCHEDULED, SD_READY or SD_IN_FIFO", SD_task_get_name(task));
606 xbt_free(task->computation_amount);
607 xbt_free(task->communication_amount);
610 /* Runs a task. This function is directly called by __SD_task_try_to_run if the task
611 * doesn't have to wait in fifos. Otherwise, it is called by __SD_task_just_done when
612 * the task gets out of its fifos.
614 void __SD_task_really_run(SD_task_t task) {
617 void **surf_workstations;
619 SD_CHECK_INIT_DONE();
620 xbt_assert0(task != NULL, "Invalid parameter");
621 xbt_assert2(__SD_task_is_ready_or_in_fifo(task), "Task '%s' is not ready or in a fifo! Task state: %d",
622 SD_task_get_name(task), SD_task_get_state(task));
623 xbt_assert1(task->workstation_list != NULL, "Task '%s': workstation_list is NULL!", SD_task_get_name(task));
627 DEBUG1("Really running task '%s'", SD_task_get_name(task));
629 /* set this task as current task for the workstations in sequential mode */
630 for (i = 0; i < task->workstation_nb; i++) {
631 if (SD_workstation_get_access_mode(task->workstation_list[i]) == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
632 task->workstation_list[i]->current_task = task;
633 xbt_assert0(__SD_workstation_is_busy(task->workstation_list[i]), "The workstation should be busy now");
637 DEBUG1("Task '%s' set as current task for its workstations", SD_task_get_name(task));
641 /* we have to create a Surf workstation array instead of the SimDag workstation array */
642 surf_workstations = xbt_new(void*, task->workstation_nb);
644 for (i = 0; i < task->workstation_nb; i++) {
645 surf_workstations[i] = task->workstation_list[i]->surf_workstation;
648 task->surf_action = surf_workstation_resource->extension_public->
649 execute_parallel_task(task->workstation_nb,
651 task->computation_amount,
652 task->communication_amount,
655 surf_workstation_resource->common_public->action_set_data(task->surf_action, task);
656 task->state_changed = 1;
658 DEBUG1("surf_action = %p", task->surf_action);
660 xbt_free(surf_workstations);
661 __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
662 __SD_task_set_state(task, SD_RUNNING);
663 xbt_assert2(__SD_task_is_running(task), "Bad state of task '%s': %d",
664 SD_task_get_name(task), SD_task_get_state(task));
668 /* Tries to run a task. This function is called by SD_simulate() when a scheduled task becomes SD_READY
669 * (ie when its dependencies are satisfied).
670 * If one of the workstations where the task is scheduled on is busy (in sequential mode),
671 * the task doesn't start.
672 * Returns whether the task has started.
674 int __SD_task_try_to_run(SD_task_t task) {
678 SD_workstation_t workstation;
680 SD_CHECK_INIT_DONE();
681 xbt_assert0(task != NULL, "Invalid parameter");
682 xbt_assert2(__SD_task_is_ready(task), "Task '%s' is not ready! Task state: %d",
683 SD_task_get_name(task), SD_task_get_state(task));
686 for (i = 0; i < task->workstation_nb; i++) {
687 can_start = !__SD_workstation_is_busy(task->workstation_list[i]);
690 DEBUG2("Task '%s' can start: %d", SD_task_get_name(task), can_start);
692 if (!can_start) { /* if the task cannot start and is not in the fifos yet*/
693 for (i = 0; i < task->workstation_nb; i++) {
694 workstation = task->workstation_list[i];
695 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
696 DEBUG2("Pushing task '%s' in the fifo of workstation '%s'", SD_task_get_name(task),
697 SD_workstation_get_name(workstation));
698 xbt_fifo_push(workstation->task_fifo, task);
701 __SD_task_set_state(task, SD_IN_FIFO);
702 xbt_assert2(__SD_task_is_in_fifo(task), "Bad state of task '%s': %d",
703 SD_task_get_name(task), SD_task_get_state(task));
704 DEBUG1("Task '%s' state is now SD_IN_FIFO", SD_task_get_name(task));
707 __SD_task_really_run(task);
713 /* This function is called by SD_simulate when a task is done.
714 * It updates task->state and task->action and executes if necessary the tasks
715 * which were waiting in fifos for the end of `task'
717 void __SD_task_just_done(SD_task_t task) {
719 SD_workstation_t workstation;
722 int candidate_nb = 0;
723 int candidate_capacity = 8;
724 SD_task_t *candidates;
727 SD_CHECK_INIT_DONE();
728 xbt_assert0(task != NULL, "Invalid parameter");
729 xbt_assert1(__SD_task_is_running(task), "The task must be running! Task state: %d", SD_task_get_state(task));
730 xbt_assert1(task->workstation_list != NULL, "Task '%s': workstation_list is NULL!", SD_task_get_name(task));
733 candidates = xbt_new(SD_task_t, 8);
735 __SD_task_set_state(task, SD_DONE);
736 surf_workstation_resource->common_public->action_free(task->surf_action);
737 task->surf_action = NULL;
739 DEBUG0("Looking for candidates");
741 /* if the task was executed on sequential workstations,
742 maybe we can execute the next task of the fifo for each workstation */
743 for (i = 0; i < task->workstation_nb; i++) {
744 workstation = task->workstation_list[i];
745 DEBUG2("Workstation '%s': access_mode = %d", SD_workstation_get_name(workstation), workstation->access_mode);
746 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
747 xbt_assert1(workstation->task_fifo != NULL, "Workstation '%s' has sequential access but no fifo!",
748 SD_workstation_get_name(workstation));
749 xbt_assert2(workstation->current_task = task, "Workstation '%s': current task should be '%s'",
750 SD_workstation_get_name(workstation), SD_task_get_name(task));
752 /* the task is over so we can release the workstation */
753 workstation->current_task = NULL;
755 DEBUG0("Getting candidate in fifo");
756 candidate = xbt_fifo_get_item_content(xbt_fifo_get_first_item(workstation->task_fifo));
758 if (candidate != NULL) {
759 DEBUG1("Candidate: '%s'", SD_task_get_name(candidate));
760 xbt_assert2(__SD_task_is_in_fifo(candidate), "Bad state of candidate '%s': %d",
761 SD_task_get_name(candidate), SD_task_get_state(candidate));
764 DEBUG1("Candidate in fifo: %p", candidate);
766 /* if there was a task waiting for my place */
767 if (candidate != NULL) {
768 /* Unfortunately, we are not sure yet that we can execute the task now,
769 because the task can be waiting more deeply in some other workstation's fifos...
770 So we memorize all candidate tasks, and then we will check for each candidate
771 whether or not all its workstations are available. */
773 /* realloc if necessary */
774 if (candidate_nb == candidate_capacity) {
775 candidate_capacity *= 2;
776 candidates = xbt_realloc(candidates, sizeof(SD_task_t) * candidate_capacity);
779 /* register the candidate */
780 candidates[candidate_nb++] = candidate;
781 candidate->fifo_checked = 0;
786 DEBUG1("Candidates found: %d", candidate_nb);
788 /* now we check every candidate task */
789 for (i = 0; i < candidate_nb; i++) {
790 candidate = candidates[i];
792 if (candidate->fifo_checked) {
793 continue; /* we have already evaluated that task*/
796 xbt_assert2(__SD_task_is_in_fifo(candidate), "Bad state of candidate '%s': %d",
797 SD_task_get_name(candidate), SD_task_get_state(candidate));
799 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
800 workstation = candidate->workstation_list[j];
802 /* I can start on this workstation if the workstation is shared
803 or if I am the first task in the fifo */
804 can_start = workstation->access_mode == SD_WORKSTATION_SHARED_ACCESS ||
805 candidate == xbt_fifo_get_item_content(xbt_fifo_get_first_item(workstation->task_fifo));
808 DEBUG2("Candidate '%s' can start: %d", SD_task_get_name(candidate), can_start);
810 /* now we are sure that I can start! */
812 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
813 workstation = candidate->workstation_list[j];
815 /* update the fifo */
816 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
817 candidate = xbt_fifo_shift(workstation->task_fifo); /* the return value is stored just for debugging */
818 DEBUG1("Head of the fifo: '%s'", (candidate != NULL) ? SD_task_get_name(candidate) : "NULL");
819 xbt_assert0(candidate == candidates[i], "Error in __SD_task_just_done: bad first task in the fifo");
821 } /* for each workstation */
823 /* finally execute the task */
824 DEBUG2("Task '%s' state: %d", SD_task_get_name(candidate), SD_task_get_state(candidate));
825 __SD_task_really_run(candidate);
827 DEBUG4("Calling __SD_task_is_running: task '%s', state set: %p, running_task_set: %p, is running: %d",
828 SD_task_get_name(candidate), candidate->state_set, sd_global->running_task_set, __SD_task_is_running(candidate));
829 xbt_assert2(__SD_task_is_running(candidate), "Bad state of task '%s': %d",
830 SD_task_get_name(candidate), SD_task_get_state(candidate));
831 DEBUG0("Okay, the task is running.");
834 candidate->fifo_checked = 1;
835 } /* for each candidate */
837 xbt_free(candidates);
840 /* Remove all dependencies associated with a task. This function is called when the task is destroyed.
842 static void __SD_task_remove_dependencies(SD_task_t task) {
843 /* we must destroy the dependencies carefuly (with SD_dependency_remove)
844 because each one is stored twice */
845 SD_dependency_t dependency;
846 while (xbt_dynar_length(task->tasks_before) > 0) {
847 xbt_dynar_get_cpy(task->tasks_before, 0, &dependency);
848 SD_task_dependency_remove(dependency->src, dependency->dst);
851 while (xbt_dynar_length(task->tasks_after) > 0) {
852 xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
853 SD_task_dependency_remove(dependency->src, dependency->dst);
858 * \brief Returns the start time of a task
860 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
862 * \param task: a task
863 * \return the start time of this task
865 double SD_task_get_start_time(SD_task_t task) {
866 SD_CHECK_INIT_DONE();
867 xbt_assert0(task != NULL, "Invalid parameter");
868 if(task->surf_action)
869 return surf_workstation_resource->common_public->action_get_start_time(task->surf_action);
871 return task->start_time;
875 * \brief Returns the finish time of a task
877 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
878 * If the state is not completed yet, the returned value is an
879 * estimation of the task finish time. This value can fluctuate
880 * until the task is completed.
882 * \param task: a task
883 * \return the start time of this task
885 double SD_task_get_finish_time(SD_task_t task) {
886 SD_CHECK_INIT_DONE();
887 xbt_assert0(task != NULL, "Invalid parameter");
889 if(task->surf_action) /* should never happen as actions are destroyed right after their completion */
890 return surf_workstation_resource->common_public->action_get_finish_time(task->surf_action);
892 return task->finish_time;
896 * \brief Destroys a task.
898 * The user data (if any) should have been destroyed first.
900 * \param task the task you want to destroy
901 * \see SD_task_create()
903 void SD_task_destroy(SD_task_t task) {
904 SD_CHECK_INIT_DONE();
905 xbt_assert0(task != NULL, "Invalid parameter");
907 DEBUG1("Destroying task %s...", SD_task_get_name(task));
909 __SD_task_remove_dependencies(task);
911 /* if the task was scheduled or ready we have to free the scheduling parameters */
912 if (__SD_task_is_scheduled_or_ready(task))
913 __SD_task_destroy_scheduling_data(task);
915 if (task->name != NULL)
916 xbt_free(task->name);
918 if (task->surf_action != NULL)
919 surf_workstation_resource->common_public->action_free(task->surf_action);
921 if (task->workstation_list != NULL)
922 xbt_free(task->workstation_list);
924 xbt_dynar_free(&task->tasks_before);
925 xbt_dynar_free(&task->tasks_after);
928 sd_global->task_number--;
930 DEBUG0("Task destroyed.");