|
Packit |
437b5e |
/*
|
|
Packit |
437b5e |
* POSIX library for Lua 5.1, 5.2 & 5.3.
|
|
Packit |
437b5e |
* (c) Gary V. Vaughan <gary@vaughan.pe>, 2013-2015
|
|
Packit |
437b5e |
* (c) Reuben Thomas <rrt@sc3d.org> 2010-2013
|
|
Packit |
437b5e |
* (c) Natanael Copa <natanael.copa@gmail.com> 2008-2010
|
|
Packit |
437b5e |
* Clean up and bug fixes by Leo Razoumov <slonik.az@gmail.com> 2006-10-11
|
|
Packit |
437b5e |
* Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br> 07 Apr 2006 23:17:49
|
|
Packit |
437b5e |
* Based on original by Claudio Terra for Lua 3.x.
|
|
Packit |
437b5e |
* With contributions by Roberto Ierusalimschy.
|
|
Packit |
437b5e |
* With documentation from Steve Donovan 2012
|
|
Packit |
437b5e |
*/
|
|
Packit |
437b5e |
/***
|
|
Packit |
437b5e |
Synchronous I/O Multiplexing.
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
Examine file descriptors for events, such as readyness for I/O.
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
@module posix.poll
|
|
Packit |
437b5e |
*/
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
#include <config.h>
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
#include <poll.h>
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
#include "_helpers.c"
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
static struct {
|
|
Packit |
437b5e |
short bit;
|
|
Packit |
437b5e |
const char *name;
|
|
Packit |
437b5e |
} poll_event_map[] = {
|
|
Packit |
437b5e |
#define MAP(_NAME) \
|
|
Packit |
437b5e |
{POLL##_NAME, #_NAME}
|
|
Packit |
437b5e |
MAP(IN),
|
|
Packit |
437b5e |
MAP(PRI),
|
|
Packit |
437b5e |
MAP(OUT),
|
|
Packit |
437b5e |
MAP(ERR),
|
|
Packit |
437b5e |
MAP(HUP),
|
|
Packit |
437b5e |
MAP(NVAL),
|
|
Packit |
437b5e |
#undef MAP
|
|
Packit |
437b5e |
};
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
#define PPOLL_EVENT_NUM (sizeof(poll_event_map) / sizeof(*poll_event_map))
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
static void
|
|
Packit |
437b5e |
poll_events_createtable(lua_State *L)
|
|
Packit |
437b5e |
{
|
|
Packit |
437b5e |
lua_createtable(L, 0, PPOLL_EVENT_NUM);
|
|
Packit |
437b5e |
}
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
static short
|
|
Packit |
437b5e |
poll_events_from_table(lua_State *L, int table)
|
|
Packit |
437b5e |
{
|
|
Packit |
437b5e |
short events = 0;
|
|
Packit |
437b5e |
size_t i;
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/* Convert to absolute index */
|
|
Packit |
437b5e |
if (table < 0)
|
|
Packit |
437b5e |
table = lua_gettop(L) + table + 1;
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
for (i = 0; i < PPOLL_EVENT_NUM; i++)
|
|
Packit |
437b5e |
{
|
|
Packit |
437b5e |
lua_getfield(L, table, poll_event_map[i].name);
|
|
Packit |
437b5e |
if (lua_toboolean(L, -1))
|
|
Packit |
437b5e |
events |= poll_event_map[i].bit;
|
|
Packit |
437b5e |
lua_pop(L, 1);
|
|
Packit |
437b5e |
}
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
return events;
|
|
Packit |
437b5e |
}
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
static void
|
|
Packit |
437b5e |
poll_events_to_table(lua_State *L, int table, short events)
|
|
Packit |
437b5e |
{
|
|
Packit |
437b5e |
size_t i;
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/* Convert to absolute index */
|
|
Packit |
437b5e |
if (table < 0)
|
|
Packit |
437b5e |
table = lua_gettop(L) + table + 1;
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
for (i = 0; i < PPOLL_EVENT_NUM; i++)
|
|
Packit |
437b5e |
{
|
|
Packit |
437b5e |
lua_pushboolean(L, events & poll_event_map[i].bit);
|
|
Packit |
437b5e |
lua_setfield(L, table, poll_event_map[i].name);
|
|
Packit |
437b5e |
}
|
|
Packit |
437b5e |
}
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
static nfds_t
|
|
Packit |
437b5e |
poll_fd_list_check_table(lua_State *L, int table)
|
|
Packit |
437b5e |
{
|
|
Packit |
437b5e |
nfds_t fd_num = 0;
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/*
|
|
Packit |
437b5e |
* Assume table is an argument number.
|
|
Packit |
437b5e |
* Should be an assert(table > 0).
|
|
Packit |
437b5e |
*/
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
luaL_checktype(L, table, LUA_TTABLE);
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/* Nil key - the one before first */
|
|
Packit |
437b5e |
lua_pushnil(L);
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/* Push each key/value pair, popping previous key */
|
|
Packit |
437b5e |
while (lua_next(L, 1) != 0)
|
|
Packit |
437b5e |
{
|
|
Packit |
437b5e |
/* Verify the fd key */
|
|
Packit |
437b5e |
luaL_argcheck(L, lua_isinteger(L, -2), table,
|
|
Packit |
437b5e |
"contains non-integer key(s)");
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/* Verify the table value */
|
|
Packit |
437b5e |
luaL_argcheck(L, lua_istable(L, -1), table,
|
|
Packit |
437b5e |
"contains non-table value(s)");
|
|
Packit |
437b5e |
lua_getfield(L, -1, "events");
|
|
Packit |
437b5e |
luaL_argcheck(L, lua_istable(L, -1), table,
|
|
Packit |
437b5e |
"contains invalid value table(s)");
|
|
Packit |
437b5e |
lua_pop(L, 1);
|
|
Packit |
437b5e |
lua_getfield(L, -1, "revents");
|
|
Packit |
437b5e |
luaL_argcheck(L, lua_isnil(L, -1) || lua_istable(L, -1), table,
|
|
Packit |
437b5e |
"contains invalid value table(s)");
|
|
Packit |
437b5e |
lua_pop(L, 1);
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/* Remove value (but leave the key) */
|
|
Packit |
437b5e |
lua_pop(L, 1);
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/* Count the fds */
|
|
Packit |
437b5e |
fd_num++;
|
|
Packit |
437b5e |
}
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
return fd_num;
|
|
Packit |
437b5e |
}
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
static void
|
|
Packit |
437b5e |
poll_fd_list_from_table(lua_State *L, int table, struct pollfd *fd_list)
|
|
Packit |
437b5e |
{
|
|
Packit |
437b5e |
struct pollfd *pollfd = fd_list;
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/*
|
|
Packit |
437b5e |
* Assume the table didn't change since
|
|
Packit |
437b5e |
* the call to poll_fd_list_check_table
|
|
Packit |
437b5e |
*/
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/* Convert to absolute index */
|
|
Packit |
437b5e |
if (table < 0)
|
|
Packit |
437b5e |
table = lua_gettop(L) + table + 1;
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/* Nil key - the one before first */
|
|
Packit |
437b5e |
lua_pushnil(L);
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/* Push each key/value pair, popping previous key */
|
|
Packit |
437b5e |
while (lua_next(L, table) != 0)
|
|
Packit |
437b5e |
{
|
|
Packit |
437b5e |
/* Transfer the fd key */
|
|
Packit |
437b5e |
pollfd->fd = lua_tointeger(L, -2);
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/* Transfer "events" field from the value */
|
|
Packit |
437b5e |
lua_getfield(L, -1, "events");
|
|
Packit |
437b5e |
pollfd->events = poll_events_from_table(L, -1);
|
|
Packit |
437b5e |
lua_pop(L, 1);
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/* Remove value (but leave the key) */
|
|
Packit |
437b5e |
lua_pop(L, 1);
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/* Proceed to next fd */
|
|
Packit |
437b5e |
pollfd++;
|
|
Packit |
437b5e |
}
|
|
Packit |
437b5e |
}
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
static void
|
|
Packit |
437b5e |
poll_fd_list_to_table(lua_State *L, int table, const struct pollfd *fd_list)
|
|
Packit |
437b5e |
{
|
|
Packit |
437b5e |
const struct pollfd *pollfd = fd_list;
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/*
|
|
Packit |
437b5e |
* Assume the table didn't change since
|
|
Packit |
437b5e |
* the call to poll_fd_list_check_table.
|
|
Packit |
437b5e |
*/
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/* Convert to absolute index */
|
|
Packit |
437b5e |
if (table < 0)
|
|
Packit |
437b5e |
table = lua_gettop(L) + table + 1;
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/* Nil key - the one before first */
|
|
Packit |
437b5e |
lua_pushnil(L);
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/* Push each key/value pair, popping previous key */
|
|
Packit |
437b5e |
while (lua_next(L, 1) != 0)
|
|
Packit |
437b5e |
{
|
|
Packit |
437b5e |
/* Transfer "revents" field to the value */
|
|
Packit |
437b5e |
lua_getfield(L, -1, "revents");
|
|
Packit |
437b5e |
if (lua_isnil(L, -1))
|
|
Packit |
437b5e |
{
|
|
Packit |
437b5e |
lua_pop(L, 1);
|
|
Packit |
437b5e |
poll_events_createtable(L);
|
|
Packit |
437b5e |
lua_pushvalue(L, -1);
|
|
Packit |
437b5e |
lua_setfield(L, -3, "revents");
|
|
Packit |
437b5e |
}
|
|
Packit |
437b5e |
poll_events_to_table(L, -1, pollfd->revents);
|
|
Packit |
437b5e |
lua_pop(L, 1);
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/* Remove value (but leave the key) */
|
|
Packit |
437b5e |
lua_pop(L, 1);
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/* Proceed to next fd */
|
|
Packit |
437b5e |
pollfd++;
|
|
Packit |
437b5e |
}
|
|
Packit |
437b5e |
}
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/***
|
|
Packit |
437b5e |
Wait for events on multiple file descriptors.
|
|
Packit |
437b5e |
@function poll
|
|
Packit |
437b5e |
@tparam table fds list of file descriptors
|
|
Packit |
437b5e |
@int[opt=-1] timeout maximum timeout in milliseconds, or -1 to block indefinitely
|
|
Packit |
437b5e |
@treturn[1] int 0 if timed out, 1 if *fd* is ready
|
|
Packit |
437b5e |
@return[2] nil
|
|
Packit |
437b5e |
@treturn[2] string error message
|
|
Packit |
437b5e |
@treturn[2] int errnum
|
|
Packit |
437b5e |
@see poll(2)
|
|
Packit |
437b5e |
@see rpoll
|
|
Packit |
437b5e |
@see poll.lua
|
|
Packit |
437b5e |
*/
|
|
Packit |
437b5e |
static int
|
|
Packit |
437b5e |
Ppoll(lua_State *L)
|
|
Packit |
437b5e |
{
|
|
Packit |
437b5e |
struct pollfd *fd_list, static_fd_list[16];
|
|
Packit |
437b5e |
nfds_t fd_num = poll_fd_list_check_table(L, 1);
|
|
Packit |
437b5e |
int r, timeout = optint(L, 2, -1);
|
|
Packit |
437b5e |
checknargs(L, 2);
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
fd_list = (fd_num <= sizeof(static_fd_list) / sizeof(*static_fd_list))
|
|
Packit |
437b5e |
? static_fd_list
|
|
Packit |
437b5e |
: lua_newuserdata(L, sizeof(*fd_list) * fd_num);
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
poll_fd_list_from_table(L, 1, fd_list);
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
r = poll(fd_list, fd_num, timeout);
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/* If any of the descriptors changed state */
|
|
Packit |
437b5e |
if (r > 0)
|
|
Packit |
437b5e |
poll_fd_list_to_table(L, 1, fd_list);
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
return pushresult(L, r, NULL);
|
|
Packit |
437b5e |
}
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
/***
|
|
Packit |
437b5e |
Wait for some event on a file descriptor.
|
|
Packit |
437b5e |
Based on [http://lua-users.org/lists/lua-l/2007-11/msg00346.html]().
|
|
Packit |
437b5e |
@function rpoll
|
|
Packit |
437b5e |
@int fd file descriptor
|
|
Packit |
437b5e |
@int[opt=-1] timeout maximum timeout in milliseconds, or -1 to block indefinitely
|
|
Packit |
437b5e |
@treturn[1] int 0 if timed out, 1 if *fd* is ready
|
|
Packit |
437b5e |
@return[2] nil
|
|
Packit |
437b5e |
@return[2] error message
|
|
Packit |
437b5e |
@treturn[2] int errnum
|
|
Packit |
437b5e |
@see poll
|
|
Packit |
437b5e |
@usage
|
|
Packit |
437b5e |
fh = io.open "one"
|
|
Packit |
437b5e |
while true do
|
|
Packit |
437b5e |
r = rpoll (fh, 500)
|
|
Packit |
437b5e |
if r == 0 then
|
|
Packit |
437b5e |
print 'timeout'
|
|
Packit |
437b5e |
elseif r == 1 then
|
|
Packit |
437b5e |
print (fh:read ())
|
|
Packit |
437b5e |
else
|
|
Packit |
437b5e |
print "finish!"
|
|
Packit |
437b5e |
break
|
|
Packit |
437b5e |
end
|
|
Packit |
437b5e |
end
|
|
Packit |
437b5e |
*/
|
|
Packit |
437b5e |
static int
|
|
Packit |
437b5e |
Prpoll(lua_State *L)
|
|
Packit |
437b5e |
{
|
|
Packit |
437b5e |
struct pollfd fds;
|
|
Packit |
437b5e |
int file = checkint(L, 1);
|
|
Packit |
437b5e |
int timeout = checkint(L, 2);
|
|
Packit |
437b5e |
checknargs(L, 2);
|
|
Packit |
437b5e |
fds.fd = file;
|
|
Packit |
437b5e |
fds.events = POLLIN;
|
|
Packit |
437b5e |
return pushresult(L, poll(&fds, 1, timeout), NULL);
|
|
Packit |
437b5e |
}
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
static const luaL_Reg posix_poll_fns[] =
|
|
Packit |
437b5e |
{
|
|
Packit |
437b5e |
LPOSIX_FUNC( Ppoll ),
|
|
Packit |
437b5e |
LPOSIX_FUNC( Prpoll ),
|
|
Packit |
437b5e |
{NULL, NULL}
|
|
Packit |
437b5e |
};
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
LUALIB_API int
|
|
Packit |
437b5e |
luaopen_posix_poll(lua_State *L)
|
|
Packit |
437b5e |
{
|
|
Packit |
437b5e |
luaL_register(L, "posix.poll", posix_poll_fns);
|
|
Packit |
437b5e |
lua_pushliteral(L, "posix.poll for " LUA_VERSION " / " PACKAGE_STRING);
|
|
Packit |
437b5e |
lua_setfield(L, -2, "version");
|
|
Packit |
437b5e |
|
|
Packit |
437b5e |
return 1;
|
|
Packit |
437b5e |
}
|