Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Add a sequential mode to the workstations. In this mode, only one task can be execute...
authorthiery <thiery@48e7efb5-ca39-0410-a469-dd3cf9ba447f>
Mon, 31 Jul 2006 09:40:31 +0000 (09:40 +0000)
committerthiery <thiery@48e7efb5-ca39-0410-a469-dd3cf9ba447f>
Mon, 31 Jul 2006 09:40:31 +0000 (09:40 +0000)
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/simgrid/simgrid/trunk@2652 48e7efb5-ca39-0410-a469-dd3cf9ba447f

examples/simdag/sd_test.c
include/simdag/datatypes.h
include/simdag/simdag.h
src/simdag/private.h
src/simdag/sd_global.c
src/simdag/sd_task.c
src/simdag/sd_workstation.c

index a54db33..b791034 100644 (file)
@@ -13,7 +13,7 @@ int main(int argc, char **argv) {
   /* initialisation of SD */
   SD_init(&argc, argv);
 
   /* initialisation of SD */
   SD_init(&argc, argv);
 
-  /* xbt_log_control_set("sd.thres=debug"); */
+  /*  xbt_log_control_set("sd.thres=debug");*/
 
   if (argc < 2) {
     INFO1("Usage: %s platform_file", argv[0]);
 
   if (argc < 2) {
     INFO1("Usage: %s platform_file", argv[0]);
@@ -29,6 +29,7 @@ int main(int argc, char **argv) {
   const SD_workstation_t *workstations = SD_workstation_get_list();
   SD_workstation_t w1 = workstations[0];
   SD_workstation_t w2 = workstations[1];
   const SD_workstation_t *workstations = SD_workstation_get_list();
   SD_workstation_t w1 = workstations[0];
   SD_workstation_t w2 = workstations[1];
+  SD_workstation_set_access_mode(w2, SD_WORKSTATION_SEQUENTIAL_ACCESS);
   const char *name1 = SD_workstation_get_name(w1);
   const char *name2 = SD_workstation_get_name(w2);
   const double computation_amount1 = 2000000;
   const char *name1 = SD_workstation_get_name(w1);
   const char *name2 = SD_workstation_get_name(w2);
   const double computation_amount1 = 2000000;
@@ -151,12 +152,6 @@ int main(int argc, char **argv) {
   SD_task_t *changed_tasks;
 
   changed_tasks = SD_simulate(-1.0);
   SD_task_t *changed_tasks;
 
   changed_tasks = SD_simulate(-1.0);
-  xbt_assert0(changed_tasks[0] == taskD &&
-             changed_tasks[1] == taskB &&
-             changed_tasks[2] == taskC &&
-             changed_tasks[3] == NULL,
-             "Unexpected simulation results");
-
   for (i = 0; changed_tasks[i] != NULL; i++) {
     INFO3("Task '%s' start time: %f, finish time: %f",
          SD_task_get_name(changed_tasks[i]),
   for (i = 0; changed_tasks[i] != NULL; i++) {
     INFO3("Task '%s' start time: %f, finish time: %f",
          SD_task_get_name(changed_tasks[i]),
@@ -164,6 +159,11 @@ int main(int argc, char **argv) {
          SD_task_get_finish_time(changed_tasks[i]));
   }
   
          SD_task_get_finish_time(changed_tasks[i]));
   }
   
+  xbt_assert0(changed_tasks[0] == taskD &&
+             changed_tasks[1] == taskB &&
+             changed_tasks[2] == NULL,
+             "Unexpected simulation results");
+
   xbt_free(changed_tasks);
 
   DEBUG0("Destroying tasks...");
   xbt_free(changed_tasks);
 
   DEBUG0("Destroying tasks...");
index 391f469..6613f54 100644 (file)
     @see SD_workstation_management */
 typedef struct SD_workstation *SD_workstation_t;
 
     @see SD_workstation_management */
 typedef struct SD_workstation *SD_workstation_t;
 
+/** @brief Workstation access mode
+    @ingroup SD_datatypes_management
+
+    By default, a workstation resource is shared, i.e. several tasks
+    can be executed at the same time on a workstation. The CPU power of
+    the workstation is shared between the running tasks on the workstation.
+    In sequential mode, only one task can use the workstation, and the other
+    tasks wait in a FIFO.
+
+    @see SD_workstation_get_access_mode(), SD_workstation_set_access_mode() */
+typedef enum {
+  SD_WORKSTATION_SHARED_ACCESS,     /**< @brief Several tasks can be executed at the same time */
+  SD_WORKSTATION_SEQUENTIAL_ACCESS  /**< @brief Only one task can be executed, the others wait in a FIFO. */
+} e_SD_workstation_access_mode_t;
+
 /** @brief Link datatype
     @ingroup SD_datatypes_management
 
 /** @brief Link datatype
     @ingroup SD_datatypes_management
 
@@ -41,10 +56,11 @@ typedef enum {
   SD_NOT_SCHEDULED = 0,      /**< @brief Initial state (not valid for SD_watch and SD_unwatch). */
   SD_SCHEDULED =     0x0001, /**< @brief A task becomes SD_SCHEDULED when you call function
                                SD_task_schedule. SD_simulate will execute it when it becomes SD_READY. */
   SD_NOT_SCHEDULED = 0,      /**< @brief Initial state (not valid for SD_watch and SD_unwatch). */
   SD_SCHEDULED =     0x0001, /**< @brief A task becomes SD_SCHEDULED when you call function
                                SD_task_schedule. SD_simulate will execute it when it becomes SD_READY. */
-  SD_READY =         0x0002, /**< @brief A scheduled task becomes ready as soon as its dependencies are satisfied. */
-  SD_RUNNING =       0x0004, /**< @brief When a task is ready, it is launched in the function SD_simulate and becomes SD_RUNNING. */
-  SD_DONE =          0x0008, /**< @brief The task is successfuly finished. */
-  SD_FAILED =        0x0010  /**< @brief A problem occured during the execution of the task. */
+  SD_READY =         0x0002, /**< @brief A scheduled task becomes ready is SD_simulate as soon as its dependencies are satisfied. */
+  SD_IN_FIFO =       0x0004, /**< @brief A ready task can have to wait in a workstation fifo if the workstation is sequential */
+  SD_RUNNING =       0x0008, /**< @brief An SD_READY or SD_IN_FIFO becomes SD_RUNNING when it is launched. */
+  SD_DONE =          0x0010, /**< @brief The task is successfuly finished. */
+  SD_FAILED =        0x0020  /**< @brief A problem occured during the execution of the task. */
 } e_SD_task_state_t;
 
 #endif
 } e_SD_task_state_t;
 
 #endif
index effb3eb..d4d1414 100644 (file)
@@ -55,6 +55,9 @@ SD_link_t*              SD_route_get_list(SD_workstation_t src, SD_workstation_t
 int                     SD_route_get_size(SD_workstation_t src, SD_workstation_t dst);
 double                  SD_workstation_get_power(SD_workstation_t workstation);
 double                  SD_workstation_get_available_power(SD_workstation_t workstation);
 int                     SD_route_get_size(SD_workstation_t src, SD_workstation_t dst);
 double                  SD_workstation_get_power(SD_workstation_t workstation);
 double                  SD_workstation_get_available_power(SD_workstation_t workstation);
+e_SD_workstation_access_mode_t SD_workstation_get_access_mode(SD_workstation_t workstation);
+void                    SD_workstation_set_access_mode(SD_workstation_t workstation,
+                                                      e_SD_workstation_access_mode_t access_mode);
 
 double    SD_workstation_get_computation_time(SD_workstation_t workstation, double computation_amount);
 double    SD_route_get_current_latency(SD_workstation_t src, SD_workstation_t dst);
 
 double    SD_workstation_get_computation_time(SD_workstation_t workstation, double computation_amount);
 double    SD_route_get_current_latency(SD_workstation_t src, SD_workstation_t dst);
index de4e653..35bcbc5 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "xbt/dict.h"
 #include "xbt/dynar.h"
 
 #include "xbt/dict.h"
 #include "xbt/dynar.h"
+#include "xbt/fifo.h"
 #include "simdag/simdag.h"
 #include "simdag/datatypes.h"
 #include "surf/surf.h"
 #include "simdag/simdag.h"
 #include "simdag/datatypes.h"
 #include "surf/surf.h"
@@ -29,6 +30,7 @@ typedef struct SD_global {
   xbt_swag_t not_scheduled_task_set;
   xbt_swag_t scheduled_task_set;
   xbt_swag_t ready_task_set;
   xbt_swag_t not_scheduled_task_set;
   xbt_swag_t scheduled_task_set;
   xbt_swag_t ready_task_set;
+  xbt_swag_t in_fifo_task_set;
   xbt_swag_t running_task_set;
   xbt_swag_t done_task_set;
   xbt_swag_t failed_task_set;
   xbt_swag_t running_task_set;
   xbt_swag_t done_task_set;
   xbt_swag_t failed_task_set;
@@ -47,6 +49,10 @@ typedef struct SD_link {
 typedef struct SD_workstation {
   void *surf_workstation; /* surf object */
   void *data; /* user data */
 typedef struct SD_workstation {
   void *surf_workstation; /* surf object */
   void *data; /* user data */
+  e_SD_workstation_access_mode_t access_mode;
+
+  xbt_fifo_t task_fifo; /* only used in sequential mode */
+  SD_task_t current_task; /* only used in sequential mode */
 } s_SD_workstation_t;
 
 /* Task */
 } s_SD_workstation_t;
 
 /* Task */
@@ -61,8 +67,11 @@ typedef struct SD_task {
   double finish_time;
   surf_action_t surf_action;
   unsigned short watch_points;
   double finish_time;
   surf_action_t surf_action;
   unsigned short watch_points;
+
   int state_changed; /* used only by SD_simulate, to make sure we put
                        the task only once in the returning array */
   int state_changed; /* used only by SD_simulate, to make sure we put
                        the task only once in the returning array */
+  int fifo_checked; /* used by SD_task_just_done to make sure we evaluate
+                      the task only once */
 
   /* dependencies */
   xbt_dynar_t tasks_before;
 
   /* dependencies */
   xbt_dynar_t tasks_before;
@@ -70,7 +79,7 @@ typedef struct SD_task {
 
   /* scheduling parameters (only exist in state SD_SCHEDULED) */
   int workstation_nb;
 
   /* scheduling parameters (only exist in state SD_SCHEDULED) */
   int workstation_nb;
-  void **workstation_list; /* surf workstations */
+  SD_workstation_t *workstation_list; /* surf workstations */
   double *computation_amount;
   double *communication_amount;
   double rate;
   double *computation_amount;
   double *communication_amount;
   double rate;
@@ -92,9 +101,12 @@ void __SD_link_destroy(void *link);
 
 SD_workstation_t __SD_workstation_create(void *surf_workstation, void *data);
 void __SD_workstation_destroy(void *workstation);
 
 SD_workstation_t __SD_workstation_create(void *surf_workstation, void *data);
 void __SD_workstation_destroy(void *workstation);
+int __SD_workstation_is_busy(SD_workstation_t workstation);
 
 void __SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state);
 
 void __SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state);
-surf_action_t __SD_task_run(SD_task_t task);
+void __SD_task_really_run(SD_task_t task);
+int __SD_task_try_to_run(SD_task_t task);
+void __SD_task_just_done(SD_task_t task);
 
 /* Functions to test if the task is in a given state.
    These functions are faster than using SD_task_get_state() */
 
 /* Functions to test if the task is in a given state.
    These functions are faster than using SD_task_get_state() */
@@ -120,6 +132,17 @@ static _XBT_INLINE int __SD_task_is_ready(SD_task_t task) {
   return task->state_set == sd_global->ready_task_set;
 }
 
   return task->state_set == sd_global->ready_task_set;
 }
 
+/* Returns whether the state of the given task is SD_IN_FIFO. */
+static _XBT_INLINE int __SD_task_is_in_fifo(SD_task_t task) {
+  return task->state_set == sd_global->in_fifo_task_set;
+}
+
+/* Returns whether the state of the given task is SD_READY or SD_IN_FIFO. */
+static _XBT_INLINE int __SD_task_is_ready_or_in_fifo(SD_task_t task) {
+  return task->state_set == sd_global->ready_task_set ||
+    task->state_set == sd_global->in_fifo_task_set;
+}
+
 /* Returns whether the state of the given task is SD_RUNNING. */
 static _XBT_INLINE int __SD_task_is_running(SD_task_t task) {
   return task->state_set == sd_global->running_task_set;
 /* Returns whether the state of the given task is SD_RUNNING. */
 static _XBT_INLINE int __SD_task_is_running(SD_task_t task) {
   return task->state_set == sd_global->running_task_set;
index c464c47..c6087f4 100644 (file)
@@ -37,6 +37,7 @@ void SD_init(int *argc, char **argv) {
   sd_global->not_scheduled_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
   sd_global->scheduled_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
   sd_global->ready_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
   sd_global->not_scheduled_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
   sd_global->scheduled_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
   sd_global->ready_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
+  sd_global->in_fifo_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
   sd_global->running_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
   sd_global->done_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
   sd_global->failed_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
   sd_global->running_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
   sd_global->done_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
   sd_global->failed_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
@@ -74,10 +75,12 @@ void SD_create_environment(const char *platform_file) {
 
   surf_timer_resource_init(platform_file);  /* tell Surf to create the environnement */
 
 
   surf_timer_resource_init(platform_file);  /* tell Surf to create the environnement */
 
+  DEBUG0("Calling surf_workstation_resource_init");
   surf_workstation_resource_init_KCCFLN05(platform_file);
   surf_workstation_resource_init_KCCFLN05(platform_file);
-/*   surf_workstation_resource_init_CLM03(platform_file); */
+  /*  surf_workstation_resource_init_CLM03(platform_file); */
 
   /* now let's create the SD wrappers for workstations and links */
 
   /* now let's create the SD wrappers for workstations and links */
+  DEBUG0("Creating SimDags hosts and links");
   xbt_dict_foreach(workstation_set, cursor, name, surf_workstation) {
     __SD_workstation_create(surf_workstation, NULL);
   }
   xbt_dict_foreach(workstation_set, cursor, name, surf_workstation) {
     __SD_workstation_create(surf_workstation, NULL);
   }
@@ -130,16 +133,14 @@ SD_task_t* SD_simulate(double how_long)
   /* explore the ready tasks */
   xbt_swag_foreach(task, sd_global->ready_task_set) {
     INFO1("Executing task '%s'", SD_task_get_name(task));
   /* explore the ready tasks */
   xbt_swag_foreach(task, sd_global->ready_task_set) {
     INFO1("Executing task '%s'", SD_task_get_name(task));
-    __SD_task_run(task);
-    surf_workstation_resource->common_public->action_set_data(task->surf_action, task);
-    task->state_changed = 1;
-    
-    changed_tasks[changed_task_number++] = task; /* replace NULL by the task */
-    if (changed_task_number == changed_task_capacity) {
-      changed_task_capacity *= 2;
-      changed_tasks = xbt_realloc(changed_tasks, sizeof(SD_task_t) * changed_task_capacity);
+    if ((task->state_changed = __SD_task_try_to_run(task))) {
+      changed_tasks[changed_task_number++] = task; /* replace NULL by the task */
+      if (changed_task_number == changed_task_capacity) {
+       changed_task_capacity *= 2;
+       changed_tasks = xbt_realloc(changed_tasks, sizeof(SD_task_t) * changed_task_capacity);
+      }
+      changed_tasks[changed_task_number] = NULL;
     }
     }
-    changed_tasks[changed_task_number] = NULL;
   }
 
   /* main loop */
   }
 
   /* main loop */
@@ -159,9 +160,9 @@ SD_task_t* SD_simulate(double how_long)
     while ((action = xbt_swag_extract(surf_workstation_resource->common_public->states.done_action_set))) {
       task = action->data;
       INFO1("Task '%s' done", SD_task_get_name(task));
     while ((action = xbt_swag_extract(surf_workstation_resource->common_public->states.done_action_set))) {
       task = action->data;
       INFO1("Task '%s' done", SD_task_get_name(task));
-      __SD_task_set_state(task, SD_DONE);
-      surf_workstation_resource->common_public->action_free(action);
-      task->surf_action = NULL;
+      DEBUG0("Calling __SD_task_just_done");
+      __SD_task_just_done(task);
+      INFO1("__SD_task_just_done called on task '%s'", SD_task_get_name(task));
 
       /* the state has changed */
       if (!task->state_changed) {
 
       /* the state has changed */
       if (!task->state_changed) {
@@ -183,16 +184,14 @@ SD_task_t* SD_simulate(double how_long)
        /* is dst ready now? */
        if (__SD_task_is_ready(dst) && !sd_global->watch_point_reached) {
          INFO1("Executing task '%s'", SD_task_get_name(dst));
        /* is dst ready now? */
        if (__SD_task_is_ready(dst) && !sd_global->watch_point_reached) {
          INFO1("Executing task '%s'", SD_task_get_name(dst));
-         dst->surf_action = __SD_task_run(dst);
-         surf_workstation_resource->common_public->action_set_data(dst->surf_action, dst);
-         dst->state_changed = 1;
-         
-         changed_tasks[changed_task_number++] = dst;
-         if (changed_task_number == changed_task_capacity) {
-           changed_task_capacity *= 2;
-           changed_tasks = xbt_realloc(changed_tasks, sizeof(SD_task_t) * changed_task_capacity);
+         if (__SD_task_try_to_run(dst)) {
+           changed_tasks[changed_task_number++] = dst;
+           if (changed_task_number == changed_task_capacity) {
+             changed_task_capacity *= 2;
+             changed_tasks = xbt_realloc(changed_tasks, sizeof(SD_task_t) * changed_task_capacity);
+           }
+           changed_tasks[changed_task_number] = NULL;
          }
          }
-         changed_tasks[changed_task_number] = NULL;
        }
       }
     }
        }
       }
     }
@@ -267,6 +266,7 @@ void SD_exit(void) {
     xbt_swag_free(sd_global->not_scheduled_task_set);
     xbt_swag_free(sd_global->scheduled_task_set);
     xbt_swag_free(sd_global->ready_task_set);
     xbt_swag_free(sd_global->not_scheduled_task_set);
     xbt_swag_free(sd_global->scheduled_task_set);
     xbt_swag_free(sd_global->ready_task_set);
+    xbt_swag_free(sd_global->in_fifo_task_set);
     xbt_swag_free(sd_global->running_task_set);
     xbt_swag_free(sd_global->done_task_set);
     xbt_swag_free(sd_global->failed_task_set);
     xbt_swag_free(sd_global->running_task_set);
     xbt_swag_free(sd_global->done_task_set);
     xbt_swag_free(sd_global->failed_task_set);
index 237483a..cfc066d 100644 (file)
@@ -104,6 +104,8 @@ e_SD_task_state_t SD_task_get_state(SD_task_t task) {
     return SD_RUNNING;
   if (task->state_set == sd_global->ready_task_set)
     return SD_READY;
     return SD_RUNNING;
   if (task->state_set == sd_global->ready_task_set)
     return SD_READY;
+  if (task->state_set == sd_global->in_fifo_task_set)
+    return SD_IN_FIFO;
   if (task->state_set == sd_global->not_scheduled_task_set)
     return SD_NOT_SCHEDULED;
   return SD_FAILED;
   if (task->state_set == sd_global->not_scheduled_task_set)
     return SD_NOT_SCHEDULED;
   return SD_FAILED;
@@ -123,6 +125,9 @@ void __SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state) {
   case SD_READY:
     task->state_set = sd_global->ready_task_set;
     break;
   case SD_READY:
     task->state_set = sd_global->ready_task_set;
     break;
+  case SD_IN_FIFO:
+    task->state_set = sd_global->in_fifo_task_set;
+    break;
   case SD_RUNNING:
     task->state_set = sd_global->running_task_set;
     task->start_time = surf_workstation_resource->common_public->
   case SD_RUNNING:
     task->state_set = sd_global->running_task_set;
     task->start_time = surf_workstation_resource->common_public->
@@ -503,12 +508,8 @@ void SD_task_schedule(SD_task_t task, int workstation_nb,
   task->communication_amount = xbt_new0(double, communication_nb);
   memcpy(task->communication_amount, communication_amount, sizeof(double) * communication_nb);
 
   task->communication_amount = xbt_new0(double, communication_nb);
   memcpy(task->communication_amount, communication_amount, sizeof(double) * communication_nb);
 
-  /* we have to create a Surf workstation array instead of the SimDag workstation array */
-  task->workstation_list = xbt_new0(void*, workstation_nb);
-  int i;
-  for (i = 0; i < workstation_nb; i++) {
-    task->workstation_list[i] = workstation_list[i]->surf_workstation;
-  }
+  task->workstation_list = xbt_new0(SD_workstation_t, workstation_nb);
+  memcpy(task->workstation_list, workstation_list, sizeof(SD_workstation_t) * workstation_nb);
 
   /* update the task state */
   if (xbt_dynar_length(task->tasks_before) == 0)
 
   /* update the task state */
   if (xbt_dynar_length(task->tasks_before) == 0)
@@ -553,40 +554,235 @@ void SD_task_unschedule(SD_task_t task) {
  */
 static void __SD_task_destroy_scheduling_data(SD_task_t task) {
   SD_CHECK_INIT_DONE();
  */
 static void __SD_task_destroy_scheduling_data(SD_task_t task) {
   SD_CHECK_INIT_DONE();
-  if (!__SD_task_is_scheduled_or_ready(task))
-    THROW1(arg_error, 0, "Task '%s' must be SD_SCHEDULED or SD_READY", SD_task_get_name(task));
+  if (!__SD_task_is_scheduled_or_ready(task) && !__SD_task_is_in_fifo(task))
+    THROW1(arg_error, 0, "Task '%s' must be SD_SCHEDULED, SD_READY or SD_IN_FIFO", SD_task_get_name(task));
 
 
-  xbt_free(task->workstation_list);
   xbt_free(task->computation_amount);
   xbt_free(task->communication_amount);
 }
 
   xbt_free(task->computation_amount);
   xbt_free(task->communication_amount);
 }
 
-/* Runs a task. This function is called by SD_simulate() when a scheduled task can start
- * (ie when its dependencies are satisfied).
+/* Runs a task. This function is directly called by __SD_task_try_to_run if the task
+ * doesn't have to wait in fifos. Otherwise, it is called by __SD_task_just_done when
+ * the task gets out of its fifos.
  */
  */
-surf_action_t __SD_task_run(SD_task_t task) {
+void __SD_task_really_run(SD_task_t task) {
   SD_CHECK_INIT_DONE();
   xbt_assert0(task != NULL, "Invalid parameter");
   SD_CHECK_INIT_DONE();
   xbt_assert0(task != NULL, "Invalid parameter");
-
-  if (!__SD_task_is_ready(task))
-    THROW2(arg_error, 0, "Task '%s' is not ready! Task state: %d",
+  xbt_assert2(__SD_task_is_ready_or_in_fifo(task), "Task '%s' is not ready or in a fifo! Task state: %d",
           SD_task_get_name(task), SD_task_get_state(task));
           SD_task_get_name(task), SD_task_get_state(task));
+  xbt_assert1(task->workstation_list != NULL, "Task '%s': workstation_list is NULL!", SD_task_get_name(task));
+
+  int i;
+  void **surf_workstations;
+
+  DEBUG1("Really running task '%s'", SD_task_get_name(task));
+
+  /* set this task as current task for the workstations in sequential mode */
+  for (i = 0; i < task->workstation_nb; i++) {
+    if (SD_workstation_get_access_mode(task->workstation_list[i]) == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
+      task->workstation_list[i]->current_task = task;
+      xbt_assert0(__SD_workstation_is_busy(task->workstation_list[i]), "The workstation should be busy now");
+    }
+  }
+  
+  DEBUG1("Task '%s' set as current task for its workstations", SD_task_get_name(task));
 
 
+  /* start the task */
+
+  /* we have to create a Surf workstation array instead of the SimDag workstation array */
+  surf_workstations = xbt_new0(void*, task->workstation_nb);
+
+  for (i = 0; i < task->workstation_nb; i++) {
+    surf_workstations[i] = task->workstation_list[i]->surf_workstation;
+  }
+  
   task->surf_action = surf_workstation_resource->extension_public->
     execute_parallel_task(task->workstation_nb,
   task->surf_action = surf_workstation_resource->extension_public->
     execute_parallel_task(task->workstation_nb,
-                         task->workstation_list,
+                         surf_workstations,
                          task->computation_amount,
                          task->communication_amount,
                          task->amount,
                          task->rate);
                          task->computation_amount,
                          task->communication_amount,
                          task->amount,
                          task->rate);
+  surf_workstation_resource->common_public->action_set_data(task->surf_action, task);
+  task->state_changed = 1;
 
   DEBUG1("surf_action = %p",  task->surf_action);
 
 
   DEBUG1("surf_action = %p",  task->surf_action);
 
+  xbt_free(surf_workstations);
   __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
   __SD_task_set_state(task, SD_RUNNING);
   __SD_task_destroy_scheduling_data(task); /* now the scheduling data are not useful anymore */
   __SD_task_set_state(task, SD_RUNNING);
+  xbt_assert2(__SD_task_is_running(task), "Bad state of task '%s': %d",
+             SD_task_get_name(task), SD_task_get_state(task));
 
 
-  return task->surf_action;
 }
 }
+
+/* Tries to run a task. This function is called by SD_simulate() when a scheduled task becomes SD_READY
+ * (ie when its dependencies are satisfied).
+ * If one of the workstations where the task is scheduled on is busy (in sequential mode),
+ * the task doesn't start.
+ * Returns whether the task has started.
+ */
+int __SD_task_try_to_run(SD_task_t task) {
+  SD_CHECK_INIT_DONE();
+  xbt_assert0(task != NULL, "Invalid parameter");
+  xbt_assert2(__SD_task_is_ready(task), "Task '%s' is not ready! Task state: %d",
+          SD_task_get_name(task), SD_task_get_state(task));
+
+  int can_start = 1;
+  int i;
+  SD_workstation_t workstation;
+
+  for (i = 0; i < task->workstation_nb; i++) {
+    can_start = !__SD_workstation_is_busy(task->workstation_list[i]);
+  }
+
+  DEBUG2("Task '%s' can start: %d", SD_task_get_name(task), can_start);
+  
+  if (!can_start) { /* if the task cannot start and is not in the fifos yet*/
+    for (i = 0; i < task->workstation_nb; i++) {
+      workstation = task->workstation_list[i];
+      if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
+       DEBUG2("Pushing task '%s' in the fifo of workstation '%s'", SD_task_get_name(task),
+              SD_workstation_get_name(workstation));
+       xbt_fifo_push(workstation->task_fifo, task);
+      }
+    }
+    __SD_task_set_state(task, SD_IN_FIFO);
+    xbt_assert2(__SD_task_is_in_fifo(task), "Bad state of task '%s': %d",
+               SD_task_get_name(task), SD_task_get_state(task));
+    DEBUG1("Task '%s' state is now SD_IN_FIFO", SD_task_get_name(task));
+  }
+  else {
+    __SD_task_really_run(task);
+  }
+
+  return can_start;
+}
+
+/* This function is called by SD_simulate when a task is done.
+ * It updates task->state and task->action and executes if necessary the tasks
+ * which were waiting in fifos for the end of `task'
+ */
+void __SD_task_just_done(SD_task_t task) {
+  SD_CHECK_INIT_DONE();
+  xbt_assert0(task != NULL, "Invalid parameter");
+  xbt_assert1(__SD_task_is_running(task), "The task must be running! Task state: %d", SD_task_get_state(task));
+  xbt_assert1(task->workstation_list != NULL, "Task '%s': workstation_list is NULL!", SD_task_get_name(task));
+
+  int i, j;
+  SD_workstation_t workstation;
+
+  SD_task_t candidate;
+  int candidate_nb = 0;
+  int candidate_capacity = 8;
+  SD_task_t *candidates = xbt_new0(SD_task_t, 8);
+  int can_start = 1;
+
+  __SD_task_set_state(task, SD_DONE);
+  surf_workstation_resource->common_public->action_free(task->surf_action);
+  task->surf_action = NULL;
+
+  DEBUG0("Looking for candidates");
+
+  /* if the task was executed on sequential workstations,
+     maybe we can execute the next task of the fifo for each workstation */
+  for (i = 0; i < task->workstation_nb; i++) {
+    workstation = task->workstation_list[i];
+    DEBUG2("Workstation '%s': access_mode = %d", SD_workstation_get_name(workstation), workstation->access_mode);
+    if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
+      xbt_assert1(workstation->task_fifo != NULL, "Workstation '%s' has sequential access but no fifo!",
+                 SD_workstation_get_name(workstation));
+      xbt_assert2(workstation->current_task = task, "Workstation '%s': current task should be '%s'",
+                 SD_workstation_get_name(workstation), SD_task_get_name(task));
+
+      /* the task is over so we can release the workstation */
+      workstation->current_task = NULL;
+
+      DEBUG0("Getting candidate in fifo");
+      candidate = xbt_fifo_get_item_content(xbt_fifo_get_first_item(workstation->task_fifo));
+
+      if (candidate != NULL) {
+       DEBUG1("Candidate: '%s'", SD_task_get_name(candidate));
+       xbt_assert2(__SD_task_is_in_fifo(candidate), "Bad state of candidate '%s': %d",
+                   SD_task_get_name(candidate), SD_task_get_state(candidate));
+      }
+
+      DEBUG1("Candidate in fifo: %p", candidate);
+
+      /* if there was a task waiting for my place */
+      if (candidate != NULL) {
+       /* Unfortunately, we are not sure yet that we can execute the task now,
+          because the task can be waiting more deeply in some other workstation's fifos...
+          So we memorize all candidate tasks, and then we will check for each candidate
+          whether or not all its workstations are available. */
+
+       /* realloc if necessary */
+       if (candidate_nb == candidate_capacity) {
+         candidate_capacity *= 2;
+         candidates = xbt_realloc(candidates, sizeof(SD_task_t) * candidate_capacity);
+       }
+
+       /* register the candidate */
+       candidates[candidate_nb++] = candidate;
+       candidate->fifo_checked = 0;
+      }
+    }
+  }
+
+  DEBUG1("Candidates found: %d", candidate_nb);
+
+  /* now we check every candidate task */
+  for (i = 0; i < candidate_nb; i++) {
+    candidate = candidates[i];
+
+    if (candidate->fifo_checked) {
+      continue; /* we have already evaluated that task*/
+    }
+
+    xbt_assert2(__SD_task_is_in_fifo(candidate), "Bad state of candidate '%s': %d",
+               SD_task_get_name(candidate), SD_task_get_state(candidate));
+
+    for (j = 0; j < candidate->workstation_nb && can_start; j++) {
+      workstation = candidate->workstation_list[j];
+
+      /* I can start on this workstation if the workstation is shared
+        or if I am the first task in the fifo */
+      can_start = workstation->access_mode == SD_WORKSTATION_SHARED_ACCESS ||
+       candidate == xbt_fifo_get_item_content(xbt_fifo_get_first_item(workstation->task_fifo));
+    }
+
+    DEBUG2("Candidate '%s' can start: %d", SD_task_get_name(candidate), can_start);
+
+    /* now we are sure that I can start! */
+    if (can_start) {
+      for (j = 0; j < candidate->workstation_nb && can_start; j++) {
+       workstation = candidate->workstation_list[j];
+
+       /* update the fifo */
+       if (workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
+         candidate = xbt_fifo_shift(workstation->task_fifo); /* the return value is stored just for debugging */
+         DEBUG1("Head of the fifo: '%s'", (candidate != NULL) ? SD_task_get_name(candidate) : "NULL");
+         xbt_assert0(candidate == candidates[i], "Error in __SD_task_just_done: bad first task in the fifo");
+       }
+      } /* for each workstation */
+      
+      /* finally execute the task */
+      DEBUG2("Task '%s' state: %d", SD_task_get_name(candidate), SD_task_get_state(candidate));
+      __SD_task_really_run(candidate);
+      
+      DEBUG4("Calling __SD_task_is_running: task '%s', state set: %p, running_task_set: %p, is running: %d",
+            SD_task_get_name(candidate), candidate->state_set, sd_global->running_task_set, __SD_task_is_running(candidate));
+      xbt_assert2(__SD_task_is_running(candidate), "Bad state of task '%s': %d",
+                 SD_task_get_name(candidate), SD_task_get_state(candidate));
+      DEBUG0("Okay, the task is running.");
+
+    } /* can start */
+    candidate->fifo_checked = 1;
+  } /* for each candidate */ 
+  
+  xbt_free(candidates);
+}
+
 /* Remove all dependencies associated with a task. This function is called when the task is destroyed.
  */
 static void __SD_task_remove_dependencies(SD_task_t task) {
 /* Remove all dependencies associated with a task. This function is called when the task is destroyed.
  */
 static void __SD_task_remove_dependencies(SD_task_t task) {
@@ -668,6 +864,9 @@ void SD_task_destroy(SD_task_t task) {
   if (task->surf_action != NULL)
     surf_workstation_resource->common_public->action_free(task->surf_action);
 
   if (task->surf_action != NULL)
     surf_workstation_resource->common_public->action_free(task->surf_action);
 
+  if (task->workstation_list != NULL)
+    xbt_free(task->workstation_list);
+
   xbt_dynar_free(&task->tasks_before);
   xbt_dynar_free(&task->tasks_after);
   xbt_free(task);
   xbt_dynar_free(&task->tasks_before);
   xbt_dynar_free(&task->tasks_after);
   xbt_free(task);
index 84a2a0e..a66d29f 100644 (file)
@@ -13,6 +13,8 @@ SD_workstation_t __SD_workstation_create(void *surf_workstation, void *data) {
   SD_workstation_t workstation = xbt_new0(s_SD_workstation_t, 1);
   workstation->surf_workstation = surf_workstation;
   workstation->data = data; /* user data */
   SD_workstation_t workstation = xbt_new0(s_SD_workstation_t, 1);
   workstation->surf_workstation = surf_workstation;
   workstation->data = data; /* user data */
+  SD_workstation_set_access_mode(workstation, SD_WORKSTATION_SHARED_ACCESS); /* default mode is shared */
+  workstation->task_fifo = NULL;
   
   const char *name = SD_workstation_get_name(workstation);
   xbt_dict_set(sd_global->workstations, name, workstation, __SD_workstation_destroy); /* add the workstation to the dictionary */
   
   const char *name = SD_workstation_get_name(workstation);
   xbt_dict_set(sd_global->workstations, name, workstation, __SD_workstation_destroy); /* add the workstation to the dictionary */
@@ -45,7 +47,7 @@ SD_workstation_t SD_workstation_get_by_name(const char *name) {
  * \return an array of \ref SD_workstation_t containing all workstations
  * \see SD_workstation_get_number()
  */
  * \return an array of \ref SD_workstation_t containing all workstations
  * \see SD_workstation_get_number()
  */
-const SD_workstation_t*  SD_workstation_get_list(void) {
+const SD_workstation_t* SD_workstation_get_list(void) {
   SD_CHECK_INIT_DONE();
   xbt_assert0(SD_workstation_get_number() > 0, "There is no workstation!");
 
   SD_CHECK_INIT_DONE();
   xbt_assert0(SD_workstation_get_number() > 0, "There is no workstation!");
 
@@ -296,11 +298,88 @@ double SD_route_get_communication_time(SD_workstation_t src, SD_workstation_t ds
   return latency + (communication_amount / min_bandwidth);
 }
 
   return latency + (communication_amount / min_bandwidth);
 }
 
+/**
+ * \brief Returns the access mode of this workstation.
+ *
+ * \param workstation a workstation
+ * \return the access mode for the tasks running on this workstation:
+ * SD_WORKSTATION_SHARED_ACCESS or SD_WORKSTATION_SEQUENTIAL_ACCESS
+ *
+ * \see SD_workstation_set_access_mode(), e_SD_workstation_access_mode_t
+ */
+ e_SD_workstation_access_mode_t SD_workstation_get_access_mode(SD_workstation_t workstation) {
+  SD_CHECK_INIT_DONE();
+  xbt_assert0(workstation != NULL, "Invalid parameter");
+  return workstation->access_mode;
+}
+
+/**
+ * \brief Sets the access mode for the tasks that will be executed on a workstation
+ *
+ * By default, a workstation resource is shared, i.e. several tasks
+ * can be executed at the same time on a workstation. The CPU power of
+ * the workstation is shared between the running tasks on the workstation.
+ * In sequential mode, only one task can use the workstation, and the other
+ * tasks wait in a FIFO.
+ *
+ * \param workstation a workstation
+ * \param access_mode the access mode you want to set to this workstation:
+ * SD_WORKSTATION_SHARED_ACCESS or SD_WORKSTATION_SEQUENTIAL_ACCESS
+ *
+ * \see SD_workstation_get_access_mode(), e_SD_workstation_access_mode_t
+ */
+void SD_workstation_set_access_mode(SD_workstation_t workstation, e_SD_workstation_access_mode_t access_mode) {
+  SD_CHECK_INIT_DONE();
+  xbt_assert0(workstation != NULL, "Invalid parameter");
+
+  if (access_mode == workstation->access_mode) {
+    return; // nothing is changed
+  }
+
+  workstation->access_mode = access_mode;
+
+  if (access_mode == SD_WORKSTATION_SHARED_ACCESS) {
+    xbt_fifo_free(workstation->task_fifo);
+    workstation->task_fifo = NULL;
+  }
+  else {
+    workstation->task_fifo = xbt_fifo_new();
+  }
+}
+
+/* Returns whether a task can start now on a workstation.
+ *//*
+int __SD_workstation_can_start(SD_workstation_t workstation, SD_task_t task) {
+  SD_CHECK_INIT_DONE();
+  xbt_assert0(workstation != NULL && task != NULL, "Invalid parameter");
+
+  return !__SD_workstation_is_busy(workstation) &&
+    (xbt_fifo_size(workstation->task_fifo) == 0) || xbt_fifo_get_first_item(workstation->task_fifo) == task);
+}
+*/
+
+/* Returns whether a workstation is busy. A workstation is busy is it is
+ * in sequential mode and a task is running on it or the fifo is not empty.
+ */
+int __SD_workstation_is_busy(SD_workstation_t workstation) {
+  SD_CHECK_INIT_DONE();
+  xbt_assert0(workstation != NULL, "Invalid parameter");
+  
+  return workstation->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS &&
+    (workstation->current_task != NULL || xbt_fifo_size(workstation->task_fifo) > 0);
+}
+
 /* Destroys a workstation.
  */
 void __SD_workstation_destroy(void *workstation) {
   SD_CHECK_INIT_DONE();
   xbt_assert0(workstation != NULL, "Invalid parameter");
   /* workstation->surf_workstation is freed by surf_exit and workstation->data is freed by the user */
 /* Destroys a workstation.
  */
 void __SD_workstation_destroy(void *workstation) {
   SD_CHECK_INIT_DONE();
   xbt_assert0(workstation != NULL, "Invalid parameter");
   /* workstation->surf_workstation is freed by surf_exit and workstation->data is freed by the user */
-  xbt_free(workstation);
+
+  SD_workstation_t w = (SD_workstation_t) workstation;
+
+  if (w->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
+    xbt_fifo_free(w->task_fifo);
+  }
+  xbt_free(w);
 }
 }