From: Georgy Kirichenko <georgy@tarantool.org> To: tarantool-patches@freelists.org Cc: Georgy Kirichenko <georgy@tarantool.org> Subject: [tarantool-patches] [PATCH] Protect lua socket io against a spurious wakeup Date: Wed, 18 Jul 2018 14:43:39 +0300 [thread overview] Message-ID: <661cb14302af460fb3779040fb9258ae37c1075e.1531914062.git.georgy@tarantool.org> (raw) socket_readable/socket_writable might return until socket become a requested state in case of a spurious wakeup. Socket functions are refactored with considering that fact. Old behavior leads to test failures. --- Issue: https://github.com/tarantool/tarantool/issues/3344 Branch: https://github.com/tarantool/tarantool/tree/g.kirichenko/gh-3344-socket-io-spurios-wakeup src/lua/socket.lua | 54 ++++++++++++++++++++++----------------- test/box/net.box.result | 3 +++ test/box/net.box.test.lua | 2 ++ 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/lua/socket.lua b/src/lua/socket.lua index 06306eae2..0b22bb91c 100644 --- a/src/lua/socket.lua +++ b/src/lua/socket.lua @@ -689,12 +689,8 @@ local function read(self, limit, timeout, check, ...) return nil end - if not socket_readable(self, timeout) then - return nil - end - if timeout <= 0 then - break - end + socket_readable(self, timeout) + fiber.testcancel() timeout = timeout - ( fiber.clock() - started ) end self._errno = boxerrno.ETIMEDOUT @@ -736,7 +732,7 @@ local function socket_write(self, octets, timeout) end local started = fiber.clock() - while true do + while timeout > 0 do local written = syswrite(self, p, e - p) if written == 0 then return p - s -- eof @@ -750,10 +746,9 @@ local function socket_write(self, octets, timeout) return nil end + socket_writable(self, timeout) + fiber.testcancel() timeout = timeout - (fiber.clock() - started) - if timeout <= 0 or not socket_writable(self, timeout) then - break - end end end @@ -935,16 +930,21 @@ local function socket_tcp_connect(s, address, port, timeout) -- Wait until the connection is established or ultimately fails. -- In either condition the socket becomes writable. To tell these -- conditions appart SO_ERROR must be consulted (man connect). - if socket_writable(s, timeout) then - s._errno = socket_getsockopt(s, 'SOL_SOCKET', 'SO_ERROR') - else - s._errno = boxerrno.ETIMEDOUT - end - if s._errno ~= 0 then - return nil + local deadline = timeout + fiber.clock() + while deadline - fiber.clock() > 0 do + if socket_writable(s, deadline - fiber.clock()) then + s._errno = socket_getsockopt(s, 'SOL_SOCKET', 'SO_ERROR') + if s._errno == 0 then + return true + else + return nil + end + end + -- timeout, spurious wakeup or cancel + fiber.testcancel() end - -- Connected - return true + s._errno = boxerrno.ETIMEDOUT + return nil end local function tcp_connect(host, port, timeout) @@ -1005,7 +1005,9 @@ end local function tcp_server_loop(server, s, addr) fiber.name(format("%s/%s:%s", server.name, addr.host, addr.port), {truncate = true}) log.info("started") - while socket_readable(s) do + while true do + fiber.testcancel() + socket_readable(s) local sc, from = socket_accept(s) if sc == nil then local errno = s._errno @@ -1325,7 +1327,9 @@ end local function lsocket_tcp_accept(self) check_socket(self) local deadline = fiber.clock() + (self.timeout or TIMEOUT_INFINITY) - repeat + while deadline - fiber.clock() > 0 do + socket_readable(self, deadline - fiber.clock()) + fiber.testcancel() local client = socket_accept(self) if client then setmetatable(client, lsocket_tcp_client_mt) @@ -1335,7 +1339,7 @@ local function lsocket_tcp_accept(self) if not errno_is_transient[errno] then break end - until not socket_readable(self, deadline - fiber.clock()) + end return nil, socket_error(self) end @@ -1390,7 +1394,9 @@ local function lsocket_tcp_receive(self, pattern, prefix) elseif pattern == "*a" then local result = { prefix } local deadline = fiber.clock() + (self.timeout or TIMEOUT_INFINITY) - repeat + while deadline - fiber.clock() > 0 do + socket_readable(self, deadline - fiber.clock()) + fiber.testcancel() local data = socket_sysread(self) if data == nil then if not errno_is_transient[self._errno] then @@ -1401,7 +1407,7 @@ local function lsocket_tcp_receive(self, pattern, prefix) else table.insert(result, data) end - until not socket_readable(self, deadline - fiber.clock()) + end if #result == 1 then return nil, 'closed', table.concat(result) end diff --git a/test/box/net.box.result b/test/box/net.box.result index 21cff4a11..4bafabdcb 100644 --- a/test/box/net.box.result +++ b/test/box/net.box.result @@ -20,6 +20,9 @@ test_run:cmd("push filter ".."'\\.lua.*:[0-9]+: ' to '.lua...\"]:<line>: '") --- - true ... +fiber.wakeup(fiber.self()) +--- +... test_run:cmd("setopt delimiter ';'") --- - true diff --git a/test/box/net.box.test.lua b/test/box/net.box.test.lua index 14fb6ebbd..76d3a5837 100644 --- a/test/box/net.box.test.lua +++ b/test/box/net.box.test.lua @@ -6,6 +6,8 @@ env = require('test_run') test_run = env.new() test_run:cmd("push filter ".."'\\.lua.*:[0-9]+: ' to '.lua...\"]:<line>: '") +fiber.wakeup(fiber.self()) + test_run:cmd("setopt delimiter ';'") function x_select(cn, space_id, index_id, iterator, offset, limit, key, opts) return cn:_request('select', opts, space_id, index_id, iterator, -- 2.18.0
next reply other threads:[~2018-07-18 11:43 UTC|newest] Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top 2018-07-18 11:43 Georgy Kirichenko [this message] 2018-07-18 12:25 ` [tarantool-patches] " Vladislav Shpilevoy 2018-07-18 16:47 ` Georgy Kirichenko
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=661cb14302af460fb3779040fb9258ae37c1075e.1531914062.git.georgy@tarantool.org \ --to=georgy@tarantool.org \ --cc=tarantool-patches@freelists.org \ --subject='Re: [tarantool-patches] [PATCH] Protect lua socket io against a spurious wakeup' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox