diff --git a/extra/exports b/extra/exports index 59ebb3499c3f3ca63f320457c973f1a10e3cd0a8..e348e9b5a2b918ddde719905b9681d774ded6604 100644 --- a/extra/exports +++ b/extra/exports @@ -13,6 +13,8 @@ guava random_bytes fiber_time fiber_time64 +fiber_clock +fiber_clock64 tarantool_lua_slab_cache ibuf_create ibuf_reinit diff --git a/src/box/lua/net_box.lua b/src/box/lua/net_box.lua index c612ab8a025fb17aeba4d9f6fa88e4f55239e47d..5cccc70723db736ccb69c57b5d359c33690ae261 100644 --- a/src/box/lua/net_box.lua +++ b/src/box/lua/net_box.lua @@ -12,7 +12,7 @@ local trigger = require('internal.trigger') local band = bit.band local max = math.max -local fiber_time = fiber.time +local fiber_clock = fiber.clock local fiber_self = fiber.self local ibuf_decode = msgpack.ibuf_decode @@ -177,10 +177,10 @@ local function create_transport(host, port, user, password, callback) -- FYI: [] on a string is valid local function wait_state(target_state, timeout) - local deadline = fiber_time() + (timeout or TIMEOUT_INFINITY) + local deadline = fiber_clock() + (timeout or TIMEOUT_INFINITY) repeat until state == target_state or target_state[state] or is_final_state[state] or - not state_cond:wait(max(0, deadline - fiber_time())) + not state_cond:wait(max(0, deadline - fiber_clock())) return state == target_state or target_state[state] or false end @@ -223,7 +223,7 @@ local function create_transport(host, port, user, password, callback) if state ~= 'active' then return last_errno or E_NO_CONNECTION, last_error end - local deadline = fiber_time() + (timeout or TIMEOUT_INFINITY) + local deadline = fiber_clock() + (timeout or TIMEOUT_INFINITY) -- alert worker to notify it of the queued outgoing data; -- if the buffer wasn't empty, assume the worker was already alerted if send_buf:size() == 0 then @@ -239,7 +239,7 @@ local function create_transport(host, port, user, password, callback) request.buffer = buffer requests[id] = request repeat - local timeout = max(0, deadline - fiber_time()) + local timeout = max(0, deadline - fiber_clock()) if not state_cond:wait(timeout) then requests[id] = nil return E_TIMEOUT, 'Timeout exceeded' @@ -321,12 +321,12 @@ local function create_transport(host, port, user, password, callback) return nil, hdr, body_rpos, body_end end end - local deadline = fiber_time() + (timeout or TIMEOUT_INFINITY) + local deadline = fiber_clock() + (timeout or TIMEOUT_INFINITY) local err, extra = send_and_recv(required, timeout) if err then return err, extra end - return send_and_recv_iproto(max(0, deadline - fiber_time())) + return send_and_recv_iproto(max(0, deadline - fiber_clock())) end local function send_and_recv_console(timeout) @@ -350,13 +350,13 @@ local function create_transport(host, port, user, password, callback) local console_sm, iproto_auth_sm, iproto_schema_sm, iproto_sm, error_sm protocol_sm = function () - local tm_begin, tm = fiber.time(), callback('fetch_connect_timeout') + local tm_begin, tm = fiber.clock(), callback('fetch_connect_timeout') connection = socket.tcp_connect(host, port, tm) if connection == nil then return error_sm(E_NO_CONNECTION, errno.strerror(errno())) end local size = IPROTO_GREETING_SIZE - local err, msg = send_and_recv(size, tm - (fiber.time() - tm_begin)) + local err, msg = send_and_recv(size, tm - (fiber.clock() - tm_begin)) if err then return error_sm(err, msg) end @@ -696,7 +696,7 @@ function remote_methods:_request(method, opts, ...) local deadline = nil if opts and opts.timeout then -- conn.space:request(, { timeout = timeout }) - deadline = fiber_time() + opts.timeout + deadline = fiber_clock() + opts.timeout else -- conn:timeout(timeout).space:request() -- @deprecated since 1.7.4 @@ -705,10 +705,10 @@ function remote_methods:_request(method, opts, ...) local buffer = opts and opts.buffer local err, res repeat - local timeout = deadline and max(0, deadline - fiber_time()) + local timeout = deadline and max(0, deadline - fiber_clock()) if self.state ~= 'active' then wait_state('active', timeout) - timeout = deadline and max(0, deadline - fiber_time()) + timeout = deadline and max(0, deadline - fiber_clock()) end err, res = perform_request(timeout, buffer, method, self.schema_version, ...) @@ -738,7 +738,7 @@ function remote_methods:ping(opts) -- conn:timeout(timeout):ping() -- @deprecated since 1.7.4 local deadline = self._deadlines[fiber_self()] - timeout = deadline and max(0, deadline - fiber_time()) + timeout = deadline and max(0, deadline - fiber_clock()) or (opts and opts.timeout) end local err = self._transport.perform_request(timeout, nil, 'ping', @@ -790,7 +790,7 @@ function remote_methods:wait_state(state, timeout) check_remote_arg(self, 'wait_state') if timeout == nil then local deadline = self._deadlines[fiber_self()] - timeout = deadline and max(0, deadline-fiber_time()) + timeout = deadline and max(0, deadline - fiber_clock()) end return self._transport.wait_state(state, timeout) end @@ -806,7 +806,7 @@ function remote_methods:timeout(timeout) "please use space:<request>(..., {timeout = t}) instead.") end -- Sic: this is broken by design - self._deadlines[fiber_self()] = (timeout and fiber_time() + timeout) + self._deadlines[fiber_self()] = (timeout and fiber_clock() + timeout) return self end @@ -909,9 +909,9 @@ function console_methods:eval(line, timeout) local transport = self._transport local pr = transport.perform_request if self.state ~= 'active' then - local deadline = fiber_time() + (timeout or TIMEOUT_INFINITY) + local deadline = fiber_clock() + (timeout or TIMEOUT_INFINITY) transport.wait_state('active', timeout) - timeout = max(0, deadline - fiber_time()) + timeout = max(0, deadline - fiber_clock()) end if self.protocol == 'Binary' then local loader = 'return require("console").eval(...)' diff --git a/src/fiber.c b/src/fiber.c index 5f093922214b7dc658d486d33bb046004bba6a8c..298c7ab2f2ae7dbe17231c9f1bc2d68074a22c29 100644 --- a/src/fiber.c +++ b/src/fiber.c @@ -354,6 +354,18 @@ fiber_time64(void) return (uint64_t) ( ev_now(loop()) * 1000000 + 0.5 ); } +double +fiber_clock(void) +{ + return ev_monotonic_now(loop()); +} + +uint64_t +fiber_clock64(void) +{ + return (uint64_t) ( ev_monotonic_now(loop()) * 1000000 + 0.5 ); +} + /** * Move current fiber to the end of ready fibers list and switch to next */ diff --git a/src/fiber.h b/src/fiber.h index f1610fc39ea6652219d4f663b966986c0abadd81..0d0930cf593359799c76bfe384958652fcd0dbcb 100644 --- a/src/fiber.h +++ b/src/fiber.h @@ -290,16 +290,32 @@ fiber_is_cancelled(); /** * Report loop begin time as double (cheap). + * Uses real time clock. */ API_EXPORT double fiber_time(void); /** * Report loop begin time as 64-bit int. + * Uses real time clock. */ API_EXPORT uint64_t fiber_time64(void); +/** + * Report loop begin time as double (cheap). + * Uses monotonic clock. + */ +API_EXPORT double +fiber_clock(void); + +/** + * Report loop begin time as 64-bit int. + * Uses monotonic clock. + */ +API_EXPORT uint64_t +fiber_clock64(void); + /** * Reschedule fiber to end of event loop cycle. */ diff --git a/src/lua/fiber.lua b/src/lua/fiber.lua index 20bdbbfead71402f372f797de133e27d405228cb..8712ee0d682aab4eda2be2cc7bcbff830c86987d 100644 --- a/src/lua/fiber.lua +++ b/src/lua/fiber.lua @@ -7,6 +7,10 @@ double fiber_time(void); uint64_t fiber_time64(void); +double +fiber_clock(void); +uint64_t +fiber_clock64(void); ]] local C = ffi.C @@ -18,6 +22,16 @@ local function fiber_time64() return C.fiber_time64() end +local function fiber_clock() + return tonumber(C.fiber_clock()) +end + +local function fiber_clock64() + return C.fiber_clock64() +end + fiber.time = fiber_time fiber.time64 = fiber_time64 +fiber.clock = fiber_clock +fiber.clock64 = fiber_clock64 return fiber diff --git a/src/lua/socket.lua b/src/lua/socket.lua index 84343ee4bc41dc297ae931b2c8ed152443953500..9270ada98f4f142fc0613d8893fd297b192ab9b6 100644 --- a/src/lua/socket.lua +++ b/src/lua/socket.lua @@ -600,9 +600,8 @@ local function read(self, limit, timeout, check, ...) return data end - local started = fiber.time() while timeout > 0 do - local started = fiber.time() + local started = fiber.clock() assert(rbuf:size() < limit) local to_read = math.min(limit - rbuf:size(), buffer.READAHEAD) @@ -635,7 +634,7 @@ local function read(self, limit, timeout, check, ...) if timeout <= 0 then break end - timeout = timeout - ( fiber.time() - started ) + timeout = timeout - ( fiber.clock() - started ) end self._errno = boxerrno.ETIMEDOUT return nil @@ -675,7 +674,7 @@ socket_methods.write = function(self, octets, timeout) return 0 end - local started = fiber.time() + local started = fiber.clock() while true do local written = syswrite(self, p, e - p) if written == 0 then @@ -690,7 +689,7 @@ socket_methods.write = function(self, octets, timeout) return nil end - timeout = timeout - (fiber.time() - started) + timeout = timeout - (fiber.clock() - started) if timeout <= 0 or not self:writable(timeout) then break end @@ -957,7 +956,7 @@ local function tcp_connect(host, port, timeout) family = 'PF_UNIX', type = 'SOCK_STREAM' }, timeout) end local timeout = timeout or TIMEOUT_INFINITY - local stop = fiber.time() + timeout + local stop = fiber.clock() + timeout local dns = getaddrinfo(host, port, timeout, { type = 'SOCK_STREAM', protocol = 'tcp' }) if dns == nil or #dns == 0 then @@ -965,7 +964,7 @@ local function tcp_connect(host, port, timeout) return nil end for i, remote in pairs(dns) do - timeout = stop - fiber.time() + timeout = stop - fiber.clock() if timeout <= 0 then boxerrno(boxerrno.ETIMEDOUT) return nil