11 #include <sys/types.h>
17 #include "lel_debug.h"
19 #include "lel_instance.h"
22 static int loop_handle_event (lua_State
*L
, struct lel_program
*prog
);
23 static void kill_exec (lua_State
*L
, struct lel_eventloop
*el
, int fd
);
25 /* ------------------------------------------------------------------------
29 struct lel_eventloop
*lel_checkeventloop (lua_State
*L
, int narg
)
31 void *ud
= luaL_checkudata (L
, narg
, L_EVENTLOOP_MT
);
32 luaL_argcheck (L
, ud
!= NULL
, 1, "`eventloop' expected");
33 return (struct lel_eventloop
*)ud
;
36 int l_eventloop_tostring (lua_State
*L
)
38 struct lel_eventloop
*el
= lel_checkeventloop (L
, 1);
39 lua_pushfstring (L
, "eventloop instance %p", el
);
43 /* ------------------------------------------------------------------------
44 * dealing with program list
47 static int progs_compare (const void *_one
, const void *_two
)
49 const struct lel_program
*const*one
= _one
;
50 const struct lel_program
*const*two
= _two
;
52 return (*one
)->fd
- (*two
)->fd
;
55 static void progs_add (struct lel_eventloop
*el
, struct lel_program
*prog
)
58 if (el
->progs_size
<= el
->progs_count
) {
61 el
->progs_size
+= LEL_PROGS_ARRAY_GROWS_BY
;
62 bytes
= el
->progs_size
* sizeof(struct lel_program
*);
64 el
->progs
= realloc (el
->progs
, bytes
);
66 // TODO: we could handle this better then blowing away
67 // all of our data if we run out of room. For now exit.
73 el
->progs
[el
->progs_count
++] = prog
;
75 qsort (el
->progs
, el
->progs_count
, sizeof (struct lel_program
*),
79 static struct lel_program
* progs_remove (struct lel_eventloop
*el
, int fd
)
81 struct lel_program key
= {.fd
= fd
};
82 struct lel_program
*pkey
= &key
;
83 struct lel_program
*found
;
84 struct lel_program
**pfound
;
88 pfound
= bsearch (&pkey
, el
->progs
, el
->progs_count
,
89 sizeof (struct lel_program
*), progs_compare
);
97 // adjust remaining entries
99 end_bytes
= (char*)(el
->progs
+ el
->progs_count
) - (char*)pfound
;
100 memmove (pfound
, pfound
+1, end_bytes
);
106 /* ------------------------------------------------------------------------
107 * executes a new process to handle events from another source
109 * lua: fd = el:add_exec(cmd, function)
111 * cmd - a string with program and parameters for execution
112 * function - a function to call back with data read
113 * fd - returned is the file descriptor or nil on error
116 int l_eventloop_add_exec (lua_State
*L
)
118 struct lel_eventloop
*el
;
119 struct lel_program
*prog
;
121 int pfds
[2]; // 0 is server, 1 is client
124 el
= lel_checkeventloop (L
, 1);
125 cmd
= luaL_checkstring (L
, 2);
126 (void)luaL_checktype (L
, 3, LUA_TFUNCTION
);
128 DBGF("** eventloop:add_exec (%s, ...) **\n", cmd
);
130 // create a new program entry
131 prog
= (struct lel_program
*) malloc (sizeof (struct lel_program
)
132 // we allocate the buffer and room for a terminator at the end
133 + LEL_PROGRAM_IO_BUF_SIZE
+ 1);
135 return lel_pusherror (L
, "failed to allocate program structure");
137 // spawn off a worker process
141 return lel_pusherror (L
, "failed to create a pipe");
145 if (pid
<0) { // fork failed...
149 return lel_pusherror (L
, "failed to fork()");
152 if (! pid
) { // client...
153 close (pfds
[0]); // close the server end
154 dup2(pfds
[1], 1); // stdout to client's end of pipe
155 close (pfds
[1]); // close the client end
156 execlp ("sh", "sh", "-c", cmd
, NULL
);
161 close (pfds
[1]); // close the client end
163 // time to setup the program entry
164 memset (prog
, 0, sizeof(*prog
));
166 prog
->cmd
= strdup (cmd
);
170 if (el
->max_fd
< prog
->fd
)
171 el
->max_fd
= prog
->fd
;
173 FD_SET (prog
->fd
, &el
->all_fds
);
176 progs_add (el
, prog
);
178 // everything is setup, but we need to get a hold of the function later;
179 // we add the function to the L_EVENTLOOP_MT with the fd as the key...
180 luaL_getmetatable (L
, L_EVENTLOOP_MT
); // [-3] = get the table
181 lua_pushinteger (L
, prog
->fd
); // [-2] = the key
182 lua_pushvalue (L
, 3); // [-1] = the function (3rd arg)
183 lua_settable (L
, -3); // eventloop[fd] = function
185 lua_pushinteger (L
, prog
->fd
);
189 /* ------------------------------------------------------------------------
190 * checks if an executable is still running
192 * lua: running = el:check_exec(fd)
194 * fd - file descriptor returned from el:add_exec()
195 * running - boolean indicating if it's still running
198 int l_eventloop_check_exec (lua_State
*L
)
200 struct lel_eventloop
*el
;
204 el
= lel_checkeventloop(L
, 1);
205 fd
= luaL_checknumber(L
, 2);
207 DBGF("** eventloop:check_exec (%d) **\n", fd
);
209 for (i
=(el
->progs_count
-1); i
>=0; i
--) {
210 struct lel_program
*prog
;
221 lua_pushboolean(L
, found
);
226 /* ------------------------------------------------------------------------
227 * kills off a previously spawned off process and cleans up
228 * (actually, it just closes the fifo)
230 * lua: el:kill_exec(fd)
232 * fd - return from add_exec()
235 int l_eventloop_kill_exec (lua_State
*L
)
237 struct lel_eventloop
*el
;
240 el
= lel_checkeventloop (L
, 1);
241 fd
= luaL_checknumber (L
, 2);
243 DBGF("** eventloop:kill_exec (%d) **\n", fd
);
245 kill_exec (L
, el
, fd
);
250 static void kill_exec (lua_State
*L
, struct lel_eventloop
*el
, int fd
)
252 struct lel_program
*prog
;
255 prog
= progs_remove (el
, fd
);
259 if (el
->max_fd
== prog
->fd
) {
261 // last entry is the new max
262 el
->max_fd
= el
->progs
[el
->progs_count
-1]->fd
;
264 // there are no more entries
268 FD_CLR (prog
->fd
, &el
->all_fds
);
270 kill (prog
->pid
, SIGTERM
);
274 // catchup on programs that quit
275 while (waitpid (-1, &status
, WNOHANG
) > 0);
277 // and we still have to remove it from the table
278 luaL_getmetatable (L
, L_EVENTLOOP_MT
); // [-3] = get the table
279 lua_pushinteger (L
, prog
->fd
); // [-2] = the key
280 lua_pushnil (L
); // [-1] = nil
281 lua_settable (L
, -3); // eventloop[fd] = nil
284 lua_gc (L
, LUA_GCSTEP
, 10);
287 /* ------------------------------------------------------------------------
288 * runs the select loop over all registered execs with timeout
290 * lua: el.run_loop (timeout)
292 int l_eventloop_run_loop (lua_State
*L
)
294 struct lel_eventloop
*el
;
299 el
= lel_checkeventloop (L
, 1);
300 timeout
= luaL_optnumber (L
, 2, 0);
302 DBGF("** eventloop:run_loop (%d) **\n", timeout
);
309 while (el
->progs_count
) {
312 // catchup on programs that quit
313 while (waitpid (-1, &status
, WNOHANG
) > 0);
319 // wait for the next event
320 rc
= select (el
->max_fd
+1, &rfds
, NULL
, &xfds
, &tv
);
322 return lel_pusherror (L
, "select failed");
328 for (i
=(el
->progs_count
-1); i
>=0; i
--) {
329 struct lel_program
*prog
;
334 if (FD_ISSET (prog
->fd
, &rfds
)) {
335 rc
= loop_handle_event (L
, prog
);
339 // count could have changed in callback
340 if (i
>= el
->progs_count
)
344 if (dead
/* || FD_ISSET (prog->fd, &xfds) */ ) {
345 DBGF("** killing %d (fd=%d) **\n",
346 prog
->pid
, prog
->fd
);
347 kill_exec(L
, el
, prog
->fd
);
352 // catchup on programs that quit
353 while (waitpid (-1, &status
, WNOHANG
) > 0);
358 /* ------------------------------------------------------------------------
359 * terminates all executables
361 int l_eventloop_kill_all (lua_State
*L
)
363 struct lel_eventloop
*el
;
366 el
= lel_checkeventloop (L
, 1);
368 for (i
=(el
->progs_count
-1); i
>=0; i
--) {
369 struct lel_program
*prog
;
372 kill_exec (L
, el
, prog
->fd
);
378 /* ------------------------------------------------------------------------
379 * read more data and call callbacks
382 static void prog_read_more (lua_State
*L
, struct lel_program
*prog
)
388 if (!prog
->buf_len
) {
389 // reset pos to beginning
393 buf
= prog
->buf
+ prog
->buf_pos
;
394 len
= LEL_PROGRAM_IO_BUF_SIZE
- prog
->buf_pos
- prog
->buf_len
;
398 if (! prog
->buf_pos
) {
399 // cannot shift data down
401 prog
->read_errno
= EBUSY
;
405 // shift data down to make some more room
406 memmove (prog
->buf
, buf
, prog
->buf_len
);
412 rc
= read (prog
->fd
, buf
, len
);
415 prog
->read_errno
= errno
;
424 static void lua_issue_callback (lua_State
*L
, struct lel_program
*prog
,
429 // backup top of stack
430 top
= lua_gettop (L
);
432 // find the call back function
433 luaL_getmetatable (L
, L_EVENTLOOP_MT
); // [-2] = get the table
434 lua_pushinteger (L
, prog
->fd
); // [-1] = the key
435 lua_gettable (L
, -2); // push (eventloop[fd])
439 lua_pushstring (L
, string
);
442 } else if (prog
->read_rc
== 0) {
445 lua_pushstring (L
, "EOF");
448 } else if (prog
->read_rc
< 0) {
451 lua_pushstring (L
, strerror(prog
->read_errno
));
455 // restore top of stack
459 static int loop_handle_event (lua_State
*L
, struct lel_program
*prog
)
463 prog_read_more (L
, prog
);
465 while (prog
->buf_len
) {
466 // as long as we have some data we try to find a full line
467 s
= prog
->buf
+ prog
->buf_pos
;
468 e
= s
+ prog
->buf_len
;
470 cr
= strchr (s
, '\n');
472 // we have a match: s..cr is our substring
473 int len
= (cr
-s
) + 1;
476 lua_issue_callback (L
, prog
, s
);
478 prog
->buf_pos
+= len
;
479 prog
->buf_len
-= len
;
481 } else if (!prog
->buf_pos
) {
482 // no match and we cannot even read more out of
483 // the buffer; we have to return the partial buffer
484 lua_issue_callback (L
, prog
, s
);
489 // no match, we will try to read more on next select()
495 return prog
->read_rc
;