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_new(s_SD_task_t, 1);
26 /* general information */
27 task->data = data; /* user data */
29 task->name = xbt_strdup(name);
33 task->state_hookup.prev = NULL;
34 task->state_hookup.next = NULL;
35 task->state_set = sd_global->not_scheduled_task_set;
36 task->state = SD_NOT_SCHEDULED;
37 xbt_swag_insert(task, task->state_set);
39 task->amount = amount;
40 task->remains = amount;
41 task->start_time = -1.0;
42 task->finish_time = -1.0;
43 task->surf_action = NULL;
44 task->watch_points = 0;
45 task->state_changed = 0;
48 task->tasks_before = xbt_dynar_new(sizeof(SD_dependency_t), NULL);
49 task->tasks_after = xbt_dynar_new(sizeof(SD_dependency_t), NULL);
51 /* scheduling parameters */
52 task->workstation_nb = 0;
53 task->workstation_list = NULL;
54 task->computation_amount = NULL;
55 task->communication_amount = NULL;
58 sd_global->task_number++;
64 * \brief Returns the user data of a task
67 * \return the user data associated with this task (can be \c NULL)
68 * \see SD_task_set_data()
70 void* SD_task_get_data(SD_task_t task) {
72 xbt_assert0(task != NULL, "Invalid parameter");
77 * \brief Sets the user data of a task
79 * The new data can be \c NULL. The old data should have been freed first
80 * if it was not \c NULL.
83 * \param data the new data you want to associate with this task
84 * \see SD_task_get_data()
86 void SD_task_set_data(SD_task_t task, void *data) {
88 xbt_assert0(task != NULL, "Invalid parameter");
93 * \brief Returns the state of a task
96 * \return the current \ref e_SD_task_state_t "state" of this task:
97 * #SD_NOT_SCHEDULED, #SD_SCHEDULED, #SD_READY, #SD_RUNNING, #SD_DONE or #SD_FAILED
98 * \see e_SD_task_state_t
100 e_SD_task_state_t SD_task_get_state(SD_task_t task) {
101 SD_CHECK_INIT_DONE();
102 xbt_assert0(task != NULL, "Invalid parameter");
106 /* Changes the state of a task. Updates the swags and the flag sd_global->watch_point_reached.
108 void __SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state) {
109 xbt_swag_remove(task, task->state_set);
111 case SD_NOT_SCHEDULED:
112 task->state_set = sd_global->not_scheduled_task_set;
115 task->state_set = sd_global->scheduled_task_set;
118 task->state_set = sd_global->ready_task_set;
121 task->state_set = sd_global->in_fifo_task_set;
124 task->state_set = sd_global->running_task_set;
125 task->start_time = surf_workstation_resource->common_public->
126 action_get_start_time(task->surf_action);
129 task->state_set = sd_global->done_task_set;
130 task->finish_time = surf_workstation_resource->common_public->
131 action_get_finish_time(task->surf_action);
135 task->state_set = sd_global->failed_task_set;
138 xbt_assert0(0, "Invalid state");
140 xbt_swag_insert(task, task->state_set);
141 task->state = new_state;
143 if (task->watch_points & new_state) {
144 INFO1("Watch point reached with task '%s'!", SD_task_get_name(task));
145 sd_global->watch_point_reached = 1;
146 SD_task_unwatch(task, new_state); /* remove the watch point */
151 * \brief Returns the name of a task
154 * \return the name of this task (can be \c NULL)
156 const char* SD_task_get_name(SD_task_t task) {
157 SD_CHECK_INIT_DONE();
158 xbt_assert0(task != NULL, "Invalid parameter");
163 * \brief Returns the total amount of a task
166 * \return the total amount of this task
167 * \see SD_task_get_remaining_amount()
169 double SD_task_get_amount(SD_task_t task) {
170 SD_CHECK_INIT_DONE();
171 xbt_assert0(task != NULL, "Invalid parameter");
176 * \brief Returns the remaining amount of a task
179 * \return the remaining amount of this task
180 * \see SD_task_get_amount()
182 double SD_task_get_remaining_amount(SD_task_t task) {
183 SD_CHECK_INIT_DONE();
184 xbt_assert0(task != NULL, "Invalid parameter");
186 if (task->surf_action)
187 return task->surf_action->remains;
189 return task->remains;
192 /* temporary function for debbuging */
193 static void __SD_print_dependencies(SD_task_t task) {
194 INFO1("The following tasks must be executed before %s:", SD_task_get_name(task));
195 xbt_dynar_t dynar = task->tasks_before;
196 int length = xbt_dynar_length(dynar);
198 SD_dependency_t dependency;
199 for (i = 0; i < length; i++) {
200 xbt_dynar_get_cpy(dynar, i, &dependency);
201 INFO1(" %s", SD_task_get_name(dependency->src));
204 INFO1("The following tasks must be executed after %s:", SD_task_get_name(task));
206 dynar = task->tasks_after;
207 length = xbt_dynar_length(dynar);
208 for (i = 0; i < length; i++) {
209 xbt_dynar_get_cpy(dynar, i, &dependency);
210 INFO1(" %s", SD_task_get_name(dependency->dst));
212 INFO0("----------------------------");
215 /* Destroys a dependency between two tasks.
217 static void __SD_task_dependency_destroy(void *dependency) {
218 if (((SD_dependency_t) dependency)->name != NULL)
219 xbt_free(((SD_dependency_t) dependency)->name);
220 xbt_free(dependency);
224 * \brief Adds a dependency between two tasks
226 * \a dst will depend on \a src, ie \a dst will not start before \a src is finished.
227 * Their \ref e_SD_task_state_t "state" must be #SD_NOT_SCHEDULED, #SD_SCHEDULED or #SD_READY.
229 * \param name the name of the new dependency (can be \c NULL)
230 * \param data the user data you want to associate with this dependency (can be \c NULL)
231 * \param src the task which must be executed first
232 * \param dst the task you want to make depend on \a src
233 * \see SD_task_dependency_remove()
235 void SD_task_dependency_add(const char *name, void *data, SD_task_t src, SD_task_t dst) {
236 SD_CHECK_INIT_DONE();
237 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
239 xbt_dynar_t dynar = src->tasks_after;
240 int length = xbt_dynar_length(dynar);
243 SD_dependency_t dependency;
246 THROW1(arg_error, 0, "Cannot add a dependency between task '%s' and itself",
247 SD_task_get_name(src));
249 if (!__SD_task_is_not_scheduled(src) && !__SD_task_is_scheduled_or_ready(src))
250 THROW1(arg_error, 0, "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULED or SD_READY", SD_task_get_name(src));
252 if (!__SD_task_is_not_scheduled(dst) && !__SD_task_is_scheduled_or_ready(dst))
253 THROW1(arg_error, 0, "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULED or SD_READY", SD_task_get_name(dst));
255 DEBUG2("SD_task_dependency_add: src = %s, dst = %s", SD_task_get_name(src), SD_task_get_name(dst));
256 for (i = 0; i < length && !found; i++) {
257 xbt_dynar_get_cpy(dynar, i, &dependency);
258 found = (dependency->dst == dst);
259 DEBUG2("Dependency %d: dependency->dst = %s", i, SD_task_get_name(dependency->dst));
263 THROW2(arg_error, 0, "A dependency already exists between task '%s' and task '%s'",
264 SD_task_get_name(src), SD_task_get_name(dst));
266 dependency = xbt_new(s_SD_dependency_t, 1);
269 dependency->name = xbt_strdup(name);
271 dependency->name = NULL;
273 dependency->data = data;
274 dependency->src = src;
275 dependency->dst = dst;
277 /* src must be executed before dst */
278 xbt_dynar_push(src->tasks_after, &dependency);
279 xbt_dynar_push(dst->tasks_before, &dependency);
281 /* if the task was ready, then dst->tasks_before is not empty anymore,
282 so we must go back to state SD_SCHEDULED */
283 if (__SD_task_is_ready(dst)) {
284 DEBUG1("SD_task_dependency_add: %s was ready and becomes scheduled!", SD_task_get_name(dst));
285 __SD_task_set_state(dst, SD_SCHEDULED);
288 /* __SD_print_dependencies(src);
289 __SD_print_dependencies(dst); */
293 * \brief Remove a dependency between two tasks
296 * \param dst a task depending on \a src
297 * \see SD_task_dependency_add()
299 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst) {
300 SD_CHECK_INIT_DONE();
301 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
303 /* remove the dependency from src->tasks_after */
304 xbt_dynar_t dynar = src->tasks_after;
305 int length = xbt_dynar_length(dynar);
308 SD_dependency_t dependency;
309 for (i = 0; i < length && !found; i++) {
310 xbt_dynar_get_cpy(dynar, i, &dependency);
311 if (dependency->dst == dst) {
312 xbt_dynar_remove_at(dynar, i, NULL);
318 "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
319 SD_task_get_name(src), SD_task_get_name(dst), SD_task_get_name(dst), SD_task_get_name(src));
321 /* remove the dependency from dst->tasks_before */
322 dynar = dst->tasks_before;
323 length = xbt_dynar_length(dynar);
326 for (i = 0; i < length && !found; i++) {
327 xbt_dynar_get_cpy(dynar, i, &dependency);
328 if (dependency->src == src) {
329 xbt_dynar_remove_at(dynar, i, NULL);
330 __SD_task_dependency_destroy(dependency);
334 /* should never happen... */
335 xbt_assert4(found, "SimDag error: task '%s' is a successor of '%s' but task '%s' is not a predecessor of task '%s'",
336 SD_task_get_name(dst), SD_task_get_name(src), SD_task_get_name(src), SD_task_get_name(dst));
338 /* if the task was scheduled and dst->tasks_before is empty now, we can make it ready */
339 if (xbt_dynar_length(dst->tasks_before) == 0 && __SD_task_is_scheduled(dst))
340 __SD_task_set_state(dst, SD_READY);
342 /* __SD_print_dependencies(src);
343 __SD_print_dependencies(dst);*/
347 * \brief Returns the user data associated with a dependency between two tasks
350 * \param dst a task depending on \a src
351 * \return the user data associated with this dependency (can be \c NULL)
352 * \see SD_task_dependency_add()
354 void *SD_task_dependency_get_data(SD_task_t src, SD_task_t dst) {
355 SD_CHECK_INIT_DONE();
356 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
358 xbt_dynar_t dynar = src->tasks_after;
359 int length = xbt_dynar_length(dynar);
362 SD_dependency_t dependency;
363 for (i = 0; i < length && !found; i++) {
364 xbt_dynar_get_cpy(dynar, i, &dependency);
365 found = (dependency->dst == dst);
368 THROW2(arg_error, 0, "No dependency found between task '%s' and '%s'", SD_task_get_name(src), SD_task_get_name(dst));
369 return dependency->data;
372 /* temporary function for debugging */
373 static void __SD_print_watch_points(SD_task_t task) {
374 static const int state_masks[] = {SD_SCHEDULED, SD_RUNNING, SD_READY, SD_DONE, SD_FAILED};
375 static const char* state_names[] = {"scheduled", "running", "ready", "done", "failed"};
377 INFO2("Task '%s' watch points (%x): ", SD_task_get_name(task), task->watch_points);
380 for (i = 0; i < 5; i++) {
381 if (task->watch_points & state_masks[i])
382 INFO1("%s ", state_names[i]);
387 * \brief Adds a watch point to a task
389 * SD_simulate() will stop as soon as the \ref e_SD_task_state_t "state" of this
390 * task becomes the one given in argument. The
391 * watch point is then automatically removed.
394 * \param state the \ref e_SD_task_state_t "state" you want to watch
395 * (cannot be #SD_NOT_SCHEDULED)
396 * \see SD_task_unwatch()
398 void SD_task_watch(SD_task_t task, e_SD_task_state_t state) {
399 SD_CHECK_INIT_DONE();
400 xbt_assert0(task != NULL, "Invalid parameter");
402 if (state & SD_NOT_SCHEDULED)
403 THROW0(arg_error, 0, "Cannot add a watch point for state SD_NOT_SCHEDULED");
405 task->watch_points = task->watch_points | state;
406 /* __SD_print_watch_points(task);*/
410 * \brief Removes a watch point from a task
413 * \param state the \ref e_SD_task_state_t "state" you no longer want to watch
414 * \see SD_task_watch()
416 void SD_task_unwatch(SD_task_t task, e_SD_task_state_t state) {
417 SD_CHECK_INIT_DONE();
418 xbt_assert0(task != NULL, "Invalid parameter");
419 xbt_assert0(state != SD_NOT_SCHEDULED,
420 "SimDag error: Cannot have a watch point for state SD_NOT_SCHEDULED");
422 task->watch_points = task->watch_points & ~state;
423 /* __SD_print_watch_points(task);*/
427 * \brief Returns an approximative estimation of the execution time of a task.
429 * The estimation is very approximative because the value returned is the time
430 * the task would take if it was executed now and if it was the only task.
432 * \param task the task to evaluate
433 * \param workstation_nb number of workstations on which the task would be executed
434 * \param workstation_list the workstations on which the task would be executed
435 * \param computation_amount computation amount for each workstation
436 * \param communication_amount communication amount between each pair of workstations
437 * \param rate task execution speed rate
440 double SD_task_get_execution_time(SD_task_t task,
442 const SD_workstation_t *workstation_list,
443 const double *computation_amount,
444 const double *communication_amount,
446 SD_CHECK_INIT_DONE();
447 xbt_assert0(task != NULL && workstation_nb > 0 && workstation_list != NULL &&
448 computation_amount != NULL && communication_amount != NULL,
449 "Invalid parameter");
451 /* the task execution time is the maximum execution time of the parallel tasks */
452 double time, max_time = 0.0;
454 for (i = 0; i < workstation_nb; i++) {
455 time = SD_workstation_get_computation_time(workstation_list[i], computation_amount[i]);
457 for (j = 0; j < workstation_nb; j++) {
458 time += SD_route_get_communication_time(workstation_list[i], workstation_list[j],
459 communication_amount[i * workstation_nb + j]);
462 if (time > max_time) {
466 return max_time * SD_task_get_amount(task);
470 * \brief Schedules a task
472 * The task state must be #SD_NOT_SCHEDULED.
473 * Once scheduled, a task will be executed as soon as possible in SD_simulate(),
474 * i.e. when its dependencies are satisfied.
476 * \param task the task you want to schedule
477 * \param workstation_nb number of workstations on which the task will be executed
478 * \param workstation_list the workstations on which the task will be executed
479 * \param computation_amount computation amount for each workstation
480 * \param communication_amount communication amount between each pair of workstations
481 * \param rate task execution speed rate
482 * \see SD_task_unschedule()
484 void SD_task_schedule(SD_task_t task, int workstation_nb,
485 const SD_workstation_t *workstation_list, const double *computation_amount,
486 const double *communication_amount, double rate) {
487 SD_CHECK_INIT_DONE();
488 xbt_assert0(task != NULL, "Invalid parameter");
489 xbt_assert0(workstation_nb > 0, "workstation_nb must be positive");
491 if (!__SD_task_is_not_scheduled(task))
492 THROW1(arg_error, 0, "Task '%s' has already been scheduled", SD_task_get_name(task));
494 task->workstation_nb = workstation_nb;
497 task->computation_amount = xbt_new(double, workstation_nb);
498 memcpy(task->computation_amount, computation_amount, sizeof(double) * workstation_nb);
500 int communication_nb = workstation_nb * workstation_nb;
501 task->communication_amount = xbt_new(double, communication_nb);
502 memcpy(task->communication_amount, communication_amount, sizeof(double) * communication_nb);
504 task->workstation_list = xbt_new(SD_workstation_t, workstation_nb);
505 memcpy(task->workstation_list, workstation_list, sizeof(SD_workstation_t) * workstation_nb);
507 /* update the task state */
508 if (xbt_dynar_length(task->tasks_before) == 0)
509 __SD_task_set_state(task, SD_READY);
511 __SD_task_set_state(task, SD_SCHEDULED);
515 * \brief Unschedules a task
517 * The task state must be #SD_SCHEDULED, #SD_READY, #SD_RUNNING or #SD_FAILED.
518 * If you call this function, the task state becomes #SD_NOT_SCHEDULED.
519 * Call SD_task_schedule() to schedule it again.
521 * \param task the task you want to unschedule
522 * \see SD_task_schedule()
524 void SD_task_unschedule(SD_task_t task) {
525 SD_CHECK_INIT_DONE();
526 xbt_assert0(task != NULL, "Invalid parameter");
528 if (task->state_set != sd_global->scheduled_task_set &&
529 task->state_set != sd_global->ready_task_set &&
530 task->state_set != sd_global->running_task_set &&
531 task->state_set != sd_global->failed_task_set)
532 THROW1(arg_error, 0, "Task %s: the state must be SD_SCHEDULED, SD_READY, SD_RUNNING or SD_FAILED",
533 SD_task_get_name(task));
535 if (__SD_task_is_scheduled_or_ready(task)) /* if the task is scheduled or ready */
536 __SD_task_destroy_scheduling_data(task);
538 if (__SD_task_is_running(task)) /* the task should become SD_FAILED */
539 surf_workstation_resource->common_public->action_cancel(task->surf_action);
541 __SD_task_set_state(task, SD_NOT_SCHEDULED);
542 task->remains = task->amount;
543 task->start_time = -1.0;
546 /* Destroys the data memorised by SD_task_schedule. Task state must be SD_SCHEDULED or SD_READY.
548 static void __SD_task_destroy_scheduling_data(SD_task_t task) {
549 SD_CHECK_INIT_DONE();
550 if (!__SD_task_is_scheduled_or_ready(task) && !__SD_task_is_in_fifo(task))
551 THROW1(arg_error, 0, "Task '%s' must be SD_SCHEDULED, SD_READY or SD_IN_FIFO", SD_task_get_name(task));
553 xbt_free(task->computation_amount);
554 xbt_free(task->communication_amount);
557 /* Runs a task. This function is directly called by __SD_task_try_to_run if the task
558 * doesn't have to wait in fifos. Otherwise, it is called by __SD_task_just_done when
559 * the task gets out of its fifos.
561 void __SD_task_really_run(SD_task_t task) {
562 SD_CHECK_INIT_DONE();
563 xbt_assert0(task != NULL, "Invalid parameter");
564 xbt_assert2(__SD_task_is_ready_or_in_fifo(task), "Task '%s' is not ready or in a fifo! Task state: %d",
565 SD_task_get_name(task), SD_task_get_state(task));
566 xbt_assert1(task->workstation_list != NULL, "Task '%s': workstation_list is NULL!", SD_task_get_name(task));
569 void **surf_workstations;
571 DEBUG1("Really running task '%s'", SD_task_get_name(task));
573 /* set this task as current task for the workstations in sequential mode */
574 for (i = 0; i < task->workstation_nb; i++) {
575 if (SD_workstation_get_access_mode(task->workstation_list[i]) == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
576 task->workstation_list[i]->current_task = task;
577 xbt_assert0(__SD_workstation_is_busy(task->workstation_list[i]), "The workstation should be busy now");
581 DEBUG1("Task '%s' set as current task for its workstations", SD_task_get_name(task));
585 /* we have to create a Surf workstation array instead of the SimDag workstation array */
586 surf_workstations = xbt_new(void*, task->workstation_nb);
588 for (i = 0; i < task->workstation_nb; i++) {
589 surf_workstations[i] = task->workstation_list[i]->surf_workstation;
592 task->surf_action = surf_workstation_resource->extension_public->
593 execute_parallel_task(task->workstation_nb,
595 task->computation_amount,
596 task->communication_amount,
599 surf_workstation_resource->common_public->action_set_data(task->surf_action, task);
600 task->state_changed = 1;
602 DEBUG1("surf_action = %p", task->surf_action);
604 xbt_free(surf_workstations);
605 __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
606 __SD_task_set_state(task, SD_RUNNING);
607 xbt_assert2(__SD_task_is_running(task), "Bad state of task '%s': %d",
608 SD_task_get_name(task), SD_task_get_state(task));
612 /* Tries to run a task. This function is called by SD_simulate() when a scheduled task becomes SD_READY
613 * (ie when its dependencies are satisfied).
614 * If one of the workstations where the task is scheduled on is busy (in sequential mode),
615 * the task doesn't start.
616 * Returns whether the task has started.
618 int __SD_task_try_to_run(SD_task_t task) {
619 SD_CHECK_INIT_DONE();
620 xbt_assert0(task != NULL, "Invalid parameter");
621 xbt_assert2(__SD_task_is_ready(task), "Task '%s' is not ready! Task state: %d",
622 SD_task_get_name(task), SD_task_get_state(task));
626 SD_workstation_t workstation;
628 for (i = 0; i < task->workstation_nb; i++) {
629 can_start = !__SD_workstation_is_busy(task->workstation_list[i]);
632 DEBUG2("Task '%s' can start: %d", SD_task_get_name(task), can_start);
634 if (!can_start) { /* if the task cannot start and is not in the fifos yet*/
635 for (i = 0; i < task->workstation_nb; i++) {
636 workstation = task->workstation_list[i];
637 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
638 DEBUG2("Pushing task '%s' in the fifo of workstation '%s'", SD_task_get_name(task),
639 SD_workstation_get_name(workstation));
640 xbt_fifo_push(workstation->task_fifo, task);
643 __SD_task_set_state(task, SD_IN_FIFO);
644 xbt_assert2(__SD_task_is_in_fifo(task), "Bad state of task '%s': %d",
645 SD_task_get_name(task), SD_task_get_state(task));
646 DEBUG1("Task '%s' state is now SD_IN_FIFO", SD_task_get_name(task));
649 __SD_task_really_run(task);
655 /* This function is called by SD_simulate when a task is done.
656 * It updates task->state and task->action and executes if necessary the tasks
657 * which were waiting in fifos for the end of `task'
659 void __SD_task_just_done(SD_task_t task) {
660 SD_CHECK_INIT_DONE();
661 xbt_assert0(task != NULL, "Invalid parameter");
662 xbt_assert1(__SD_task_is_running(task), "The task must be running! Task state: %d", SD_task_get_state(task));
663 xbt_assert1(task->workstation_list != NULL, "Task '%s': workstation_list is NULL!", SD_task_get_name(task));
666 SD_workstation_t workstation;
669 int candidate_nb = 0;
670 int candidate_capacity = 8;
671 SD_task_t *candidates = xbt_new(SD_task_t, 8);
674 __SD_task_set_state(task, SD_DONE);
675 surf_workstation_resource->common_public->action_free(task->surf_action);
676 task->surf_action = NULL;
678 DEBUG0("Looking for candidates");
680 /* if the task was executed on sequential workstations,
681 maybe we can execute the next task of the fifo for each workstation */
682 for (i = 0; i < task->workstation_nb; i++) {
683 workstation = task->workstation_list[i];
684 DEBUG2("Workstation '%s': access_mode = %d", SD_workstation_get_name(workstation), workstation->access_mode);
685 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
686 xbt_assert1(workstation->task_fifo != NULL, "Workstation '%s' has sequential access but no fifo!",
687 SD_workstation_get_name(workstation));
688 xbt_assert2(workstation->current_task = task, "Workstation '%s': current task should be '%s'",
689 SD_workstation_get_name(workstation), SD_task_get_name(task));
691 /* the task is over so we can release the workstation */
692 workstation->current_task = NULL;
694 DEBUG0("Getting candidate in fifo");
695 candidate = xbt_fifo_get_item_content(xbt_fifo_get_first_item(workstation->task_fifo));
697 if (candidate != NULL) {
698 DEBUG1("Candidate: '%s'", SD_task_get_name(candidate));
699 xbt_assert2(__SD_task_is_in_fifo(candidate), "Bad state of candidate '%s': %d",
700 SD_task_get_name(candidate), SD_task_get_state(candidate));
703 DEBUG1("Candidate in fifo: %p", candidate);
705 /* if there was a task waiting for my place */
706 if (candidate != NULL) {
707 /* Unfortunately, we are not sure yet that we can execute the task now,
708 because the task can be waiting more deeply in some other workstation's fifos...
709 So we memorize all candidate tasks, and then we will check for each candidate
710 whether or not all its workstations are available. */
712 /* realloc if necessary */
713 if (candidate_nb == candidate_capacity) {
714 candidate_capacity *= 2;
715 candidates = xbt_realloc(candidates, sizeof(SD_task_t) * candidate_capacity);
718 /* register the candidate */
719 candidates[candidate_nb++] = candidate;
720 candidate->fifo_checked = 0;
725 DEBUG1("Candidates found: %d", candidate_nb);
727 /* now we check every candidate task */
728 for (i = 0; i < candidate_nb; i++) {
729 candidate = candidates[i];
731 if (candidate->fifo_checked) {
732 continue; /* we have already evaluated that task*/
735 xbt_assert2(__SD_task_is_in_fifo(candidate), "Bad state of candidate '%s': %d",
736 SD_task_get_name(candidate), SD_task_get_state(candidate));
738 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
739 workstation = candidate->workstation_list[j];
741 /* I can start on this workstation if the workstation is shared
742 or if I am the first task in the fifo */
743 can_start = workstation->access_mode == SD_WORKSTATION_SHARED_ACCESS ||
744 candidate == xbt_fifo_get_item_content(xbt_fifo_get_first_item(workstation->task_fifo));
747 DEBUG2("Candidate '%s' can start: %d", SD_task_get_name(candidate), can_start);
749 /* now we are sure that I can start! */
751 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
752 workstation = candidate->workstation_list[j];
754 /* update the fifo */
755 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
756 candidate = xbt_fifo_shift(workstation->task_fifo); /* the return value is stored just for debugging */
757 DEBUG1("Head of the fifo: '%s'", (candidate != NULL) ? SD_task_get_name(candidate) : "NULL");
758 xbt_assert0(candidate == candidates[i], "Error in __SD_task_just_done: bad first task in the fifo");
760 } /* for each workstation */
762 /* finally execute the task */
763 DEBUG2("Task '%s' state: %d", SD_task_get_name(candidate), SD_task_get_state(candidate));
764 __SD_task_really_run(candidate);
766 DEBUG4("Calling __SD_task_is_running: task '%s', state set: %p, running_task_set: %p, is running: %d",
767 SD_task_get_name(candidate), candidate->state_set, sd_global->running_task_set, __SD_task_is_running(candidate));
768 xbt_assert2(__SD_task_is_running(candidate), "Bad state of task '%s': %d",
769 SD_task_get_name(candidate), SD_task_get_state(candidate));
770 DEBUG0("Okay, the task is running.");
773 candidate->fifo_checked = 1;
774 } /* for each candidate */
776 xbt_free(candidates);
779 /* Remove all dependencies associated with a task. This function is called when the task is destroyed.
781 static void __SD_task_remove_dependencies(SD_task_t task) {
782 /* we must destroy the dependencies carefuly (with SD_dependency_remove)
783 because each one is stored twice */
784 SD_dependency_t dependency;
785 while (xbt_dynar_length(task->tasks_before) > 0) {
786 xbt_dynar_get_cpy(task->tasks_before, 0, &dependency);
787 SD_task_dependency_remove(dependency->src, dependency->dst);
790 while (xbt_dynar_length(task->tasks_after) > 0) {
791 xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
792 SD_task_dependency_remove(dependency->src, dependency->dst);
797 * \brief Returns the start time of a task
799 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
801 * \param task: a task
802 * \return the start time of this task
804 double SD_task_get_start_time(SD_task_t task) {
805 SD_CHECK_INIT_DONE();
806 xbt_assert0(task != NULL, "Invalid parameter");
807 if(task->surf_action)
808 return surf_workstation_resource->common_public->action_get_start_time(task->surf_action);
810 return task->start_time;
814 * \brief Returns the finish time of a task
816 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
817 * If the state is not completed yet, the returned value is an
818 * estimation of the task finish time. This value can fluctuate
819 * until the task is completed.
821 * \param task: a task
822 * \return the start time of this task
824 double SD_task_get_finish_time(SD_task_t task) {
825 SD_CHECK_INIT_DONE();
826 xbt_assert0(task != NULL, "Invalid parameter");
828 if(task->surf_action) /* should never happen as actions are destroyed right after their completion */
829 return surf_workstation_resource->common_public->action_get_finish_time(task->surf_action);
831 return task->finish_time;
835 * \brief Destroys a task.
837 * The user data (if any) should have been destroyed first.
839 * \param task the task you want to destroy
840 * \see SD_task_create()
842 void SD_task_destroy(SD_task_t task) {
843 SD_CHECK_INIT_DONE();
844 xbt_assert0(task != NULL, "Invalid parameter");
846 DEBUG1("Destroying task %s...", SD_task_get_name(task));
848 __SD_task_remove_dependencies(task);
850 /* if the task was scheduled or ready we have to free the scheduling parameters */
851 if (__SD_task_is_scheduled_or_ready(task))
852 __SD_task_destroy_scheduling_data(task);
854 if (task->name != NULL)
855 xbt_free(task->name);
857 if (task->surf_action != NULL)
858 surf_workstation_resource->common_public->action_free(task->surf_action);
860 if (task->workstation_list != NULL)
861 xbt_free(task->workstation_list);
863 xbt_dynar_free(&task->tasks_before);
864 xbt_dynar_free(&task->tasks_after);
867 sd_global->task_number--;
869 DEBUG0("Task destroyed.");