/*=========================================================================*\ * Timeout management functions * LuaSocket toolkit * * RCS ID: $Id$ \*=========================================================================*/ #include #include #include #include "luasocket.h" #include "auxiliar.h" #include "timeout.h" #ifdef _WIN32 #include #else #include #include #endif /* min and max macros */ #ifndef MIN #define MIN(x, y) ((x) < (y) ? x : y) #endif #ifndef MAX #define MAX(x, y) ((x) > (y) ? x : y) #endif /*=========================================================================*\ * Internal function prototypes \*=========================================================================*/ static int tm_lua_gettime(lua_State *L); static int tm_lua_sleep(lua_State *L); static luaL_reg func[] = { { "gettime", tm_lua_gettime }, { "sleep", tm_lua_sleep }, { NULL, NULL } }; /*=========================================================================*\ * Exported functions. \*=========================================================================*/ /*-------------------------------------------------------------------------*\ * Initialize structure \*-------------------------------------------------------------------------*/ void tm_init(p_tm tm, int block, int total) { tm->block = block; tm->total = total; } /*-------------------------------------------------------------------------*\ * Determines how much time we have left for the next system call, * if the previous call was successful * Input * tm: timeout control structure * Returns * the number of ms left or -1 if there is no time limit \*-------------------------------------------------------------------------*/ int tm_get(p_tm tm) { if (tm->block < 0 && tm->total < 0) { return -1; } else if (tm->block < 0) { int t = tm->total - tm_gettime() + tm->start; return MAX(t, 0); } else if (tm->total < 0) { return tm->block; } else { int t = tm->total - tm_gettime() + tm->start; return MIN(tm->block, MAX(t, 0)); } } /*-------------------------------------------------------------------------*\ * Returns time since start of operation * Input * tm: timeout control structure * Returns * start field of structure \*-------------------------------------------------------------------------*/ int tm_getstart(p_tm tm) { return tm->start; } /*-------------------------------------------------------------------------*\ * Determines how much time we have left for the next system call, * if the previous call was a failure * Input * tm: timeout control structure * Returns * the number of ms left or -1 if there is no time limit \*-------------------------------------------------------------------------*/ int tm_getretry(p_tm tm) { if (tm->block < 0 && tm->total < 0) { return -1; } else if (tm->block < 0) { int t = tm->total - tm_gettime() + tm->start; return MAX(t, 0); } else if (tm->total < 0) { int t = tm->block - tm_gettime() + tm->start; return MAX(t, 0); } else { int t = tm->total - tm_gettime() + tm->start; return MIN(tm->block, MAX(t, 0)); } } /*-------------------------------------------------------------------------*\ * Marks the operation start time in structure * Input * tm: timeout control structure \*-------------------------------------------------------------------------*/ p_tm tm_markstart(p_tm tm) { tm->start = tm_gettime(); return tm; } /*-------------------------------------------------------------------------*\ * Gets time in ms, relative to system startup. * Returns * time in ms. \*-------------------------------------------------------------------------*/ #ifdef _WIN32 int tm_gettime(void) { return GetTickCount(); } #else int tm_gettime(void) { struct timeval v; gettimeofday(&v, (struct timezone *) NULL); return v.tv_sec * 1000 + v.tv_usec/1000; } #endif /*-------------------------------------------------------------------------*\ * Initializes module \*-------------------------------------------------------------------------*/ int tm_open(lua_State *L) { luaL_openlib(L, NULL, func, 0); return 0; } /*-------------------------------------------------------------------------*\ * Sets timeout values for IO operations * Lua Input: base, time [, mode] * time: time out value in seconds * mode: "b" for block timeout, "t" for total timeout. (default: b) \*-------------------------------------------------------------------------*/ int tm_meth_settimeout(lua_State *L, p_tm tm) { int ms = lua_isnil(L, 2) ? -1 : (int) (luaL_checknumber(L, 2)*1000.0); const char *mode = luaL_optstring(L, 3, "b"); switch (*mode) { case 'b': tm->block = ms; break; case 'r': case 't': tm->total = ms; break; default: luaL_argcheck(L, 0, 3, "invalid timeout mode"); break; } lua_pushnumber(L, 1); return 1; } /*=========================================================================*\ * Test support functions \*=========================================================================*/ /*-------------------------------------------------------------------------*\ * Returns the time the system has been up, in secconds. \*-------------------------------------------------------------------------*/ static int tm_lua_gettime(lua_State *L) { lua_pushnumber(L, tm_gettime()/1000.0); return 1; } /*-------------------------------------------------------------------------*\ * Sleep for n seconds. \*-------------------------------------------------------------------------*/ int tm_lua_sleep(lua_State *L) { double n = luaL_checknumber(L, 1); #ifdef _WIN32 Sleep((int)(n*1000)); #else struct timespec t, r; t.tv_sec = (int) n; n -= t.tv_sec; t.tv_nsec = (int) (n * 1000000000) % 1000000000; nanosleep(&t, &r); #endif return 0; }