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
, pid
);
189 /* ------------------------------------------------------------------------
190 * kills off a previously spawned off process and cleans up
191 * (actually, it just closes the fifo)
193 * lua: el:kill_exec(fd)
195 * fd - return from add_exec()
198 int l_eventloop_kill_exec (lua_State
*L
)
200 struct lel_eventloop
*el
;
203 el
= lel_checkeventloop (L
, 1);
204 fd
= luaL_checknumber (L
, 2);
206 DBGF("** eventloop:kill_exec (%d) **\n", fd
);
208 kill_exec (L
, el
, fd
);
213 static void kill_exec (lua_State
*L
, struct lel_eventloop
*el
, int fd
)
215 struct lel_program
*prog
;
218 prog
= progs_remove (el
, fd
);
222 if (el
->max_fd
== prog
->fd
) {
224 // last entry is the new max
225 el
->max_fd
= el
->progs
[el
->progs_count
-1]->fd
;
227 // there are no more entries
231 FD_CLR (prog
->fd
, &el
->all_fds
);
233 kill (prog
->pid
, SIGTERM
);
237 // catchup on programs that quit
238 while (waitpid (-1, &status
, WNOHANG
) > 0);
240 // and we still have to remove it from the table
241 luaL_getmetatable (L
, L_EVENTLOOP_MT
); // [-3] = get the table
242 lua_pushinteger (L
, prog
->fd
); // [-2] = the key
243 lua_pushnil (L
); // [-1] = nil
244 lua_settable (L
, -3); // eventloop[fd] = function
247 lua_gc (L
, LUA_GCSTEP
, 10);
250 /* ------------------------------------------------------------------------
251 * runs the select loop over all registered execs with timeout
253 * lua: el.run_loop (timeout)
255 int l_eventloop_run_loop (lua_State
*L
)
257 struct lel_eventloop
*el
;
262 el
= lel_checkeventloop (L
, 1);
263 timeout
= luaL_optnumber (L
, 2, 0);
265 DBGF("** eventloop:run_loop (%d) **\n", timeout
);
272 while (el
->progs_count
) {
275 // catchup on programs that quit
276 while (waitpid (-1, &status
, WNOHANG
) > 0);
281 // wait for the next event
282 rc
= select (el
->max_fd
+1, &rfds
, NULL
, &xfds
, &tv
);
284 return lel_pusherror (L
, "select failed");
290 for (i
=(el
->progs_count
-1); i
>=0; i
--) {
291 struct lel_program
*prog
;
296 if (FD_ISSET (prog
->fd
, &rfds
)) {
297 rc
= loop_handle_event (L
, prog
);
301 // count could have changed in callback
302 if (i
>= el
->progs_count
)
306 if (dead
/* || FD_ISSET (prog->fd, &xfds) */ ) {
307 DBGF("** killing %d (fd=%d) **\n",
308 prog
->pid
, prog
->fd
);
309 kill_exec(L
, el
, prog
->fd
);
314 // catchup on programs that quit
315 while (waitpid (-1, &status
, WNOHANG
) > 0);
320 /* ------------------------------------------------------------------------
321 * terminates all executables
323 int l_eventloop_kill_all (lua_State
*L
)
325 struct lel_eventloop
*el
;
328 el
= lel_checkeventloop (L
, 1);
330 for (i
=(el
->progs_count
-1); i
>=0; i
--) {
331 struct lel_program
*prog
;
334 kill_exec (L
, el
, prog
->fd
);
340 /* ------------------------------------------------------------------------
341 * read more data and call callbacks
344 static void prog_read_more (lua_State
*L
, struct lel_program
*prog
)
350 if (!prog
->buf_len
) {
351 // reset pos to beginning
355 buf
= prog
->buf
+ prog
->buf_pos
;
356 len
= LEL_PROGRAM_IO_BUF_SIZE
- prog
->buf_pos
- prog
->buf_len
;
360 if (! prog
->buf_pos
) {
361 // cannot shift data down
363 prog
->read_errno
= EBUSY
;
367 // shift data down to make some more room
368 memmove (prog
->buf
, buf
, prog
->buf_len
);
374 rc
= read (prog
->fd
, buf
, len
);
377 prog
->read_errno
= errno
;
386 static void lua_issue_callback (lua_State
*L
, struct lel_program
*prog
,
391 // backup top of stack
392 top
= lua_gettop (L
);
394 // find the call back function
395 luaL_getmetatable (L
, L_EVENTLOOP_MT
); // [-2] = get the table
396 lua_pushinteger (L
, prog
->fd
); // [-1] = the key
397 lua_gettable (L
, -2); // push (eventloop[fd])
401 lua_pushstring (L
, string
);
404 } else if (prog
->read_rc
== 0) {
407 lua_pushstring (L
, "EOF");
410 } else if (prog
->read_rc
< 0) {
413 lua_pushstring (L
, strerror(prog
->read_errno
));
417 // restore top of stack
421 static int loop_handle_event (lua_State
*L
, struct lel_program
*prog
)
425 prog_read_more (L
, prog
);
427 while (prog
->buf_len
) {
428 // as long as we have some data we try to find a full line
429 s
= prog
->buf
+ prog
->buf_pos
;
430 e
= s
+ prog
->buf_len
;
432 cr
= strchr (s
, '\n');
434 // we have a match: s..cr is our substring
435 int len
= (cr
-s
) + 1;
438 lua_issue_callback (L
, prog
, s
);
440 prog
->buf_pos
+= len
;
441 prog
->buf_len
-= len
;
443 } else if (!prog
->buf_pos
) {
444 // no match and we cannot even read more out of
445 // the buffer; we have to return the partial buffer
446 lua_issue_callback (L
, prog
, s
);
451 // no match, we will try to read more on next select()
457 return prog
->read_rc
;