From c9ef7471f0c74572c21f72a9beeece0246e798cb Mon Sep 17 00:00:00 2001 From: Roman Tsisyk <roman@tsisyk.com> Date: Thu, 8 Oct 2015 17:45:59 +0300 Subject: [PATCH] Add coio_wait() to public C API Extract bsdsocket_io_wait() from bsdsocket.cc to public C API. This very simple patch allow to use Tarantool event machine in stored C procedures. Other changes: replace fiber_wakeup() with fiber_call() here to save extra event loop iteration. --- src/coio.cc | 39 +++++++++++++++++++++++++++++++++ src/coio.h | 24 ++++++++++++++++++++ src/lua/bsdsocket.cc | 46 ++------------------------------------- src/lua/bsdsocket.lua | 8 +++---- src/trivia/CMakeLists.txt | 1 + 5 files changed, 70 insertions(+), 48 deletions(-) diff --git a/src/coio.cc b/src/coio.cc index 64298c745d..c803a79eae 100644 --- a/src/coio.cc +++ b/src/coio.cc @@ -705,3 +705,42 @@ coio_waitpid(pid_t pid) return status; } +/* Values of COIO_READ(WRITE) must equal to EV_READ(WRITE) */ +static_assert(COIO_READ == (int) EV_READ, "TNT_IO_READ"); +static_assert(COIO_WRITE == (int) EV_WRITE, "TNT_IO_WRITE"); + +struct coio_wdata { + struct fiber *fiber; + int revents; +}; + +static void +coio_wait_cb(struct ev_loop *loop, ev_io *watcher, int revents) +{ + (void) loop; + struct coio_wdata *wdata = (struct coio_wdata *) watcher->data; + wdata->revents = revents; + fiber_call(wdata->fiber); +} + +int +coio_wait(int fd, int events, double timeout) +{ + struct ev_io io; + coio_init(&io, fd); + ev_io_init(&io, coio_wait_cb, fd, events); + struct coio_wdata wdata = { + /* .fiber = */ fiber(), + /* .revents = */ 0 + }; + io.data = &wdata; + + /* A special hack to work with zero timeout */ + ev_set_priority(&io, EV_MAXPRI); + ev_io_start(loop(), &io); + + fiber_yield_timeout(timeout); + + ev_io_stop(loop(), &io); + return wdata.revents; +} diff --git a/src/coio.h b/src/coio.h index 3fdc8579d7..f43811c9e1 100644 --- a/src/coio.h +++ b/src/coio.h @@ -32,6 +32,7 @@ */ #include "evio.h" #include "fiber.h" +#include "trivia/util.h" /** * Co-operative I/O @@ -183,5 +184,28 @@ coio_stat_stat_timeout(ev_stat *stat, ev_tstamp delay); int coio_waitpid(pid_t pid); +/** \cond public */ + +enum { + /** READ event */ + COIO_READ = 0x1, + /** WRITE event */ + COIO_WRITE = 0x2, +}; + +/** + * Wait until READ or WRITE event on socket (\a fd). Yields. + * \param fd - non-blocking socket file description + * \param events - requested events to wait. + * Combination of TNT_IO_READ | TNT_IO_WRITE bit flags. + * \param timeoout - timeout in seconds. + * \retval 0 - timeout + * \retval >0 - returned events. Combination of TNT_IO_READ | TNT_IO_WRITE + * bit flags. + */ +API_EXPORT int +coio_wait(int fd, int event, double timeout); + +/** \endcond public */ #endif /* TARANTOOL_COIO_H_INCLUDED */ diff --git a/src/lua/bsdsocket.cc b/src/lua/bsdsocket.cc index db5a6866e3..79a2a14fbc 100644 --- a/src/lua/bsdsocket.cc +++ b/src/lua/bsdsocket.cc @@ -49,6 +49,7 @@ extern "C" { #include <lualib.h> } +#include <coio.h> #include <coeio.h> #include <fiber.h> #include <scoped_guard.h> @@ -379,21 +380,6 @@ bsdsocket_nonblock(int fh, int mode) return mode ? 1 : 0; } -struct bsdsocket_io_wdata { - struct fiber *fiber; - int io; -}; - -static void -bsdsocket_io(struct ev_loop *loop, ev_io *watcher, int revents) -{ - (void) loop; - struct bsdsocket_io_wdata *wdata = - (struct bsdsocket_io_wdata *)watcher->data; - wdata->io = revents; - fiber_wakeup(wdata->fiber); -} - static int lbox_bsdsocket_iowait(struct lua_State *L) { @@ -401,35 +387,7 @@ lbox_bsdsocket_iowait(struct lua_State *L) int events = lua_tointeger(L, 2); ev_tstamp timeout = lua_tonumber(L, 3); - switch (events) { - case 0: - events = EV_READ; - break; - case 1: - events = EV_WRITE; - break; - case 2: - events = EV_READ | EV_WRITE; - break; - default: - assert(false); - } - - struct ev_io io; - ev_io_init(&io, bsdsocket_io, fh, events); - struct bsdsocket_io_wdata wdata = { fiber(), 0 }; - io.data = &wdata; - ev_set_priority(&io, EV_MAXPRI); - ev_io_start(loop(), &io); - - fiber_yield_timeout(timeout); - ev_io_stop(loop(), &io); - - int ret = 0; - if (wdata.io & EV_READ) - ret |= 1; - if (wdata.io & EV_WRITE) - ret |= 2; + int ret = coio_wait(fh, events, timeout); lua_pushinteger(L, ret); return 1; diff --git a/src/lua/bsdsocket.lua b/src/lua/bsdsocket.lua index cb0b11e51a..edffec7014 100644 --- a/src/lua/bsdsocket.lua +++ b/src/lua/bsdsocket.lua @@ -270,20 +270,20 @@ local function wait_safely(self, what, timeout) self.waiters[fid] = true local res = internal.iowait(fd, what, timeout) self.waiters[fid] = nil - fiber.testcancel() if res == 0 then self._errno = boxerrno.ETIMEDOUT return 0 end + fiber.testcancel() return res end socket_methods.readable = function(self, timeout) - return wait_safely(self, 0, timeout) ~= 0 + return wait_safely(self, 1, timeout) ~= 0 end socket_methods.wait = function(self, timeout) - local wres = wait_safely(self, 2, timeout) + local wres = wait_safely(self, 3, timeout) local res = '' if bit.band(wres, 1) ~= 0 then res = res .. 'R' @@ -295,7 +295,7 @@ socket_methods.wait = function(self, timeout) end socket_methods.writable = function(self, timeout) - return wait_safely(self, 1, timeout) ~= 0 + return wait_safely(self, 2, timeout) ~= 0 end socket_methods.listen = function(self, backlog) diff --git a/src/trivia/CMakeLists.txt b/src/trivia/CMakeLists.txt index f92d73e8a1..dce4d39c34 100644 --- a/src/trivia/CMakeLists.txt +++ b/src/trivia/CMakeLists.txt @@ -1,6 +1,7 @@ set(api_headers ${CMAKE_CURRENT_BINARY_DIR}/config.h ${CMAKE_SOURCE_DIR}/src/say.h + ${CMAKE_SOURCE_DIR}/src/coio.h ${CMAKE_SOURCE_DIR}/src/coeio.h ${CMAKE_SOURCE_DIR}/src/lua/utils.h ${CMAKE_SOURCE_DIR}/src/box/txn.h -- GitLab