Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
First series of changes to lua-bindings in order to
[simgrid.git] / src / bindings / lua / lua_comm.c
1 /* Copyright (c) 2010, 2012-2014. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include "lua_private.h"
8 #include <lauxlib.h>
9
10 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(lua_comm, bindings, "Lua bindings (comm module)");
11
12 #define COMM_MODULE_NAME "simgrid.comm"
13
14 /* ********************************************************************************* */
15 /*                                simgrid.comm API                                   */
16 /* ********************************************************************************* */
17
18 /**
19  * \brief Ensures that a value in the stack is a comm and returns it.
20  * \param L a Lua state
21  * \param index an index in the Lua stack
22  * \return the C comm
23  */
24 msg_comm_t sglua_check_comm(lua_State* L, int index)
25 {
26   msg_comm_t comm = *((msg_comm_t*) luaL_checkudata(L, index, COMM_MODULE_NAME));
27   return comm;
28 }
29
30 /**
31  * \brief Pushes a comm onto the stack.
32  * \param L a Lua state
33  * \param comm a comm
34  */
35 void sglua_push_comm(lua_State* L, msg_comm_t comm)
36 {
37   msg_comm_t* userdata = (msg_comm_t*) lua_newuserdata(L, sizeof(msg_comm_t));
38                                 /* comm */
39   *userdata = comm;
40   luaL_getmetatable(L, COMM_MODULE_NAME);
41                                 /* comm mt */
42   lua_setmetatable(L, -2);
43                                 /* comm */
44 }
45
46 /**
47  * \brief Blocks the current process until a communication is finished.
48  * \param L a Lua state
49  * \return number of values returned to Lua
50  *
51  * - Argument 1 (comm): a comm (previously created by isend or irecv)
52  * - Argument 2 (number, optional): timeout (default is no timeout)
53  * - Return values (task or nil + string): in case of success, returns the task
54  * received if you are the receiver and nil if you are the sender. In case of
55  * failure, returns nil plus an error string.
56  */
57 static int l_comm_wait(lua_State* L) {
58
59   msg_comm_t comm = sglua_check_comm(L, 1);
60   double timeout = -1;
61   if (lua_gettop(L) >= 2) {
62     timeout = luaL_checknumber(L, 2);
63   }
64                                   /* comm ... */
65   msg_error_t res = MSG_comm_wait(comm, timeout);
66
67   if (res == MSG_OK) {
68     msg_task_t task = MSG_comm_get_task(comm);
69     if (MSG_task_get_sender(task) == MSG_process_self()) {
70       /* I'm the sender */
71       return 0;
72     }
73     else {
74       /* I'm the receiver: find the Lua task from the C task */
75       sglua_task_unregister(L, task);
76                                   /* comm ... task */
77       return 1;
78     }
79   }
80   else {
81     /* the communication has failed */
82     lua_pushnil(L);
83                                   /* comm ... nil */
84     lua_pushstring(L, sglua_get_msg_error(res));
85                                   /* comm ... nil error */
86     return 2;
87   }
88 }
89
90 /**
91  * @brief Returns whether a communication is finished.
92  *
93  * Unlike wait(), This function always returns immediately.
94  *
95  * - Argument 1 (comm): a comm (previously created by isend or irecv)
96  * - Return values (task/boolean or nil + string): if the communication is not
97  * finished, return false. If the communication is finished and was successful,
98  * returns the task received if you are the receiver or true if you are the
99  * sender. If the communication is finished and has failed, returns nil
100  * plus an error string.
101  */
102 static int l_comm_test(lua_State* L) {
103
104   msg_comm_t comm = sglua_check_comm(L, 1);
105                                   /* comm ... */
106   if (!MSG_comm_test(comm)) {
107     /* not finished yet */
108     lua_pushboolean(L, 0);
109                                   /* comm ... false */
110     return 1;
111   }
112   else {
113     /* finished but may have failed */
114     msg_error_t res = MSG_comm_get_status(comm);
115
116     if (res == MSG_OK) {
117       msg_task_t task = MSG_comm_get_task(comm);
118       if (MSG_task_get_sender(task) == MSG_process_self()) {
119         /* I'm the sender */
120         lua_pushboolean(L, 1);
121                                   /* comm ... true */
122         return 1;
123       }
124       else {
125         /* I'm the receiver: find the Lua task from the C task*/
126         sglua_task_unregister(L, task);
127                                   /* comm ... task */
128         return 1;
129       }
130     }
131     else {
132       /* the communication has failed */
133       lua_pushnil(L);
134                                   /* comm ... nil */
135       lua_pushstring(L, sglua_get_msg_error(res));
136                                   /* comm ... nil error */
137       return 2;
138     }
139   }
140 }
141
142 static const luaL_Reg comm_functions[] = {
143   {"wait", l_comm_wait},
144   {"test", l_comm_test},
145   /* TODO waitany, testany */
146   {NULL, NULL}
147 };
148
149 /**
150  * \brief Finalizes a comm userdata.
151  * \param L a Lua state
152  * \return number of values returned to Lua
153  *
154  * - Argument 1 (userdata): a comm
155  */
156 static int l_comm_gc(lua_State* L)
157 {
158                                   /* ctask */
159   msg_comm_t comm = *((msg_comm_t*) luaL_checkudata(L, 1, COMM_MODULE_NAME));
160   MSG_comm_destroy(comm);
161   return 0;
162 }
163
164 /**
165  * \brief Metamethods of the comm userdata.
166  */
167 static const luaL_Reg comm_meta[] = {
168   {"__gc", l_comm_gc},
169   {NULL, NULL}
170 };
171
172 /**
173  * \brief Registers the comm functions into the table simgrid.comm.
174  *
175  * Also initialize the metatable of the comm userdata type.
176  *
177  * \param L a lua state
178  */
179 void sglua_register_comm_functions(lua_State* L)
180 {
181   /* create a table simgrid.comm and fill it with com functions */
182   lua_newtable(L);
183   luaL_setfuncs(L, comm_functions, 0);
184   lua_setglobal(L, COMM_MODULE_NAME);
185   /*luaL_openlib(L, COMM_MODULE_NAME, comm_functions, 0);*/
186                                   /* simgrid.comm */
187
188   /* create the metatable for comms, add it to the Lua registry */
189   luaL_newmetatable(L, COMM_MODULE_NAME);
190                                   /* simgrid.comm mt */
191   /* fill the metatable */
192   luaL_setfuncs(L, comm_meta, 0);
193   luaL_setmetatable(L, COMM_MODULE_NAME);
194   /*luaL_openlib(L, NULL, comm_meta, 0);*/
195                                   /* simgrid.comm mt */
196   /*lua_pushvalue(L, -2);*/
197                                   /* simgrid.comm mt simgrid.comm */
198   /* metatable.__index = simgrid.comm
199    * we put the comm functions inside the comm itself:
200    * this allows to write my_comm:method(args) for
201    * simgrid.comm.method(my_comm, args) */
202   lua_setfield(L, -2, "__index");
203                                   /* simgrid.comm mt */
204   lua_pop(L, 2);
205                                   /* -- */
206 }
207