Skip to content

Commit a509476

Browse files
membphisagentzh
authored andcommitted
bugfix: ngx.semaphore: when nginx workers exit, the harmless error message "semaphore gc wait queue is not empty" might be logged.
Signed-off-by: Yichun Zhang (agentzh) <agentzh@gmail.com>
1 parent cc0a793 commit a509476

File tree

4 files changed

+276
-2
lines changed

4 files changed

+276
-2
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ install:
8383
- git clone https://github.com/openresty/srcache-nginx-module.git ../srcache-nginx-module
8484
- git clone https://github.com/openresty/redis2-nginx-module.git ../redis2-nginx-module
8585
- git clone https://github.com/openresty/lua-resty-core.git ../lua-resty-core
86+
- git clone https://github.com/openresty/lua-resty-lrucache.git ../lua-resty-lrucache
8687
- git clone -b v2.1-agentzh https://github.com/openresty/luajit2.git
8788

8889
before_script:

src/ngx_http_lua_semaphore.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -557,8 +557,11 @@ ngx_http_lua_ffi_sema_gc(ngx_http_lua_sema_t *sem)
557557
return;
558558
}
559559

560-
if (!ngx_queue_empty(&sem->wait_queue)) {
561-
ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, 0,
560+
if (!ngx_terminate
561+
&& !ngx_quit
562+
&& !ngx_queue_empty(&sem->wait_queue))
563+
{
564+
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
562565
"in lua semaphore gc wait queue is"
563566
" not empty while the semaphore %p is being "
564567
"destroyed", sem);

t/153-semaphore-hup.t

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
# vim:set ft= ts=4 sw=4 et fdm=marker:
2+
use lib 'lib';
3+
use Test::Nginx::Socket::Lua;
4+
5+
#worker_connections(10140);
6+
#workers(1);
7+
log_level('warn');
8+
master_process_enabled(1);
9+
repeat_each(1);
10+
11+
plan tests => repeat_each() * (blocks() * 3);
12+
13+
no_long_string();
14+
#no_diff();
15+
16+
add_block_preprocessor(sub {
17+
my $block = shift;
18+
19+
my $http_config = $block->http_config || '';
20+
$http_config .= <<'_EOC_';
21+
lua_package_path "../lua-resty-core/lib/?.lua;../lua-resty-lrucache/lib/?.lua;;";
22+
lua_shared_dict shdict 4m;
23+
24+
init_by_lua_block {
25+
require "resty.core"
26+
local process = require "ngx.process"
27+
local ok, err = process.enable_privileged_agent()
28+
if not ok then
29+
ngx.log(ngx.ERR, "failed to enable_privileged_agent: ", err)
30+
end
31+
}
32+
33+
init_worker_by_lua_block {
34+
local function test(pre)
35+
if pre then
36+
return
37+
end
38+
39+
local semaphore = require "ngx.semaphore"
40+
local sem = semaphore.new()
41+
42+
ngx.log(ngx.ERR, "created semaphore object")
43+
44+
local function sem_wait()
45+
46+
local ok, err = sem:wait(100)
47+
if not ok then
48+
ngx.log(ngx.ERR, "err: ", err)
49+
else
50+
ngx.log(ngx.ERR, "wait success")
51+
end
52+
end
53+
54+
while not ngx.worker.exiting() do
55+
local co = ngx.thread.spawn(sem_wait)
56+
ngx.thread.wait(co)
57+
end
58+
end
59+
60+
local ok, err = ngx.timer.at(0, test)
61+
if not ok then
62+
ngx.log(ngx.ERR, "failed to create semaphore timer err: ", err)
63+
end
64+
65+
local function reload(pre)
66+
if pre then
67+
return
68+
end
69+
70+
shdict = ngx.shared.shdict
71+
local success = shdict:add("reloaded", 1)
72+
if not success then
73+
return
74+
end
75+
76+
ngx.log(ngx.ERR, "try to reload nginx")
77+
78+
local f, err = io.open(ngx.config.prefix() .. "/logs/nginx.pid", "r")
79+
if not f then
80+
ngx.say("failed to open nginx.pid: ", err)
81+
return
82+
end
83+
84+
local pid = f:read()
85+
86+
f:close()
87+
os.execute("kill -HUP " .. pid)
88+
end
89+
90+
local typ = require "ngx.process".type
91+
if typ() == "privileged agent" then
92+
local ok, err = ngx.timer.at(0.1, reload)
93+
if not ok then
94+
ngx.log(ngx.ERR, "failed to create semaphore timer err: ", err)
95+
end
96+
end
97+
}
98+
_EOC_
99+
$block->set_value("http_config", $http_config);
100+
});
101+
102+
run_tests();
103+
104+
__DATA__
105+
106+
=== TEST 1: timer + reload
107+
--- config
108+
location /test {
109+
content_by_lua_block {
110+
ngx.sleep(1)
111+
ngx.say("hello")
112+
}
113+
}
114+
--- request
115+
GET /test
116+
--- response_body
117+
hello
118+
--- grep_error_log eval: qr/created semaphore object|try to reload nginx|semaphore gc wait queue is not empty/
119+
--- grep_error_log_out
120+
created semaphore object
121+
created semaphore object
122+
try to reload nginx
123+
created semaphore object
124+
created semaphore object
125+
--- skip_nginx: 3: < 1.11.2
126+
--- no_check_leak
127+
128+
129+
130+
=== TEST 2: timer + reload (lua code cache off)
131+
--- http_config
132+
lua_code_cache off;
133+
--- config
134+
location /test {
135+
content_by_lua_block {
136+
ngx.sleep(1)
137+
ngx.say("hello")
138+
}
139+
}
140+
--- request
141+
GET /test
142+
--- response_body
143+
hello
144+
--- grep_error_log eval: qr/created semaphore object|try to reload nginx|semaphore gc wait queue is not empty/
145+
--- grep_error_log_out
146+
created semaphore object
147+
created semaphore object
148+
try to reload nginx
149+
created semaphore object
150+
created semaphore object
151+
--- skip_nginx: 3: < 1.11.2
152+
--- no_check_leak

t/154-semaphore.t

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# vim:set ft=ts=4 sw=4 et fdm=marker:
2+
use lib 'lib';
3+
use Test::Nginx::Socket::Lua;
4+
5+
#worker_connections(10140);
6+
#workers(1);
7+
#log_level('warn');
8+
9+
repeat_each(2);
10+
11+
plan tests => repeat_each() * (blocks() * 3) + blocks();
12+
13+
no_long_string();
14+
#no_diff();
15+
16+
add_block_preprocessor(sub {
17+
my $block = shift;
18+
19+
my $http_config = $block->http_config || '';
20+
$http_config .= <<'_EOC_';
21+
lua_package_path "../lua-resty-core/lib/?.lua;../lua-resty-lrucache/lib/?.lua;;";
22+
23+
init_by_lua_block {
24+
require "resty.core"
25+
}
26+
_EOC_
27+
$block->set_value("http_config", $http_config);
28+
});
29+
30+
run_tests();
31+
32+
__DATA__
33+
34+
=== TEST 1: timer + shutdown error log
35+
--- config
36+
location /test {
37+
content_by_lua_block {
38+
local function test(pre)
39+
40+
local semaphore = require "ngx.semaphore"
41+
local sem = semaphore.new()
42+
43+
local function sem_wait()
44+
45+
local ok, err = sem:wait(10)
46+
if not ok then
47+
ngx.log(ngx.ERR, "err: ", err)
48+
else
49+
ngx.log(ngx.ERR, "wait success")
50+
end
51+
end
52+
53+
while not ngx.worker.exiting() do
54+
local co = ngx.thread.spawn(sem_wait)
55+
ngx.thread.wait(co)
56+
end
57+
end
58+
59+
local ok, err = ngx.timer.at(0, test)
60+
ngx.log(ngx.ERR, "hello, world")
61+
ngx.say("time: ", ok)
62+
}
63+
}
64+
--- request
65+
GET /test
66+
--- response_body
67+
time: 1
68+
--- grep_error_log eval: qr/hello, world|semaphore gc wait queue is not empty/
69+
--- grep_error_log_out
70+
hello, world
71+
--- shutdown_error_log
72+
--- no_shutdown_error_log
73+
semaphore gc wait queue is not empty
74+
75+
76+
77+
=== TEST 2: timer + shutdown error log (lua code cache off)
78+
--- http_config
79+
lua_code_cache off;
80+
--- config
81+
location /test {
82+
content_by_lua_block {
83+
local function test(pre)
84+
85+
local semaphore = require "ngx.semaphore"
86+
local sem = semaphore.new()
87+
88+
local function sem_wait()
89+
90+
local ok, err = sem:wait(10)
91+
if not ok then
92+
ngx.log(ngx.ERR, "err: ", err)
93+
else
94+
ngx.log(ngx.ERR, "wait success")
95+
end
96+
end
97+
98+
while not ngx.worker.exiting() do
99+
local co = ngx.thread.spawn(sem_wait)
100+
ngx.thread.wait(co)
101+
end
102+
end
103+
104+
local ok, err = ngx.timer.at(0, test)
105+
ngx.log(ngx.ERR, "hello, world")
106+
ngx.say("time: ", ok)
107+
}
108+
}
109+
--- request
110+
GET /test
111+
--- response_body
112+
time: 1
113+
--- grep_error_log eval: qr/hello, world|semaphore gc wait queue is not empty/
114+
--- grep_error_log_out
115+
hello, world
116+
--- shutdown_error_log
117+
--- no_shutdown_error_log
118+
semaphore gc wait queue is not empty

0 commit comments

Comments
 (0)