소스 검색

Allow Lua background scripts to use timers

bel2125 4 년 전
부모
커밋
1348faacc2
4개의 변경된 파일61개의 추가작업 그리고 15개의 파일을 삭제
  1. 20 0
      src/civetweb.c
  2. 8 2
      src/mod_lua.inl
  3. 19 9
      test/lua_backbround_script_timer.lua
  4. 14 4
      test/page2.lua

+ 20 - 0
src/civetweb.c

@@ -2540,6 +2540,7 @@ struct mg_context {
 	/* Lua specific: Background operations and shared websockets */
 #if defined(USE_LUA)
 	void *lua_background_state;
+	pthread_mutex_t lua_bg_mutex; /* Protect background state */
 #endif
 
 	/* Server nonce */
@@ -19135,9 +19136,11 @@ master_thread_run(struct mg_context *ctx)
 #if defined(USE_LUA)
 	if (ctx->lua_background_state) {
 		lua_State *lstate = (lua_State *)ctx->lua_background_state;
+		pthread_mutex_lock(&ctx->lua_bg_mutex);
 		/* call "start()" in Lua */
 		lua_getglobal(lstate, "start");
 		(void)lua_pcall(lstate, /* args */ 0, /* results */ 0, 0);
+		pthread_mutex_unlock(&ctx->lua_bg_mutex);
 	}
 #endif
 
@@ -19197,10 +19200,12 @@ master_thread_run(struct mg_context *ctx)
 	if (ctx->lua_background_state) {
 		lua_State *lstate = (lua_State *)ctx->lua_background_state;
 		/* call "stop()" in Lua */
+		pthread_mutex_lock(&ctx->lua_bg_mutex);
 		lua_getglobal(lstate, "stop");
 		(void)lua_pcall(lstate, /* args */ 0, /* results */ 0, 0);
 		lua_close(lstate);
 		ctx->lua_background_state = 0;
+		pthread_mutex_unlock(&ctx->lua_bg_mutex);
 	}
 #endif
 
@@ -19287,6 +19292,10 @@ free_context(struct mg_context *ctx)
 	/* Destroy other context global data structures mutex */
 	(void)pthread_mutex_destroy(&ctx->nonce_mutex);
 
+#if defined(USE_LUA)
+	(void)pthread_mutex_destroy(&ctx->lua_bg_mutex);
+#endif
+
 	/* Deallocate config parameters */
 	for (i = 0; i < NUM_OPTIONS; i++) {
 		if (ctx->dd.config[i] != NULL) {
@@ -19542,6 +19551,9 @@ static
 	ctx->sq_blocked = 0;
 #endif
 	ok &= (0 == pthread_mutex_init(&ctx->nonce_mutex, &pthread_mutex_attr));
+#if defined(USE_LUA)
+	ok &= (0 == pthread_mutex_init(&ctx->lua_bg_mutex, &pthread_mutex_attr));
+#endif
 	if (!ok) {
 		const char *err_msg =
 		    "Cannot initialize thread synchronization objects";
@@ -19737,6 +19749,9 @@ static
 		struct vec eq_vec;
 		const char *sparams;
 
+		memset(ebuf, 0, sizeof(ebuf));
+		pthread_mutex_lock(&ctx->lua_bg_mutex);
+
 		/* Create a Lua state, load all standard libraries and the mg table */
 		lua_State *state = mg_lua_context_script_prepare(
 		    ctx->dd.config[LUA_BACKGROUND_SCRIPT], ctx, ebuf, sizeof(ebuf));
@@ -19753,6 +19768,8 @@ static
 				            config_options[DOCUMENT_ROOT].name,
 				            ebuf);
 			}
+			pthread_mutex_unlock(&ctx->lua_bg_mutex);
+
 			free_context(ctx);
 			pthread_setspecific(sTlsKey, NULL);
 			return NULL;
@@ -19795,6 +19812,8 @@ static
 				            config_options[DOCUMENT_ROOT].name,
 				            ebuf);
 			}
+			pthread_mutex_unlock(&ctx->lua_bg_mutex);
+
 			free_context(ctx);
 			pthread_setspecific(sTlsKey, NULL);
 			return NULL;
@@ -19802,6 +19821,7 @@ static
 
 		/* state remains valid */
 		ctx->lua_background_state = (void *)state;
+		pthread_mutex_unlock(&ctx->lua_bg_mutex);
 
 	} else {
 		ctx->lua_background_state = 0;

+ 8 - 2
src/mod_lua.inl

@@ -2210,7 +2210,7 @@ lwebsocket_set_timer(lua_State *L, int is_periodic)
 		/* Argument for timer */
 		arg->L = L;
 		arg->script = (ws ? ws->script : NULL);
-		arg->pmutex = (ws ? &(ws->ws_mutex) : NULL);
+		arg->pmutex = (ws ? &(ws->ws_mutex) : &(ctx->lua_bg_mutex));
 		memcpy(arg->txt, "return(", 7);
 		memcpy(arg->txt + 7, action_txt, action_txt_len);
 		arg->txt[action_txt_len + 7] = ')';
@@ -2245,7 +2245,7 @@ lwebsocket_set_timer(lua_State *L, int is_periodic)
 		/* Argument for timer */
 		arg->L = L;
 		arg->script = (ws ? ws->script : NULL);
-		arg->pmutex = (ws ? &(ws->ws_mutex) : NULL);
+		arg->pmutex = (ws ? &(ws->ws_mutex) : &(ctx->lua_bg_mutex));
 		arg->funcref = funcref;
 		if (0
 		    == timer_add(ctx,
@@ -3466,6 +3466,12 @@ mg_lua_context_script_run(lua_State *L,
 		int ret = lua_toboolean(L, -1);
 		if (ret == 0) {
 			/* Script returned false */
+			mg_snprintf(NULL,
+			            NULL, /* No truncation check for ebuf */
+			            ebuf,
+			            ebuf_len,
+			            "Script %s returned false\n",
+			            file_name);
 			lua_close(L);
 			return 0;
 		}

+ 19 - 9
test/lua_backbround_script_timer.lua

@@ -1,9 +1,19 @@
-shared.timer = 0
-
-function timer()
-	shared.timer = shared.timer + 1
-end
-
-mg.set_interval(timer,5)
-
-return true;
+-- Declare a shared "timer" counter and functions "timer"
+-- and "start" when the script is loading.
+shared.timer = 0
+
+function timer()
+    -- Increment shared value.
+    shared.timer = shared.timer + 1
+	-- Return true to keep interval timer running or false to stop.
+    return true
+end
+
+function start()
+    -- The "start" function is called when the server is ready.
+	-- At this point, a timer can be created.
+    mg.set_interval(timer, 5)
+end
+
+-- Return false to abort server startup.
+return true;

+ 14 - 4
test/page2.lua

@@ -184,7 +184,7 @@ xmlev = xml.eval(xmlstr)
 mg.write(htmlEsc(xmlstr))
 mg.write("\n-->\n")
 mg.write(type(xmlev) .. ":\n")
-mg.write(printTable(xmlev, 1)) 
+mg.write(printTable(xmlev, 1))
 mg.write("</pre>\n</p>\n")
 
 mg.write("<p>lua2xml:<br>\n<pre>\n");
@@ -237,7 +237,7 @@ jsonev = json.decode(jsonstr)
 mg.write(htmlEsc(jsonstr))
 mg.write("\n-->\n")
 mg.write(type(jsonev) .. ":\n")
-mg.write(printTable(jsonev, 1)) 
+mg.write(printTable(jsonev, 1))
 mg.write("</pre>\n</p>\n")
 
 mg.write("<p>lua2json:<br>\n<pre>\n");
@@ -270,11 +270,21 @@ if mg.request_info.query_string then
 end
 
 
--- Next section ...
+-- Test timer from Lua background script
 mg.write("\n<hr/>\n")
 
+mg.write("<p>\nLua shared.timer ");
+if (shared and shared.timer) then
+  mg.write(tostring(shared.timer))
+  mg.write([[ <button onClick="window.location.reload();">Refresh Page</button>]])
+else
+  mg.write("not available")
+end
+mg.write("\n</p>\n")
+
+-- Next section ...
+mg.write("\n<hr/>\n")
 
 mg.write([[
 </body></html>
 ]])
-