diff --git a/src/coio.cc b/src/coio.cc index 3d143d9a2f0a0b43c449127463adb221b3486185..eea2b53d256843e74b0c20454c4ff32de8c8a355 100644 --- a/src/coio.cc +++ b/src/coio.cc @@ -172,30 +172,37 @@ coio_accept(struct ev_io *coio, struct sockaddr_in *addr, { ev_tstamp start, delay; evio_timeout_init(&start, &delay, timeout); - while (true) { - /* Assume that there are waiting clients - * available */ - int fd = sio_accept(coio->fd, addr, &addrlen); - if (fd >= 0) { - evio_setsockopt_tcp(fd); - return fd; - } - /* The socket is not ready, yield */ - if (! ev_is_active(coio)) { - ev_io_set(coio, coio->fd, EV_READ); - ev_io_start(coio); - } - /* - * Yield control to other fibers until the - * timeout is reached. - */ - bool is_timedout = coio_fiber_yield_timeout(coio, delay); - fiber_testcancel(); - if (is_timedout) { - errno = ETIMEDOUT; - tnt_raise(SocketError, coio->fd, "accept"); + + { + auto scoped_guard = make_scoped_guard([=] { + ev_io_stop(coio); + }); + + while (true) { + /* Assume that there are waiting clients + * available */ + int fd = sio_accept(coio->fd, addr, &addrlen); + if (fd >= 0) { + evio_setsockopt_tcp(fd); + return fd; + } + /* The socket is not ready, yield */ + if (! ev_is_active(coio)) { + ev_io_set(coio, coio->fd, EV_READ); + ev_io_start(coio); + } + /* + * Yield control to other fibers until the + * timeout is reached. + */ + bool is_timedout = coio_fiber_yield_timeout(coio, delay); + fiber_testcancel(); + if (is_timedout) { + errno = ETIMEDOUT; + tnt_raise(SocketError, coio->fd, "accept"); + } + evio_timeout_update(start, &delay); } - evio_timeout_update(start, &delay); } } diff --git a/test/box/socket.result b/test/box/socket.result index 9fe4147b6e3556f95ee3f08b90006e5cb1078fb7..0d01a4bfbbe4da61e3b4ee4e287dbe7aa6c6c0b7 100644 --- a/test/box/socket.result +++ b/test/box/socket.result @@ -933,9 +933,25 @@ lua reps --- - 3 ... -lua function server() ms = box.socket.tcp() ms:bind('127.0.0.1', 8181) ms:listen() while true do local s = ms:accept( .5 ) if s ~= 'timeout' then print("accepted connection ", s) s:send('Hello world') s:shutdown(box.socket.SHUT_RDWR) end end end box.fiber.wrap(server) +lua function server() ms = box.socket.tcp() ms:bind('127.0.0.1', 8181) ms:listen() while true do local s = ms:accept( .5 ) if s ~= 'timeout' then print("accepted connection ", s) s:send('Hello world') s:shutdown(box.socket.SHUT_RDWR) end end end fbr = box.fiber.wrap(server) --- ... Hello world Hello world Hello world +lua box.fiber.cancel(fbr) +--- +... +lua ms:close() +--- +... +lua a = '127.0.0.1' p = 12345 function srv() ms = box.socket.tcp() ms:bind(a, p) ms:listen() ms:accept() end fbr = box.fiber.wrap(srv) box.socket.tcp():connect(a, p) box.socket.tcp():connect(a, p) +--- +... +lua box.fiber.cancel(fbr) +--- +error: 'fiber.resume(): the fiber is dead' +... +lua ms:close() +--- +... diff --git a/test/box/socket.test b/test/box/socket.test index d544fc117eb6a79bad163b1a7b5035be1a4e60d8..93d84681ca3f5b869d87520f78e927be4fecc859 100644 --- a/test/box/socket.test +++ b/test/box/socket.test @@ -580,7 +580,7 @@ function server() end end -box.fiber.wrap(server) +fbr = box.fiber.wrap(server) """ exec admin "lua " + test.replace('\n', ' ') @@ -602,3 +602,32 @@ s.connect(('127.0.0.1', 8181)) data = s.recv(1024) s.close() print data + +#cleanup +exec admin "lua box.fiber.cancel(fbr)" +exec admin "lua ms:close()" + + +# GH-183 bug test. Tarantool must not crash after the code below: +test=""" +a = '127.0.0.1' +p = 12345 +function srv() + ms = box.socket.tcp() + ms:bind(a, p) + ms:listen() + ms:accept() +end + +fbr = box.fiber.wrap(srv) + +box.socket.tcp():connect(a, p) +box.socket.tcp():connect(a, p) +""" + +exec admin "lua " + test.replace('\n', ' ') + +#cleanup +exec admin "lua box.fiber.cancel(fbr)" +exec admin "lua ms:close()" +