Skip to content

Commit 2f7c650

Browse files
authored
feature: implemented a new 'lua_sa_restart' directive, which sets the SA_RESTART flag on nginx workers signal dispositions.
1 parent c65f573 commit 2f7c650

9 files changed

+296
-0
lines changed

README.markdown

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,6 +1065,7 @@ Directives
10651065
* [lua_check_client_abort](#lua_check_client_abort)
10661066
* [lua_max_pending_timers](#lua_max_pending_timers)
10671067
* [lua_max_running_timers](#lua_max_running_timers)
1068+
* [lua_sa_restart](#lua_sa_restart)
10681069

10691070

10701071
The basic building blocks of scripting Nginx with Lua are directives. Directives are used to specify when the user Lua code is run and
@@ -3069,6 +3070,23 @@ This directive was first introduced in the `v0.8.0` release.
30693070

30703071
[Back to TOC](#directives)
30713072

3073+
lua_sa_restart
3074+
--------------
3075+
3076+
**syntax:** *lua_sa_restart on|off*
3077+
3078+
**default:** *lua_sa_restart on*
3079+
3080+
**context:** *http*
3081+
3082+
When enabled, this module will set the `SA_RESTART` flag on nginx workers signal dispositions.
3083+
3084+
This allows Lua I/O primitives to not be interrupted by nginx's handling of various signals.
3085+
3086+
This directive was first introduced in the `v0.10.14` release.
3087+
3088+
[Back to TOC](#directives)
3089+
30723090
Nginx API for Lua
30733091
=================
30743092

config

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,17 @@ ngx_feature_test='setsockopt(1, SOL_SOCKET, SO_PASSCRED, NULL, 0);'
476476

477477
. auto/feature
478478

479+
ngx_feature="SA_RESTART"
480+
ngx_feature_libs=
481+
ngx_feature_name="NGX_HTTP_LUA_HAVE_SA_RESTART"
482+
ngx_feature_run=no
483+
ngx_feature_incs="#include <signal.h>"
484+
ngx_feature_path=
485+
ngx_feature_test='struct sigaction act;
486+
act.sa_flags |= SA_RESTART;'
487+
488+
. auto/feature
489+
479490
ngx_feature="__attribute__(constructor)"
480491
ngx_feature_libs=
481492
ngx_feature_name="NGX_HTTP_LUA_HAVE_CONSTRUCTOR"

doc/HttpLuaModule.wiki

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2595,6 +2595,20 @@ When exceeding this limit, Nginx will stop running the callbacks of newly expire
25952595
25962596
This directive was first introduced in the <code>v0.8.0</code> release.
25972597
2598+
== lua_sa_restart ==
2599+
2600+
'''syntax:''' ''lua_sa_restart on|off''
2601+
2602+
'''default:''' ''lua_sa_restart on''
2603+
2604+
'''context:''' ''http''
2605+
2606+
When enabled, this module will set the `SA_RESTART` flag on nginx workers signal dispositions.
2607+
2608+
This allows Lua I/O primitives to not be interrupted by nginx's handling of various signals.
2609+
2610+
This directive was first introduced in the <code>v0.10.14</code> release.
2611+
25982612
= Nginx API for Lua =
25992613
26002614
<!-- inline-toc -->

src/ngx_http_lua_common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,8 @@ struct ngx_http_lua_main_conf_s {
255255

256256
ngx_int_t host_var_index;
257257

258+
ngx_flag_t set_sa_restart;
259+
258260
unsigned requires_header_filter:1;
259261
unsigned requires_body_filter:1;
260262
unsigned requires_capture_filter:1;

src/ngx_http_lua_initworkerby.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle)
6767
}
6868
#endif /* NGX_WIN32 */
6969

70+
#if (NGX_HTTP_LUA_HAVE_SA_RESTART)
71+
if (lmcf->set_sa_restart) {
72+
ngx_http_lua_set_sa_restart(ngx_cycle->log);
73+
}
74+
#endif
75+
7076
if (lmcf->init_worker_handler == NULL) {
7177
return NGX_OK;
7278
}

src/ngx_http_lua_module.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,13 @@ static ngx_command_t ngx_http_lua_cmds[] = {
104104
0,
105105
NULL },
106106

107+
{ ngx_string("lua_sa_restart"),
108+
NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG,
109+
ngx_conf_set_flag_slot,
110+
NGX_HTTP_MAIN_CONF_OFFSET,
111+
offsetof(ngx_http_lua_main_conf_t, set_sa_restart),
112+
NULL },
113+
107114
#if (NGX_PCRE)
108115
{ ngx_string("lua_regex_cache_max_entries"),
109116
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
@@ -869,6 +876,8 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf)
869876
lmcf->postponed_to_rewrite_phase_end = NGX_CONF_UNSET;
870877
lmcf->postponed_to_access_phase_end = NGX_CONF_UNSET;
871878

879+
lmcf->set_sa_restart = NGX_CONF_UNSET;
880+
872881
#if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM)
873882
lmcf->malloc_trim_cycle = NGX_CONF_UNSET_UINT;
874883
#endif
@@ -909,6 +918,12 @@ ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf)
909918
lmcf->max_running_timers = 256;
910919
}
911920

921+
#if (NGX_HTTP_LUA_HAVE_SA_RESTART)
922+
if (lmcf->set_sa_restart == NGX_CONF_UNSET) {
923+
lmcf->set_sa_restart = 1;
924+
}
925+
#endif
926+
912927
#if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM)
913928
if (lmcf->malloc_trim_cycle == NGX_CONF_UNSET_UINT) {
914929
lmcf->malloc_trim_cycle = 1000; /* number of reqs */

src/ngx_http_lua_util.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,25 @@
7070
#endif
7171

7272

73+
#if (NGX_HTTP_LUA_HAVE_SA_RESTART)
74+
#define NGX_HTTP_LUA_SA_RESTART_SIGS { \
75+
ngx_signal_value(NGX_RECONFIGURE_SIGNAL), \
76+
ngx_signal_value(NGX_REOPEN_SIGNAL), \
77+
ngx_signal_value(NGX_NOACCEPT_SIGNAL), \
78+
ngx_signal_value(NGX_TERMINATE_SIGNAL), \
79+
ngx_signal_value(NGX_SHUTDOWN_SIGNAL), \
80+
ngx_signal_value(NGX_CHANGEBIN_SIGNAL), \
81+
SIGALRM, \
82+
SIGINT, \
83+
SIGIO, \
84+
SIGCHLD, \
85+
SIGSYS, \
86+
SIGPIPE, \
87+
0 \
88+
};
89+
#endif
90+
91+
7392
char ngx_http_lua_code_cache_key;
7493
char ngx_http_lua_regex_cache_key;
7594
char ngx_http_lua_socket_pool_key;
@@ -4195,4 +4214,32 @@ ngx_http_lua_cleanup_free(ngx_http_request_t *r, ngx_http_cleanup_pt *cleanup)
41954214
}
41964215

41974216

4217+
#if (NGX_HTTP_LUA_HAVE_SA_RESTART)
4218+
void
4219+
ngx_http_lua_set_sa_restart(ngx_log_t *log)
4220+
{
4221+
int *signo;
4222+
int sigs[] = NGX_HTTP_LUA_SA_RESTART_SIGS;
4223+
struct sigaction act;
4224+
4225+
for (signo = sigs; *signo != 0; signo++) {
4226+
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
4227+
"setting SA_RESTART for signal %d", *signo);
4228+
4229+
if (sigaction(*signo, NULL, &act) != 0) {
4230+
ngx_log_error(NGX_LOG_WARN, log, ngx_errno, "failed to get "
4231+
"sigaction for signal %d", *signo);
4232+
}
4233+
4234+
act.sa_flags |= SA_RESTART;
4235+
4236+
if (sigaction(*signo, &act, NULL) != 0) {
4237+
ngx_log_error(NGX_LOG_WARN, log, ngx_errno, "failed to set "
4238+
"sigaction for signal %d", *signo);
4239+
}
4240+
}
4241+
}
4242+
#endif
4243+
4244+
41984245
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */

src/ngx_http_lua_util.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,9 @@ ngx_http_cleanup_t *ngx_http_lua_cleanup_add(ngx_http_request_t *r,
250250
void ngx_http_lua_cleanup_free(ngx_http_request_t *r,
251251
ngx_http_cleanup_pt *cleanup);
252252

253+
#if (NGX_HTTP_LUA_HAVE_SA_RESTART)
254+
void ngx_http_lua_set_sa_restart(ngx_log_t *log);
255+
#endif
253256

254257
#define ngx_http_lua_check_if_abortable(L, ctx) \
255258
if ((ctx)->no_abort) { \

t/159-sa-restart.t

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# vim:set ft= ts=4 sw=4 et fdm=marker:
2+
3+
use Test::Nginx::Socket::Lua;
4+
5+
add_block_preprocessor(sub {
6+
my $block = shift;
7+
8+
my $http_config = $block->http_config || '';
9+
10+
$http_config .= <<_EOC_;
11+
init_by_lua_block {
12+
function test_sa_restart()
13+
local signals = {
14+
"HUP",
15+
--"INFO",
16+
--"XCPU",
17+
--"USR1",
18+
--"USR2",
19+
"ALRM",
20+
--"INT",
21+
"IO",
22+
"CHLD",
23+
"WINCH",
24+
}
25+
26+
for _, signame in ipairs(signals) do
27+
local cmd = string.format("kill -s %s %d && sleep 0.01",
28+
signame, ngx.worker.pid())
29+
local err = select(2, io.popen(cmd):read("*a"))
30+
if err then
31+
error("SIG" .. signame .. " caused: " .. err)
32+
end
33+
end
34+
end
35+
}
36+
_EOC_
37+
38+
$block->set_value("http_config", $http_config);
39+
40+
if (!defined $block->config) {
41+
my $config = <<_EOC_;
42+
location /t {
43+
echo ok;
44+
}
45+
_EOC_
46+
47+
$block->set_value("config", $config);
48+
}
49+
50+
if (!defined $block->request) {
51+
$block->set_value("request", "GET /t");
52+
}
53+
54+
if (!defined $block->response_body) {
55+
$block->set_value("ignore_response_body");
56+
}
57+
58+
if (!defined $block->no_error_log) {
59+
$block->set_value("no_error_log", "[error]");
60+
}
61+
});
62+
63+
plan tests => repeat_each() * (blocks() * 2 + 1);
64+
65+
no_long_string();
66+
run_tests();
67+
68+
__DATA__
69+
70+
=== TEST 1: lua_sa_restart default - sets SA_RESTART in init_worker_by_lua*
71+
--- http_config
72+
init_worker_by_lua_block {
73+
test_sa_restart()
74+
}
75+
76+
77+
78+
=== TEST 2: lua_sa_restart off - does not set SA_RESTART
79+
--- http_config
80+
lua_sa_restart off;
81+
82+
init_worker_by_lua_block {
83+
test_sa_restart()
84+
}
85+
--- no_error_log
86+
[crit]
87+
--- error_log
88+
Interrupted system call
89+
90+
91+
92+
=== TEST 3: lua_sa_restart on (default) - sets SA_RESTART if no init_worker_by_lua* phase is defined
93+
--- config
94+
location /t {
95+
content_by_lua_block {
96+
test_sa_restart()
97+
}
98+
}
99+
100+
101+
102+
=== TEST 4: lua_sa_restart on (default) - SA_RESTART is effective in rewrite_by_lua*
103+
--- config
104+
location /t {
105+
rewrite_by_lua_block {
106+
test_sa_restart()
107+
}
108+
109+
echo ok;
110+
}
111+
112+
113+
114+
=== TEST 5: lua_sa_restart on (default) - SA_RESTART is effective in access_by_lua*
115+
--- config
116+
location /t {
117+
access_by_lua_block {
118+
test_sa_restart()
119+
}
120+
121+
echo ok;
122+
}
123+
124+
125+
126+
=== TEST 6: lua_sa_restart on (default) - SA_RESTART is effective in content_by_lua*
127+
--- config
128+
location /t {
129+
content_by_lua_block {
130+
test_sa_restart()
131+
}
132+
}
133+
134+
135+
136+
=== TEST 7: lua_sa_restart on (default) - SA_RESTART is effective in header_filter_by_lua*
137+
--- config
138+
location /t {
139+
echo ok;
140+
141+
header_filter_by_lua_block {
142+
test_sa_restart()
143+
}
144+
}
145+
146+
147+
148+
=== TEST 8: lua_sa_restart on (default) - SA_RESTART is effective in body_filter_by_lua*
149+
--- config
150+
location /t {
151+
echo ok;
152+
153+
body_filter_by_lua_block {
154+
test_sa_restart()
155+
}
156+
}
157+
158+
159+
160+
=== TEST 9: lua_sa_restart on (default) - SA_RESTART is effective in log_by_lua*
161+
--- config
162+
location /t {
163+
echo ok;
164+
165+
log_by_lua_block {
166+
test_sa_restart()
167+
}
168+
}
169+
170+
171+
172+
=== TEST 10: lua_sa_restart on (default) - SA_RESTART is effective in timer phase
173+
--- config
174+
location /t {
175+
echo ok;
176+
177+
log_by_lua_block {
178+
ngx.timer.at(0, test_sa_restart)
179+
}
180+
}

0 commit comments

Comments
 (0)