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;
55 sd_global->task_number++;
61 * \brief Returns the user data of a task
64 * \return the user data associated with this task (can be \c NULL)
65 * \see SD_task_set_data()
67 void* SD_task_get_data(SD_task_t task) {
69 xbt_assert0(task != NULL, "Invalid parameter");
74 * \brief Sets the user data of a task
76 * The new data can be \c NULL. The old data should have been freed first
77 * if it was not \c NULL.
80 * \param data the new data you want to associate with this task
81 * \see SD_task_get_data()
83 void SD_task_set_data(SD_task_t task, void *data) {
85 xbt_assert0(task != NULL, "Invalid parameter");
90 * \brief Returns the state of a task
93 * \return the current \ref e_SD_task_state_t "state" of this task:
94 * #SD_NOT_SCHEDULED, #SD_SCHEDULED, #SD_READY, #SD_RUNNING, #SD_DONE or #SD_FAILED
95 * \see e_SD_task_state_t
97 e_SD_task_state_t SD_task_get_state(SD_task_t task) {
99 xbt_assert0(task != NULL, "Invalid parameter");
101 if (task->state_set == sd_global->scheduled_task_set)
103 if (task->state_set == sd_global->done_task_set)
105 if (task->state_set == sd_global->running_task_set)
107 if (task->state_set == sd_global->ready_task_set)
109 if (task->state_set == sd_global->in_fifo_task_set)
111 if (task->state_set == sd_global->not_scheduled_task_set)
112 return SD_NOT_SCHEDULED;
116 /* Changes the state of a task. Updates the swags and the flag sd_global->watch_point_reached.
118 void __SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state) {
119 xbt_swag_remove(task, task->state_set);
121 case SD_NOT_SCHEDULED:
122 task->state_set = sd_global->not_scheduled_task_set;
125 task->state_set = sd_global->scheduled_task_set;
128 task->state_set = sd_global->ready_task_set;
131 task->state_set = sd_global->in_fifo_task_set;
134 task->state_set = sd_global->running_task_set;
135 task->start_time = surf_workstation_resource->common_public->
136 action_get_start_time(task->surf_action);
139 task->state_set = sd_global->done_task_set;
140 task->finish_time = surf_workstation_resource->common_public->
141 action_get_finish_time(task->surf_action);
145 task->state_set = sd_global->failed_task_set;
148 xbt_assert0(0, "Invalid state");
150 xbt_swag_insert(task, task->state_set);
152 if (task->watch_points & new_state) {
153 INFO1("Watch point reached with task '%s'!", SD_task_get_name(task));
154 sd_global->watch_point_reached = 1;
155 SD_task_unwatch(task, new_state); /* remove the watch point */
160 * \brief Returns the name of a task
163 * \return the name of this task (can be \c NULL)
165 const char* SD_task_get_name(SD_task_t task) {
166 SD_CHECK_INIT_DONE();
167 xbt_assert0(task != NULL, "Invalid parameter");
172 * \brief Returns the total amount of a task
175 * \return the total amount of this task
176 * \see SD_task_get_remaining_amount()
178 double SD_task_get_amount(SD_task_t task) {
179 SD_CHECK_INIT_DONE();
180 xbt_assert0(task != NULL, "Invalid parameter");
185 * \brief Returns the remaining amount of a task
188 * \return the remaining amount of this task
189 * \see SD_task_get_amount()
191 double SD_task_get_remaining_amount(SD_task_t task) {
192 SD_CHECK_INIT_DONE();
193 xbt_assert0(task != NULL, "Invalid parameter");
195 if (task->surf_action)
196 return task->surf_action->remains;
198 return task->remains;
201 /* temporary function for debbuging */
202 static void __SD_print_dependencies(SD_task_t task) {
203 INFO1("The following tasks must be executed before %s:", SD_task_get_name(task));
204 xbt_dynar_t dynar = task->tasks_before;
205 int length = xbt_dynar_length(dynar);
207 SD_dependency_t dependency;
208 for (i = 0; i < length; i++) {
209 xbt_dynar_get_cpy(dynar, i, &dependency);
210 INFO1(" %s", SD_task_get_name(dependency->src));
213 INFO1("The following tasks must be executed after %s:", SD_task_get_name(task));
215 dynar = task->tasks_after;
216 length = xbt_dynar_length(dynar);
217 for (i = 0; i < length; i++) {
218 xbt_dynar_get_cpy(dynar, i, &dependency);
219 INFO1(" %s", SD_task_get_name(dependency->dst));
221 INFO0("----------------------------");
224 /* Destroys a dependency between two tasks.
226 static void __SD_task_dependency_destroy(void *dependency) {
227 if (((SD_dependency_t) dependency)->name != NULL)
228 xbt_free(((SD_dependency_t) dependency)->name);
229 xbt_free(dependency);
233 * \brief Adds a dependency between two tasks
235 * \a dst will depend on \a src, ie \a dst will not start before \a src is finished.
236 * Their \ref e_SD_task_state_t "state" must be #SD_NOT_SCHEDULED, #SD_SCHEDULED or #SD_READY.
238 * \param name the name of the new dependency (can be \c NULL)
239 * \param data the user data you want to associate with this dependency (can be \c NULL)
240 * \param src the task which must be executed first
241 * \param dst the task you want to make depend on \a src
242 * \see SD_task_dependency_remove()
244 void SD_task_dependency_add(const char *name, void *data, SD_task_t src, SD_task_t dst) {
245 SD_CHECK_INIT_DONE();
246 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
248 xbt_dynar_t dynar = src->tasks_after;
249 int length = xbt_dynar_length(dynar);
252 SD_dependency_t dependency;
255 THROW1(arg_error, 0, "Cannot add a dependency between task '%s' and itself",
256 SD_task_get_name(src));
258 if (!__SD_task_is_not_scheduled(src) && !__SD_task_is_scheduled_or_ready(src))
259 THROW1(arg_error, 0, "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULED or SD_READY", SD_task_get_name(src));
261 if (!__SD_task_is_not_scheduled(dst) && !__SD_task_is_scheduled_or_ready(dst))
262 THROW1(arg_error, 0, "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULED or SD_READY", SD_task_get_name(dst));
264 DEBUG2("SD_task_dependency_add: src = %s, dst = %s", SD_task_get_name(src), SD_task_get_name(dst));
265 for (i = 0; i < length && !found; i++) {
266 xbt_dynar_get_cpy(dynar, i, &dependency);
267 found = (dependency->dst == dst);
268 DEBUG2("Dependency %d: dependency->dst = %s", i, SD_task_get_name(dependency->dst));
272 THROW2(arg_error, 0, "A dependency already exists between task '%s' and task '%s'",
273 SD_task_get_name(src), SD_task_get_name(dst));
275 dependency = xbt_new0(s_SD_dependency_t, 1);
278 dependency->name = xbt_strdup(name);
280 dependency->name = NULL;
282 dependency->data = data;
283 dependency->src = src;
284 dependency->dst = dst;
286 /* src must be executed before dst */
287 xbt_dynar_push(src->tasks_after, &dependency);
288 xbt_dynar_push(dst->tasks_before, &dependency);
290 /* if the task was ready, then dst->tasks_before is not empty anymore,
291 so we must go back to state SD_SCHEDULED */
292 if (__SD_task_is_ready(dst)) {
293 DEBUG1("SD_task_dependency_add: %s was ready and becomes scheduled!", SD_task_get_name(dst));
294 __SD_task_set_state(dst, SD_SCHEDULED);
297 /* __SD_print_dependencies(src);
298 __SD_print_dependencies(dst); */
302 * \brief Remove a dependency between two tasks
305 * \param dst a task depending on \a src
306 * \see SD_task_dependency_add()
308 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst) {
309 SD_CHECK_INIT_DONE();
310 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
312 /* remove the dependency from src->tasks_after */
313 xbt_dynar_t dynar = src->tasks_after;
314 int length = xbt_dynar_length(dynar);
317 SD_dependency_t dependency;
318 for (i = 0; i < length && !found; i++) {
319 xbt_dynar_get_cpy(dynar, i, &dependency);
320 if (dependency->dst == dst) {
321 xbt_dynar_remove_at(dynar, i, NULL);
327 "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'",
328 SD_task_get_name(src), SD_task_get_name(dst), SD_task_get_name(dst), SD_task_get_name(src));
330 /* remove the dependency from dst->tasks_before */
331 dynar = dst->tasks_before;
332 length = xbt_dynar_length(dynar);
335 for (i = 0; i < length && !found; i++) {
336 xbt_dynar_get_cpy(dynar, i, &dependency);
337 if (dependency->src == src) {
338 xbt_dynar_remove_at(dynar, i, NULL);
339 __SD_task_dependency_destroy(dependency);
343 /* should never happen... */
344 xbt_assert4(found, "SimDag error: task '%s' is a successor of '%s' but task '%s' is not a predecessor of task '%s'",
345 SD_task_get_name(dst), SD_task_get_name(src), SD_task_get_name(src), SD_task_get_name(dst));
347 /* if the task was scheduled and dst->tasks_before is empty now, we can make it ready */
348 if (xbt_dynar_length(dst->tasks_before) == 0 && __SD_task_is_scheduled(dst))
349 __SD_task_set_state(dst, SD_READY);
351 /* __SD_print_dependencies(src);
352 __SD_print_dependencies(dst);*/
356 * \brief Returns the user data associated with a dependency between two tasks
359 * \param dst a task depending on \a src
360 * \return the user data associated with this dependency (can be \c NULL)
361 * \see SD_task_dependency_add()
363 void *SD_task_dependency_get_data(SD_task_t src, SD_task_t dst) {
364 SD_CHECK_INIT_DONE();
365 xbt_assert0(src != NULL && dst != NULL, "Invalid parameter");
367 xbt_dynar_t dynar = src->tasks_after;
368 int length = xbt_dynar_length(dynar);
371 SD_dependency_t dependency;
372 for (i = 0; i < length && !found; i++) {
373 xbt_dynar_get_cpy(dynar, i, &dependency);
374 found = (dependency->dst == dst);
377 THROW2(arg_error, 0, "No dependency found between task '%s' and '%s'", SD_task_get_name(src), SD_task_get_name(dst));
378 return dependency->data;
381 /* temporary function for debugging */
382 static void __SD_print_watch_points(SD_task_t task) {
383 static const int state_masks[] = {SD_SCHEDULED, SD_RUNNING, SD_READY, SD_DONE, SD_FAILED};
384 static const char* state_names[] = {"scheduled", "running", "ready", "done", "failed"};
386 INFO2("Task '%s' watch points (%x): ", SD_task_get_name(task), task->watch_points);
389 for (i = 0; i < 5; i++) {
390 if (task->watch_points & state_masks[i])
391 INFO1("%s ", state_names[i]);
396 * \brief Adds a watch point to a task
398 * SD_simulate() will stop as soon as the \ref e_SD_task_state_t "state" of this
399 * task becomes the one given in argument. The
400 * watch point is then automatically removed.
403 * \param state the \ref e_SD_task_state_t "state" you want to watch
404 * (cannot be #SD_NOT_SCHEDULED)
405 * \see SD_task_unwatch()
407 void SD_task_watch(SD_task_t task, e_SD_task_state_t state) {
408 SD_CHECK_INIT_DONE();
409 xbt_assert0(task != NULL, "Invalid parameter");
411 if (state & SD_NOT_SCHEDULED)
412 THROW0(arg_error, 0, "Cannot add a watch point for state SD_NOT_SCHEDULED");
414 task->watch_points = task->watch_points | state;
415 /* __SD_print_watch_points(task);*/
419 * \brief Removes a watch point from a task
422 * \param state the \ref e_SD_task_state_t "state" you no longer want to watch
423 * \see SD_task_watch()
425 void SD_task_unwatch(SD_task_t task, e_SD_task_state_t state) {
426 SD_CHECK_INIT_DONE();
427 xbt_assert0(task != NULL, "Invalid parameter");
428 xbt_assert0(state != SD_NOT_SCHEDULED,
429 "SimDag error: Cannot have a watch point for state SD_NOT_SCHEDULED");
431 task->watch_points = task->watch_points & ~state;
432 /* __SD_print_watch_points(task);*/
436 * \brief Returns an approximative estimation of the execution time of a task.
438 * The estimation is very approximative because the value returned is the time
439 * the task would take if it was executed now and if it was the only task.
441 * \param task the task to evaluate
442 * \param workstation_nb number of workstations on which the task would be executed
443 * \param workstation_list the workstations on which the task would be executed
444 * \param computation_amount computation amount for each workstation
445 * \param communication_amount communication amount between each pair of workstations
446 * \param rate task execution speed rate
449 double SD_task_get_execution_time(SD_task_t task,
451 const SD_workstation_t *workstation_list,
452 const double *computation_amount,
453 const double *communication_amount,
455 SD_CHECK_INIT_DONE();
456 xbt_assert0(task != NULL && workstation_nb > 0 && workstation_list != NULL &&
457 computation_amount != NULL && communication_amount != NULL,
458 "Invalid parameter");
460 /* the task execution time is the maximum execution time of the parallel tasks */
461 double time, max_time = 0.0;
463 for (i = 0; i < workstation_nb; i++) {
464 time = SD_workstation_get_computation_time(workstation_list[i], computation_amount[i]);
466 for (j = 0; j < workstation_nb; j++) {
467 time += SD_route_get_communication_time(workstation_list[i], workstation_list[j],
468 communication_amount[i * workstation_nb + j]);
471 if (time > max_time) {
475 return max_time * SD_task_get_amount(task);
479 * \brief Schedules a task
481 * The task state must be #SD_NOT_SCHEDULED.
482 * Once scheduled, a task will be executed as soon as possible in SD_simulate(),
483 * i.e. when its dependencies are satisfied.
485 * \param task the task you want to schedule
486 * \param workstation_nb number of workstations on which the task will be executed
487 * \param workstation_list the workstations on which the task will be executed
488 * \param computation_amount computation amount for each workstation
489 * \param communication_amount communication amount between each pair of workstations
490 * \param rate task execution speed rate
491 * \see SD_task_unschedule()
493 void SD_task_schedule(SD_task_t task, int workstation_nb,
494 const SD_workstation_t *workstation_list, const double *computation_amount,
495 const double *communication_amount, double rate) {
496 SD_CHECK_INIT_DONE();
497 xbt_assert0(task != NULL, "Invalid parameter");
498 xbt_assert0(workstation_nb > 0, "workstation_nb must be positive");
500 if (!__SD_task_is_not_scheduled(task))
501 THROW1(arg_error, 0, "Task '%s' has already been scheduled", SD_task_get_name(task));
503 task->workstation_nb = workstation_nb;
506 task->computation_amount = xbt_new0(double, workstation_nb);
507 memcpy(task->computation_amount, computation_amount, sizeof(double) * workstation_nb);
509 int communication_nb = workstation_nb * workstation_nb;
510 task->communication_amount = xbt_new0(double, communication_nb);
511 memcpy(task->communication_amount, communication_amount, sizeof(double) * communication_nb);
513 task->workstation_list = xbt_new0(SD_workstation_t, workstation_nb);
514 memcpy(task->workstation_list, workstation_list, sizeof(SD_workstation_t) * workstation_nb);
516 /* update the task state */
517 if (xbt_dynar_length(task->tasks_before) == 0)
518 __SD_task_set_state(task, SD_READY);
520 __SD_task_set_state(task, SD_SCHEDULED);
524 * \brief Unschedules a task
526 * The task state must be #SD_SCHEDULED, #SD_READY, #SD_RUNNING or #SD_FAILED.
527 * If you call this function, the task state becomes #SD_NOT_SCHEDULED.
528 * Call SD_task_schedule() to schedule it again.
530 * \param task the task you want to unschedule
531 * \see SD_task_schedule()
533 void SD_task_unschedule(SD_task_t task) {
534 SD_CHECK_INIT_DONE();
535 xbt_assert0(task != NULL, "Invalid parameter");
537 if (task->state_set != sd_global->scheduled_task_set &&
538 task->state_set != sd_global->ready_task_set &&
539 task->state_set != sd_global->running_task_set &&
540 task->state_set != sd_global->failed_task_set)
541 THROW1(arg_error, 0, "Task %s: the state must be SD_SCHEDULED, SD_READY, SD_RUNNING or SD_FAILED",
542 SD_task_get_name(task));
544 if (__SD_task_is_scheduled_or_ready(task)) /* if the task is scheduled or ready */
545 __SD_task_destroy_scheduling_data(task);
547 if (__SD_task_is_running(task)) /* the task should become SD_FAILED */
548 surf_workstation_resource->common_public->action_cancel(task->surf_action);
550 __SD_task_set_state(task, SD_NOT_SCHEDULED);
551 task->remains = task->amount;
552 task->start_time = -1.0;
555 /* Destroys the data memorised by SD_task_schedule. Task state must be SD_SCHEDULED or SD_READY.
557 static void __SD_task_destroy_scheduling_data(SD_task_t task) {
558 SD_CHECK_INIT_DONE();
559 if (!__SD_task_is_scheduled_or_ready(task) && !__SD_task_is_in_fifo(task))
560 THROW1(arg_error, 0, "Task '%s' must be SD_SCHEDULED, SD_READY or SD_IN_FIFO", SD_task_get_name(task));
562 xbt_free(task->computation_amount);
563 xbt_free(task->communication_amount);
566 /* Runs a task. This function is directly called by __SD_task_try_to_run if the task
567 * doesn't have to wait in fifos. Otherwise, it is called by __SD_task_just_done when
568 * the task gets out of its fifos.
570 void __SD_task_really_run(SD_task_t task) {
571 SD_CHECK_INIT_DONE();
572 xbt_assert0(task != NULL, "Invalid parameter");
573 xbt_assert2(__SD_task_is_ready_or_in_fifo(task), "Task '%s' is not ready or in a fifo! Task state: %d",
574 SD_task_get_name(task), SD_task_get_state(task));
575 xbt_assert1(task->workstation_list != NULL, "Task '%s': workstation_list is NULL!", SD_task_get_name(task));
578 void **surf_workstations;
580 DEBUG1("Really running task '%s'", SD_task_get_name(task));
582 /* set this task as current task for the workstations in sequential mode */
583 for (i = 0; i < task->workstation_nb; i++) {
584 if (SD_workstation_get_access_mode(task->workstation_list[i]) == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
585 task->workstation_list[i]->current_task = task;
586 xbt_assert0(__SD_workstation_is_busy(task->workstation_list[i]), "The workstation should be busy now");
590 DEBUG1("Task '%s' set as current task for its workstations", SD_task_get_name(task));
594 /* we have to create a Surf workstation array instead of the SimDag workstation array */
595 surf_workstations = xbt_new0(void*, task->workstation_nb);
597 for (i = 0; i < task->workstation_nb; i++) {
598 surf_workstations[i] = task->workstation_list[i]->surf_workstation;
601 task->surf_action = surf_workstation_resource->extension_public->
602 execute_parallel_task(task->workstation_nb,
604 task->computation_amount,
605 task->communication_amount,
608 surf_workstation_resource->common_public->action_set_data(task->surf_action, task);
609 task->state_changed = 1;
611 DEBUG1("surf_action = %p", task->surf_action);
613 xbt_free(surf_workstations);
614 __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
615 __SD_task_set_state(task, SD_RUNNING);
616 xbt_assert2(__SD_task_is_running(task), "Bad state of task '%s': %d",
617 SD_task_get_name(task), SD_task_get_state(task));
621 /* Tries to run a task. This function is called by SD_simulate() when a scheduled task becomes SD_READY
622 * (ie when its dependencies are satisfied).
623 * If one of the workstations where the task is scheduled on is busy (in sequential mode),
624 * the task doesn't start.
625 * Returns whether the task has started.
627 int __SD_task_try_to_run(SD_task_t task) {
628 SD_CHECK_INIT_DONE();
629 xbt_assert0(task != NULL, "Invalid parameter");
630 xbt_assert2(__SD_task_is_ready(task), "Task '%s' is not ready! Task state: %d",
631 SD_task_get_name(task), SD_task_get_state(task));
635 SD_workstation_t workstation;
637 for (i = 0; i < task->workstation_nb; i++) {
638 can_start = !__SD_workstation_is_busy(task->workstation_list[i]);
641 DEBUG2("Task '%s' can start: %d", SD_task_get_name(task), can_start);
643 if (!can_start) { /* if the task cannot start and is not in the fifos yet*/
644 for (i = 0; i < task->workstation_nb; i++) {
645 workstation = task->workstation_list[i];
646 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
647 DEBUG2("Pushing task '%s' in the fifo of workstation '%s'", SD_task_get_name(task),
648 SD_workstation_get_name(workstation));
649 xbt_fifo_push(workstation->task_fifo, task);
652 __SD_task_set_state(task, SD_IN_FIFO);
653 xbt_assert2(__SD_task_is_in_fifo(task), "Bad state of task '%s': %d",
654 SD_task_get_name(task), SD_task_get_state(task));
655 DEBUG1("Task '%s' state is now SD_IN_FIFO", SD_task_get_name(task));
658 __SD_task_really_run(task);
664 /* This function is called by SD_simulate when a task is done.
665 * It updates task->state and task->action and executes if necessary the tasks
666 * which were waiting in fifos for the end of `task'
668 void __SD_task_just_done(SD_task_t task) {
669 SD_CHECK_INIT_DONE();
670 xbt_assert0(task != NULL, "Invalid parameter");
671 xbt_assert1(__SD_task_is_running(task), "The task must be running! Task state: %d", SD_task_get_state(task));
672 xbt_assert1(task->workstation_list != NULL, "Task '%s': workstation_list is NULL!", SD_task_get_name(task));
675 SD_workstation_t workstation;
678 int candidate_nb = 0;
679 int candidate_capacity = 8;
680 SD_task_t *candidates = xbt_new0(SD_task_t, 8);
683 __SD_task_set_state(task, SD_DONE);
684 surf_workstation_resource->common_public->action_free(task->surf_action);
685 task->surf_action = NULL;
687 DEBUG0("Looking for candidates");
689 /* if the task was executed on sequential workstations,
690 maybe we can execute the next task of the fifo for each workstation */
691 for (i = 0; i < task->workstation_nb; i++) {
692 workstation = task->workstation_list[i];
693 DEBUG2("Workstation '%s': access_mode = %d", SD_workstation_get_name(workstation), workstation->access_mode);
694 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
695 xbt_assert1(workstation->task_fifo != NULL, "Workstation '%s' has sequential access but no fifo!",
696 SD_workstation_get_name(workstation));
697 xbt_assert2(workstation->current_task = task, "Workstation '%s': current task should be '%s'",
698 SD_workstation_get_name(workstation), SD_task_get_name(task));
700 /* the task is over so we can release the workstation */
701 workstation->current_task = NULL;
703 DEBUG0("Getting candidate in fifo");
704 candidate = xbt_fifo_get_item_content(xbt_fifo_get_first_item(workstation->task_fifo));
706 if (candidate != NULL) {
707 DEBUG1("Candidate: '%s'", SD_task_get_name(candidate));
708 xbt_assert2(__SD_task_is_in_fifo(candidate), "Bad state of candidate '%s': %d",
709 SD_task_get_name(candidate), SD_task_get_state(candidate));
712 DEBUG1("Candidate in fifo: %p", candidate);
714 /* if there was a task waiting for my place */
715 if (candidate != NULL) {
716 /* Unfortunately, we are not sure yet that we can execute the task now,
717 because the task can be waiting more deeply in some other workstation's fifos...
718 So we memorize all candidate tasks, and then we will check for each candidate
719 whether or not all its workstations are available. */
721 /* realloc if necessary */
722 if (candidate_nb == candidate_capacity) {
723 candidate_capacity *= 2;
724 candidates = xbt_realloc(candidates, sizeof(SD_task_t) * candidate_capacity);
727 /* register the candidate */
728 candidates[candidate_nb++] = candidate;
729 candidate->fifo_checked = 0;
734 DEBUG1("Candidates found: %d", candidate_nb);
736 /* now we check every candidate task */
737 for (i = 0; i < candidate_nb; i++) {
738 candidate = candidates[i];
740 if (candidate->fifo_checked) {
741 continue; /* we have already evaluated that task*/
744 xbt_assert2(__SD_task_is_in_fifo(candidate), "Bad state of candidate '%s': %d",
745 SD_task_get_name(candidate), SD_task_get_state(candidate));
747 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
748 workstation = candidate->workstation_list[j];
750 /* I can start on this workstation if the workstation is shared
751 or if I am the first task in the fifo */
752 can_start = workstation->access_mode == SD_WORKSTATION_SHARED_ACCESS ||
753 candidate == xbt_fifo_get_item_content(xbt_fifo_get_first_item(workstation->task_fifo));
756 DEBUG2("Candidate '%s' can start: %d", SD_task_get_name(candidate), can_start);
758 /* now we are sure that I can start! */
760 for (j = 0; j < candidate->workstation_nb && can_start; j++) {
761 workstation = candidate->workstation_list[j];
763 /* update the fifo */
764 if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
765 candidate = xbt_fifo_shift(workstation->task_fifo); /* the return value is stored just for debugging */
766 DEBUG1("Head of the fifo: '%s'", (candidate != NULL) ? SD_task_get_name(candidate) : "NULL");
767 xbt_assert0(candidate == candidates[i], "Error in __SD_task_just_done: bad first task in the fifo");
769 } /* for each workstation */
771 /* finally execute the task */
772 DEBUG2("Task '%s' state: %d", SD_task_get_name(candidate), SD_task_get_state(candidate));
773 __SD_task_really_run(candidate);
775 DEBUG4("Calling __SD_task_is_running: task '%s', state set: %p, running_task_set: %p, is running: %d",
776 SD_task_get_name(candidate), candidate->state_set, sd_global->running_task_set, __SD_task_is_running(candidate));
777 xbt_assert2(__SD_task_is_running(candidate), "Bad state of task '%s': %d",
778 SD_task_get_name(candidate), SD_task_get_state(candidate));
779 DEBUG0("Okay, the task is running.");
782 candidate->fifo_checked = 1;
783 } /* for each candidate */
785 xbt_free(candidates);
788 /* Remove all dependencies associated with a task. This function is called when the task is destroyed.
790 static void __SD_task_remove_dependencies(SD_task_t task) {
791 /* we must destroy the dependencies carefuly (with SD_dependency_remove)
792 because each one is stored twice */
793 SD_dependency_t dependency;
794 while (xbt_dynar_length(task->tasks_before) > 0) {
795 xbt_dynar_get_cpy(task->tasks_before, 0, &dependency);
796 SD_task_dependency_remove(dependency->src, dependency->dst);
799 while (xbt_dynar_length(task->tasks_after) > 0) {
800 xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
801 SD_task_dependency_remove(dependency->src, dependency->dst);
806 * \brief Returns the start time of a task
808 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
810 * \param task: a task
811 * \return the start time of this task
813 double SD_task_get_start_time(SD_task_t task) {
814 SD_CHECK_INIT_DONE();
815 xbt_assert0(task != NULL, "Invalid parameter");
816 if(task->surf_action)
817 return surf_workstation_resource->common_public->action_get_start_time(task->surf_action);
819 return task->start_time;
823 * \brief Returns the finish time of a task
825 * The task state must be SD_RUNNING, SD_DONE or SD_FAILED.
826 * If the state is not completed yet, the returned value is an
827 * estimation of the task finish time. This value can fluctuate
828 * until the task is completed.
830 * \param task: a task
831 * \return the start time of this task
833 double SD_task_get_finish_time(SD_task_t task) {
834 SD_CHECK_INIT_DONE();
835 xbt_assert0(task != NULL, "Invalid parameter");
837 if(task->surf_action) /* should never happen as actions are destroyed right after their completion */
838 return surf_workstation_resource->common_public->action_get_finish_time(task->surf_action);
840 return task->finish_time;
844 * \brief Destroys a task.
846 * The user data (if any) should have been destroyed first.
848 * \param task the task you want to destroy
849 * \see SD_task_create()
851 void SD_task_destroy(SD_task_t task) {
852 SD_CHECK_INIT_DONE();
853 xbt_assert0(task != NULL, "Invalid parameter");
855 DEBUG1("Destroying task %s...", SD_task_get_name(task));
857 __SD_task_remove_dependencies(task);
859 /* if the task was scheduled or ready we have to free the scheduling parameters */
860 if (__SD_task_is_scheduled_or_ready(task))
861 __SD_task_destroy_scheduling_data(task);
863 if (task->name != NULL)
864 xbt_free(task->name);
866 if (task->surf_action != NULL)
867 surf_workstation_resource->common_public->action_free(task->surf_action);
869 if (task->workstation_list != NULL)
870 xbt_free(task->workstation_list);
872 xbt_dynar_free(&task->tasks_before);
873 xbt_dynar_free(&task->tasks_after);
876 sd_global->task_number--;
878 DEBUG0("Task destroyed.");