From 5395f540f8f016397872d8b12c066e2930d439ef Mon Sep 17 00:00:00 2001 From: Dmitry Simonenko <pmwkaa@gmail.com> Date: Wed, 27 Mar 2013 16:32:20 +0400 Subject: [PATCH] Bug1160869: incorrect fiber call order. (https://bugs.launchpad.net/tarantool/+bug/1160869) Lua socket object creates coio object that bind to a current fiber, after yield it will resume it in a different fiber context after a complete io operation. Fix this situation by updating current coio fiber in most lua socket operations. --- include/coio.h | 3 +++ src/coio.m | 6 ++++++ src/lua/lua_socket.m | 10 ++++++++++ test/box/socket.result | 19 +++++++++++++++++++ test/box/socket.test | 24 ++++++++++++++++++++++++ 5 files changed, 62 insertions(+) diff --git a/include/coio.h b/include/coio.h index da9814f2fe..11ad141763 100644 --- a/include/coio.h +++ b/include/coio.h @@ -65,6 +65,9 @@ coio_accept(struct ev_io *coio, struct sockaddr_in *addr, socklen_t addrlen, void coio_init(struct ev_io *coio); +void +coio_update_fiber(struct ev_io *coio); + ssize_t coio_read_ahead_timeout(struct ev_io *coio, void *buf, size_t sz, size_t bufsiz, ev_tstamp timeout); diff --git a/src/coio.m b/src/coio.m index c27da2523f..461f70c15d 100644 --- a/src/coio.m +++ b/src/coio.m @@ -46,6 +46,12 @@ coio_init(struct ev_io *coio) coio->fd = -1; } +void +coio_update_fiber(struct ev_io *coio) +{ + coio->data = fiber; +} + /** * Connect to a host. */ diff --git a/src/lua/lua_socket.m b/src/lua/lua_socket.m index e49e7b6397..337f5506b5 100644 --- a/src/lua/lua_socket.m +++ b/src/lua/lua_socket.m @@ -257,6 +257,7 @@ lbox_socket_shutdown(struct lua_State *L) { struct bio_socket *s = bio_checkactivesocket(L, -1); int how = luaL_checkint(L, 2); + coio_update_fiber(&s->coio); bio_clearerr(s); if (shutdown(s->coio.fd, how)) return bio_pushsockerror(L, s, errno); @@ -297,6 +298,7 @@ lbox_socket_connect(struct lua_State *L) timeout = luaL_checknumber(L, 4); if (evio_is_active(&s->coio)) return bio_pushsockerror(L, s, EALREADY); + coio_update_fiber(&s->coio); bio_clearerr(s); /* try to resolve a hostname */ @@ -347,6 +349,7 @@ lbox_socket_send(struct lua_State *L) timeout = luaL_checknumber(L, 3); if (s->iob == NULL) return bio_pushsenderror(L, s, 0, ENOTCONN); + coio_update_fiber(&s->coio); bio_clearerr(s); @try { ssize_t nwr = coio_write_timeout(&s->coio, buf, buf_size, @@ -384,6 +387,7 @@ lbox_socket_recv(struct lua_State *L) timeout = luaL_checknumber(L, 3); if (s->iob == NULL) return bio_pushrecverror(L, s, ENOTCONN); + coio_update_fiber(&s->coio); /* Clear possible old timeout status. */ bio_clearerr(s); /* @@ -565,6 +569,7 @@ lbox_socket_readline(struct lua_State *L) struct bio_socket *s = bio_checkactivesocket(L, 1); if (s->iob == NULL) return bio_pushrecverror(L, s, ENOTCONN); + coio_update_fiber(&s->coio); bio_clearerr(s); unsigned int limit = UINT_MAX; @@ -653,6 +658,7 @@ lbox_socket_bind(struct lua_State *L) timeout = luaL_checknumber(L, 4); if (evio_is_active(&s->coio)) return bio_pusherror(L, s, EALREADY); + coio_update_fiber(&s->coio); bio_clearerr(s); /* try to resolve a hostname */ struct addrinfo *ai = coeio_resolve(s->socktype, host, port, timeout); @@ -684,6 +690,7 @@ static int lbox_socket_listen(struct lua_State *L) { struct bio_socket *s = bio_checkactivesocket(L, 1); + coio_update_fiber(&s->coio); bio_clearerr(s); if (listen(s->coio.fd, sio_listen_backlog())) return bio_pusherror(L, s, errno); @@ -708,6 +715,7 @@ lbox_socket_accept(struct lua_State *L) double timeout = TIMEOUT_INFINITY; if (lua_gettop(L) == 2) timeout = luaL_checknumber(L, 2); + coio_update_fiber(&s->coio); bio_clearerr(s); struct sockaddr_storage addr; @@ -757,6 +765,7 @@ lbox_socket_sendto(struct lua_State *L) double timeout = TIMEOUT_INFINITY; if (lua_gettop(L) == 5) timeout = luaL_checknumber(L, 5); + coio_update_fiber(&s->coio); bio_clearerr(s); /* try to resolve a hostname */ @@ -821,6 +830,7 @@ lbox_socket_recvfrom(struct lua_State *L) double timeout = TIMEOUT_INFINITY; if (lua_gettop(L) == 3) timeout = luaL_checknumber(L, 3); + coio_update_fiber(&s->coio); bio_clearerr(s); /* Maybe initialize the buffer, can throw ER_MEMORY_ISSUE. */ diff --git a/test/box/socket.result b/test/box/socket.result index befd43b982..61e50ff231 100644 --- a/test/box/socket.result +++ b/test/box/socket.result @@ -907,3 +907,22 @@ ping lua s:close() --- ... +lua reps = 0 function bug1160869() local s = box.socket.tcp() s:connect('127.0.0.1', box.cfg.primary_port) box.fiber.resume( box.fiber.create(function() box.fiber.detach() while true do s:recv(12) reps = reps + 1 end end) ) return s:send(box.pack('iii', 65280, 0, 1)) end +--- +... +lua bug1160869() +--- + - 12 +... +lua bug1160869() +--- + - 12 +... +lua bug1160869() +--- + - 12 +... +lua reps +--- + - 3 +... diff --git a/test/box/socket.test b/test/box/socket.test index 180927a61c..0d64817b3b 100644 --- a/test/box/socket.test +++ b/test/box/socket.test @@ -509,3 +509,27 @@ print(data) s.close() exec admin "lua s:close()" + +# Bug #1160869: incorrect fiber call order. +# (https://bugs.launchpad.net/tarantool/+bug/1160869) +# +test=""" +reps = 0 +function bug1160869() + local s = box.socket.tcp() + s:connect('127.0.0.1', box.cfg.primary_port) + box.fiber.resume( box.fiber.create(function() + box.fiber.detach() + while true do + s:recv(12) + reps = reps + 1 + end + end) ) + return s:send(box.pack('iii', 65280, 0, 1)) +end +""" +exec admin "lua " + test.replace('\n', ' ') +exec admin "lua bug1160869()" +exec admin "lua bug1160869()" +exec admin "lua bug1160869()" +exec admin "lua reps" -- GitLab