| /*=========================================================================*\ |
| * Timeout management functions |
| * LuaSocket toolkit |
| * |
| * RCS ID: $Id: timeout.c,v 1.30 2005/10/07 04:40:59 diego Exp $ |
| \*=========================================================================*/ |
| #include <stdio.h> |
| |
| #include "lua.h" |
| #include "lauxlib.h" |
| |
| #include "auxiliar.h" |
| #include "timeout.h" |
| |
| #ifdef _WIN32 |
| #include <windows.h> |
| #else |
| #include <time.h> |
| #include <sys/time.h> |
| #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 timeout_lua_gettime(lua_State *L); |
| static int timeout_lua_sleep(lua_State *L); |
| |
| static luaL_reg func[] = { |
| { "gettime", timeout_lua_gettime }, |
| { "sleep", timeout_lua_sleep }, |
| { NULL, NULL } |
| }; |
| |
| /*=========================================================================*\ |
| * Exported functions. |
| \*=========================================================================*/ |
| /*-------------------------------------------------------------------------*\ |
| * Initialize structure |
| \*-------------------------------------------------------------------------*/ |
| void timeout_init(p_timeout tm, double block, double 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 |
| \*-------------------------------------------------------------------------*/ |
| double timeout_get(p_timeout tm) { |
| if (tm->block < 0.0 && tm->total < 0.0) { |
| return -1; |
| } else if (tm->block < 0.0) { |
| double t = tm->total - timeout_gettime() + tm->start; |
| return MAX(t, 0.0); |
| } else if (tm->total < 0.0) { |
| return tm->block; |
| } else { |
| double t = tm->total - timeout_gettime() + tm->start; |
| return MIN(tm->block, MAX(t, 0.0)); |
| } |
| } |
| |
| /*-------------------------------------------------------------------------*\ |
| * Returns time since start of operation |
| * Input |
| * tm: timeout control structure |
| * Returns |
| * start field of structure |
| \*-------------------------------------------------------------------------*/ |
| double timeout_getstart(p_timeout 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 |
| \*-------------------------------------------------------------------------*/ |
| double timeout_getretry(p_timeout tm) { |
| if (tm->block < 0.0 && tm->total < 0.0) { |
| return -1; |
| } else if (tm->block < 0.0) { |
| double t = tm->total - timeout_gettime() + tm->start; |
| return MAX(t, 0.0); |
| } else if (tm->total < 0.0) { |
| double t = tm->block - timeout_gettime() + tm->start; |
| return MAX(t, 0.0); |
| } else { |
| double t = tm->total - timeout_gettime() + tm->start; |
| return MIN(tm->block, MAX(t, 0.0)); |
| } |
| } |
| |
| /*-------------------------------------------------------------------------*\ |
| * Marks the operation start time in structure |
| * Input |
| * tm: timeout control structure |
| \*-------------------------------------------------------------------------*/ |
| p_timeout timeout_markstart(p_timeout tm) { |
| tm->start = timeout_gettime(); |
| return tm; |
| } |
| |
| /*-------------------------------------------------------------------------*\ |
| * Gets time in s, relative to January 1, 1970 (UTC) |
| * Returns |
| * time in s. |
| \*-------------------------------------------------------------------------*/ |
| #ifdef _WIN32 |
| double timeout_gettime(void) { |
| FILETIME ft; |
| double t; |
| GetSystemTimeAsFileTime(&ft); |
| /* Windows file time (time since January 1, 1601 (UTC)) */ |
| t = ft.dwLowDateTime/1.0e7 + ft.dwHighDateTime*(4294967296.0/1.0e7); |
| /* convert to Unix Epoch time (time since January 1, 1970 (UTC)) */ |
| return (t - 11644473600.0); |
| } |
| #else |
| double timeout_gettime(void) { |
| struct timeval v; |
| gettimeofday(&v, (struct timezone *) NULL); |
| /* Unix Epoch time (time since January 1, 1970 (UTC)) */ |
| return v.tv_sec + v.tv_usec/1.0e6; |
| } |
| #endif |
| |
| /*-------------------------------------------------------------------------*\ |
| * Initializes module |
| \*-------------------------------------------------------------------------*/ |
| int timeout_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 timeout_meth_settimeout(lua_State *L, p_timeout tm) { |
| double t = luaL_optnumber(L, 2, -1); |
| const char *mode = luaL_optstring(L, 3, "b"); |
| switch (*mode) { |
| case 'b': |
| tm->block = t; |
| break; |
| case 'r': case 't': |
| tm->total = t; |
| 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 timeout_lua_gettime(lua_State *L) |
| { |
| lua_pushnumber(L, timeout_gettime()); |
| return 1; |
| } |
| |
| /*-------------------------------------------------------------------------*\ |
| * Sleep for n seconds. |
| \*-------------------------------------------------------------------------*/ |
| int timeout_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); |
| if (t.tv_nsec >= 1000000000) t.tv_nsec = 999999999; |
| while (nanosleep(&t, &r) != 0) { |
| t.tv_sec = r.tv_sec; |
| t.tv_nsec = r.tv_nsec; |
| } |
| #endif |
| return 0; |
| } |