wrap_Thread.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. /**
  2. * Copyright (c) 2006-2010 LOVE Development Team
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. #include "wrap_Thread.h"
  21. // anonymous namespace for getting an std::string from the stack
  22. // that may contain embedded NULLs
  23. namespace
  24. {
  25. std::string luax_checklstring(lua_State *L, int idx)
  26. {
  27. size_t len;
  28. const char* str = luaL_checklstring(L, idx, &len);
  29. return std::string(str, len);
  30. }
  31. }
  32. namespace love
  33. {
  34. namespace thread
  35. {
  36. namespace sdl
  37. {
  38. Thread *luax_checkthread(lua_State *L, int idx)
  39. {
  40. return luax_checktype<Thread>(L, idx, "Thread", THREAD_THREAD_T);
  41. }
  42. int w_Thread_start(lua_State *L)
  43. {
  44. Thread *t = luax_checkthread(L, 1);
  45. t->start();
  46. return 0;
  47. }
  48. int w_Thread_kill(lua_State *L)
  49. {
  50. Thread *t = luax_checkthread(L, 1);
  51. t->kill();
  52. return 0;
  53. }
  54. int w_Thread_wait(lua_State *L)
  55. {
  56. Thread *t = luax_checkthread(L, 1);
  57. t->wait();
  58. return 0;
  59. }
  60. int w_Thread_getName(lua_State *L)
  61. {
  62. Thread *t = luax_checkthread(L, 1);
  63. // allow names containing \0
  64. lua_pushlstring(L, t->getName().c_str(), t->getName().length());
  65. return 1;
  66. }
  67. int w_Thread_receive(lua_State *L)
  68. {
  69. Thread *t = luax_checkthread(L, 1);
  70. std::string name = luax_checklstring(L, 2);
  71. ThreadVariant *v = t->receive(name);
  72. if (!v)
  73. {
  74. lua_pushnil(L);
  75. return 1;
  76. }
  77. v->retain();
  78. t->clear(name);
  79. switch(v->type)
  80. {
  81. case BOOLEAN:
  82. lua_pushboolean(L, v->data.boolean);
  83. break;
  84. case NUMBER:
  85. lua_pushnumber(L, v->data.number);
  86. break;
  87. case STRING:
  88. lua_pushlstring(L, v->data.string.str, v->data.string.len);
  89. break;
  90. case LUSERDATA:
  91. lua_pushlightuserdata(L, v->data.userdata);
  92. break;
  93. case FUSERDATA:
  94. {
  95. const char *name = NULL;
  96. love::types.find(v->udatatype, name);
  97. ((love::Object *) v->data.userdata)->retain();
  98. luax_newtype(L, name, v->flags, v->data.userdata);
  99. break;
  100. }
  101. default:
  102. lua_pushnil(L);
  103. break;
  104. }
  105. v->release();
  106. return 1;
  107. }
  108. int w_Thread_demand(lua_State *L)
  109. {
  110. Thread *t = luax_checkthread(L, 1);
  111. std::string name = luax_checklstring(L, 2);
  112. ThreadVariant *v = t->demand(name);
  113. if (!v)
  114. {
  115. lua_pushnil(L);
  116. return 1;
  117. }
  118. v->retain();
  119. t->clear(name);
  120. switch(v->type)
  121. {
  122. case BOOLEAN:
  123. lua_pushboolean(L, v->data.boolean);
  124. break;
  125. case NUMBER:
  126. lua_pushnumber(L, v->data.number);
  127. break;
  128. case STRING:
  129. lua_pushlstring(L, v->data.string.str, v->data.string.len);
  130. break;
  131. case LUSERDATA:
  132. lua_pushlightuserdata(L, v->data.userdata);
  133. break;
  134. case FUSERDATA:
  135. {
  136. const char *name = NULL;
  137. types.find(v->udatatype, name);
  138. ((love::Object *) v->data.userdata)->retain();
  139. luax_newtype(L, name, v->flags, v->data.userdata);
  140. break;
  141. }
  142. default:
  143. lua_pushnil(L);
  144. break;
  145. }
  146. v->release();
  147. return 1;
  148. }
  149. int w_Thread_peek(lua_State *L)
  150. {
  151. Thread *t = luax_checkthread(L, 1);
  152. std::string name = luax_checklstring(L, 2);
  153. ThreadVariant *v = t->receive(name);
  154. if (!v)
  155. {
  156. lua_pushnil(L);
  157. return 1;
  158. }
  159. v->retain();
  160. switch(v->type)
  161. {
  162. case BOOLEAN:
  163. lua_pushboolean(L, v->data.boolean);
  164. break;
  165. case NUMBER:
  166. lua_pushnumber(L, v->data.number);
  167. break;
  168. case STRING:
  169. lua_pushlstring(L, v->data.string.str, v->data.string.len);
  170. break;
  171. case LUSERDATA:
  172. lua_pushlightuserdata(L, v->data.userdata);
  173. break;
  174. case FUSERDATA:
  175. {
  176. const char *name = NULL;
  177. types.find(v->udatatype, name);
  178. ((love::Object *) v->data.userdata)->retain();
  179. luax_newtype(L, name, v->flags, v->data.userdata);
  180. break;
  181. }
  182. default:
  183. lua_pushnil(L);
  184. break;
  185. }
  186. v->release();
  187. return 1;
  188. }
  189. Type extractudatatype(lua_State * L, int idx)
  190. {
  191. Type t = INVALID_ID;
  192. if (!lua_isuserdata(L, idx))
  193. return t;
  194. if (luaL_getmetafield (L, idx, "__tostring") == 0)
  195. return t;
  196. lua_pushvalue(L, idx);
  197. int result = lua_pcall(L, 1, 1, 0);
  198. if (result == 0)
  199. types.find(lua_tostring(L, -1), t);
  200. if (result == 0 || result == LUA_ERRRUN)
  201. lua_pop(L, 1);
  202. return t;
  203. }
  204. int w_Thread_send(lua_State *L)
  205. {
  206. Thread *t = luax_checkthread(L, 1);
  207. std::string name = luax_checklstring(L, 2);
  208. ThreadVariant *v;
  209. if (lua_isboolean(L, 3))
  210. {
  211. v = new ThreadVariant(luax_toboolean(L, 3));
  212. }
  213. else if (lua_isnumber(L, 3))
  214. {
  215. v = new ThreadVariant(lua_tonumber(L, 3));
  216. }
  217. else if (lua_isstring(L, 3))
  218. {
  219. size_t len;
  220. const char *str = lua_tolstring(L, 3, &len);
  221. v = new ThreadVariant(str, len);
  222. }
  223. else if (lua_islightuserdata(L, 3))
  224. {
  225. v = new ThreadVariant(lua_touserdata(L, 3));
  226. }
  227. else if (lua_isuserdata(L, 3))
  228. {
  229. v = new ThreadVariant(extractudatatype(L, 3), lua_touserdata(L, 3));
  230. }
  231. else
  232. {
  233. return luaL_error(L, "Expected boolean, number, string or userdata");
  234. }
  235. t->send(name, v);
  236. v->release();
  237. return 0;
  238. }
  239. static const luaL_Reg type_functions[] = {
  240. { "start", w_Thread_start },
  241. { "kill", w_Thread_kill },
  242. { "wait", w_Thread_wait },
  243. { "getName", w_Thread_getName },
  244. { "receive", w_Thread_receive },
  245. { "demand", w_Thread_demand },
  246. { "peek", w_Thread_peek },
  247. { "send", w_Thread_send },
  248. { 0, 0 }
  249. };
  250. int luaopen_thread(lua_State *L)
  251. {
  252. return luax_register_type(L, "Thread", type_functions);
  253. }
  254. static ThreadModule *instance;
  255. int w_newThread(lua_State *L)
  256. {
  257. std::string name = luax_checklstring(L, 1);
  258. love::Data *data;
  259. if (lua_isstring(L, 2))
  260. luax_convobj(L, 2, "filesystem", "newFile");
  261. if (luax_istype(L, 2, FILESYSTEM_FILE_T))
  262. data = luax_checktype<love::filesystem::File>(L, 2, "File", FILESYSTEM_FILE_T)->read();
  263. else
  264. data = luax_checktype<love::Data>(L, 2, "Data", DATA_T);
  265. Thread *t = instance->newThread(name, data);
  266. if (!t)
  267. return luaL_error(L, "A thread with that name already exists.");
  268. luax_newtype(L, "Thread", THREAD_THREAD_T, (void*)t);
  269. return 1;
  270. }
  271. int w_getThreads(lua_State *L)
  272. {
  273. unsigned count = instance->getThreadCount();
  274. Thread **list = new Thread*[count];
  275. instance->getThreads(list);
  276. lua_newtable(L);
  277. for (unsigned int i = 0; i<count; i++)
  278. {
  279. luax_newtype(L, "Thread", THREAD_THREAD_T, (void*) list[i]);
  280. list[i]->lock();
  281. list[i]->retain();
  282. list[i]->unlock();
  283. // allow names containing \0
  284. lua_pushlstring(L, list[i]->getName().c_str(), list[i]->getName().length());
  285. lua_settable(L, -3);
  286. }
  287. delete[] list;
  288. return 1;
  289. }
  290. int w_getThread(lua_State *L)
  291. {
  292. if (lua_isnoneornil(L, 1))
  293. {
  294. lua_getglobal(L, "love");
  295. lua_getfield(L, -1, "_curthread");
  296. return 1;
  297. }
  298. std::string name = luax_checklstring(L, 1);
  299. Thread *t = instance->getThread(name);
  300. if (t)
  301. {
  302. luax_newtype(L, "Thread", THREAD_THREAD_T, (void*)t);
  303. t->lock();
  304. t->retain();
  305. t->unlock();
  306. }
  307. else
  308. lua_pushnil(L);
  309. return 1;
  310. }
  311. // List of functions to wrap.
  312. static const luaL_Reg module_functions[] = {
  313. { "newThread", w_newThread },
  314. { "getThread", w_getThread },
  315. { "getThreads", w_getThreads },
  316. { 0, 0 }
  317. };
  318. static const lua_CFunction types[] = {
  319. luaopen_thread,
  320. 0
  321. };
  322. int luaopen_love_thread(lua_State *L)
  323. {
  324. if(instance == 0)
  325. {
  326. try
  327. {
  328. instance = new ThreadModule();
  329. lua_getglobal(L, "love");
  330. Thread *curthread = instance->getThread("main");
  331. curthread->lock();
  332. curthread->retain();
  333. curthread->unlock();
  334. luax_newtype(L, "Thread", THREAD_THREAD_T, (void*)curthread);
  335. lua_setfield(L, -2, "_curthread");
  336. }
  337. catch(Exception & e)
  338. {
  339. return luaL_error(L, e.what());
  340. }
  341. }
  342. else
  343. instance->retain();
  344. WrappedModule w;
  345. w.module = instance;
  346. w.name = "thread";
  347. w.flags = MODULE_T;
  348. w.functions = module_functions;
  349. w.types = types;
  350. return luax_register_module(L, w);
  351. }
  352. }
  353. }
  354. }