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
);
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
);
317 /* ------------------------------------------------------------------------
318 * terminates all executables
320 int l_eventloop_kill_all (lua_State
*L
)
322 struct lel_eventloop
*el
;
325 el
= lel_checkeventloop (L
, 1);
327 for (i
=(el
->progs_count
-1); i
>=0; i
--) {
328 struct lel_program
*prog
;
331 kill_exec (L
, el
, prog
->fd
);
337 /* ------------------------------------------------------------------------
338 * read more data and call callbacks
341 static void prog_read_more (lua_State
*L
, struct lel_program
*prog
)
347 if (!prog
->buf_len
) {
348 // reset pos to beginning
352 buf
= prog
->buf
+ prog
->buf_pos
;
353 len
= LEL_PROGRAM_IO_BUF_SIZE
- prog
->buf_pos
- prog
->buf_len
;
357 if (! prog
->buf_pos
) {
358 // cannot shift data down
360 prog
->read_errno
= EBUSY
;
364 // shift data down to make some more room
365 memmove (prog
->buf
, buf
, prog
->buf_len
);
371 rc
= read (prog
->fd
, buf
, len
);
374 prog
->read_errno
= errno
;
383 static void lua_issue_callback (lua_State
*L
, struct lel_program
*prog
,
388 // backup top of stack
389 top
= lua_gettop (L
);
391 // find the call back function
392 luaL_getmetatable (L
, L_EVENTLOOP_MT
); // [-2] = get the table
393 lua_pushinteger (L
, prog
->fd
); // [-1] = the key
394 lua_gettable (L
, -2); // push (eventloop[fd])
398 lua_pushstring (L
, string
);
401 } else if (prog
->read_rc
== 0) {
404 lua_pushstring (L
, "EOF");
407 } else if (prog
->read_rc
< 0) {
410 lua_pushstring (L
, strerror(prog
->read_errno
));
414 // restore top of stack
418 static int loop_handle_event (lua_State
*L
, struct lel_program
*prog
)
422 prog_read_more (L
, prog
);
424 while (prog
->buf_len
) {
425 // as long as we have some data we try to find a full line
426 s
= prog
->buf
+ prog
->buf_pos
;
427 e
= s
+ prog
->buf_len
;
429 cr
= strchr (s
, '\n');
431 // we have a match: s..cr is our substring
432 int len
= (cr
-s
) + 1;
435 lua_issue_callback (L
, prog
, s
);
437 prog
->buf_pos
+= len
;
438 prog
->buf_len
-= len
;
440 } else if (!prog
->buf_pos
) {
441 // no match and we cannot even read more out of
442 // the buffer; we have to return the partial buffer
443 lua_issue_callback (L
, prog
, s
);
448 // no match, we will try to read more on next select()
454 return prog
->read_rc
;