@@ -617,3 +617,122 @@ GET /t
617617ok_count=10
618618--- no_error_log
619619[error]
620+
621+
622+
623+ === TEST 11: kill uthread with child coroutine pending cosocket read after GC
624+ --- config
625+ lua_socket_log_errors off;
626+
627+ location = /slow-body {
628+ content_by_lua_block {
629+ local body = string.rep("x", 8192)
630+
631+ ngx.header["Content-Type"] = "text/plain"
632+ ngx.header["Content-Length"] = #body
633+
634+ ngx.print(body:sub(1, 64))
635+ ngx.flush(true)
636+ ngx.sleep(0.2)
637+ ngx.print(body:sub(65))
638+ }
639+ }
640+
641+ location = /t {
642+ access_by_lua_block {
643+ local port = tonumber(ngx.var.server_port)
644+ local pinned_sockets = {}
645+ local slow_read_pending = false
646+
647+ local function read_content_length(sock)
648+ local line, err = sock:receive("*l")
649+ if not line then
650+ return nil, err
651+ end
652+
653+ local content_length
654+ while true do
655+ line, err = sock:receive("*l")
656+ if not line then
657+ return nil, err
658+ end
659+
660+ if line == "" then
661+ return content_length
662+ end
663+
664+ local name, value = line:match("^([^:]+):%s*(.*)$")
665+ if name and name:lower() == "content-length" then
666+ content_length = tonumber(value)
667+ end
668+ end
669+ end
670+
671+ local fast = ngx.thread.spawn(function()
672+ for _ = 1, 1000 do
673+ if slow_read_pending then
674+ break
675+ end
676+ ngx.sleep(0.001)
677+ end
678+
679+ return "ok"
680+ end)
681+
682+ local slow = ngx.thread.spawn(function()
683+ local child = coroutine.create(function()
684+ local sock = ngx.socket.tcp()
685+ pinned_sockets[#pinned_sockets + 1] = sock
686+
687+ sock:settimeout(10000)
688+ local ok, err = sock:connect("127.0.0.1", port)
689+ if not ok then
690+ return nil, err
691+ end
692+
693+ ok, err = sock:send("GET /slow-body HTTP/1.1\r\nHost: localhost\r\n\r\n")
694+ if not ok then
695+ return nil, err
696+ end
697+
698+ local content_length
699+ content_length, err = read_content_length(sock)
700+ if not content_length then
701+ return nil, err
702+ end
703+
704+ slow_read_pending = true
705+ return sock:receive(content_length)
706+ end)
707+
708+ local ok, body, err = coroutine.resume(child)
709+ if not ok then
710+ return nil, body
711+ end
712+
713+ return body, err
714+ end)
715+
716+ ngx.thread.wait(fast, slow)
717+ ngx.thread.kill(fast)
718+ ngx.thread.kill(slow)
719+
720+ fast = nil
721+ slow = nil
722+ collectgarbage("collect")
723+ collectgarbage("collect")
724+
725+ ngx.sleep(0.3)
726+
727+ ngx.say("survived pinned=", #pinned_sockets)
728+ }
729+
730+ content_by_lua_block {
731+ }
732+ }
733+ --- request
734+ GET /t
735+ --- response_body
736+ survived pinned=1
737+ --- no_error_log
738+ [alert]
0 commit comments