226 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			226 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*=========================================================================*\
 | 
						|
* Timeout management functions
 | 
						|
* LuaSocket toolkit
 | 
						|
\*=========================================================================*/
 | 
						|
#include <stdio.h>
 | 
						|
#include <limits.h>
 | 
						|
#include <float.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
 | 
						|
 | 
						|
namespace NS_SLUA {    
 | 
						|
 | 
						|
/*=========================================================================*\
 | 
						|
* Internal function prototypes
 | 
						|
\*=========================================================================*/
 | 
						|
static int timeout_lua_gettime(lua_State *L);
 | 
						|
static int timeout_lua_sleep(lua_State *L);
 | 
						|
 | 
						|
static luaL_Reg timeout_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) {
 | 
						|
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
 | 
						|
    luaL_setfuncs(L, timeout_func, 0);
 | 
						|
#else
 | 
						|
    luaL_openlib(L, NULL, timeout_func, 0);
 | 
						|
#endif
 | 
						|
    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
 | 
						|
 | 
						|
} // end NS_SLUA
 |