Skip to content

Commit 657a08f

Browse files
truemedianzhaozg
authored andcommitted
rework luv work vm storage
moves work vm storage into a garbage collected userdata. this allows for each lua state to manage its own storage. this removes the need for a global array of work vms.
1 parent 1b29585 commit 657a08f

File tree

2 files changed

+69
-65
lines changed

2 files changed

+69
-65
lines changed

src/luv.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -852,11 +852,6 @@ static int loop_gc(lua_State *L) {
852852
while (uv_loop_close(loop)) {
853853
uv_run(loop, UV_RUN_DEFAULT);
854854
}
855-
/* do cleanup in main thread */
856-
lua_getglobal(L, "_THREAD");
857-
if (lua_isnil(L, -1))
858-
luv_work_cleanup();
859-
lua_pop(L, 1);
860855
return 0;
861856
}
862857

src/work.c

Lines changed: 69 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,20 @@
1616
*/
1717
#include "private.h"
1818

19+
typedef struct {
20+
lua_State** vms;
21+
unsigned int nvms;
22+
unsigned int idx_vms;
23+
uv_mutex_t vm_mutex;
24+
} luv_work_vms_t;
25+
1926
typedef struct {
2027
lua_State* L; /* vm in main */
2128
char* code; /* thread entry code */
2229
size_t len;
2330

2431
int after_work_cb; /* ref, run in main ,call after work cb*/
32+
luv_work_vms_t* vms; /* userdata owned by L, so parent thread can clean up old states */
2533
} luv_work_ctx_t;
2634

2735
typedef struct {
@@ -35,16 +43,6 @@ typedef struct {
3543

3644
static uv_once_t once_vmkey = UV_ONCE_INIT;
3745
static uv_key_t tls_vmkey; /* thread local storage key for Lua state */
38-
static uv_mutex_t vm_mutex;
39-
40-
static unsigned int idx_vms = 0;
41-
static unsigned int nvms = 0;
42-
static lua_State** vms;
43-
static lua_State* default_vms[4];
44-
45-
#ifndef ARRAY_SIZE
46-
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
47-
#endif
4846

4947
#if LUV_UV_VERSION_GEQ(1, 30, 0)
5048
#define MAX_THREADPOOL_SIZE 1024
@@ -127,7 +125,7 @@ static int luv_work_cb(lua_State* L) {
127125
return LUA_OK;
128126
}
129127

130-
static lua_State* luv_work_acquire_vm(void)
128+
static lua_State* luv_work_acquire_vm(luv_work_vms_t* vms)
131129
{
132130
lua_State* L = uv_key_get(&tls_vmkey);
133131
if (L == NULL)
@@ -137,17 +135,35 @@ static lua_State* luv_work_acquire_vm(void)
137135
lua_pushboolean(L, 1);
138136
lua_setglobal(L, "_THREAD");
139137

140-
uv_mutex_lock(&vm_mutex);
141-
vms[idx_vms] = L;
142-
idx_vms += 1;
143-
uv_mutex_unlock(&vm_mutex);
138+
uv_mutex_lock(&vms->vm_mutex);
139+
vms->vms[vms->idx_vms] = L;
140+
vms->idx_vms += 1;
141+
uv_mutex_unlock(&vms->vm_mutex);
144142
}
145143
return L;
146144
}
147145

146+
static int luv_work_cleanup(lua_State *L)
147+
{
148+
unsigned int i;
149+
luv_work_vms_t *vms = (luv_work_vms_t*)lua_touserdata(L, 1);
150+
151+
if (!vms || vms->nvms == 0)
152+
return 0;
153+
154+
for (i = 0; i < vms->nvms && vms->vms[i]; i++)
155+
release_vm_cb(vms->vms[i]);
156+
157+
free(vms->vms);
158+
159+
uv_mutex_destroy(&vms->vm_mutex);
160+
vms->nvms = 0;
161+
return 0;
162+
}
163+
148164
static void luv_work_cb_wrapper(uv_work_t* req) {
149165
luv_work_t* work = (luv_work_t*)req->data;
150-
lua_State *L = luv_work_acquire_vm();
166+
lua_State *L = luv_work_acquire_vm(work->ctx->vms);
151167
luv_ctx_t* lctx = luv_context(L);
152168

153169
// If exit is called on a thread in the thread pool, abort is called in
@@ -197,6 +213,10 @@ static int luv_new_work(lua_State* L) {
197213
ctx = (luv_work_ctx_t*)lua_newuserdata(L, sizeof(*ctx));
198214
memset(ctx, 0, sizeof(*ctx));
199215

216+
lua_rawgetp(L, LUA_REGISTRYINDEX, &luv_work_cleanup);
217+
ctx->vms = (luv_work_vms_t*)lua_touserdata(L, -1);
218+
lua_pop(L, 1);
219+
200220
ctx->len = len;
201221
ctx->code = code;
202222

@@ -247,7 +267,6 @@ static const luaL_Reg luv_work_ctx_methods[] = {
247267

248268
static void luv_key_init_once(void)
249269
{
250-
const char* val;
251270
int status = uv_key_create(&tls_vmkey);
252271
if (status != 0)
253272
{
@@ -256,17 +275,26 @@ static void luv_key_init_once(void)
256275
uv_err_name(status), uv_strerror(status));
257276
abort();
258277
}
259-
status = uv_mutex_init(&vm_mutex);
260-
if (status != 0)
261-
{
262-
fprintf(stderr, "*** threadpool not works\n");
263-
fprintf(stderr, "Error to uv_mutex_init with %s: %s\n",
264-
uv_err_name(status), uv_strerror(status));
265-
abort();
266-
}
278+
}
279+
280+
static void luv_work_init(lua_State* L) {
281+
luaL_newmetatable(L, "luv_work_ctx");
282+
lua_pushcfunction(L, luv_work_ctx_tostring);
283+
lua_setfield(L, -2, "__tostring");
284+
lua_pushcfunction(L, luv_work_ctx_gc);
285+
lua_setfield(L, -2, "__gc");
286+
luaL_newlib(L, luv_work_ctx_methods);
287+
lua_setfield(L, -2, "__index");
288+
lua_pop(L, 1);
267289

290+
luaL_newmetatable(L, "luv_work_vms");
291+
lua_pushcfunction(L, luv_work_cleanup);
292+
lua_setfield(L, -2, "__gc");
293+
lua_pop(L, 1);
294+
268295
/* ref to https://github.com/libuv/libuv/blob/v1.x/src/threadpool.c init_threads */
269-
nvms = ARRAY_SIZE(default_vms);
296+
const char* val;
297+
unsigned int nvms = 4;
270298
val = getenv("UV_THREADPOOL_SIZE");
271299
if (val != NULL)
272300
nvms = atoi(val);
@@ -275,44 +303,25 @@ static void luv_key_init_once(void)
275303
if (nvms > MAX_THREADPOOL_SIZE)
276304
nvms = MAX_THREADPOOL_SIZE;
277305

278-
vms = default_vms;
279-
if (nvms > ARRAY_SIZE(default_vms)) {
280-
vms = malloc(nvms * sizeof(vms[0]));
281-
if (vms == NULL) {
282-
nvms = ARRAY_SIZE(default_vms);
283-
vms = default_vms;
284-
}
285-
memset(vms, 0, sizeof(vms[0]) * nvms);
306+
luv_work_vms_t* vms = (luv_work_vms_t*)lua_newuserdata(L, sizeof(luv_work_vms_t));
307+
int status = uv_mutex_init(&vms->vm_mutex);
308+
if (status != 0)
309+
{
310+
fprintf(stderr, "*** threadpool not works\n");
311+
fprintf(stderr, "Error to uv_mutex_init with %s: %s\n",
312+
uv_err_name(status), uv_strerror(status));
313+
abort();
286314
}
287-
idx_vms = 0;
288-
}
289315

290-
static void luv_work_cleanup(void)
291-
{
292-
unsigned int i;
316+
vms->vms = (lua_State**)calloc(nvms, sizeof(lua_State*));
317+
vms->nvms = nvms;
318+
vms->idx_vms = 0;
293319

294-
if (nvms == 0)
295-
return;
296-
297-
for (i = 0; i < nvms && vms[i]; i++)
298-
release_vm_cb(vms[i]);
299-
300-
if (vms != default_vms)
301-
free(vms);
302-
303-
uv_mutex_destroy(&vm_mutex);
304-
nvms = 0;
305-
}
320+
luaL_getmetatable(L, "luv_work_vms");
321+
lua_setmetatable(L, -2);
306322

307-
static void luv_work_init(lua_State* L) {
308-
luaL_newmetatable(L, "luv_work_ctx");
309-
lua_pushcfunction(L, luv_work_ctx_tostring);
310-
lua_setfield(L, -2, "__tostring");
311-
lua_pushcfunction(L, luv_work_ctx_gc);
312-
lua_setfield(L, -2, "__gc");
313-
luaL_newlib(L, luv_work_ctx_methods);
314-
lua_setfield(L, -2, "__index");
315-
lua_pop(L, 1);
323+
// store the luv_work_vms_t in registry
324+
lua_rawsetp(L, LUA_REGISTRYINDEX, &luv_work_cleanup);
316325

317326
uv_once(&once_vmkey, luv_key_init_once);
318327
}

0 commit comments

Comments
 (0)