PageRenderTime 64ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/lasync.c

http://luasync.googlecode.com/
C | 792 lines | 666 code | 120 blank | 6 comment | 130 complexity | ec4376c0819b050f58567c9efa2dbd52 MD5 | raw file
  1. /*
  2. * lasync.c
  3. * libevent binding for Lua 5.1
  4. * Copyright 2007 Gary Ng<linux@garyng.com>
  5. * This code can be distributed under the LGPL license
  6. */
  7. #include <stdio.h>
  8. #include <memory.h>
  9. #include <fcntl.h>
  10. #include <assert.h>
  11. #include <errno.h>
  12. #ifndef _WIN32
  13. #include <sys/socket.h>
  14. #include <sys/wait.h>
  15. #include <sys/time.h>
  16. #else
  17. #include <windows.h>
  18. #include <time.h>
  19. #endif
  20. #include <errno.h>
  21. #include <event.h>
  22. #define LUA_LIB
  23. #include "lua.h"
  24. #include "lauxlib.h"
  25. typedef struct {
  26. struct event_base *base;
  27. int dispatcher;
  28. int is_select;
  29. int event_fd_map;
  30. int event_obj_map;
  31. int r_cnt;
  32. int w_cnt;
  33. int rtab;
  34. int wtab;
  35. int o_rtab;
  36. int o_wtab;
  37. int dispatcher_idx;
  38. int fd_map_idx;
  39. int event_map_idx;
  40. int auto_requeue;
  41. int event_objects;
  42. lua_State *L;
  43. } libevent_context;
  44. typedef struct {
  45. struct event ev;
  46. int obj;
  47. int event_obj;
  48. int active;
  49. int fd;
  50. int want;
  51. int once;
  52. double timeout;
  53. libevent_context *libevent;
  54. } event_context;
  55. libevent_context libevent_handle;
  56. #define MYVERSION "Libevent for " LUA_VERSION " 0.1"
  57. #define MYEVENT "Libevent object"
  58. #define MYEVENT_BASE "Libevent base object"
  59. static void Pevent_call(int fd, short ev, void *arg)
  60. {
  61. event_context *p = arg;
  62. libevent_context *libevent = p->libevent;
  63. lua_State *L = libevent->L;
  64. int top = lua_gettop(L);
  65. struct timeval tv, *ptv = NULL;
  66. double t = p->timeout;
  67. int loop_dispatcher = libevent->dispatcher_idx > 0 && !lua_isnoneornil(L, libevent->dispatcher_idx);
  68. if (t >= 0) {
  69. tv.tv_sec = (int) t;
  70. tv.tv_usec = (t - tv.tv_sec)*1000000;
  71. ptv = &tv;
  72. }
  73. if (p->active == 0) return;
  74. lua_rawgeti(L, libevent->event_map_idx, p->event_obj);
  75. #if 0
  76. lua_pushinteger(L, p->event_obj);
  77. lua_gettable(L, libevent->event_map_idx);
  78. #endif
  79. if (lua_isuserdata(L,-1) &&
  80. luaL_checkudata(L,-1,MYEVENT) &&
  81. lua_touserdata(L,-1) == p) {
  82. unsigned char *actions[4]={NULL, NULL, NULL, NULL};
  83. int i;
  84. if (libevent->auto_requeue && !p->once) {
  85. event_add(&p->ev, ptv);
  86. }
  87. if (ev & EV_READ & p->want) actions[0] = "readable";
  88. if (ev & EV_WRITE & p->want) actions[1] = "writable";
  89. if (ev & EV_TIMEOUT & p->want) actions[2] = "timeout";
  90. if (ev & EV_SIGNAL & p->want) actions[3] = "signal";
  91. for (i = 0; i < sizeof(actions)/sizeof(unsigned char *); i++) {
  92. unsigned char *action;
  93. if (action = actions[i]) {
  94. lua_pushstring(L, action);
  95. if (loop_dispatcher) {
  96. lua_gettable(L, libevent->dispatcher_idx);
  97. if (!lua_isnil(L, -1)) {
  98. lua_pushvalue(L, libevent->dispatcher_idx);
  99. lua_pushvalue(L, -3);
  100. lua_call(L, 2, 0);
  101. } else {
  102. lua_pop(L,1);
  103. }
  104. } else {
  105. lua_gettable(L, -2);
  106. if (!lua_isnil(L, -1)) {
  107. lua_pushvalue(L, -2);
  108. lua_call(L, 1, 0);
  109. } else {
  110. lua_pop(L,1);
  111. }
  112. }
  113. }
  114. }
  115. }
  116. lua_pop(L,1);
  117. }
  118. void Pevent_select(int fd, short ev, void *arg)
  119. {
  120. event_context *p = arg;
  121. libevent_context *libevent = p->libevent;
  122. lua_State *L = libevent->L;
  123. int top = lua_gettop(L);
  124. if (fd == -1 || p->active == 0) return;
  125. lua_pushinteger(L, p->obj);
  126. lua_gettable(L, libevent->fd_map_idx);
  127. if (!lua_isnil(L, -1)) {
  128. if (ev & EV_READ && p->want & EV_READ) {
  129. p->want &= ~EV_READ;
  130. if (1 || !lua_isnil(L, -1)) { /* interested */
  131. libevent->r_cnt++;
  132. lua_pushinteger(L, libevent->r_cnt);
  133. lua_pushvalue(L, -2);
  134. lua_settable(L, libevent->o_rtab);
  135. lua_pushvalue(L, -1);
  136. lua_pushinteger(L, libevent->r_cnt);
  137. lua_settable(L, libevent->o_rtab);
  138. }
  139. }
  140. if (ev & EV_WRITE && p->want & EV_WRITE) {
  141. p->want &= ~EV_WRITE;
  142. if (1 || !lua_isnil(L, -1)) { /* interested */
  143. libevent->w_cnt++;
  144. lua_pushvalue(L, -1);
  145. lua_pushinteger(L, libevent->w_cnt);
  146. lua_settable(L, libevent->o_wtab);
  147. lua_pushinteger(L, libevent->w_cnt);
  148. lua_pushvalue(L, -2);
  149. lua_settable(L, libevent->o_wtab);
  150. }
  151. }
  152. }
  153. lua_pop(L,1);
  154. }
  155. static void Pevent_cb(int fd, short ev, void *arg)
  156. {
  157. event_context *p = arg;
  158. libevent_context *libevent = p->libevent;
  159. if (libevent->is_select) {
  160. Pevent_select(fd, ev, arg);
  161. } else {
  162. Pevent_call(fd, ev, arg);
  163. }
  164. }
  165. static event_context *Pevent(lua_State *L, int i, char *who)
  166. {
  167. if (!lua_isuserdata(L,i)) return NULL;
  168. if (luaL_checkudata(L,i,MYEVENT)==NULL) {
  169. return NULL;
  170. #if 0
  171. luaL_typerror(L,i,MYEVENT);
  172. #endif
  173. }
  174. return lua_touserdata(L,i);
  175. }
  176. static void Pevent_close(lua_State *L)
  177. {
  178. event_context *p = Pevent(L, 1,"event close");
  179. if (p->active) {
  180. event_del(&p->ev);
  181. lua_rawgeti(L, LUA_REGISTRYINDEX, p->libevent->event_fd_map);
  182. luaL_unref(L, -1, p->obj);
  183. lua_rawgeti(L, LUA_REGISTRYINDEX, p->libevent->event_obj_map);
  184. luaL_unref(L, -1, p->event_obj);
  185. p->event_obj = -1;
  186. p->obj = -1;
  187. lua_pop(L,2);
  188. }
  189. p->active = 0;
  190. }
  191. static int Levent_settimeout(lua_State *L)
  192. {
  193. event_context *p = Pevent(L, 1,"settimeout");
  194. int t = luaL_optinteger(L,2, -1);
  195. if (!p) return 0;
  196. if ((t < 0 && p->timeout >= 0) && (p->want & (EV_READ | EV_WRITE)) == 0) {
  197. event_del(&p->ev);
  198. p->active = 0;
  199. }
  200. else if ((t >= 0 && p->timeout < 0) && (p->want & (EV_READ | EV_WRITE)) == 0) {
  201. struct timeval tv, *ptv = NULL;
  202. if (t >= 0) {
  203. tv.tv_sec = (int) t;
  204. tv.tv_usec = (t - tv.tv_sec)*1000000;
  205. ptv = &tv;
  206. }
  207. if(p->fd >=0) event_add(&p->ev, ptv);
  208. else evtimer_add(&p->ev, ptv);
  209. p->active = 1;
  210. }
  211. p->timeout = t;
  212. return 0;
  213. }
  214. static int Levent_want(lua_State *L)
  215. {
  216. event_context *p = Pevent(L, 1,"want");
  217. int want = luaL_optinteger(L,2, EV_READ | EV_WRITE | EV_TIMEOUT | EV_SIGNAL);
  218. if (!p) return 0;
  219. p->want |= want;
  220. if (p->want & (EV_READ | EV_WRITE) || p->timeout >= 0.0) {
  221. struct timeval tv, *ptv = NULL;
  222. double t = p->timeout;
  223. if (t >= 0) {
  224. tv.tv_sec = (int) t;
  225. tv.tv_usec = (t - tv.tv_sec)*1000000;
  226. ptv = &tv;
  227. }
  228. if(p->fd >=0) event_add(&p->ev, ptv);
  229. else evtimer_add(&p->ev, ptv);
  230. p->active = 1;
  231. }
  232. return 0;
  233. }
  234. static int Levent_skip(lua_State *L)
  235. {
  236. event_context *p = Pevent(L, 1,"skip");
  237. int skip = luaL_optinteger(L, 2,0);
  238. if (!p) return 0;
  239. p->want &= ~skip;
  240. if ((p->want & (EV_READ | EV_WRITE)) == 0 && p->timeout < 0) {
  241. event_del(&p->ev);
  242. p->active = 0;
  243. }
  244. return 0;
  245. }
  246. static int Levent_gc(lua_State *L)
  247. {
  248. event_context *p = Pevent(L, 1,"gc");
  249. p->libevent->event_objects -=1;
  250. Pevent_close(L);
  251. #if 0
  252. lua_rawgeti(L, LUA_REGISTRYINDEX, p->libevent->event_fd_map);
  253. luaL_unref(L, -1, p->obj);
  254. lua_rawgeti(L, LUA_REGISTRYINDEX, p->libevent->event_obj_map);
  255. luaL_unref(L, -1, p->event_obj);
  256. #endif
  257. return 0;
  258. }
  259. static int Levent_object(lua_State *L)
  260. {
  261. event_context *p = Pevent(L, 1,"object");
  262. if (!p) return 0;
  263. lua_rawgeti(L, LUA_REGISTRYINDEX, p->libevent->event_fd_map);
  264. lua_rawgeti(L, -1, p->obj);
  265. if (lua_isnil(L, -1) && p->fd >= 0) {
  266. p->obj = -1;
  267. Pevent_close(L);
  268. }
  269. return 1;
  270. }
  271. static int Levent_getfd(lua_State *L)
  272. {
  273. event_context *p = Pevent(L, 1,"fd");
  274. if (!p) return 0;
  275. lua_pushnumber(L, p->fd);
  276. return 1;
  277. }
  278. static int Levent_close(lua_State *L)
  279. {
  280. #if 1
  281. Pevent_close(L);
  282. #endif
  283. return 0;
  284. }
  285. static int Levent_requeue(lua_State *L)
  286. {
  287. event_context *p = Pevent(L, 1,"requeue");
  288. struct timeval tv, *ptv = NULL;
  289. double t = p->timeout;
  290. if (t >= 0) {
  291. tv.tv_sec = (int) t;
  292. tv.tv_usec = (t - tv.tv_sec)*1000000;
  293. ptv = &tv;
  294. }
  295. if(p->fd >=0) event_add(&p->ev, ptv);
  296. else evtimer_add(&p->ev, ptv);
  297. return 0;
  298. }
  299. static int Levent_open(lua_State *L)
  300. {
  301. event_context *p = Pevent(L, 1,"open");
  302. double t = luaL_optnumber(L, 2, p->fd < 0 ? 0.1 : -1);
  303. struct timeval tv, *ptv = NULL;
  304. if (!p->active && p->event_obj >= 0) {
  305. if (t >= 0) {
  306. tv.tv_sec = (int) t;
  307. tv.tv_usec = (t - tv.tv_sec)*1000000;
  308. ptv = &tv;
  309. }
  310. if(p->fd >= 0) event_add(&p->ev, ptv);
  311. else evtimer_add(&p->ev, ptv);
  312. p->active = 1;
  313. p->timeout = t;
  314. }
  315. lua_pushvalue(L,1);
  316. return 1;
  317. }
  318. static int Levent_base(lua_State *L)
  319. {
  320. int auto_requeue = luaL_optinteger(L,2,1);
  321. libevent_context **p = lua_newuserdata(L, sizeof(libevent_context*));
  322. *p = &libevent_handle;
  323. (*p)->auto_requeue = auto_requeue;
  324. luaL_getmetatable(L, MYEVENT_BASE);
  325. lua_setmetatable(L,-2);
  326. if (lua_istable(L,1) || lua_isuserdata(L,1)) {
  327. lua_pushvalue(L,1);
  328. (*p)->dispatcher = luaL_ref(L, LUA_REGISTRYINDEX);
  329. } else {
  330. (*p)->dispatcher = -1;
  331. }
  332. return 1;
  333. }
  334. static libevent_context **Pevent_base(lua_State *L, int i)
  335. {
  336. if (luaL_checkudata(L,i,MYEVENT_BASE)==NULL) {
  337. luaL_typerror(L,i,MYEVENT_BASE);
  338. }
  339. return lua_touserdata(L,i);
  340. }
  341. static int Levent_base_close(lua_State *L)
  342. {
  343. libevent_context *libevent = *Pevent_base(L, 1);
  344. if (libevent->dispatcher != -1) {
  345. luaL_unref(L, LUA_REGISTRYINDEX, libevent->dispatcher);
  346. libevent->dispatcher = -1;
  347. }
  348. }
  349. static int Levent_loopexit(lua_State *L)
  350. {
  351. struct timeval tv, *ptv = NULL;
  352. libevent_context *libevent = *Pevent_base(L, 1);
  353. tv.tv_sec = (int) 0;
  354. tv.tv_usec = 0;
  355. ptv = &tv;
  356. event_base_loopexit(libevent->base, NULL);
  357. return 0;
  358. }
  359. static int Levent_loop(lua_State *L)
  360. {
  361. libevent_context *libevent = *Pevent_base(L, 1);
  362. int once = luaL_optinteger(L,3,0);
  363. int flags = once ? EVLOOP_NONBLOCK | EVLOOP_ONCE : 0;
  364. int ret;
  365. int top = lua_gettop(L);
  366. libevent->r_cnt = 0;
  367. libevent->w_cnt = 0;
  368. libevent->rtab = -1;
  369. libevent->wtab = -1;
  370. libevent->o_rtab = -1;
  371. libevent->o_wtab = -1;
  372. libevent->L = L;
  373. libevent->is_select = 0;
  374. lua_settop(L, 4);
  375. if (lua_istable(L,2) || lua_isuserdata(L,2)) {
  376. lua_pushvalue(L,2);
  377. } else if (libevent->dispatcher > 0)
  378. lua_rawgeti(L, LUA_REGISTRYINDEX, libevent->dispatcher); /* don't do it in the call back */
  379. else
  380. lua_pushnil(L);
  381. libevent->dispatcher_idx = lua_gettop(L);
  382. lua_rawgeti(L, LUA_REGISTRYINDEX, libevent->event_fd_map); /* don't do it in the call back */
  383. libevent->fd_map_idx = lua_gettop(L);
  384. lua_rawgeti(L, LUA_REGISTRYINDEX, libevent->event_obj_map); /* don't do it in the call back */
  385. libevent->event_map_idx = lua_gettop(L);
  386. ret = event_base_loop(libevent->base, flags);
  387. if (ret < 0) {
  388. lua_pushnil(L);
  389. lua_pushnumber(L,ret);
  390. lua_pushstring(L,strerror(errno));
  391. return 3;
  392. }
  393. else {
  394. lua_pushnumber(L,1);
  395. return 1;
  396. }
  397. }
  398. static int Levent_select(lua_State *L)
  399. {
  400. libevent_context *libevent = *Pevent_base(L, 1);
  401. double t = luaL_optnumber(L, 4, -1);
  402. int flags = EVLOOP_ONCE;
  403. int i = 0;
  404. int itab, rtab, wtab;
  405. event_context tout;
  406. struct timeval tv, *ptv = NULL;
  407. if (t >= 0.0) {
  408. tv.tv_sec = (int) t;
  409. tv.tv_usec = (t - tv.tv_sec)*1000000;
  410. tout.libevent = libevent;
  411. evtimer_set(&tout.ev, Pevent_cb, &tout);
  412. evtimer_add(&tout.ev, &tv);
  413. flags |= EVLOOP_NONBLOCK;
  414. ptv = &tv;
  415. }
  416. lua_settop(L, 4);
  417. lua_rawgeti(L, LUA_REGISTRYINDEX, libevent->event_fd_map); /* don't do it in the call back */
  418. libevent->fd_map_idx = lua_gettop(L);
  419. lua_newtable(L); rtab = lua_gettop(L);
  420. lua_newtable(L); wtab = lua_gettop(L);
  421. libevent->r_cnt = 0;
  422. libevent->w_cnt = 0;
  423. libevent->rtab = 2;
  424. libevent->wtab = 3;
  425. libevent->o_rtab = rtab;
  426. libevent->o_wtab = wtab;
  427. libevent->L = L;
  428. libevent->is_select = 1;
  429. libevent->dispatcher_idx = -1;
  430. i=0;
  431. while (++i) {
  432. int dirty = 0;
  433. lua_pushnumber(L,i);
  434. lua_gettable(L, 2);
  435. if (lua_isnil(L,-1)) {
  436. lua_pop(L,1);
  437. break;
  438. }
  439. lua_pushstring(L,"dirty");
  440. lua_gettable(L,-2);
  441. if (!lua_isnil(L, -1)) {
  442. lua_pushvalue(L,-2);
  443. lua_call(L, 1, 1);
  444. dirty = lua_toboolean(L, -1);
  445. }
  446. lua_pop(L,1);
  447. if (dirty) {
  448. lua_pushnumber(L, ++libevent->r_cnt);
  449. lua_pushvalue(L,-2);
  450. lua_settable(L, libevent->o_rtab);
  451. lua_pushnumber(L, libevent->r_cnt);
  452. lua_settable(L, libevent->o_rtab);
  453. } else {
  454. lua_pushstring(L,"event");
  455. lua_gettable(L,-2);
  456. if (!lua_isnil(L, -1)) {
  457. event_context *p = Pevent(L, -1, "select");
  458. p->want = EV_READ;
  459. }
  460. lua_pop(L,2);
  461. }
  462. }
  463. i=0;
  464. while (++i) {
  465. lua_pushnumber(L,i);
  466. lua_gettable(L, 3);
  467. if (lua_isnil(L,-1)) {
  468. lua_pop(L,1);
  469. break;
  470. }
  471. lua_pushstring(L,"event");
  472. lua_gettable(L,-2);
  473. if (!lua_isnil(L, -1)) {
  474. event_context *p = Pevent(L, -1, "select");
  475. p->want |= EV_WRITE;
  476. }
  477. lua_pop(L,2);
  478. }
  479. event_base_loop(libevent->base, flags);
  480. if (t >= 0.0) evtimer_del(&tout.ev);
  481. return 2;
  482. }
  483. static int Levent_state(lua_State *L)
  484. {
  485. libevent_context *libevent = *Pevent_base(L, 1);
  486. lua_pushnumber(L, libevent->event_objects);
  487. return 1;
  488. }
  489. static int Levent(lua_State *L)
  490. {
  491. libevent_context *libevent = *Pevent_base(L, 1);
  492. const int fd = luaL_checkinteger(L, 2);
  493. event_context *p;
  494. int map_idx,event_map_idx;
  495. if (lua_isnoneornil(L,3)) luaL_error(L,"lasync.event: parameter #2 must be an object");
  496. lua_settop(L, 4);
  497. lua_rawgeti(L, LUA_REGISTRYINDEX, libevent->event_fd_map);
  498. map_idx = lua_gettop(L);
  499. lua_rawgeti(L, LUA_REGISTRYINDEX, libevent->event_obj_map);
  500. event_map_idx = lua_gettop(L);
  501. p = lua_newuserdata(L,sizeof(event_context));
  502. if (lua_isnoneornil(L,4)) {
  503. p->once = fd < 0;
  504. }
  505. else {
  506. p->once = luaL_checkinteger(L,4);
  507. }
  508. p->timeout = fd < 0 ? 0.1 : -1;
  509. p->fd = fd;
  510. p->active = 0;
  511. if (fd < 0)
  512. p->want = EV_TIMEOUT;
  513. else
  514. p->want = EV_READ | EV_WRITE | EV_SIGNAL | EV_TIMEOUT;
  515. p->libevent = libevent;
  516. if (fd >= 0) event_set(&p->ev, fd, EV_READ | EV_WRITE, Pevent_cb, p);
  517. else evtimer_set(&p->ev, Pevent_cb, p);
  518. luaL_getmetatable(L, MYEVENT);
  519. lua_setmetatable(L,-2);
  520. lua_pushvalue(L, 3);
  521. p->obj = luaL_ref(L, map_idx);
  522. lua_pushvalue(L, -1);
  523. p->event_obj = luaL_ref(L, event_map_idx);
  524. libevent->event_objects += 1;
  525. return 1;
  526. }
  527. static int Lprobe_read(lua_State *L)
  528. {
  529. #ifndef _WIN32
  530. int fd = luaL_checkinteger(L,1);
  531. int i = 0;
  532. struct {
  533. char buf[1];
  534. struct msghdr msg;
  535. struct iovec iov;
  536. } msg;
  537. int ret;
  538. memset(&msg,0,sizeof(msg));
  539. msg.iov.iov_base = msg.buf;
  540. msg.iov.iov_len = sizeof(msg.buf);
  541. msg.msg.msg_iov = &msg.iov;
  542. msg.msg.msg_iovlen = 1;
  543. for (i = 0; i < 1; i++) {
  544. ret = sendmsg(fd, &msg.msg, i == 0 ? MSG_PEEK : 0);
  545. if (ret <= 0) {
  546. if (errno != EOPNOTSUPP || i == 1) {
  547. lua_pushnil(L);
  548. if (errno == EAGAIN || errno == EWOULDBLOCK) lua_pushstring(L,"timeout");
  549. else lua_pushstring(L,"closed");
  550. return 2;
  551. }
  552. } else {
  553. lua_pushboolean(L, 1);
  554. return 1;
  555. }
  556. }
  557. #else
  558. return 0;
  559. #endif
  560. }
  561. static int Lprobe(lua_State *L)
  562. {
  563. #ifndef _WIN32
  564. int fd = luaL_checkinteger(L,1);
  565. int i = 0;
  566. struct {
  567. char buf[1];
  568. struct msghdr msg;
  569. struct iovec iov;
  570. } msg;
  571. int ret;
  572. memset(&msg,0,sizeof(msg));
  573. msg.iov.iov_base = msg.buf;
  574. msg.iov.iov_len = sizeof(msg.buf);
  575. msg.msg.msg_iov = &msg.iov;
  576. msg.msg.msg_iovlen = 1;
  577. for (i = 0; i < 2; i++) {
  578. ret = sendmsg(fd, &msg.msg, i == 0 ? MSG_OOB : 0);
  579. if (ret <= 0) {
  580. if (errno != EOPNOTSUPP || i == 1) {
  581. lua_pushnil(L);
  582. if (errno == EAGAIN || errno == EWOULDBLOCK) lua_pushstring(L,"timeout");
  583. else lua_pushstring(L,"closed");
  584. return 2;
  585. }
  586. } else {
  587. lua_pushboolean(L, 1);
  588. return 1;
  589. }
  590. }
  591. #else
  592. return 0;
  593. #endif
  594. }
  595. static const luaL_reg Rm[] = {
  596. { "probe", Lprobe },
  597. { "probe_read", Lprobe_read},
  598. { "handle", Levent_base },
  599. { NULL, NULL }
  600. };
  601. static const luaL_reg Rbase[] = {
  602. { "event", Levent },
  603. { "state", Levent_state },
  604. { "select", Levent_select},
  605. { "loop", Levent_loop},
  606. { "loopexit", Levent_loopexit},
  607. { NULL, NULL }
  608. };
  609. static const luaL_reg Revent[] = {
  610. { "__gc", Levent_gc },
  611. { "object", Levent_object},
  612. { "getfd", Levent_getfd},
  613. { "close", Levent_close},
  614. { "want", Levent_want},
  615. { "settimeout", Levent_settimeout},
  616. { "skip", Levent_skip},
  617. { "open", Levent_open},
  618. { "requeue", Levent_requeue},
  619. { NULL, NULL },
  620. };
  621. LUA_API int luaopen_lasync(lua_State *L)
  622. {
  623. struct event_base *base;
  624. base = event_init();
  625. if (!base) {
  626. luaL_error(L,"luaevent: failed to allocate libevent handle base");
  627. }
  628. libevent_handle.base = base;
  629. luaL_newmetatable(L,MYEVENT);
  630. lua_pushliteral(L,"__index");
  631. lua_pushvalue(L,-2);
  632. lua_settable(L,-3);
  633. luaL_openlib(L,NULL,Revent,0);
  634. luaL_newmetatable(L,MYEVENT_BASE);
  635. lua_pushliteral(L,"__index");
  636. lua_pushvalue(L,-2);
  637. lua_settable(L,-3);
  638. luaL_openlib(L,NULL,Rbase,0);
  639. lua_newtable(L); /* fdmap */
  640. lua_newtable(L); /* fdmap metatable {__mode="kv"} */
  641. lua_pushliteral(L,"__mode");
  642. lua_pushstring(L,"v");
  643. lua_settable(L,-3);
  644. lua_setmetatable(L, -2);
  645. libevent_handle.event_fd_map = luaL_ref(L, LUA_REGISTRYINDEX);
  646. lua_newtable(L); /* event map */
  647. lua_newtable(L); /* event map metatable {__mode="kv"} */
  648. lua_pushliteral(L,"__mode");
  649. lua_pushstring(L,"v");
  650. lua_settable(L,-3);
  651. lua_setmetatable(L, -2);
  652. libevent_handle.event_obj_map = luaL_ref(L, LUA_REGISTRYINDEX);
  653. libevent_handle.L = L;
  654. libevent_handle.dispatcher = -1;
  655. luaL_openlib(L,"lasync",Rm,0);
  656. lua_pushliteral(L,"version"); /** version */
  657. lua_pushliteral(L,MYVERSION);
  658. lua_settable(L,-3);
  659. lua_pushliteral(L,"EV_READ");
  660. lua_pushinteger(L,EV_READ);
  661. lua_settable(L,-3);
  662. lua_pushliteral(L,"EV_WRITE");
  663. lua_pushinteger(L,EV_WRITE);
  664. lua_settable(L,-3);
  665. lua_pushliteral(L,"EV_TIMEOUT");
  666. lua_pushinteger(L,EV_TIMEOUT);
  667. lua_settable(L,-3);
  668. lua_pushliteral(L,"EV_SIGNAL");
  669. lua_pushinteger(L,EV_SIGNAL);
  670. lua_settable(L,-3);
  671. return 1;
  672. }