mirror of
				https://github.com/lunarmodules/luasocket.git
				synced 2025-10-31 02:15:38 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			219 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			219 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*=========================================================================*\
 | |
| * Timeout management functions
 | |
| * LuaSocket toolkit
 | |
| \*=========================================================================*/
 | |
| #include <stdio.h>
 | |
| #include <limits.h>
 | |
| #include <float.h>
 | |
| 
 | |
| #include "lua.h"
 | |
| #include "lauxlib.h"
 | |
| #include "compat.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_setfuncs(L, 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.
 | |
| \*-------------------------------------------------------------------------*/
 | |
| #ifdef _WIN32
 | |
| int timeout_lua_sleep(lua_State *L)
 | |
| {
 | |
|     double n = luaL_checknumber(L, 1);
 | |
|     if (n < 0.0) n = 0.0;
 | |
|     if (n < DBL_MAX/1000.0) n *= 1000.0;
 | |
|     if (n > INT_MAX) n = INT_MAX;
 | |
|     Sleep((int)n);
 | |
|     return 0;
 | |
| }
 | |
| #else
 | |
| int timeout_lua_sleep(lua_State *L)
 | |
| {
 | |
|     double n = luaL_checknumber(L, 1);
 | |
|     struct timespec t, r;
 | |
|     if (n < 0.0) n = 0.0;
 | |
|     if (n > INT_MAX) n = INT_MAX;
 | |
|     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;
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| #endif
 |