MEDIUM: threads/lua: Add locks around the Lua execution parts.

Note that the Lua processing is not really thread safe. It provides
heavy system which consists to add our own lock function in the Lua
code and recompile the library. This system will probably not accepted
by maintainers of various distribs.

Our main excution point of the Lua is the function lua_resume(). A
quick looking on the Lua sources displays a lua_lock() a the start
of function and a lua_unlock() at the end of the function. So I
conclude that the Lua thread safe mode just perform a mutex around
all execution. So I prefer to do this in the HAProxy code, it will be
easier for distro maintainers.

Note that the HAProxy lua functions rounded by the macro SET_SAFE_LJMP
and RESET_SAFE_LJMP manipulates the Lua stack, so it will be careful
to set mutex around these functions.
This commit is contained in:
Thierry FOURNIER 2017-07-12 11:41:21 +02:00 committed by Willy Tarreau
parent ffbad79027
commit 61ba0e2b6d
2 changed files with 35 additions and 1 deletions

View File

@ -165,6 +165,7 @@ enum lock_label {
PATLRU_LOCK,
VARS_LOCK,
COMP_POOL_LOCK,
LUA_LOCK,
LOCK_LABELS
};
struct lock_stat {
@ -252,7 +253,7 @@ static inline void show_lock_stats()
"LISTENER", "LISTENER_QUEUE", "PROXY", "SERVER",
"UPDATED_SERVERS", "LBPRM", "SIGNALS", "STK_TABLE", "STK_SESS",
"APPLETS", "PEER", "BUF_WQ", "STREAMS", "SSL", "SSL_GEN_CERTS",
"PATREF", "PATEXP", "PATLRU", "VARS", "COMP_POOL" };
"PATREF", "PATEXP", "PATLRU", "VARS", "COMP_POOL", "LUA" };
int lbl;
for (lbl = 0; lbl < LOCK_LABELS; lbl++) {

View File

@ -25,6 +25,7 @@
#include <common/cfgparse.h>
#include <common/xref.h>
#include <common/hathreads.h>
#include <types/cli.h>
#include <types/hlua.h>
@ -97,7 +98,26 @@
* RESET_SAFE_LJMP reset the longjmp. These function must be macro
* because they must be exists in the program stack when the longjmp
* is called.
*
* Note that the Lua processing is not really thread safe. It provides
* heavy system which consists to add our own lock function in the Lua
* code and recompile the library. This system will probably not accepted
* by maintainers of various distribs.
*
* Our main excution point of the Lua is the function lua_resume(). A
* quick looking on the Lua sources displays a lua_lock() a the start
* of function and a lua_unlock() at the end of the function. So I
* conclude that the Lua thread safe mode just perform a mutex around
* all execution. So I prefer to do this in the HAProxy code, it will be
* easier for distro maintainers.
*
* Note that the HAProxy lua functions rounded by the macro SET_SAFE_LJMP
* and RESET_SAFE_LJMP manipulates the Lua stack, so it will be careful
* to set mutex around these functions.
*/
#ifdef USE_THREAD
HA_SPINLOCK_T hlua_global_lock;
#endif
THREAD_LOCAL jmp_buf safe_ljmp_env;
static int hlua_panic_safe(lua_State *L) { return 0; }
static int hlua_panic_ljmp(lua_State *L) { longjmp(safe_ljmp_env, 1); }
@ -105,9 +125,11 @@ static int hlua_panic_ljmp(lua_State *L) { longjmp(safe_ljmp_env, 1); }
#define SET_SAFE_LJMP(__L) \
({ \
int ret; \
SPIN_LOCK(LUA_LOCK, &hlua_global_lock); \
if (setjmp(safe_ljmp_env) != 0) { \
lua_atpanic(__L, hlua_panic_safe); \
ret = 0; \
SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock); \
} else { \
lua_atpanic(__L, hlua_panic_ljmp); \
ret = 1; \
@ -121,6 +143,7 @@ static int hlua_panic_ljmp(lua_State *L) { longjmp(safe_ljmp_env, 1); }
#define RESET_SAFE_LJMP(__L) \
do { \
lua_atpanic(__L, hlua_panic_safe); \
SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock); \
} while(0)
/* Applet status flags */
@ -968,6 +991,11 @@ static enum hlua_exec hlua_ctx_resume(struct hlua *lua, int yield_allowed)
if (!HLUA_IS_RUNNING(lua))
lua->run_time = 0;
/* Lock the whole Lua execution. This lock must be before the
* label "resume_execution".
*/
SPIN_LOCK(LUA_LOCK, &hlua_global_lock);
resume_execution:
/* This hook interrupts the Lua processing each 'hlua_nb_instruction'
@ -1125,6 +1153,9 @@ resume_execution:
break;
}
/* This is the main exit point, remove the Lua lock. */
SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock);
return ret;
}
@ -7236,6 +7267,8 @@ void hlua_init(void)
};
#endif
SPIN_INIT(&hlua_global_lock);
/* Initialise struct hlua and com signals pool */
pool2_hlua = create_pool("hlua", sizeof(struct hlua), MEM_F_SHARED);