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) {
24 SD_task_t task = xbt_new0(s_SD_task_t, 1);
26 /* general information */
27 task->data = data; /* user data */
29 task->name = xbt_strdup(name);
33 task->state_set = sd_global->not_scheduled_task_set;
34 xbt_swag_insert(task,task->state_set);
36 task->amount = amount;
37 task->remains = amount;
38 task->start_time = -1.0;
39 task->finish_time = -1.0;
40 task->surf_action = NULL;
41 task->watch_points = 0;
42 task->state_changed = 0;
45 task->tasks_before = xbt_dynar_new(sizeof(SD_dependency_t), NULL);
46 task->tasks_after = xbt_dynar_new(sizeof(SD_dependency_t), NULL);
48 /* scheduling parameters */
49 task->workstation_nb = 0;
50 task->workstation_list = NULL;
51 task->computation_amount = NULL;
52 task->communication_amount = NULL;
59 * \brief Returns the user data of a task
62 * \return the user data associated with this task (can be \c NULL)
63 * \see SD_task_set_data()
65 void* SD_task_get_data(SD_task_t task) {
67 xbt_assert0(task != NULL, "Invalid parameter");
72 * \brief Sets the user data of a task
74 * The new data can be \c NULL. The old data should have been freed first
75 * if it was not \c NULL.
78 * \param data the new data you want to associate with this task
79 * \see SD_task_get_data()
81 void SD_task_set_data(SD_task_t task, void *data) {
83 xbt_assert0(task != NULL, "Invalid parameter");
88 * \brief Returns the state of a task
91 * \return the current \ref e_SD_task_state_t "state" of this task:
92 * #SD_NOT_SCHEDULED, #SD_SCHEDULED, #SD_READY, #SD_RUNNING, #SD_DONE or #SD_FAILED
93 * \see e_SD_task_state_t
95 e_SD_task_state_t SD_task_get_state(SD_task_t task) {
97 xbt_assert0(task != NULL, "Invalid parameter");
99 if (task->state_set == sd_global->scheduled_task_set)
101 if (task->state_set == sd_global->done_task_set)
103 if (task->state_set == sd_global->running_task_set)
105 if (task->state_set == sd_global->ready_task_set)
107 if (task->state_set == sd_global->in_fifo_task_set)
109 if (task->state_set == sd_global->not_scheduled_task_set)
110 return SD_NOT_SCHEDULED;
114 /* Changes the state of a task. Updates the swags and the flag sd_global->watch_point_reached.
116 void __SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state) {
117 xbt_swag_remove(task, task->state_set);
119 case SD_NOT_SCHEDULED:
120 task->state_set = sd_global->not_scheduled_task_set;
123 task->state_set = sd_global->scheduled_task_set;
126 task->state_set = sd_global->ready_task_set;
129 task->state_set = sd_global->in_fifo_task_set;
132 task->state_set = sd_global->running_task_set;
133 task->start_time = surf_workstation_resource->common_public->
134 action_get_start_time(task->surf_action);
137 task->state_set = sd_global->done_task_set;
138 task->finish_time = surf_workstation_resource->common_public->
139 action_get_finish_time(task->surf_action);
143 task->state_set = sd_global->failed_task_set;
146 xbt_assert0(0, "Invalid state");
148 xbt_swag_insert(task, task->state_set);
150 if (task->watch_points & new_state) {
151 INFO1("Watch point reached with task '%s'!", SD_task_get_name(task));
152 sd_global->watch_point_reached = 1;
153 SD_task_unwatch(task, new_state); /* remove the watch point */
158 * \brief Returns the name of a task
161 * \return the name of this task (can be \c NULL)
163 const char* SD_task_get_name(SD_task_t task) {
164 SD_CHECK_INIT_DONE();
165 xbt_assert0(task != NULL, "Invalid parameter");
170 * \brief Returns the total amount of a task
173 * \return the total amount of this task
174 * \see SD_task_get_remaining_amount()
176 double SD_task_get_amount(SD_task_t task) {
177 SD_CHECK_INIT_DONE();
178 xbt_assert0(task != NULL, "Invalid parameter");
183 * \brief Returns the remaining amount of a task
186 * \return the remaining amount of this task
187 * \see SD_task_get_amount()
189 double SD_task_get_remaining_amount(SD_task_t task) {
190 SD_CHECK_INIT_DONE();
191 xbt_assert0(task != NULL, "Invalid parameter");
193 if (task->surf_action)
194 return task->surf_action->remains;
196 return task->remains;
199 /* temporary function for debbuging */
200 static void __SD_print_dependencies(SD_task_t task) {
201 INFO1("The following tasks must be executed before %s:", SD_task_get_name(task));
202 xbt_dynar_t dynar = task->tasks_before;
203 int length = xbt_dynar_length(dynar);
205 SD_dependency_t dependency;
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) {
243 SD_CHECK_INIT_DONE();
244 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
246 xbt_dynar_t dynar = src->tasks_after;
247 int length = xbt_dynar_length(dynar);
250 SD_dependency_t dependency;
253 THROW1(arg_error, 0, "Cannot add a dependency between task '%s' and itself",
254 SD_task_get_name(src));
256 if (!__SD_task_is_not_scheduled(src) && !__SD_task_is_scheduled_or_ready(src))
257 THROW1(arg_error, 0, "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULED or SD_READY", SD_task_get_name(src));
259 if (!__SD_task_is_not_scheduled(dst) && !__SD_task_is_scheduled_or_ready(dst))
260 THROW1(arg_error, 0, "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULED or SD_READY", SD_task_get_name(dst));
262 DEBUG2("SD_task_dependency_add: src = %s, dst = %s", SD_task_get_name(src), SD_task_get_name(dst));
263 for (i = 0; i < length && !found; i++) {
264 xbt_dynar_get_cpy(dynar, i, &dependency);
265 found = (dependency->dst == dst);
266 DEBUG2("Dependency %d: dependency->dst = %s", i, SD_task_get_name(dependency->dst));
270 THROW2(arg_error, 0, "A dependency already exists between task '%s' and task '%s'",
271 SD_task_get_name(src), SD_task_get_name(dst));
273 dependency = xbt_new0(s_SD_dependency_t, 1);
276 dependency->name = xbt_strdup(name);
278 dependency->name = NULL;
280 dependency->data = data;
281 dependency->src = src;
282 dependency->dst = dst;
284 /* src must be executed before dst */
285 xbt_dynar_push(src->tasks_after, &dependency);
286 xbt_dynar_push(dst->tasks_before, &dependency);
288 /* if the task was ready, then dst->tasks_before is not empty anymore,
289 so we must go back to state SD_SCHEDULED */
290 if (__SD_task_is_ready(dst)) {
291 DEBUG1("SD_task_dependency_add: %s was ready and becomes scheduled!", SD_task_get_name(dst));
292 __SD_task_set_state(dst, SD_SCHEDULED);
295 /* __SD_print_dependencies(src);
296 __SD_print_dependencies(dst); */
300 * \brief Remove a dependency between two tasks
303 * \param dst a task depending on \a src
304 * \see SD_task_dependency_add()
306 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst) {
307 SD_CHECK_INIT_DONE();
308 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
310 /* remove the dependency from src->tasks_after */
311 xbt_dynar_t dynar = src->tasks_after;
312 int length = xbt_dynar_length(dynar);
315 SD_dependency_t dependency;
316 for (i = 0; i < length && !found; i++) {
317 xbt_dynar_get_cpy(dynar, i, &dependency);
318 if (dependency->dst == dst) {
319 xbt_dynar_remove_at(dynar, i, NULL);
325 "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
326 SD_task_get_name(src), SD_task_get_name(dst), SD_task_get_name(dst), SD_task_get_name(src));
328 /* remove the dependency from dst->tasks_before */
329 dynar = dst->tasks_before;
330 length = xbt_dynar_length(dynar);
333 for (i = 0; i < length && !found; i++) {
334 xbt_dynar_get_cpy(dynar, i, &dependency);
335 if (dependency->src == src) {
336 xbt_dynar_remove_at(dynar, i, NULL);
337 __SD_task_dependency_destroy(dependency);
341 /* should never happen... */
342 xbt_assert4(found, "SimDag error: task '%s' is a successor of '%s' but task '%s' is not a predecessor of task '%s'",
343 SD_task_get_name(dst), SD_task_get_name(src), SD_task_get_name(src), SD_task_get_name(dst));
345 /* if the task was scheduled and dst->tasks_before is empty now, we can make it ready */
346 if (xbt_dynar_length(dst->tasks_before) == 0 && __SD_task_is_scheduled(dst))
347 __SD_task_set_state(dst, SD_READY);
349 /* __SD_print_dependencies(src);
350 __SD_print_dependencies(dst);*/
354 * \brief Returns the user data associated with a dependency between two tasks
357 * \param dst a task depending on \a src
358 * \return the user data associated with this dependency (can be \c NULL)
359 * \see SD_task_dependency_add()
361 void *SD_task_dependency_get_data(SD_task_t src, SD_task_t dst) {
362 SD_CHECK_INIT_DONE();
363 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
365 xbt_dynar_t dynar = src->tasks_after;
366 int length = xbt_dynar_length(dynar);
369 SD_dependency_t dependency;
370 for (i = 0; i < length && !found; i++) {
371 xbt_dynar_get_cpy(dynar, i, &dependency);
372 found = (dependency->dst == dst);
375 THROW2(arg_error, 0, "No dependency found between task '%s' and '%s'", SD_task_get_name(src), SD_task_get_name(dst));
376 return dependency->data;
379 /* temporary function for debugging */
380 static void __SD_print_watch_points(SD_task_t task) {
381 static const int state_masks[] = {SD_SCHEDULED, SD_RUNNING, SD_READY, SD_DONE, SD_FAILED};
382 static const char* state_names[] = {"scheduled", "running", "ready", "done", "failed"};
384 INFO2("Task '%s' watch points (%x): ", SD_task_get_name(task), task->watch_points);
387 for (i = 0; i < 5; i++) {
388 if (task->watch_points & state_masks[i])
389 INFO1("%s ", state_names[i]);
394 * \brief Adds a watch point to a task
396 * SD_simulate() will stop as soon as the \ref e_SD_task_state_t "state" of this
397 * task becomes the one given in argument. The
398 * watch point is then automatically removed.
401 * \param state the \ref e_SD_task_state_t "state" you want to watch
402 * (cannot be #SD_NOT_SCHEDULED)
403 * \see SD_task_unwatch()
405 void SD_task_watch(SD_task_t task, e_SD_task_state_t state) {
406 SD_CHECK_INIT_DONE();
407 xbt_assert0(task != NULL, "Invalid parameter");
409 if (state & SD_NOT_SCHEDULED)
410 THROW0(arg_error, 0, "Cannot add a watch point for state SD_NOT_SCHEDULED");
412 task->watch_points = task->watch_points | state;
413 /* __SD_print_watch_points(task);*/
417 * \brief Removes a watch point from a task
420 * \param state the \ref e_SD_task_state_t "state" you no longer want to watch
421 * \see SD_task_watch()
423 void SD_task_unwatch(SD_task_t task, e_SD_task_state_t state) {
424 SD_CHECK_INIT_DONE();
425 xbt_assert0(task != NULL, "Invalid parameter");
426 xbt_assert0(state != SD_NOT_SCHEDULED,
427 "SimDag error: Cannot have a watch point for state SD_NOT_SCHEDULED");
429 task->watch_points = task->watch_points & ~state;
430 /* __SD_print_watch_points(task);*/
434 * \brief Returns an approximative estimation of the execution time of a task.
436 * The estimation is very approximative because the value returned is the time
437 * the task would take if it was executed now and if it was the only task.
439 * \param task the task to evaluate
440 * \param workstation_nb number of workstations on which the task would be executed
441 * \param workstation_list the workstations on which the task would be executed
442 * \param computation_amount computation amount for each workstation
443 * \param communication_amount communication amount between each pair of workstations
444 * \param rate task execution speed rate
447 double SD_task_get_execution_time(SD_task_t task,
449 const SD_workstation_t *workstation_list,
450 const double *computation_amount,
451 const double *communication_amount,
453 SD_CHECK_INIT_DONE();
454 xbt_assert0(task != NULL && workstation_nb > 0 && workstation_list != NULL &&
455 computation_amount != NULL && communication_amount != NULL,
456 "Invalid parameter");
458 /* the task execution time is the maximum execution time of the parallel tasks */
459 double time, max_time = 0.0;
461 for (i = 0; i < workstation_nb; i++) {
462 time = SD_workstation_get_computation_time(workstation_list[i], computation_amount[i]);
464 for (j = 0; j < workstation_nb; j++) {
465 time += SD_route_get_communication_time(workstation_list[i], workstation_list[j],
466 communication_amount[i * workstation_nb + j]);
469 if (time > max_time) {
473 return max_time * SD_task_get_amount(task);
477 * \brief Schedules a task
479 * The task state must be #SD_NOT_SCHEDULED.
480 * Once scheduled, a task will be executed as soon as possible in SD_simulate(),
481 * i.e. when its dependencies are satisfied.
483 * \param task the task you want to schedule
484 * \param workstation_nb number of workstations on which the task will be executed
485 * \param workstation_list the workstations on which the task will be executed
486 * \param computation_amount computation amount for each workstation
487 * \param communication_amount communication amount between each pair of workstations
488 * \param rate task execution speed rate
489 * \see SD_task_unschedule()
491 void SD_task_schedule(SD_task_t task, int workstation_nb,
492 const SD_workstation_t *workstation_list, const double *computation_amount,
493 const double *communication_amount, double rate) {
494 SD_CHECK_INIT_DONE();
495 xbt_assert0(task != NULL, "Invalid parameter");
496 xbt_assert0(workstation_nb > 0, "workstation_nb must be positive");
498 if (!__SD_task_is_not_scheduled(task))
499 THROW1(arg_error, 0, "Task '%s' has already been scheduled", SD_task_get_name(task));
501 task->workstation_nb = workstation_nb;
504 task->computation_amount = xbt_new0(double, workstation_nb);
505 memcpy(task->computation_amount, computation_amount, sizeof(double) * workstation_nb);
507 int communication_nb = workstation_nb * workstation_nb;
508 task->communication_amount = xbt_new0(double, communication_nb);
509 memcpy(task->communication_amount, communication_amount, sizeof(double) * communication_nb);
511 task->workstation_list = xbt_new0(SD_workstation_t, workstation_nb);
512 memcpy(task->workstation_list, workstation_list, sizeof(SD_workstation_t) * workstation_nb);
514 /* update the task state */
515 if (xbt_dynar_length(task->tasks_before) == 0)
516 __SD_task_set_state(task, SD_READY);
518 __SD_task_set_state(task, SD_SCHEDULED);
522 * \brief Unschedules a task
524 * The task state must be #SD_SCHEDULED, #SD_READY, #SD_RUNNING or #SD_FAILED.
525 * If you call this function, the task state becomes #SD_NOT_SCHEDULED.
526 * Call SD_task_schedule() to schedule it again.
528 * \param task the task you want to unschedule
529 * \see SD_task_schedule()
531 void SD_task_unschedule(SD_task_t task) {
532 SD_CHECK_INIT_DONE();
533 xbt_assert0(task != NULL, "Invalid parameter");
535 if (task->state_set != sd_global->scheduled_task_set &&
536 task->state_set != sd_global->ready_task_set &&
537 task->state_set != sd_global->running_task_set &&
538 task->state_set != sd_global->failed_task_set)
539 THROW1(arg_error, 0, "Task %s: the state must be SD_SCHEDULED, SD_READY, SD_RUNNING or SD_FAILED",
540 SD_task_get_name(task));
542 if (__SD_task_is_scheduled_or_ready(task)) /* if the task is scheduled or ready */
543 __SD_task_destroy_scheduling_data(task);
545 if (__SD_task_is_running(task)) /* the task should become SD_FAILED */
546 surf_workstation_resource->common_public->action_cancel(task->surf_action);
548 __SD_task_set_state(task, SD_NOT_SCHEDULED);
549 task->remains = task->amount;
550 task->start_time = -1.0;
553 /* Destroys the data memorised by SD_task_schedule. Task state must be SD_SCHEDULED or SD_READY.
555 static void __SD_task_destroy_scheduling_data(SD_task_t task) {
556 SD_CHECK_INIT_DONE();
557 if (!__SD_task_is_scheduled_or_ready(task) && !__SD_task_is_in_fifo(task))
558 THROW1(arg_error, 0, "Task '%s' must be SD_SCHEDULED, SD_READY or SD_IN_FIFO", SD_task_get_name(task));
560 xbt_free(task->computation_amount);
561 xbt_free(task->communication_amount);
564 /* Runs a task. This function is directly called by __SD_task_try_to_run if the task
565 * doesn't have to wait in fifos. Otherwise, it is called by __SD_task_just_done when
566 * the task gets out of its fifos.
568 void __SD_task_really_run(SD_task_t task) {
569 SD_CHECK_INIT_DONE();
570 xbt_assert0(task != NULL, "Invalid parameter");
571 xbt_assert2(__SD_task_is_ready_or_in_fifo(task), "Task '%s' is not ready or in a fifo! Task state: %d",
572 SD_task_get_name(task), SD_task_get_state(task));
573 xbt_assert1(task->workstation_list != NULL, "Task '%s': workstation_list is NULL!", SD_task_get_name(task));
576 void **surf_workstations;
578 DEBUG1("Really running task '%s'", SD_task_get_name(task));
580 /* set this task as current task for the workstations in sequential mode */
581 for (i = 0; i < task->workstation_nb; i++) {
582 if (SD_workstation_get_access_mode(task->workstation_list[i]) == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
583 task->workstation_list[i]->current_task = task;
584 xbt_assert0(__SD_workstation_is_busy(task->workstation_list[i]), "The workstation should be busy now");
588 DEBUG1("Task '%s' set as current task for its workstations", SD_task_get_name(task));
592 /* we have to create a Surf workstation array instead of the SimDag workstation array */
593 surf_workstations = xbt_new0(void*, task->workstation_nb);
595 for (i = 0; i < task->workstation_nb; i++) {
596 surf_workstations[i] = task->workstation_list[i]->surf_workstation;
599 task->surf_action = surf_workstation_resource->extension_public->
600 execute_parallel_task(task->workstation_nb,
602 task->computation_amount,
603 task->communication_amount,
606 surf_workstation_resource->common_public->action_set_data(task->surf_action, task);
607 task->state_changed = 1;
609 DEBUG1("surf_action = %p", task->surf_action);
611 xbt_free(surf_workstations);
612 __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
613 __SD_task_set_state(task, SD_RUNNING);
614 xbt_assert2(__SD_task_is_running(task), "Bad state of task '%s': %d",
615 SD_task_get_name(task), SD_task_get_state(task));
619 /* Tries to run a task. This function is called by SD_simulate() when a scheduled task becomes SD_READY
620 * (ie when its dependencies are satisfied).
621 * If one of the workstations where the task is scheduled on is busy (in sequential mode),
622 * the task doesn't start.
623 * Returns whether the task has started.
625 int __SD_task_try_to_run(SD_task_t task) {
626 SD_CHECK_INIT_DONE();
627 xbt_assert0(task != NULL, "Invalid parameter");
628 xbt_assert2(__SD_task_is_ready(task), "Task '%s' is not ready! Task state: %d",
629 SD_task_get_name(task), SD_task_get_state(task));
633 SD_workstation_t workstation;
635 for (i = 0; i < task->workstation_nb; i++) {
636 can_start = !__SD_workstation_is_busy(task->workstation_list[i]);
639 DEBUG2("Task '%s' can start: %d", SD_task_get_name(task), can_start);
641 if (!can_start) { /* if the task cannot start and is not in the fifos yet*/
642 for (i = 0; i < task->workstation_nb; i++) {
643 workstation = task->workstation_list[i];
644 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
645 DEBUG2("Pushing task '%s' in the fifo of workstation '%s'", SD_task_get_name(task),
646 SD_workstation_get_name(workstation));
647 xbt_fifo_push(workstation->task_fifo, task);
650 __SD_task_set_state(task, SD_IN_FIFO);
651 xbt_assert2(__SD_task_is_in_fifo(task), "Bad state of task '%s': %d",
652 SD_task_get_name(task), SD_task_get_state(task));
653 DEBUG1("Task '%s' state is now SD_IN_FIFO", SD_task_get_name(task));
656 __SD_task_really_run(task);
662 /* This function is called by SD_simulate when a task is done.
663 * It updates task->state and task->action and executes if necessary the tasks
664 * which were waiting in fifos for the end of `task'
666 void __SD_task_just_done(SD_task_t task) {
667 SD_CHECK_INIT_DONE();
668 xbt_assert0(task != NULL, "Invalid parameter");
669 xbt_assert1(__SD_task_is_running(task), "The task must be running! Task state: %d", SD_task_get_state(task));
670 xbt_assert1(task->workstation_list != NULL, "Task '%s': workstation_list is NULL!", SD_task_get_name(task));
673 SD_workstation_t workstation;
676 int candidate_nb = 0;
677 int candidate_capacity = 8;
678 SD_task_t *candidates = xbt_new0(SD_task_t, 8);
681 __SD_task_set_state(task, SD_DONE);
682 surf_workstation_resource->common_public->action_free(task->surf_action);
683 task->surf_action = NULL;
685 DEBUG0("Looking for candidates");
687 /* if the task was executed on sequential workstations,
688 maybe we can execute the next task of the fifo for each workstation */
689 for (i = 0; i < task->workstation_nb; i++) {
690 workstation = task->workstation_list[i];
691 DEBUG2("Workstation '%s': access_mode = %d", SD_workstation_get_name(workstation), workstation->access_mode);
692 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
693 xbt_assert1(workstation->task_fifo != NULL, "Workstation '%s' has sequential access but no fifo!",
694 SD_workstation_get_name(workstation));
695 xbt_assert2(workstation->current_task = task, "Workstation '%s': current task should be '%s'",
696 SD_workstation_get_name(workstation), SD_task_get_name(task));
698 /* the task is over so we can release the workstation */
699 workstation->current_task = NULL;
701 DEBUG0("Getting candidate in fifo");
702 candidate = xbt_fifo_get_item_content(xbt_fifo_get_first_item(workstation->task_fifo));
704 if (candidate != NULL) {
705 DEBUG1("Candidate: '%s'", SD_task_get_name(candidate));
706 xbt_assert2(__SD_task_is_in_fifo(candidate), "Bad state of candidate '%s': %d",
707 SD_task_get_name(candidate), SD_task_get_state(candidate));
710 DEBUG1("Candidate in fifo: %p", candidate);
712 /* if there was a task waiting for my place */
713 if (candidate != NULL) {
714 /* Unfortunately, we are not sure yet that we can execute the task now,
715 because the task can be waiting more deeply in some other workstation's fifos...
716 So we memorize all candidate tasks, and then we will check for each candidate
717 whether or not all its workstations are available. */
719 /* realloc if necessary */
720 if (candidate_nb == candidate_capacity) {
721 candidate_capacity *= 2;
722 candidates = xbt_realloc(candidates, sizeof(SD_task_t) * candidate_capacity);
725 /* register the candidate */
726 candidates[candidate_nb++] = candidate;
727 candidate->fifo_checked = 0;
732 DEBUG1("Candidates found: %d", candidate_nb);
734 /* now we check every candidate task */
735 for (i = 0; i < candidate_nb; i++) {
736 candidate = candidates[i];
738 if (candidate->fifo_checked) {
739 continue; /* we have already evaluated that task*/
742 xbt_assert2(__SD_task_is_in_fifo(candidate), "Bad state of candidate '%s': %d",
743 SD_task_get_name(candidate), SD_task_get_state(candidate));
745 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
746 workstation = candidate->workstation_list[j];
748 /* I can start on this workstation if the workstation is shared
749 or if I am the first task in the fifo */
750 can_start = workstation->access_mode == SD_WORKSTATION_SHARED_ACCESS ||
751 candidate == xbt_fifo_get_item_content(xbt_fifo_get_first_item(workstation->task_fifo));
754 DEBUG2("Candidate '%s' can start: %d", SD_task_get_name(candidate), can_start);
756 /* now we are sure that I can start! */
758 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
759 workstation = candidate->workstation_list[j];
761 /* update the fifo */
762 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
763 candidate = xbt_fifo_shift(workstation->task_fifo); /* the return value is stored just for debugging */
764 DEBUG1("Head of the fifo: '%s'", (candidate != NULL) ? SD_task_get_name(candidate) : "NULL");
765 xbt_assert0(candidate == candidates[i], "Error in __SD_task_just_done: bad first task in the fifo");
767 } /* for each workstation */
769 /* finally execute the task */
770 DEBUG2("Task '%s' state: %d", SD_task_get_name(candidate), SD_task_get_state(candidate));
771 __SD_task_really_run(candidate);
773 DEBUG4("Calling __SD_task_is_running: task '%s', state set: %p, running_task_set: %p, is running: %d",
774 SD_task_get_name(candidate), candidate->state_set, sd_global->running_task_set, __SD_task_is_running(candidate));
775 xbt_assert2(__SD_task_is_running(candidate), "Bad state of task '%s': %d",
776 SD_task_get_name(candidate), SD_task_get_state(candidate));
777 DEBUG0("Okay, the task is running.");
780 candidate->fifo_checked = 1;
781 } /* for each candidate */
783 xbt_free(candidates);
786 /* Remove all dependencies associated with a task. This function is called when the task is destroyed.
788 static void __SD_task_remove_dependencies(SD_task_t task) {
789 /* we must destroy the dependencies carefuly (with SD_dependency_remove)
790 because each one is stored twice */
791 SD_dependency_t dependency;
792 while (xbt_dynar_length(task->tasks_before) > 0) {
793 xbt_dynar_get_cpy(task->tasks_before, 0, &dependency);
794 SD_task_dependency_remove(dependency->src, dependency->dst);
797 while (xbt_dynar_length(task->tasks_after) > 0) {
798 xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
799 SD_task_dependency_remove(dependency->src, dependency->dst);
804 * \brief Returns the start time of a task
806 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
808 * \param task: a task
809 * \return the start time of this task
811 double SD_task_get_start_time(SD_task_t task) {
812 SD_CHECK_INIT_DONE();
813 xbt_assert0(task != NULL, "Invalid parameter");
814 if(task->surf_action)
815 return surf_workstation_resource->common_public->action_get_start_time(task->surf_action);
817 return task->start_time;
821 * \brief Returns the finish time of a task
823 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
824 * If the state is not completed yet, the returned value is an
825 * estimation of the task finish time. This value can fluctuate
826 * until the task is completed.
828 * \param task: a task
829 * \return the start time of this task
831 double SD_task_get_finish_time(SD_task_t task) {
832 SD_CHECK_INIT_DONE();
833 xbt_assert0(task != NULL, "Invalid parameter");
835 if(task->surf_action) /* should never happen as actions are destroyed right after their completion */
836 return surf_workstation_resource->common_public->action_get_finish_time(task->surf_action);
838 return task->finish_time;
842 * \brief Destroys a task.
844 * The user data (if any) should have been destroyed first.
846 * \param task the task you want to destroy
847 * \see SD_task_create()
849 void SD_task_destroy(SD_task_t task) {
850 SD_CHECK_INIT_DONE();
851 xbt_assert0(task != NULL, "Invalid parameter");
853 DEBUG1("Destroying task %s...", SD_task_get_name(task));
855 __SD_task_remove_dependencies(task);
857 /* if the task was scheduled or ready we have to free the scheduling parameters */
858 if (__SD_task_is_scheduled_or_ready(task))
859 __SD_task_destroy_scheduling_data(task);
861 if (task->name != NULL)
862 xbt_free(task->name);
864 if (task->surf_action != NULL)
865 surf_workstation_resource->common_public->action_free(task->surf_action);
867 if (task->workstation_list != NULL)
868 xbt_free(task->workstation_list);
870 xbt_dynar_free(&task->tasks_before);
871 xbt_dynar_free(&task->tasks_after);
874 DEBUG0("Task destroyed.");