obs-scripting-lua-source.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. /******************************************************************************
  2. Copyright (C) 2017 by Hugh Bailey <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ******************************************************************************/
  14. #include "obs-scripting-lua.h"
  15. #include "cstrcache.h"
  16. #include <obs-module.h>
  17. /* ========================================================================= */
  18. static inline const char *get_table_string_(lua_State *script, int idx,
  19. const char *name, const char *func)
  20. {
  21. const char *str = "";
  22. lua_pushstring(script, name);
  23. lua_gettable(script, idx - 1);
  24. if (!lua_isstring(script, -1))
  25. warn("%s: no item '%s' of type %s", func, name, "string");
  26. else
  27. str = cstrcache_get(lua_tostring(script, -1));
  28. lua_pop(script, 1);
  29. return str;
  30. }
  31. static inline int get_table_int_(lua_State *script, int idx,
  32. const char *name, const char *func)
  33. {
  34. int val = 0;
  35. lua_pushstring(script, name);
  36. lua_gettable(script, idx - 1);
  37. val = (int)lua_tointeger(script, -1);
  38. lua_pop(script, 1);
  39. UNUSED_PARAMETER(func);
  40. return val;
  41. }
  42. static inline void get_callback_from_table_(lua_State *script, int idx,
  43. const char *name, int *p_reg_idx, const char *func)
  44. {
  45. *p_reg_idx = LUA_REFNIL;
  46. lua_pushstring(script, name);
  47. lua_gettable(script, idx - 1);
  48. if (!lua_isfunction(script, -1)) {
  49. if (!lua_isnil(script, -1)) {
  50. warn("%s: item '%s' is not a function", func, name);
  51. }
  52. lua_pop(script, 1);
  53. } else {
  54. *p_reg_idx = luaL_ref(script, LUA_REGISTRYINDEX);
  55. }
  56. }
  57. #define get_table_string(script, idx, name) \
  58. get_table_string_(script, idx, name, __FUNCTION__)
  59. #define get_table_int(script, idx, name) \
  60. get_table_int_(script, idx, name, __FUNCTION__)
  61. #define get_callback_from_table(script, idx, name, p_reg_idx) \
  62. get_callback_from_table_(script, idx, name, p_reg_idx, __FUNCTION__)
  63. bool ls_get_libobs_obj_(lua_State * script,
  64. const char *type,
  65. int lua_idx,
  66. void * libobs_out,
  67. const char *id,
  68. const char *func,
  69. int line)
  70. {
  71. swig_type_info *info = SWIG_TypeQuery(script, type);
  72. if (info == NULL) {
  73. warn("%s:%d: SWIG could not find type: %s%s%s",
  74. func,
  75. line,
  76. id ? id : "",
  77. id ? "::" : "",
  78. type);
  79. return false;
  80. }
  81. int ret = SWIG_ConvertPtr(script, lua_idx, libobs_out, info, 0);
  82. if (!SWIG_IsOK(ret)) {
  83. warn("%s:%d: SWIG failed to convert lua object to obs "
  84. "object: %s%s%s",
  85. func,
  86. line,
  87. id ? id : "",
  88. id ? "::" : "",
  89. type);
  90. return false;
  91. }
  92. return true;
  93. }
  94. #define ls_get_libobs_obj(type, lua_index, obs_obj) \
  95. ls_get_libobs_obj_(ls->script, #type " *", lua_index, obs_obj, \
  96. ls->id, __FUNCTION__, __LINE__)
  97. bool ls_push_libobs_obj_(lua_State * script,
  98. const char *type,
  99. void * libobs_in,
  100. bool ownership,
  101. const char *id,
  102. const char *func,
  103. int line)
  104. {
  105. swig_type_info *info = SWIG_TypeQuery(script, type);
  106. if (info == NULL) {
  107. warn("%s:%d: SWIG could not find type: %s%s%s",
  108. func,
  109. line,
  110. id ? id : "",
  111. id ? "::" : "",
  112. type);
  113. return false;
  114. }
  115. SWIG_NewPointerObj(script, libobs_in, info, (int)ownership);
  116. return true;
  117. }
  118. #define ls_push_libobs_obj(type, obs_obj, ownership) \
  119. ls_push_libobs_obj_(ls->script, #type " *", obs_obj, ownership, \
  120. ls->id, __FUNCTION__, __LINE__)
  121. /* ========================================================================= */
  122. struct obs_lua_data;
  123. struct obs_lua_source {
  124. struct obs_lua_script *data;
  125. lua_State * script;
  126. const char *id;
  127. const char *display_name;
  128. int func_create;
  129. int func_destroy;
  130. int func_get_width;
  131. int func_get_height;
  132. int func_get_defaults;
  133. int func_get_properties;
  134. int func_update;
  135. int func_activate;
  136. int func_deactivate;
  137. int func_show;
  138. int func_hide;
  139. int func_video_tick;
  140. int func_video_render;
  141. int func_save;
  142. int func_load;
  143. pthread_mutex_t definition_mutex;
  144. struct obs_lua_data *first_source;
  145. struct obs_lua_source *next;
  146. struct obs_lua_source **p_prev_next;
  147. };
  148. extern pthread_mutex_t lua_source_def_mutex;
  149. struct obs_lua_source *first_source_def = NULL;
  150. struct obs_lua_data {
  151. obs_source_t * source;
  152. struct obs_lua_source *ls;
  153. int lua_data_ref;
  154. struct obs_lua_data *next;
  155. struct obs_lua_data **p_prev_next;
  156. };
  157. #define call_func(name, args, rets) \
  158. call_func_(ls->script, ls->func_ ## name, args, rets, #name, \
  159. ls->display_name)
  160. #define have_func(name) \
  161. (ls->func_ ## name != LUA_REFNIL)
  162. #define ls_push_data() \
  163. lua_rawgeti(ls->script, LUA_REGISTRYINDEX, ld->lua_data_ref)
  164. #define ls_pop(count) \
  165. lua_pop(ls->script, count)
  166. #define lock_script() \
  167. struct obs_lua_script *__data = ls->data; \
  168. struct obs_lua_script *__prev_script = current_lua_script; \
  169. current_lua_script = __data; \
  170. pthread_mutex_lock(&__data->mutex);
  171. #define unlock_script() \
  172. pthread_mutex_unlock(&__data->mutex); \
  173. current_lua_script = __prev_script;
  174. static const char *obs_lua_source_get_name(void *type_data)
  175. {
  176. struct obs_lua_source *ls = type_data;
  177. return ls->display_name;
  178. }
  179. static void *obs_lua_source_create(obs_data_t *settings, obs_source_t *source)
  180. {
  181. struct obs_lua_source *ls = obs_source_get_type_data(source);
  182. struct obs_lua_data *data = NULL;
  183. pthread_mutex_lock(&ls->definition_mutex);
  184. if (!ls->script)
  185. goto fail;
  186. if (!have_func(create))
  187. goto fail;
  188. lock_script();
  189. ls_push_libobs_obj(obs_data_t, settings, false);
  190. ls_push_libobs_obj(obs_source_t, source, false);
  191. call_func(create, 2, 1);
  192. int lua_data_ref = luaL_ref(ls->script, LUA_REGISTRYINDEX);
  193. if (lua_data_ref != LUA_REFNIL) {
  194. data = bmalloc(sizeof(*data));
  195. data->source = source;
  196. data->ls = ls;
  197. data->lua_data_ref = lua_data_ref;
  198. }
  199. unlock_script();
  200. if (data) {
  201. struct obs_lua_data *next = ls->first_source;
  202. data->next = next;
  203. data->p_prev_next = &ls->first_source;
  204. if (next) next->p_prev_next = &data->next;
  205. ls->first_source = data;
  206. }
  207. fail:
  208. pthread_mutex_unlock(&ls->definition_mutex);
  209. return data;
  210. }
  211. static void call_destroy(struct obs_lua_data *ld)
  212. {
  213. struct obs_lua_source *ls = ld->ls;
  214. ls_push_data();
  215. call_func(destroy, 1, 0);
  216. luaL_unref(ls->script, LUA_REGISTRYINDEX, ld->lua_data_ref);
  217. ld->lua_data_ref = LUA_REFNIL;
  218. }
  219. static void obs_lua_source_destroy(void *data)
  220. {
  221. struct obs_lua_data * ld = data;
  222. struct obs_lua_source *ls = ld->ls;
  223. struct obs_lua_data * next;
  224. pthread_mutex_lock(&ls->definition_mutex);
  225. if (!ls->script)
  226. goto fail;
  227. if (!have_func(destroy))
  228. goto fail;
  229. lock_script();
  230. call_destroy(ld);
  231. unlock_script();
  232. fail:
  233. next = ld->next;
  234. *ld->p_prev_next = next;
  235. if (next) next->p_prev_next = ld->p_prev_next;
  236. bfree(data);
  237. pthread_mutex_unlock(&ls->definition_mutex);
  238. }
  239. static uint32_t obs_lua_source_get_width(void *data)
  240. {
  241. struct obs_lua_data * ld = data;
  242. struct obs_lua_source *ls = ld->ls;
  243. uint32_t width = 0;
  244. pthread_mutex_lock(&ls->definition_mutex);
  245. if (!ls->script)
  246. goto fail;
  247. if (!have_func(get_width))
  248. goto fail;
  249. lock_script();
  250. ls_push_data();
  251. if (call_func(get_width, 1, 1)) {
  252. width = (uint32_t)lua_tointeger(ls->script, -1);
  253. ls_pop(1);
  254. }
  255. unlock_script();
  256. fail:
  257. pthread_mutex_unlock(&ls->definition_mutex);
  258. return width;
  259. }
  260. static uint32_t obs_lua_source_get_height(void *data)
  261. {
  262. struct obs_lua_data * ld = data;
  263. struct obs_lua_source *ls = ld->ls;
  264. uint32_t height = 0;
  265. pthread_mutex_lock(&ls->definition_mutex);
  266. if (!ls->script)
  267. goto fail;
  268. if (!have_func(get_height))
  269. goto fail;
  270. lock_script();
  271. ls_push_data();
  272. if (call_func(get_height, 1, 1)) {
  273. height = (uint32_t)lua_tointeger(ls->script, -1);
  274. ls_pop(1);
  275. }
  276. unlock_script();
  277. fail:
  278. pthread_mutex_unlock(&ls->definition_mutex);
  279. return height;
  280. }
  281. static void obs_lua_source_get_defaults(void *type_data, obs_data_t *settings)
  282. {
  283. struct obs_lua_source *ls = type_data;
  284. pthread_mutex_lock(&ls->definition_mutex);
  285. if (!ls->script)
  286. goto fail;
  287. if (!have_func(get_defaults))
  288. goto fail;
  289. lock_script();
  290. ls_push_libobs_obj(obs_data_t, settings, false);
  291. call_func(get_defaults, 1, 0);
  292. unlock_script();
  293. fail:
  294. pthread_mutex_unlock(&ls->definition_mutex);
  295. }
  296. static obs_properties_t *obs_lua_source_get_properties(void *data)
  297. {
  298. struct obs_lua_data * ld = data;
  299. struct obs_lua_source *ls = ld->ls;
  300. obs_properties_t * props = NULL;
  301. pthread_mutex_lock(&ls->definition_mutex);
  302. if (!ls->script)
  303. goto fail;
  304. if (!have_func(get_properties))
  305. goto fail;
  306. lock_script();
  307. ls_push_data();
  308. if (call_func(get_properties, 1, 1)) {
  309. ls_get_libobs_obj(obs_properties_t, -1, &props);
  310. ls_pop(1);
  311. }
  312. unlock_script();
  313. fail:
  314. pthread_mutex_unlock(&ls->definition_mutex);
  315. return props;
  316. }
  317. static void obs_lua_source_update(void *data, obs_data_t *settings)
  318. {
  319. struct obs_lua_data * ld = data;
  320. struct obs_lua_source *ls = ld->ls;
  321. pthread_mutex_lock(&ls->definition_mutex);
  322. if (!ls->script)
  323. goto fail;
  324. if (!have_func(update))
  325. goto fail;
  326. lock_script();
  327. ls_push_data();
  328. ls_push_libobs_obj(obs_data_t, settings, false);
  329. call_func(update, 2, 0);
  330. unlock_script();
  331. fail:
  332. pthread_mutex_unlock(&ls->definition_mutex);
  333. }
  334. #define DEFINE_VOID_DATA_CALLBACK(name) \
  335. static void obs_lua_source_ ## name(void *data) \
  336. { \
  337. struct obs_lua_data * ld = data; \
  338. struct obs_lua_source *ls = ld->ls; \
  339. if (!have_func(name)) \
  340. return; \
  341. lock_script(); \
  342. ls_push_data(); \
  343. call_func(name, 1, 0); \
  344. unlock_script(); \
  345. }
  346. DEFINE_VOID_DATA_CALLBACK(activate)
  347. DEFINE_VOID_DATA_CALLBACK(deactivate)
  348. DEFINE_VOID_DATA_CALLBACK(show)
  349. DEFINE_VOID_DATA_CALLBACK(hide)
  350. #undef DEFINE_VOID_DATA_CALLBACK
  351. static void obs_lua_source_video_tick(void *data, float seconds)
  352. {
  353. struct obs_lua_data * ld = data;
  354. struct obs_lua_source *ls = ld->ls;
  355. pthread_mutex_lock(&ls->definition_mutex);
  356. if (!ls->script)
  357. goto fail;
  358. if (!have_func(video_tick))
  359. goto fail;
  360. lock_script();
  361. ls_push_data();
  362. lua_pushnumber(ls->script, (double)seconds);
  363. call_func(video_tick, 2, 0);
  364. unlock_script();
  365. fail:
  366. pthread_mutex_unlock(&ls->definition_mutex);
  367. }
  368. static void obs_lua_source_video_render(void *data, gs_effect_t *effect)
  369. {
  370. struct obs_lua_data * ld = data;
  371. struct obs_lua_source *ls = ld->ls;
  372. pthread_mutex_lock(&ls->definition_mutex);
  373. if (!ls->script)
  374. goto fail;
  375. if (!have_func(video_render))
  376. goto fail;
  377. lock_script();
  378. ls_push_data();
  379. ls_push_libobs_obj(gs_effect_t, effect, false);
  380. call_func(video_render, 2, 0);
  381. unlock_script();
  382. fail:
  383. pthread_mutex_unlock(&ls->definition_mutex);
  384. }
  385. static void obs_lua_source_save(void *data, obs_data_t *settings)
  386. {
  387. struct obs_lua_data * ld = data;
  388. struct obs_lua_source *ls = ld->ls;
  389. pthread_mutex_lock(&ls->definition_mutex);
  390. if (!ls->script)
  391. goto fail;
  392. if (!have_func(save))
  393. goto fail;
  394. lock_script();
  395. ls_push_data();
  396. ls_push_libobs_obj(obs_data_t, settings, false);
  397. call_func(save, 2, 0);
  398. unlock_script();
  399. fail:
  400. pthread_mutex_unlock(&ls->definition_mutex);
  401. }
  402. static void obs_lua_source_load(void *data, obs_data_t *settings)
  403. {
  404. struct obs_lua_data * ld = data;
  405. struct obs_lua_source *ls = ld->ls;
  406. pthread_mutex_lock(&ls->definition_mutex);
  407. if (!ls->script)
  408. goto fail;
  409. if (!have_func(load))
  410. goto fail;
  411. lock_script();
  412. ls_push_data();
  413. ls_push_libobs_obj(obs_data_t, settings, false);
  414. call_func(load, 2, 0);
  415. unlock_script();
  416. fail:
  417. pthread_mutex_unlock(&ls->definition_mutex);
  418. }
  419. static void source_type_unload(struct obs_lua_source *ls)
  420. {
  421. #define unref(name) \
  422. luaL_unref(ls->script, LUA_REGISTRYINDEX, name); \
  423. name = LUA_REFNIL
  424. unref(ls->func_create);
  425. unref(ls->func_destroy);
  426. unref(ls->func_get_width);
  427. unref(ls->func_get_height);
  428. unref(ls->func_get_defaults);
  429. unref(ls->func_get_properties);
  430. unref(ls->func_update);
  431. unref(ls->func_activate);
  432. unref(ls->func_deactivate);
  433. unref(ls->func_show);
  434. unref(ls->func_hide);
  435. unref(ls->func_video_tick);
  436. unref(ls->func_video_render);
  437. unref(ls->func_save);
  438. unref(ls->func_load);
  439. #undef unref
  440. }
  441. static void obs_lua_source_free_type_data(void *type_data)
  442. {
  443. struct obs_lua_source *ls = type_data;
  444. pthread_mutex_lock(&ls->definition_mutex);
  445. if (ls->script) {
  446. lock_script();
  447. source_type_unload(ls);
  448. unlock_script();
  449. ls->script = NULL;
  450. }
  451. pthread_mutex_unlock(&ls->definition_mutex);
  452. pthread_mutex_destroy(&ls->definition_mutex);
  453. bfree(ls);
  454. }
  455. EXPORT void obs_enable_source_type(const char *name, bool enable);
  456. static inline struct obs_lua_source *find_existing(const char *id)
  457. {
  458. struct obs_lua_source *existing = NULL;
  459. pthread_mutex_lock(&lua_source_def_mutex);
  460. struct obs_lua_source *ls = first_source_def;
  461. while (ls) {
  462. /* can compare pointers here due to string table */
  463. if (ls->id == id) {
  464. existing = ls;
  465. break;
  466. }
  467. ls = ls->next;
  468. }
  469. pthread_mutex_unlock(&lua_source_def_mutex);
  470. return existing;
  471. }
  472. static int obs_lua_register_source(lua_State *script)
  473. {
  474. struct obs_lua_source ls = {0};
  475. struct obs_lua_source *existing = NULL;
  476. struct obs_lua_source *v = NULL;
  477. struct obs_source_info info = {0};
  478. const char *id;
  479. if (!verify_args1(script, is_table))
  480. goto fail;
  481. id = get_table_string(script, -1, "id");
  482. if (!id || !*id)
  483. goto fail;
  484. /* redefinition */
  485. existing = find_existing(id);
  486. if (existing) {
  487. if (existing->script) {
  488. existing = NULL;
  489. goto fail;
  490. }
  491. pthread_mutex_lock(&existing->definition_mutex);
  492. }
  493. v = existing ? existing : &ls;
  494. v->script = script;
  495. v->id = id;
  496. info.id = v->id;
  497. info.type = (enum obs_source_type)get_table_int(script, -1, "type");
  498. info.output_flags = get_table_int(script, -1, "output_flags");
  499. lua_pushstring(script, "get_name");
  500. lua_gettable(script, -2);
  501. if (lua_pcall(script, 0, 1, 0) == 0) {
  502. v->display_name = cstrcache_get(lua_tostring(script, -1));
  503. lua_pop(script, 1);
  504. }
  505. if (!v->display_name ||
  506. !*v->display_name ||
  507. !*info.id ||
  508. !info.output_flags)
  509. goto fail;
  510. #define get_callback(val) \
  511. do { \
  512. get_callback_from_table(script, -1, #val, &v->func_ ## val); \
  513. info.val = obs_lua_source_ ## val; \
  514. } while (false)
  515. get_callback(create);
  516. get_callback(destroy);
  517. get_callback(get_width);
  518. get_callback(get_height);
  519. get_callback(get_properties);
  520. get_callback(update);
  521. get_callback(activate);
  522. get_callback(deactivate);
  523. get_callback(show);
  524. get_callback(hide);
  525. get_callback(video_tick);
  526. get_callback(video_render);
  527. get_callback(save);
  528. get_callback(load);
  529. #undef get_callback
  530. get_callback_from_table(script, -1, "get_defaults",
  531. &v->func_get_defaults);
  532. if (!existing) {
  533. ls.data = current_lua_script;
  534. pthread_mutex_init(&ls.definition_mutex, NULL);
  535. info.type_data = bmemdup(&ls, sizeof(ls));
  536. info.free_type_data = obs_lua_source_free_type_data;
  537. info.get_name = obs_lua_source_get_name;
  538. info.get_defaults2 = obs_lua_source_get_defaults;
  539. obs_register_source(&info);
  540. pthread_mutex_lock(&lua_source_def_mutex);
  541. v = info.type_data;
  542. struct obs_lua_source *next = first_source_def;
  543. v->next = next;
  544. if (next) next->p_prev_next = &v->next;
  545. v->p_prev_next = &first_source_def;
  546. first_source_def = v;
  547. pthread_mutex_unlock(&lua_source_def_mutex);
  548. } else {
  549. existing->script = script;
  550. existing->data = current_lua_script;
  551. obs_enable_source_type(id, true);
  552. struct obs_lua_data *ld = v->first_source;
  553. while (ld) {
  554. struct obs_lua_source *ls = v;
  555. if (have_func(create)) {
  556. obs_source_t *source = ld->source;
  557. obs_data_t *settings = obs_source_get_settings(
  558. source);
  559. ls_push_libobs_obj(obs_data_t, settings, false);
  560. ls_push_libobs_obj(obs_source_t, source, false);
  561. call_func(create, 2, 1);
  562. ld->lua_data_ref = luaL_ref(ls->script,
  563. LUA_REGISTRYINDEX);
  564. obs_data_release(settings);
  565. }
  566. ld = ld->next;
  567. }
  568. }
  569. fail:
  570. if (existing) {
  571. pthread_mutex_unlock(&existing->definition_mutex);
  572. }
  573. return 0;
  574. }
  575. /* ========================================================================= */
  576. void add_lua_source_functions(lua_State *script)
  577. {
  578. lua_getglobal(script, "obslua");
  579. lua_pushstring(script, "obs_register_source");
  580. lua_pushcfunction(script, obs_lua_register_source);
  581. lua_rawset(script, -3);
  582. lua_pop(script, 1);
  583. }
  584. static inline void undef_source_type(struct obs_lua_script *data,
  585. struct obs_lua_source *ls)
  586. {
  587. pthread_mutex_lock(&ls->definition_mutex);
  588. pthread_mutex_lock(&data->mutex);
  589. obs_enable_source_type(ls->id, false);
  590. struct obs_lua_data *ld = ls->first_source;
  591. while (ld) {
  592. call_destroy(ld);
  593. ld = ld->next;
  594. }
  595. source_type_unload(ls);
  596. ls->script = NULL;
  597. pthread_mutex_unlock(&data->mutex);
  598. pthread_mutex_unlock(&ls->definition_mutex);
  599. }
  600. void undef_lua_script_sources(struct obs_lua_script *data)
  601. {
  602. pthread_mutex_lock(&lua_source_def_mutex);
  603. struct obs_lua_source *def = first_source_def;
  604. while (def) {
  605. if (def->script == data->script)
  606. undef_source_type(data, def);
  607. def = def->next;
  608. }
  609. pthread_mutex_unlock(&lua_source_def_mutex);
  610. }