wrap_Thread.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  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. Thread *luax_checkthread(lua_State *L, int idx)
  37. {
  38. return luax_checktype<Thread>(L, idx, "Thread", THREAD_THREAD_T);
  39. }
  40. int w_Thread_start(lua_State *L)
  41. {
  42. Thread *t = luax_checkthread(L, 1);
  43. t->start();
  44. return 0;
  45. }
  46. int w_Thread_kill(lua_State *L)
  47. {
  48. Thread *t = luax_checkthread(L, 1);
  49. t->kill();
  50. return 0;
  51. }
  52. int w_Thread_wait(lua_State *L)
  53. {
  54. Thread *t = luax_checkthread(L, 1);
  55. t->wait();
  56. return 0;
  57. }
  58. int w_Thread_getName(lua_State *L)
  59. {
  60. Thread *t = luax_checkthread(L, 1);
  61. // allow names containing \0
  62. lua_pushlstring(L, t->getName().c_str(), t->getName().length());
  63. return 1;
  64. }
  65. bool __pushThreadVariant(lua_State *L, ThreadVariant *v)
  66. {
  67. if (!v)
  68. {
  69. lua_pushnil(L);
  70. return false;
  71. }
  72. switch(v->type)
  73. {
  74. case BOOLEAN:
  75. lua_pushboolean(L, v->data.boolean);
  76. break;
  77. case NUMBER:
  78. lua_pushnumber(L, v->data.number);
  79. break;
  80. case STRING:
  81. lua_pushlstring(L, v->data.string.str, v->data.string.len);
  82. break;
  83. case LUSERDATA:
  84. lua_pushlightuserdata(L, v->data.userdata);
  85. break;
  86. case FUSERDATA:
  87. if (v->udatatype != INVALID_ID)
  88. {
  89. const char *name = NULL;
  90. love::types.find(v->udatatype, name);
  91. ((love::Object *) v->data.userdata)->retain();
  92. luax_newtype(L, name, v->flags, v->data.userdata);
  93. }
  94. else
  95. lua_pushlightuserdata(L, v->data.userdata);
  96. // I know this is not the same
  97. // sadly, however, it's the most
  98. // I can do (at the moment).
  99. break;
  100. default:
  101. lua_pushnil(L);
  102. break;
  103. }
  104. return true;
  105. }
  106. int w_Thread_get(lua_State *L)
  107. {
  108. Thread *t = luax_checkthread(L, 1);
  109. std::string name = luax_checklstring(L, 2);
  110. t->lock();
  111. ThreadVariant *v = t->get(name);
  112. t->clear(name);
  113. t->unlock();
  114. if (!__pushThreadVariant(L, v))
  115. return 1;
  116. t->lock();
  117. v->release();
  118. t->unlock();
  119. return 1;
  120. }
  121. int w_Thread_getKeys(lua_State *L)
  122. {
  123. Thread *t = luax_checkthread(L, 1);
  124. t->lock();
  125. std::vector<std::string> keys = t->getKeys();
  126. t->unlock();
  127. lua_createtable(L, keys.size(), 0);
  128. int i = 1;
  129. for (std::vector<std::string>::iterator it = keys.begin(); it != keys.end(); it++)
  130. {
  131. lua_pushnumber(L, i++);
  132. lua_pushlstring(L, it->c_str(), it->length());
  133. lua_settable(L, -3);
  134. }
  135. return 1;
  136. }
  137. int w_Thread_demand(lua_State *L)
  138. {
  139. Thread *t = luax_checkthread(L, 1);
  140. std::string name = luax_checklstring(L, 2);
  141. t->lock();
  142. ThreadVariant *v = t->demand(name);
  143. t->clear(name);
  144. t->unlock();
  145. if (!__pushThreadVariant(L, v))
  146. return 1;
  147. t->lock();
  148. v->release();
  149. t->unlock();
  150. return 1;
  151. }
  152. int w_Thread_peek(lua_State *L)
  153. {
  154. Thread *t = luax_checkthread(L, 1);
  155. std::string name = luax_checklstring(L, 2);
  156. t->lock();
  157. ThreadVariant *v = t->get(name);
  158. t->unlock();
  159. if (!__pushThreadVariant(L, v))
  160. return 1;
  161. t->lock();
  162. v->release();
  163. t->unlock();
  164. return 1;
  165. }
  166. Type extractudatatype(lua_State * L, int idx)
  167. {
  168. Type t = INVALID_ID;
  169. if (!lua_isuserdata(L, idx))
  170. return t;
  171. if (luaL_getmetafield (L, idx, "__tostring") == 0)
  172. return t;
  173. lua_pushvalue(L, idx);
  174. int result = lua_pcall(L, 1, 1, 0);
  175. if (result == 0)
  176. types.find(lua_tostring(L, -1), t);
  177. if (result == 0 || result == LUA_ERRRUN)
  178. lua_pop(L, 1);
  179. return t;
  180. }
  181. int w_Thread_set(lua_State *L)
  182. {
  183. Thread *t = luax_checkthread(L, 1);
  184. std::string name = luax_checklstring(L, 2);
  185. ThreadVariant *v;
  186. size_t len;
  187. const char *str;
  188. switch(lua_type(L, 3))
  189. {
  190. case LUA_TBOOLEAN:
  191. v = new ThreadVariant(luax_toboolean(L, 3));
  192. break;
  193. case LUA_TNUMBER:
  194. v = new ThreadVariant(lua_tonumber(L, 3));
  195. break;
  196. case LUA_TSTRING:
  197. str = lua_tolstring(L, 3, &len);
  198. v = new ThreadVariant(str, len);
  199. break;
  200. case LUA_TLIGHTUSERDATA:
  201. v = new ThreadVariant(lua_touserdata(L, 3));
  202. break;
  203. case LUA_TUSERDATA:
  204. v = new ThreadVariant(extractudatatype(L, 3), lua_touserdata(L, 3));
  205. break;
  206. default:
  207. return luaL_error(L, "Expected boolean, number, string or userdata");
  208. }
  209. t->set(name, v);
  210. t->lock();
  211. v->release();
  212. t->unlock();
  213. return 0;
  214. }
  215. static const luaL_Reg type_functions[] = {
  216. { "start", w_Thread_start },
  217. { "kill", w_Thread_kill },
  218. { "wait", w_Thread_wait },
  219. { "getName", w_Thread_getName },
  220. { "get", w_Thread_get },
  221. { "getKeys", w_Thread_getKeys },
  222. { "demand", w_Thread_demand },
  223. { "peek", w_Thread_peek },
  224. { "set", w_Thread_set },
  225. { 0, 0 }
  226. };
  227. int luaopen_thread(lua_State *L)
  228. {
  229. return luax_register_type(L, "Thread", type_functions);
  230. }
  231. static ThreadModule *instance;
  232. int w_newThread(lua_State *L)
  233. {
  234. std::string name = luax_checklstring(L, 1);
  235. love::Data *data;
  236. if (lua_isstring(L, 2))
  237. luax_convobj(L, 2, "filesystem", "newFile");
  238. if (luax_istype(L, 2, FILESYSTEM_FILE_T))
  239. {
  240. try {
  241. data = luax_checktype<love::filesystem::File>(L, 2, "File", FILESYSTEM_FILE_T)->read();
  242. } catch (love::Exception & e) {
  243. return luaL_error(L, e.what());
  244. }
  245. }
  246. else
  247. {
  248. data = luax_checktype<love::Data>(L, 2, "Data", DATA_T);
  249. data->retain();
  250. }
  251. Thread *t = instance->newThread(name, data);
  252. // do not worry, file->read() returns retained data
  253. data->release();
  254. if (!t)
  255. return luaL_error(L, "A thread with that name already exists.");
  256. luax_newtype(L, "Thread", THREAD_THREAD_T, (void*)t);
  257. return 1;
  258. }
  259. int w_getThreads(lua_State *L)
  260. {
  261. unsigned count = instance->getThreadCount();
  262. Thread **list = new Thread*[count];
  263. instance->getThreads(list);
  264. lua_newtable(L);
  265. for (unsigned int i = 0; i<count; i++)
  266. {
  267. // allow names containing \0
  268. lua_pushlstring(L, list[i]->getName().c_str(), list[i]->getName().length());
  269. luax_newtype(L, "Thread", THREAD_THREAD_T, (void*) list[i]);
  270. list[i]->lock();
  271. list[i]->retain();
  272. list[i]->unlock();
  273. lua_settable(L, -3);
  274. }
  275. delete[] list;
  276. return 1;
  277. }
  278. int w_getThread(lua_State *L)
  279. {
  280. if (lua_isnoneornil(L, 1))
  281. {
  282. lua_getglobal(L, "love");
  283. lua_getfield(L, -1, "_curthread");
  284. return 1;
  285. }
  286. std::string name = luax_checklstring(L, 1);
  287. Thread *t = instance->getThread(name);
  288. if (t)
  289. {
  290. luax_newtype(L, "Thread", THREAD_THREAD_T, (void*)t);
  291. t->lock();
  292. t->retain();
  293. t->unlock();
  294. }
  295. else
  296. lua_pushnil(L);
  297. return 1;
  298. }
  299. // List of functions to wrap.
  300. static const luaL_Reg module_functions[] = {
  301. { "newThread", w_newThread },
  302. { "getThread", w_getThread },
  303. { "getThreads", w_getThreads },
  304. { 0, 0 }
  305. };
  306. static const lua_CFunction types[] = {
  307. luaopen_thread,
  308. 0
  309. };
  310. int luaopen_love_thread(lua_State *L)
  311. {
  312. if(instance == 0)
  313. {
  314. try
  315. {
  316. instance = new ThreadModule();
  317. lua_getglobal(L, "love");
  318. Thread *curthread = instance->getThread("main");
  319. curthread->lock();
  320. curthread->retain();
  321. curthread->unlock();
  322. luax_newtype(L, "Thread", THREAD_THREAD_T, (void*)curthread);
  323. lua_setfield(L, -2, "_curthread");
  324. }
  325. catch(Exception & e)
  326. {
  327. return luaL_error(L, e.what());
  328. }
  329. }
  330. else
  331. instance->retain();
  332. WrappedModule w;
  333. w.module = instance;
  334. w.name = "thread";
  335. w.flags = MODULE_T;
  336. w.functions = module_functions;
  337. w.types = types;
  338. return luax_register_module(L, w);
  339. }
  340. }
  341. }