* 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)
{
}
/**
- * \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) {
}
/**
- * \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: ... */
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);
* - 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);
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;
}
const char* mailbox = luaL_checkstring(L, 1);
int timeout;
if (lua_gettop(L) >= 2) {
- /* mailbox timeout */
+ /* mailbox timeout ... */
timeout = luaL_checknumber(L, 2);
}
else {
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;
}
}
}
+/**
+ * \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[] = {
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;
}
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;
}
* 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;
}
}
}
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);
/* simgrid.task mt */
lua_pop(L, 2);
/* -- */
+
+ /* set up MSG to copy Lua tasks between states */
+ MSG_task_set_copy_callback(task_copy_callback);
}
/**