Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Lua: copy the Lua task right after the C task using an MSG callback
[simgrid.git] / src / bindings / lua / simgrid_lua.c
index acd4e49..b2d541a 100644 (file)
@@ -77,6 +77,7 @@ static m_task_t sglua_checktask(lua_State* L, int index)
  * the same metatable. For the regular table, the metatable allows OO-style
  * writing such as your_task:send(someone).
  * For the userdata, the metatable is used to check its type.
+ * TODO: make the task name an optional last parameter
  */
 static int l_task_new(lua_State* L)
 {
@@ -162,12 +163,8 @@ static int l_task_execute(lua_State* L)
 }
 
 /**
- * \brief Pops the Lua task on top of the stack and registers it so that a
- * receiver can retrieve it later knowing the C task.
- *
- * After calling this function, you can send the C task to someone and he
- * will be able to also get the corresponding Lua task.
- *
+ * \brief Pops the Lua task from the stack and registers it so that the
+ * process can retrieve it later knowing the C task.
  * \param L a lua state
  */
 static void task_register(lua_State* L) {
@@ -201,18 +198,19 @@ static void task_unregister(lua_State* L, m_task_t task) {
 }
 
 /**
- * \brief When a C task has been received, retrieves the corresponding Lua
- * task from the sender and pushes it onto the receiver's stack.
+ * \brief This function is called when a C task has just been copied.
  *
- * This function should be called from the receiver process.
+ * This callback is used to copy the corresponding Lua task.
  *
- * \param dst the receiver
- * \param task the task just received
+ * \param task the task copied
+ * \param src_process the sender
+ * \param dst_process the receiver
  */
-static void task_copy(lua_State* dst, m_task_t task) {
+static void task_copy_callback(m_task_t task, m_process_t src_process,
+    m_process_t dst_process) {
 
-  m_process_t src_proc = MSG_task_get_sender(task);
-  lua_State* src = MSG_process_get_data(src_proc);
+  lua_State* src = MSG_process_get_data(src_process);
+  lua_State* dst = MSG_process_get_data(dst_process);
 
                                   /* src: ...
                                      dst: ... */
@@ -221,10 +219,10 @@ static void task_copy(lua_State* dst, m_task_t task) {
   sglua_copy_value(src, dst);
                                   /* src: ... task
                                      dst: ... task */
+  task_register(dst);             /* dst: ... */
 
-  /* the receiver is the owner of the task and may destroy it:
-   * make the C task NULL on the sender side so that it doesn't garbage
-   * collect it */
+  /* the receiver is now the owner of the task and may destroy it:
+   * make the sender forget the C task so that it doesn't garbage */
   lua_getfield(src, -1, "__simgrid_task");
                                   /* src: ... task ctask */
   m_task_t* udata = (m_task_t*) luaL_checkudata(src, -1, TASK_MODULE_NAME);
@@ -241,15 +239,15 @@ static void task_copy(lua_State* dst, m_task_t task) {
  * - Argument 1 (task): the task to send
  * - Argument 2 (string or compatible): mailbox name, as a real string or any
  * type convertible to string (numbers always are)
- * - Return values (nil or string): nil if the communication was successful,
- * or an error string in case of failure, which may be "timeout",
+ * - Return values (boolean + string): true if the communication was successful,
+ * or false plus an error string in case of failure, which may be "timeout",
  * "host failure" or "transfer failure"
  */
 static int l_task_send(lua_State* L)
 {
   m_task_t task = sglua_checktask(L, 1);
   const char* mailbox = luaL_checkstring(L, 2);
-                                  /* task mailbox */
+                                  /* task mailbox ... */
   lua_settop(L, 1);
                                   /* task */
   task_register(L);
@@ -257,27 +255,81 @@ static int l_task_send(lua_State* L)
   MSG_error_t res = MSG_task_send(task, mailbox);
 
   if (res == MSG_OK) {
-    return 0;
+    lua_pushboolean(L, 1);
+                                  /* true */
+    return 1;
   }
   else {
     /* the communication has failed, I'm still the owner of the task */
     task_unregister(L, task);
                                   /* task */
+    lua_pushboolean(L, 0);
+                                  /* task false */
     lua_pushstring(L, msg_errors[res]);
-                                  /* task error */
-    return 1;
+                                  /* task false error */
+    return 2;
   }
 }
 
+/**
+ * \brief Sends a task on a mailbox.
+ * \param L a Lua state
+ * \return number of values returned to Lua
+ *
+ * This is a non-blocking function: use simgrid.comm.wait() or
+ * simgrid.comm.test() to end the communication.
+ *
+ * - Argument 1 (task): the task to send
+ * - Argument 2 (string or compatible): mailbox name, as a real string or any
+ * type convertible to string (numbers always are)
+ * - Return value (comm): a communication object to be used later with wait or test
+ */
 static int l_task_isend(lua_State* L)
 {
-  // TODO
-  return 0;
+  m_task_t task = sglua_checktask(L, 1);
+  const char* mailbox = luaL_checkstring(L, 2);
+                                  /* task mailbox ... */
+  lua_settop(L, 1);
+                                  /* task */
+  task_register(L);
+                                  /* -- */
+  msg_comm_t comm = MSG_task_isend(task, mailbox);
+
+  msg_comm_t* userdata = (msg_comm_t*) lua_newuserdata(L, sizeof(msg_comm_t));
+                                  /* comm */
+  *userdata = comm;
+  luaL_getmetatable(L, COMM_MODULE_NAME);
+                                  /* comm mt */
+  lua_setmetatable(L, -2);
+                                  /* comm */
+  return 1;
 }
 
+/**
+ * \brief Sends a task on a mailbox on a best effort way (detached send).
+ * \param L a Lua state
+ * \return number of values returned to Lua
+ *
+ * Like simgrid.task.isend, this is a non-blocking function.
+ * You can use this function if you don't care about when the communication
+ * ends and whether it succeeds.
+ * FIXME: isn't this equivalent to calling simgrid.task.isend() and ignoring
+ * the result?
+ *
+ * - Argument 1 (task): the task to send
+ * - Argument 2 (string or compatible): mailbox name, as a real string or any
+ * type convertible to string (numbers always are)
+ */
 static int l_task_dsend(lua_State* L)
 {
-  // TODO
+  m_task_t task = sglua_checktask(L, 1);
+  const char* mailbox = luaL_checkstring(L, 2);
+                                  /* task mailbox ... */
+  lua_settop(L, 1);
+                                  /* task */
+  task_register(L);
+                                  /* -- */
+  MSG_task_dsend(task, mailbox, NULL);
   return 0;
 }
 
@@ -298,7 +350,7 @@ static int l_task_recv(lua_State* L)
   const char* mailbox = luaL_checkstring(L, 1);
   int timeout;
   if (lua_gettop(L) >= 2) {
-                                  /* mailbox timeout */
+                                  /* mailbox timeout ... */
     timeout = luaL_checknumber(L, 2);
   }
   else {
@@ -306,11 +358,11 @@ static int l_task_recv(lua_State* L)
     timeout = -1;
     /* no timeout by default */
   }
-                                  /* mailbox ... -- */
+                                  /* mailbox ... */
   MSG_error_t res = MSG_task_receive_with_timeout(&task, mailbox, timeout);
 
   if (res == MSG_OK) {
-    task_copy(L, task);
+    task_unregister(L, task);
                                   /* mailbox ... task */
     return 1;
   }
@@ -323,10 +375,35 @@ static int l_task_recv(lua_State* L)
   }
 }
 
+/**
+ * \brief Asynchronously receives a task on a mailbox.
+ * \param L a Lua state
+ * \return number of values returned to Lua
+ *
+ * This is a non-blocking function: use simgrid.comm.wait() or
+ * simgrid.comm.test() to end the communication and get the task in case of
+ * success.
+ *
+ * - Argument 1 (string or compatible): mailbox name, as a real string or any
+ * type convertible to string (numbers always are)
+ * - Return value (comm): a communication object to be used later with wait or test
+ */
+
 static int l_task_irecv(lua_State* L)
 {
-  // TODO
-  return 0;
+  const char* mailbox = luaL_checkstring(L, 1);
+                                  /* mailbox ... */
+  m_task_t* task = xbt_new0(m_task_t, 1); // FIXME fix this leak
+  msg_comm_t comm = MSG_task_irecv(task, mailbox);
+
+  msg_comm_t* userdata = (msg_comm_t*) lua_newuserdata(L, sizeof(msg_comm_t));
+                                  /* mailbox ... comm */
+  *userdata = comm;
+  luaL_getmetatable(L, COMM_MODULE_NAME);
+                                  /* mailbox ... comm mt */
+  lua_setmetatable(L, -2);
+                                  /* mailbox ... comm */
+  return 1;
 }
 
 static const luaL_reg task_functions[] = {
@@ -398,7 +475,6 @@ static const luaL_reg task_meta[] = {
 static msg_comm_t sglua_checkcomm(lua_State* L, int index)
 {
   msg_comm_t comm = *((msg_comm_t*) luaL_checkudata(L, index, COMM_MODULE_NAME));
-  lua_pop(L, 1);
   return comm;
 }
 
@@ -430,8 +506,8 @@ static int l_comm_wait(lua_State* L) {
       return 0;
     }
     else {
-      /* I'm the receiver: copy the Lua task from the sender */
-      task_copy(L, task);
+      /* I'm the receiver: find the Lua task from the C task */
+      task_unregister(L, task);
                                   /* comm ... task */
       return 1;
     }
@@ -452,44 +528,48 @@ static int l_comm_wait(lua_State* L) {
  * Unlike wait(), This function always returns immediately.
  *
  * - Argument 1 (comm): a comm (previously created by isend or irecv)
- * - Return value 1 (boolean): indicates whether the comm is finished
- * (note that a finished comm may have failed)
- * - Return value 2 (task): if you are the receiver, returns the task received
- * in case of success, or nil if the comm has failed
- * - Return value 3 (string): if the comm has failed, returns an error string
+ * - Return values (task/boolean or nil + string): if the communication is not
+ * finished, return false. If the communication is finished and was successful,
+ * returns the task received if you are the receiver or true if you are the
+ * sender. If the communication is finished and has failed, returns nil
+ * plus an error string.
  */
 static int l_comm_test(lua_State* L) {
 
   msg_comm_t comm = sglua_checkcomm(L, 1);
                                   /* comm ... */
   if (!MSG_comm_test(comm)) {
-    return 0;
+    /* not finished yet */
+    lua_pushboolean(L, 0);
+                                  /* comm ... false */
+    return 1;
   }
   else {
+    /* finished but may have failed */
     MSG_error_t res = MSG_comm_get_status(comm);
 
     if (res == MSG_OK) {
-      lua_pushboolean(L, 1);
-                                  /* comm ... true */
       m_task_t task = MSG_comm_get_task(comm);
       if (MSG_task_get_sender(task) == MSG_process_self()) {
         /* I'm the sender */
+        lua_pushboolean(L, 1);
+                                  /* comm ... true */
         return 1;
       }
       else {
-        /* I'm the receiver: copy the Lua task from the sender */
-        task_copy(L, task);
-                                    /* comm ... true task */
-        return 2;
+        /* I'm the receiver: find the Lua task from the C task*/
+        task_unregister(L, task);
+                                  /* comm ... task */
+        return 1;
       }
     }
     else {
       /* the communication has failed */
       lua_pushnil(L);
-                                    /* comm ... true nil */
+                                  /* comm ... nil */
       lua_pushstring(L, msg_errors[res]);
-                                    /* comm ... true nil error */
-      return 3;
+                                  /* comm ... nil error */
+      return 2;
     }
   }
 }
@@ -797,9 +877,9 @@ static int gras_add_process_function(lua_State * L)
   if (xbt_dict_is_empty(machine_set)
       || xbt_dict_is_empty(process_function_set)
       || xbt_dynar_is_empty(process_list)) {
-    process_function_set = xbt_dict_new();
+    process_function_set = xbt_dict_new_homogeneous(NULL);
     process_list = xbt_dynar_new(sizeof(s_process_t), s_process_free);
-    machine_set = xbt_dict_new();
+    machine_set = xbt_dict_new_homogeneous(NULL);
   }
 
   xbt_dict_set(machine_set, process_host, NULL, NULL);
@@ -1140,6 +1220,9 @@ static void register_task_functions(lua_State* L)
                                   /* simgrid.task mt */
   lua_pop(L, 2);
                                   /* -- */
+
+  /* set up MSG to copy Lua tasks between states */
+  MSG_task_set_copy_callback(task_copy_callback);
 }
 
 /**