diff --git a/src/lj_api.c b/src/lj_api.c index 8b00436d9b..af906ce852 100644 --- a/src/lj_api.c +++ b/src/lj_api.c @@ -26,6 +26,49 @@ #include "lj_strscan.h" #include "lj_strfmt.h" +#if LJ_TARGET_POSIX +#include <time.h> +#endif + +#if LJ_TARGET_WINDOWS +static inline uint64_t get_high_resolution_time(void) +{ + LARGE_INTEGER cnt; + QueryPerformanceCounter(&cnt); + return cnt.QuadPart; +} +#elif LJ_TARGET_POSIX +static inline uint64_t get_high_resolution_time(void) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + return 1000000000ULL * ts.tv_sec + ts.tv_nsec; +} +#endif + +static int gc_step_timeout(lua_State *L, uint32_t timeout_usec) +{ +#if LJ_TARGET_WINDOWS || LJ_TARGET_POSIX + int res = 0; + uint64_t timeout = timeout_usec * 1000; + + uint64_t time_current = get_high_resolution_time(); + + timeout += time_current; + while (time_current < timeout) { + if (lj_gc_step(L) > 0) { + res = 1; + break; + } + + time_current = get_high_resolution_time(); + } + return res; +#else + return -1; +#endif +} + /* -- Common helper functions --------------------------------------------- */ #define lj_checkapi_slot(idx) \ @@ -1299,11 +1342,17 @@ LUA_API int lua_gc(lua_State *L, int what, int data) g->gc.threshold = (a <= g->gc.total) ? (g->gc.total - a) : 0; while (g->gc.total >= g->gc.threshold) if (lj_gc_step(L) > 0) { - res = 1; - break; + res = 1; + break; } break; } + case LUA_GCTIMEOUT: + res = gc_step_timeout(L, (uint32_t)data); + if (res >= 0) { + g->gc.threshold = LJ_MAX_MEM; + } + break; case LUA_GCSETPAUSE: res = (int)(g->gc.pause); g->gc.pause = (MSize)data; diff --git a/src/lua.h b/src/lua.h index 6d1634d1ce..bc577ede51 100644 --- a/src/lua.h +++ b/src/lua.h @@ -228,6 +228,7 @@ LUA_API int (lua_status) (lua_State *L); #define LUA_GCSETPAUSE 6 #define LUA_GCSETSTEPMUL 7 #define LUA_GCISRUNNING 9 +#define LUA_GCTIMEOUT 10 LUA_API int (lua_gc) (lua_State *L, int what, int data);