From c7f578f6a2163b37a7279bcfb6812e3735c689bd Mon Sep 17 00:00:00 2001 From: Ilya Orlov Date: Sat, 11 Jun 2022 19:47:56 +0300 Subject: [PATCH] [GC] Added option to collect garbage before timeout expires --- src/lj_api.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++-- src/lj_str.c | 2 +- 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/lj_api.c b/src/lj_api.c index 8b00436d9b..c9a714c8bc 100644 --- a/src/lj_api.c +++ b/src/lj_api.c @@ -26,6 +26,63 @@ #include "lj_strscan.h" #include "lj_strfmt.h" +#include +#if LJ_TARGET_POSIX +#include +#elif LJ_TARGET_WINDOWS +#define timercmp(a, b, CMP) \ + (((a)->tv_sec == (b)->tv_sec) ? \ + ((a)->tv_nsec CMP (b)->tv_nsec) : \ + ((a)->tv_sec CMP (b)->tv_sec)) +#define timeradd(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \ + (result)->tv_nsec = (a)->tv_nsec + (b)->tv_nsec; \ + if ((result)->tv_nsec >= 1000000000) \ + { \ + ++(result)->tv_sec; \ + (result)->tv_nsec -= 1000000000; \ + } \ + } while (0) +#endif + +static void gc_step_timeout(lua_State *L, uint32_t timeout_usec) +{ +#if LJ_TARGET_POSIX + struct timeval tv_timeout; + tv_timeout.tv_sec = 0; + tv_timeout.tv_usec = timeout_usec; + + struct timeval tv_current; + gettimeofday(&tv_current, NULL); + + timeradd(&tv_current, &tv_timeout, &tv_timeout); + while (timercmp(&tv_current, &tv_timeout, <)) { + if (lj_gc_step(L) > 0) { + break; + } + + gettimeofday(&tv_current, NULL); + } +#elif LJ_TARGET_WINDOWS + struct timespec tv_timeout; + tv_timeout.tv_sec = 0; + tv_timeout.tv_nsec = timeout_usec * 1000; + + struct timespec tv_current; + timespec_get(&tv_current, TIME_UTC); + + timeradd(&tv_current, &tv_timeout, &tv_timeout); + while (timercmp(&tv_current, &tv_timeout, < )) { + if (lj_gc_step(L) > 0) { + break; + } + + timespec_get(&tv_current, TIME_UTC); + } +#endif +} + /* -- Common helper functions --------------------------------------------- */ #define lj_checkapi_slot(idx) \ @@ -1299,11 +1356,16 @@ 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: { + gc_step_timeout(L, (uint32_t)data); + g->gc.threshold = LJ_MAX_MEM; + break; + } case LUA_GCSETPAUSE: res = (int)(g->gc.pause); g->gc.pause = (MSize)data; diff --git a/src/lj_str.c b/src/lj_str.c index f02f2e0f01..a4407fbe6b 100644 --- a/src/lj_str.c +++ b/src/lj_str.c @@ -153,7 +153,7 @@ GCstr *lj_str_new(lua_State *L, const char *str, size_t lenx) if (LJ_LIKELY((((uintptr_t)str+len-1) & (LJ_PAGESIZE-1)) <= LJ_PAGESIZE-4)) { while (o != NULL) { GCstr *sx = gco2str(o); - if (sx->len == len && str_fastcmp(str, strdata(sx), len) == 0) { + if (sx->len == len && strncmp(str, strdata(sx), len) == 0) { /* Resurrect if dead. Can only happen with fixstring() (keywords). */ if (isdead(g, o)) flipwhite(o); return sx; /* Return existing string. */