2014-03-10 14:04:58 +08:00
|
|
|
/*=========================================================================*\
|
|
|
|
* 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
|
|
|
|
|
|
|
|
/*=========================================================================*\
|
|
|
|
* 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) {
|
2014-03-20 17:04:54 +08:00
|
|
|
#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
|
|
|
|
luaL_setfuncs(L, func, 0);
|
|
|
|
#else
|
2014-03-10 14:04:58 +08:00
|
|
|
luaL_openlib(L, NULL, func, 0);
|
2014-03-20 17:04:54 +08:00
|
|
|
#endif
|
2014-03-10 14:04:58 +08:00
|
|
|
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
|