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+
1926typedef 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
2735typedef struct {
@@ -35,16 +43,6 @@ typedef struct {
3543
3644static uv_once_t once_vmkey = UV_ONCE_INIT ;
3745static 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+
148164static 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
248268static 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