Introduce monotonic timer functions. (#24)
* Introduce monotonic timer functions. Old fast timers are available through compiler switch. Add tests for both timers. * Bump version to 2.2.2.
This commit is contained in:
parent
df8d0da251
commit
67e214c5df
|
@ -1,5 +1,5 @@
|
|||
packageName = "chronos"
|
||||
version = "2.2.1"
|
||||
version = "2.2.2"
|
||||
author = "Status Research & Development GmbH"
|
||||
description = "Chronos"
|
||||
license = "Apache License 2.0 or MIT"
|
||||
|
@ -9,26 +9,45 @@ skipDirs = @["tests"]
|
|||
|
||||
requires "nim > 0.18.0"
|
||||
|
||||
task test, "Run all tests":
|
||||
for tfile in @[
|
||||
"testsync",
|
||||
"testsoon",
|
||||
"testtime",
|
||||
"testfut",
|
||||
"testsignal",
|
||||
"testaddress",
|
||||
"testdatagram",
|
||||
"teststream",
|
||||
"testserver",
|
||||
"testbugs",
|
||||
]:
|
||||
for cmd in @[
|
||||
"nim c -r -d:useSysAssert -d:useGcAssert tests/" & tfile,
|
||||
"nim c -r tests/" & tfile,
|
||||
#"nim c -r --gc:markAndSweep tests/" & tfile,
|
||||
"nim c -r -d:release tests/" & tfile
|
||||
]:
|
||||
echo "\n" & cmd
|
||||
exec cmd
|
||||
rmFile("tests/" & tfile.toExe())
|
||||
import ospaths
|
||||
|
||||
task test, "Run all tests":
|
||||
|
||||
var testFiles = @[
|
||||
"testsync",
|
||||
"testsoon",
|
||||
"testtime",
|
||||
"testfut",
|
||||
"testsignal",
|
||||
"testaddress",
|
||||
"testdatagram",
|
||||
"teststream",
|
||||
"testserver",
|
||||
"testbugs",
|
||||
]
|
||||
|
||||
var testCommands = @[
|
||||
"nim c -r -d:useSysAssert -d:useGcAssert",
|
||||
"nim c -r",
|
||||
"nim c -r -d:release"
|
||||
]
|
||||
|
||||
var timerCommands = @[
|
||||
" -d:asyncTimer=system",
|
||||
" -d:asyncTimer=mono"
|
||||
]
|
||||
|
||||
for tfile in testFiles:
|
||||
if tfile == "testtime":
|
||||
for cmd in testCommands:
|
||||
for def in timerCommands:
|
||||
var commandLine = (cmd & def & " tests") / tfile
|
||||
echo "\n" & commandLine
|
||||
exec commandLine
|
||||
rmFile("tests" / tfile.toExe())
|
||||
else:
|
||||
for cmd in testCommands:
|
||||
var commandLine = (cmd & " tests") / tfile
|
||||
echo "\n" & commandLine
|
||||
exec commandLine
|
||||
rmFile("tests" / tfile.toExe())
|
||||
|
|
|
@ -165,6 +165,13 @@ export asyncfutures2, timer
|
|||
|
||||
# TODO: Check if yielded future is nil and throw a more meaningful exception
|
||||
|
||||
when defined(windows):
|
||||
import winlean, sets, hashes
|
||||
else:
|
||||
import selectors
|
||||
from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK,
|
||||
MSG_NOSIGNAL
|
||||
|
||||
type
|
||||
AsyncError* = object of Exception
|
||||
## Generic async exception
|
||||
|
@ -172,7 +179,7 @@ type
|
|||
## Timeout exception
|
||||
|
||||
TimerCallback* = object
|
||||
finishAt*: uint64
|
||||
finishAt*: Moment
|
||||
function*: AsyncCallback
|
||||
|
||||
PDispatcherBase = ref object of RootRef
|
||||
|
@ -188,6 +195,24 @@ proc initCallSoonProc() =
|
|||
if asyncfutures2.getCallSoonProc().isNil:
|
||||
asyncfutures2.setCallSoonProc(callSoon)
|
||||
|
||||
func getAsyncTimestamp*(a: Duration): auto {.inline.} =
|
||||
## Return rounded up value of duration with milliseconds resolution.
|
||||
##
|
||||
## This function also take care on int32 overflow, because Linux and Windows
|
||||
## accepts signed 32bit integer as timeout.
|
||||
let milsec = Millisecond.nanoseconds()
|
||||
let nansec = a.nanoseconds()
|
||||
var res = nansec div milsec
|
||||
let mid = nansec mod milsec
|
||||
when defined(windows):
|
||||
res = min(cast[int64](high(int32) - 1), res)
|
||||
result = cast[DWORD](res)
|
||||
result += DWORD(min(1'i32, cast[int32](mid)))
|
||||
else:
|
||||
res = min(cast[int64](high(int32) - 1), res)
|
||||
result = cast[int32](res)
|
||||
result += min(1, cast[int32](mid))
|
||||
|
||||
template processTimersGetTimeout(loop, timeout: untyped) =
|
||||
var count = len(loop.timers)
|
||||
if count > 0:
|
||||
|
@ -199,10 +224,7 @@ template processTimersGetTimeout(loop, timeout: untyped) =
|
|||
loop.callbacks.addLast(loop.timers.pop().function)
|
||||
dec(count)
|
||||
if count > 0:
|
||||
when defined(windows):
|
||||
timeout = DWORD(lastFinish - curTime)
|
||||
else:
|
||||
timeout = int(lastFinish - curTime)
|
||||
timeout = (lastFinish - curTime).getAsyncTimestamp()
|
||||
|
||||
if timeout == 0:
|
||||
if len(loop.callbacks) == 0:
|
||||
|
@ -215,7 +237,7 @@ template processTimersGetTimeout(loop, timeout: untyped) =
|
|||
timeout = 0
|
||||
|
||||
template processTimers(loop: untyped) =
|
||||
var curTime = fastEpochTime()
|
||||
var curTime = Moment.now()
|
||||
var count = len(loop.timers)
|
||||
if count > 0:
|
||||
while count > 0:
|
||||
|
@ -238,7 +260,6 @@ template processCallbacks(loop: untyped) =
|
|||
callable.function(callable.udata)
|
||||
|
||||
when defined(windows) or defined(nimdoc):
|
||||
import winlean, sets, hashes
|
||||
type
|
||||
WSAPROC_TRANSMITFILE = proc(hSocket: SocketHandle, hFile: Handle,
|
||||
nNumberOfBytesToWrite: DWORD,
|
||||
|
@ -316,7 +337,7 @@ when defined(windows) or defined(nimdoc):
|
|||
proc poll*() =
|
||||
## Perform single asynchronous step.
|
||||
let loop = getGlobalDispatcher()
|
||||
var curTime = fastEpochTime()
|
||||
var curTime = Moment.now()
|
||||
var curTimeout = DWORD(0)
|
||||
|
||||
# Moving expired timers to `loop.callbacks` and calculate timeout
|
||||
|
@ -328,8 +349,10 @@ when defined(windows) or defined(nimdoc):
|
|||
var customOverlapped: PtrCustomOverlapped
|
||||
|
||||
let res = getQueuedCompletionStatus(
|
||||
loop.ioPort, addr lpNumberOfBytesTransferred, addr lpCompletionKey,
|
||||
cast[ptr POVERLAPPED](addr customOverlapped), curTimeout).bool
|
||||
loop.ioPort, addr lpNumberOfBytesTransferred,
|
||||
addr lpCompletionKey, cast[ptr POVERLAPPED](addr customOverlapped),
|
||||
curTimeout).bool
|
||||
|
||||
if res:
|
||||
customOverlapped.data.bytesCount = lpNumberOfBytesTransferred
|
||||
customOverlapped.data.errCode = OSErrorCode(-1)
|
||||
|
@ -428,9 +451,6 @@ when defined(windows) or defined(nimdoc):
|
|||
return fd in disp.handles
|
||||
|
||||
else:
|
||||
import selectors
|
||||
from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK,
|
||||
MSG_NOSIGNAL
|
||||
type
|
||||
AsyncFD* = distinct cint
|
||||
|
||||
|
@ -611,7 +631,7 @@ else:
|
|||
proc poll*() =
|
||||
## Perform single asynchronous step.
|
||||
let loop = getGlobalDispatcher()
|
||||
var curTime = fastEpochTime()
|
||||
var curTime = Moment.now()
|
||||
var curTimeout = 0
|
||||
|
||||
when ioselSupportedPlatform:
|
||||
|
@ -655,7 +675,7 @@ else:
|
|||
proc initAPI() =
|
||||
discard getGlobalDispatcher()
|
||||
|
||||
proc addTimer*(at: uint64, cb: CallbackFunc, udata: pointer = nil) =
|
||||
proc addTimer*(at: Moment, cb: CallbackFunc, udata: pointer = nil) =
|
||||
## Arrange for the callback ``cb`` to be called at the given absolute
|
||||
## timestamp ``at``. You can also pass ``udata`` to callback.
|
||||
let loop = getGlobalDispatcher()
|
||||
|
@ -663,7 +683,11 @@ proc addTimer*(at: uint64, cb: CallbackFunc, udata: pointer = nil) =
|
|||
function: AsyncCallback(function: cb, udata: udata))
|
||||
loop.timers.push(tcb)
|
||||
|
||||
proc removeTimer*(at: uint64, cb: CallbackFunc, udata: pointer = nil) =
|
||||
proc addTimer*(at: int64, cb: CallbackFunc, udata: pointer = nil) {.
|
||||
inline, deprecated: "Use addTimer(Duration, cb, udata)".} =
|
||||
addTimer(Moment.init(at, Millisecond), cb, udata)
|
||||
|
||||
proc removeTimer*(at: Moment, cb: CallbackFunc, udata: pointer = nil) =
|
||||
## Remove timer callback ``cb`` with absolute timestamp ``at`` from waiting
|
||||
## queue.
|
||||
let loop = getGlobalDispatcher()
|
||||
|
@ -677,18 +701,25 @@ proc removeTimer*(at: uint64, cb: CallbackFunc, udata: pointer = nil) =
|
|||
if index != -1:
|
||||
loop.timers.del(index)
|
||||
|
||||
proc sleepAsync*(ms: int): Future[void] =
|
||||
proc removeTimer*(at: int64, cb: CallbackFunc, udata: pointer = nil) {.
|
||||
inline, deprecated: "Use removeTimer(Duration, cb, udata)".} =
|
||||
removeTimer(Moment.init(at, Millisecond), cb, udata)
|
||||
|
||||
proc sleepAsync*(ms: Duration): Future[void] =
|
||||
## Suspends the execution of the current async procedure for the next
|
||||
## ``ms`` milliseconds.
|
||||
var retFuture = newFuture[void]("sleepAsync")
|
||||
proc completion(data: pointer) =
|
||||
if not retFuture.finished:
|
||||
retFuture.complete()
|
||||
addTimer(fastEpochTime() + uint64(ms),
|
||||
completion, cast[pointer](retFuture))
|
||||
addTimer(Moment.fromNow(ms), completion, cast[pointer](retFuture))
|
||||
return retFuture
|
||||
|
||||
proc withTimeout*[T](fut: Future[T], timeout: int): Future[bool] =
|
||||
proc sleepAsync*(ms: int): Future[void] {.
|
||||
inline, deprecated: "Use sleepAsync(Duration)".} =
|
||||
result = sleepAsync(ms.milliseconds())
|
||||
|
||||
proc withTimeout*[T](fut: Future[T], timeout: Duration): Future[bool] =
|
||||
## Returns a future which will complete once ``fut`` completes or after
|
||||
## ``timeout`` milliseconds has elapsed.
|
||||
##
|
||||
|
@ -704,11 +735,15 @@ proc withTimeout*[T](fut: Future[T], timeout: int): Future[bool] =
|
|||
else:
|
||||
if not retFuture.finished:
|
||||
retFuture.complete(true)
|
||||
addTimer(fastEpochTime() + uint64(timeout), continuation, nil)
|
||||
addTimer(Moment.fromNow(timeout), continuation, nil)
|
||||
fut.addCallback(continuation)
|
||||
return retFuture
|
||||
|
||||
proc wait*[T](fut: Future[T], timeout = -1): Future[T] =
|
||||
proc withTimeout*[T](fut: Future[T], timeout: int): Future[bool] {.
|
||||
inline, deprecated: "Use withTimeout(Future[T], Duration)".} =
|
||||
result = withTimeout(fut, timeout.milliseconds())
|
||||
|
||||
proc wait*[T](fut: Future[T], timeout = InfiniteDuration): Future[T] =
|
||||
## Returns a future which will complete once future ``fut`` completes
|
||||
## or if timeout of ``timeout`` milliseconds has been expired.
|
||||
##
|
||||
|
@ -726,9 +761,9 @@ proc wait*[T](fut: Future[T], timeout = -1): Future[T] =
|
|||
retFuture.fail(fut.error)
|
||||
else:
|
||||
retFuture.complete(fut.read())
|
||||
if timeout == -1:
|
||||
if timeout.isInfinite():
|
||||
retFuture = fut
|
||||
elif timeout == 0:
|
||||
elif timeout.isZero():
|
||||
if fut.finished:
|
||||
if fut.failed:
|
||||
retFuture.fail(fut.error)
|
||||
|
@ -737,10 +772,19 @@ proc wait*[T](fut: Future[T], timeout = -1): Future[T] =
|
|||
else:
|
||||
retFuture.fail(newException(AsyncTimeoutError, ""))
|
||||
else:
|
||||
addTimer(fastEpochTime() + uint64(timeout), continuation, nil)
|
||||
addTimer(Moment.fromNow(timeout), continuation, nil)
|
||||
fut.addCallback(continuation)
|
||||
return retFuture
|
||||
|
||||
proc wait*[T](fut: Future[T], timeout = -1): Future[T] {.
|
||||
inline, deprecated: "Use wait(Future[T], Duration)".} =
|
||||
if timeout == -1:
|
||||
wait(fut, InfiniteDuration)
|
||||
elif timeout == 0:
|
||||
wait(fut, ZeroDuration)
|
||||
else:
|
||||
wait(fut, timeout.milliseconds())
|
||||
|
||||
include asyncmacro2
|
||||
|
||||
proc callSoon(cbproc: CallbackFunc, data: pointer = nil) =
|
||||
|
|
|
@ -8,45 +8,437 @@
|
|||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
|
||||
|
||||
## This module implements cross-platform system timer with
|
||||
## milliseconds resolution.
|
||||
##
|
||||
## Timer supports two types of clocks:
|
||||
## ``system`` uses the most fast OS primitive to obtain wall clock time.
|
||||
## ``mono`` uses monotonic clock time (default).
|
||||
##
|
||||
## ``system`` clock is affected by discontinuous jumps in the system time. This
|
||||
## clock is significantly faster then ``mono`` clock in most of the cases.
|
||||
##
|
||||
## ``mono`` clock is not affected by discontinuous jumps in the system time.
|
||||
## This clock is slower then ``system`` clock.
|
||||
##
|
||||
## You can specify which timer you want to use ``-d:asyncTimer=<system/mono>``.
|
||||
const asyncTimer* {.strdefine.} = "mono"
|
||||
|
||||
when defined(windows):
|
||||
from winlean import DWORD
|
||||
|
||||
from winlean import DWORD, getSystemTimeAsFileTime, FILETIME
|
||||
when asyncTimer == "system":
|
||||
from winlean import getSystemTimeAsFileTime, FILETIME
|
||||
|
||||
proc fastEpochTime*(): uint64 {.inline.} =
|
||||
var t: FILETIME
|
||||
getSystemTimeAsFileTime(t)
|
||||
result = ((uint64(t.dwHighDateTime) shl 32) or
|
||||
uint64(t.dwLowDateTime)) div 10_000
|
||||
proc fastEpochTime*(): uint64 {.
|
||||
inline, deprecated: "Use Moment.now()".} =
|
||||
## Timer resolution is millisecond.
|
||||
var t: FILETIME
|
||||
getSystemTimeAsFileTime(t)
|
||||
result = ((cast[uint64](t.dwHighDateTime) shl 32) or
|
||||
cast[uint64](t.dwLowDateTime)) div 10_000
|
||||
|
||||
proc fastEpochTimeNano(): uint64 {.inline.} =
|
||||
## Timer resolution is nanosecond.
|
||||
var t: FILETIME
|
||||
getSystemTimeAsFileTime(t)
|
||||
result = ((cast[uint64](t.dwHighDateTime) shl 32) or
|
||||
cast[uint64](t.dwLowDateTime)) * 100
|
||||
|
||||
else:
|
||||
proc QueryPerformanceCounter(res: var uint64) {.
|
||||
importc: "QueryPerformanceCounter", stdcall, dynlib: "kernel32".}
|
||||
proc QueryPerformanceFrequency(res: var uint64) {.
|
||||
importc: "QueryPerformanceFrequency", stdcall, dynlib: "kernel32".}
|
||||
|
||||
var queryFrequencyM: uint64
|
||||
var queryFrequencyN: uint64
|
||||
|
||||
proc fastEpochTimeNano(): uint64 {.inline.} =
|
||||
## Procedure's resolution is nanosecond.
|
||||
var res: uint64
|
||||
QueryPerformanceCounter(res)
|
||||
result = res * queryFrequencyN
|
||||
|
||||
proc fastEpochTime*(): uint64 {.
|
||||
inline, deprecated: "Use Moment.now()".} =
|
||||
## Procedure's resolution is millisecond.
|
||||
var res: uint64
|
||||
QueryPerformanceCounter(res)
|
||||
result = res div queryFrequencyM
|
||||
|
||||
proc setupQueryFrequence() =
|
||||
var freq: uint64
|
||||
QueryPerformanceFrequency(freq)
|
||||
if freq < 1000:
|
||||
queryFrequencyM = freq
|
||||
else:
|
||||
queryFrequencyM = freq div 1_000
|
||||
queryFrequencyN = 1_000_000_000'u64 div freq
|
||||
|
||||
setupQueryFrequence()
|
||||
|
||||
elif defined(macosx):
|
||||
|
||||
from posix import Timeval
|
||||
when asyncTimer == "system":
|
||||
from posix import Timeval
|
||||
|
||||
proc posix_gettimeofday(tp: var Timeval, unused: pointer = nil) {.
|
||||
importc: "gettimeofday", header: "<sys/time.h>".}
|
||||
proc posix_gettimeofday(tp: var Timeval, unused: pointer = nil) {.
|
||||
importc: "gettimeofday", header: "<sys/time.h>".}
|
||||
|
||||
proc fastEpochTime*(): uint64 {.inline.} =
|
||||
var t: Timeval
|
||||
posix_gettimeofday(t)
|
||||
result = (uint64(t.tv_sec) * 1_000 + uint64(t.tv_usec) div 1_000)
|
||||
proc fastEpochTime*(): uint64 {.
|
||||
inline, deprecated: "Use Moment.now()".} =
|
||||
## Procedure's resolution is millisecond.
|
||||
var t: Timeval
|
||||
posix_gettimeofday(t)
|
||||
result = (cast[uint64](t.tv_sec) * 1_000 +
|
||||
cast[uint64](t.tv_usec) div 1_000)
|
||||
|
||||
proc fastEpochTimeNano(): uint64 {.inline.} =
|
||||
## Procedure's resolution is nanosecond.
|
||||
var t: Timeval
|
||||
posix_gettimeofday(t)
|
||||
result = (cast[uint64](t.tv_sec) * 1_000_000_000 +
|
||||
cast[uint64](t.tv_usec) * 1_000)
|
||||
else:
|
||||
from posix import clock_gettime, Timespec, CLOCK_MONOTONIC
|
||||
|
||||
proc fastEpochTime*(): uint64 {.
|
||||
inline, deprecated: "Use Moment.now()".} =
|
||||
## Procedure's resolution is millisecond.
|
||||
var t: Timespec
|
||||
discard clock_gettime(CLOCK_MONOTONIC, t)
|
||||
result = ((cast[uint64](t.tv_sec) * 1_000) +
|
||||
(cast[uint64](t.tv_nsec) div 1_000_000))
|
||||
|
||||
proc fastEpochTimeNano(): uint64 {.inline.} =
|
||||
## Procedure's resolution is nanosecond.
|
||||
var t: Timespec
|
||||
discard clock_gettime(CLOCK_MONOTONIC, t)
|
||||
result = cast[uint64](t.tv_sec) * 1_000_000_000'u64 +
|
||||
cast[uint64](t.tv_nsec)
|
||||
|
||||
elif defined(posix):
|
||||
from posix import clock_gettime, Timespec, CLOCK_REALTIME, CLOCK_MONOTONIC
|
||||
|
||||
from posix import clock_gettime, Timespec, CLOCK_REALTIME
|
||||
when asyncTimer == "system":
|
||||
proc fastEpochTime*(): uint64 {.
|
||||
inline, deprecated: "Use Moment.now()".} =
|
||||
## Procedure's resolution is millisecond.
|
||||
var t: Timespec
|
||||
discard clock_gettime(CLOCK_REALTIME, t)
|
||||
result = (cast[uint64](t.tv_sec) * 1_000 +
|
||||
(cast[uint64](t.tv_nsec) div 1_000_000))
|
||||
|
||||
proc fastEpochTime*(): uint64 {.inline.} =
|
||||
var t: Timespec
|
||||
discard clock_gettime(CLOCK_REALTIME, t)
|
||||
result = (uint64(t.tv_sec) * 1_000 + uint64(t.tv_nsec) div 1_000_000)
|
||||
proc fastEpochTimeNano(): uint64 {.inline.} =
|
||||
## Procedure's resolution is nanosecond.
|
||||
var t: Timespec
|
||||
discard clock_gettime(CLOCK_REALTIME, t)
|
||||
result = cast[uint64](t.tv_sec) * 1_000_000_000'u64 +
|
||||
cast[uint64](t.tv_nsec)
|
||||
|
||||
else:
|
||||
proc fastEpochTime*(): uint64 {.
|
||||
inline, deprecated: "Use Moment.now()".} =
|
||||
## Procedure's resolution is millisecond.
|
||||
var t: Timespec
|
||||
discard clock_gettime(CLOCK_MONOTONIC, t)
|
||||
result = (cast[uint64](t.tv_sec) * 1_000 +
|
||||
(cast[uint64](t.tv_nsec) div 1_000_000))
|
||||
|
||||
proc fastEpochTimeNano(): uint64 {.inline.} =
|
||||
## Procedure's resolution is nanosecond.
|
||||
var t: Timespec
|
||||
discard clock_gettime(CLOCK_MONOTONIC, t)
|
||||
result = cast[uint64](t.tv_sec) * 1_000_000_000'u64 +
|
||||
cast[uint64](t.tv_nsec)
|
||||
|
||||
elif defined(nimdoc):
|
||||
|
||||
proc fastEpochTime*(): uint64
|
||||
proc fastEpochTime*(): uint64 {.deprecated: "Use Moment.now()".}
|
||||
## Returns system's timer in milliseconds.
|
||||
|
||||
else:
|
||||
error("Sorry, your operation system is not yet supported!")
|
||||
|
||||
type
|
||||
Moment* = object
|
||||
## A Moment in time. Its value has no direct meaning, but can be compared
|
||||
## with other Moments. Moments are captured using a monotonically
|
||||
## non-decreasing clock (by default).
|
||||
value: int64
|
||||
|
||||
Duration* = object
|
||||
## A Duration is the interval between to points in time.
|
||||
value: int64
|
||||
|
||||
when sizeof(int) == 4:
|
||||
type SomeIntegerI64* = SomeSignedInt|uint|uint8|uint16|uint32
|
||||
else:
|
||||
type SomeIntegerI64* = SomeSignedInt|uint8|uint16|uint32
|
||||
|
||||
func `+`*(a: Duration, b: Duration): Duration {.inline.} =
|
||||
## Duration + Duration = Duration
|
||||
result.value = a.value + b.value
|
||||
|
||||
func `+`*(a: Duration, b: Moment): Moment {.inline.} =
|
||||
## Duration + Moment = Moment
|
||||
result.value = a.value + b.value
|
||||
|
||||
func `+`*(a: Moment, b: Duration): Moment {.inline.} =
|
||||
## Moment + Duration = Moment
|
||||
result.value = a.value + b.value
|
||||
|
||||
func `+=`*(a: var Moment, b: Duration) {.inline.} =
|
||||
## Moment += Duration
|
||||
a.value += b.value
|
||||
|
||||
func `+=`*(a: var Duration, b: Duration) {.inline.} =
|
||||
## Duration += Duration
|
||||
a.value += b.value
|
||||
|
||||
func `-`*(a, b: Moment): Duration {.inline.} =
|
||||
## Moment - Moment = Duration
|
||||
##
|
||||
## Note: Duration can't be negative.
|
||||
result.value = if a.value >= b.value: a.value - b.value else: 0'i64
|
||||
|
||||
func `-`*(a: Moment, b: Duration): Moment {.inline.} =
|
||||
## Moment - Duration = Moment
|
||||
##
|
||||
## Note: Moment can be negative
|
||||
result.value = a.value - b.value
|
||||
|
||||
func `-`*(a: Duration, b: Duration): Duration {.inline.} =
|
||||
## Duration - Duration = Duration
|
||||
##
|
||||
## Note: Duration can't be negative.
|
||||
result.value = if a.value >= b.value: a.value - b.value else: 0'i64
|
||||
|
||||
func `-=`*(a: var Duration, b: Duration): Duration {.inline.} =
|
||||
## Duration -= Duration
|
||||
a.value = if a.value >= b.value: a.value - b.value else: 0'i64
|
||||
|
||||
func `-=`*(a: var Moment, b: Duration): Moment {.inline.} =
|
||||
## Moment -= Duration
|
||||
a.value -= b.value
|
||||
|
||||
func `==`*(a, b: Duration): bool {.inline.} =
|
||||
## Returns ``true`` if ``a`` equal to ``b``.
|
||||
result = (a.value == b.value)
|
||||
|
||||
func `==`*(a, b: Moment): bool {.inline.} =
|
||||
## Returns ``true`` if ``a`` equal to ``b``.
|
||||
result = (a.value == b.value)
|
||||
|
||||
func `<`*(a, b: Duration): bool {.inline.} =
|
||||
## Returns ``true`` if ``a`` less then ``b``.
|
||||
result = (a.value < b.value)
|
||||
|
||||
func `<`*(a, b: Moment): bool {.inline.} =
|
||||
## Returns ``true`` if ``a`` less then ``b``.
|
||||
result = (a.value < b.value)
|
||||
|
||||
func `<=`*(a, b: Duration): bool {.inline.} =
|
||||
## Returns ``true`` if ``a`` less or equal ``b``.
|
||||
result = (a.value <= b.value)
|
||||
|
||||
func `<=`*(a, b: Moment): bool {.inline.} =
|
||||
## Returns ``true`` if ``a`` less or equal ``b``.
|
||||
result = (a.value <= b.value)
|
||||
|
||||
func `>`*(a, b: Duration): bool {.inline.} =
|
||||
## Returns ``true`` if ``a`` bigger then ``b``.
|
||||
result = (a.value > b.value)
|
||||
|
||||
func `>`*(a, b: Moment): bool {.inline.} =
|
||||
## Returns ``true`` if ``a`` bigger then ``b``.
|
||||
result = (a.value > b.value)
|
||||
|
||||
func `>=`*(a, b: Duration): bool {.inline.} =
|
||||
## Returns ``true`` if ``a`` bigger or equal ``b``.
|
||||
result = (a.value >= b.value)
|
||||
|
||||
func `>=`*(a, b: Moment): bool {.inline.} =
|
||||
## Returns ``true`` if ``a`` bigger or equal ``b``.
|
||||
result = (a.value >= b.value)
|
||||
|
||||
func `*`*(a: Duration, b: SomeIntegerI64): Duration {.inline.} =
|
||||
## Returns Duration multiplied by scalar integer.
|
||||
result.value = a.value * cast[int64](b)
|
||||
|
||||
func `*`*(a: SomeIntegerI64, b: Duration): Duration {.inline.} =
|
||||
## Returns Duration multiplied by scalar integer.
|
||||
result.value = cast[int64](a) * b.value
|
||||
|
||||
func `div`*(a: Duration, b: SomeIntegerI64): Duration {.inline.} =
|
||||
## Returns Duration which is result of dividing a Duration by scalar integer.
|
||||
result.value = a.value div cast[int64](b)
|
||||
|
||||
const
|
||||
Nanosecond* = Duration(value: 1'i64)
|
||||
Microsecond* = Nanosecond * 1_000'i64
|
||||
Millisecond* = Microsecond * 1_000'i64
|
||||
Second* = Millisecond * 1_000'i64
|
||||
Minute* = Second * 60'i64
|
||||
Hour* = Minute * 60'i64
|
||||
Day* = Hour * 24'i64
|
||||
Week* = Day * 7'i64
|
||||
|
||||
ZeroDuration* = Duration(value: 0'i64)
|
||||
InfiniteDuration* = Duration(value: high(int64))
|
||||
|
||||
func nanoseconds*(v: SomeIntegerI64): Duration {.inline.} =
|
||||
## Initialize Duration with nanoseconds value ``v``.
|
||||
result.value = cast[int64](v)
|
||||
|
||||
func microseconds*(v: SomeIntegerI64): Duration {.inline.} =
|
||||
## Initialize Duration with microseconds value ``v``.
|
||||
result.value = cast[int64](v) * Microsecond.value
|
||||
|
||||
func milliseconds*(v: SomeIntegerI64): Duration {.inline.} =
|
||||
## Initialize Duration with milliseconds value ``v``.
|
||||
result.value = cast[int64](v) * Millisecond.value
|
||||
|
||||
func seconds*(v: SomeIntegerI64): Duration {.inline.} =
|
||||
## Initialize Duration with seconds value ``v``.
|
||||
result.value = cast[int64](v) * Second.value
|
||||
|
||||
func minutes*(v: SomeIntegerI64): Duration {.inline.} =
|
||||
## Initialize Duration with minutes value ``v``.
|
||||
result.value = Minute.value * cast[int64](v)
|
||||
|
||||
func hours*(v: SomeIntegerI64): Duration {.inline.} =
|
||||
## Initialize Duration with hours value ``v``.
|
||||
result.value = cast[int64](v) * Hour.value
|
||||
|
||||
func days*(v: SomeIntegerI64): Duration {.inline.} =
|
||||
## Initialize Duration with days value ``v``.
|
||||
result.value = cast[int64](v) * Day.value
|
||||
|
||||
func weeks*(v: SomeIntegerI64): Duration {.inline.} =
|
||||
## Initialize Duration with weeks value ``v``.
|
||||
result.value = cast[int64](v) * Week.value
|
||||
|
||||
func nanoseconds*(v: Duration): int64 {.inline.} =
|
||||
## Round Duration ``v`` to nanoseconds.
|
||||
result = v.value
|
||||
|
||||
func microseconds*(v: Duration): int64 {.inline.} =
|
||||
## Round Duration ``v`` to microseconds.
|
||||
result = v.value div Microsecond.value
|
||||
|
||||
func milliseconds*(v: Duration): int64 {.inline.} =
|
||||
## Round Duration ``v`` to milliseconds.
|
||||
result = v.value div Millisecond.value
|
||||
|
||||
func seconds*(v: Duration): int64 {.inline.} =
|
||||
## Round Duration ``v`` to seconds.
|
||||
result = v.value div Second.value
|
||||
|
||||
func minutes*(v: Duration): int64 {.inline.} =
|
||||
## Round Duration ``v`` to minutes.
|
||||
result = v.value div Minute.value
|
||||
|
||||
func hours*(v: Duration): int64 {.inline.} =
|
||||
## Round Duration ``v`` to hours.
|
||||
result = v.value div Hour.value
|
||||
|
||||
func days*(v: Duration): int64 {.inline.} =
|
||||
## Round Duration ``v`` to days.
|
||||
result = v.value div Day.value
|
||||
|
||||
func weeks*(v: Duration): int64 {.inline.} =
|
||||
## Round Duration ``v`` to weeks.
|
||||
result = v.value div Week.value
|
||||
|
||||
func nanos*(v: SomeIntegerI64): Duration {.inline.} =
|
||||
result = nanoseconds(v)
|
||||
|
||||
func micros*(v: SomeIntegerI64): Duration {.inline.} =
|
||||
result = microseconds(v)
|
||||
|
||||
func millis*(v: SomeIntegerI64): Duration {.inline.} =
|
||||
result = milliseconds(v)
|
||||
|
||||
func secs*(v: SomeIntegerI64): Duration {.inline.} =
|
||||
result = seconds(v)
|
||||
|
||||
func nanos*(v: Duration): int64 {.inline.} =
|
||||
result = nanoseconds(v)
|
||||
|
||||
func micros*(v: Duration): int64 {.inline.} =
|
||||
result = microseconds(v)
|
||||
|
||||
func millis*(v: Duration): int64 {.inline.} =
|
||||
result = milliseconds(v)
|
||||
|
||||
func secs*(v: Duration): int64 {.inline.} =
|
||||
result = seconds(v)
|
||||
|
||||
func `$`*(a: Duration): string {.inline.} =
|
||||
## Returns string representation of Duration ``a`` as nanoseconds value.
|
||||
var v = a.value
|
||||
if v >= Week.value:
|
||||
result = $(v div Week.value) & "w"
|
||||
v = v mod Week.value
|
||||
if v >= Day.value:
|
||||
result &= $(v div Day.value) & "d"
|
||||
v = v mod Day.value
|
||||
if v >= Hour.value:
|
||||
result &= $(v div Hour.value) & "h"
|
||||
v = v mod Hour.value
|
||||
if v >= Minute.value:
|
||||
result &= $(v div Minute.value) & "m"
|
||||
v = v mod Minute.value
|
||||
if v >= Second.value:
|
||||
result &= $(v div Second.value) & "s"
|
||||
v = v mod Second.value
|
||||
if v >= Millisecond.value:
|
||||
result &= $(v div Millisecond.value) & "ms"
|
||||
v = v mod Millisecond.value
|
||||
if v >= Microsecond.value:
|
||||
result &= $(v div Microsecond.value) & "us"
|
||||
v = v mod Microsecond.value
|
||||
if v >= Nanosecond.value:
|
||||
result &= $(v div Nanosecond.value) & "ns"
|
||||
|
||||
func `$`*(a: Moment): string {.inline.} =
|
||||
## Returns string representation of Moment ``a`` as nanoseconds value.
|
||||
result = $(a.value)
|
||||
result.add("ns")
|
||||
|
||||
func isZero*(a: Duration): bool {.inline.} =
|
||||
## Returns ``true`` if Duration ``a`` is ``0``.
|
||||
result = (a.value == 0)
|
||||
|
||||
func isInfinite*(a: Duration): bool {.inline.} =
|
||||
## Returns ``true`` if Duration ``a`` is infinite.
|
||||
result = (a.value == InfiniteDuration.value)
|
||||
|
||||
proc now*(t: typedesc[Moment]): Moment {.inline.} =
|
||||
## Returns current moment in time as Moment.
|
||||
result.value = cast[int64](fastEpochTimeNano())
|
||||
|
||||
func init*(t: typedesc[Moment], value: int64, precision: Duration): Moment =
|
||||
## Initialize Moment with absolute time value ``value`` with precision
|
||||
## ``precision``.
|
||||
result.value = value * precision.value
|
||||
|
||||
proc fromNow*(t: typedesc[Moment], a: Duration): Moment {.inline.} =
|
||||
## Returns moment in time which is equal to current moment + Duration.
|
||||
result = Moment.now() + a
|
||||
|
||||
when defined(posix):
|
||||
from posix import Time, Suseconds, Timeval, Timespec
|
||||
|
||||
func toTimeval*(a: Duration): Timeval =
|
||||
## Convert Duration ``a`` to ``Timeval`` object.
|
||||
let m = a.value mod Second.value
|
||||
result.tv_sec = cast[Time](a.value div Second.value)
|
||||
result.tv_usec = cast[Suseconds](m div Microsecond.value)
|
||||
|
||||
func toTimespec*(a: Duration): Timespec =
|
||||
## Convert Duration ``a`` to ``Timespec`` object.
|
||||
result.tv_sec = cast[Time](a.value div Second.value)
|
||||
result.tv_nsec = cast[int](a.value mod Second.value)
|
||||
|
|
|
@ -582,7 +582,7 @@ when defined(windows):
|
|||
if pipeHandle == INVALID_HANDLE_VALUE:
|
||||
let err = osLastError()
|
||||
if int32(err) == ERROR_PIPE_BUSY:
|
||||
addTimer(fastEpochTime() + 50, pipeContinuation, nil)
|
||||
addTimer(Moment.fromNow(50.milliseconds), pipeContinuation, nil)
|
||||
else:
|
||||
retFuture.fail(getTransportOsError(err))
|
||||
else:
|
||||
|
|
|
@ -444,7 +444,7 @@ proc testConnReset(): Future[bool] {.async.} =
|
|||
var dgram2 = newDatagramTransport(clientMark)
|
||||
var data = "MESSAGE"
|
||||
asyncCheck dgram2.sendTo(ta, data)
|
||||
await sleepAsync(1000)
|
||||
await sleepAsync(2000.milliseconds)
|
||||
result = (counter == 0)
|
||||
dgram2.close()
|
||||
await dgram2.join()
|
||||
|
|
|
@ -10,7 +10,7 @@ import unittest
|
|||
import ../chronos
|
||||
|
||||
proc testFuture1(): Future[int] {.async.} =
|
||||
await sleepAsync(100)
|
||||
await sleepAsync(1.milliseconds)
|
||||
|
||||
proc testFuture2(): Future[int] {.async.} =
|
||||
return 1
|
||||
|
@ -18,11 +18,14 @@ proc testFuture2(): Future[int] {.async.} =
|
|||
proc testFuture3(): Future[int] {.async.} =
|
||||
result = await testFuture2()
|
||||
|
||||
proc testFuture100(): Future[int] {.async.} =
|
||||
await sleepAsync(100.milliseconds)
|
||||
|
||||
proc testFuture4(): Future[int] {.async.} =
|
||||
## Test for not immediately completed future and timeout = -1
|
||||
result = 0
|
||||
try:
|
||||
var res = await wait(testFuture1(), -1)
|
||||
var res = await wait(testFuture1(), InfiniteDuration)
|
||||
result = 1
|
||||
except:
|
||||
result = 0
|
||||
|
@ -33,7 +36,7 @@ proc testFuture4(): Future[int] {.async.} =
|
|||
## Test for immediately completed future and timeout = -1
|
||||
result = 0
|
||||
try:
|
||||
var res = await wait(testFuture2(), -1)
|
||||
var res = await wait(testFuture2(), InfiniteDuration)
|
||||
result = 2
|
||||
except:
|
||||
result = 0
|
||||
|
@ -44,7 +47,7 @@ proc testFuture4(): Future[int] {.async.} =
|
|||
## Test for not immediately completed future and timeout = 0
|
||||
result = 0
|
||||
try:
|
||||
var res = await wait(testFuture1(), 0)
|
||||
var res = await wait(testFuture1(), 0.milliseconds)
|
||||
except AsyncTimeoutError:
|
||||
result = 3
|
||||
|
||||
|
@ -54,7 +57,7 @@ proc testFuture4(): Future[int] {.async.} =
|
|||
## Test for immediately completed future and timeout = 0
|
||||
result = 0
|
||||
try:
|
||||
var res = await wait(testFuture2(), 0)
|
||||
var res = await wait(testFuture2(), 0.milliseconds)
|
||||
result = 4
|
||||
except:
|
||||
result = 0
|
||||
|
@ -65,7 +68,7 @@ proc testFuture4(): Future[int] {.async.} =
|
|||
## Test for future which cannot be completed in timeout period
|
||||
result = 0
|
||||
try:
|
||||
var res = await wait(testFuture1(), 50)
|
||||
var res = await wait(testFuture100(), 50.milliseconds)
|
||||
except AsyncTimeoutError:
|
||||
result = 5
|
||||
|
||||
|
@ -74,7 +77,7 @@ proc testFuture4(): Future[int] {.async.} =
|
|||
|
||||
## Test for future which will be completed before timeout exceeded.
|
||||
try:
|
||||
var res = await wait(testFuture1(), 300)
|
||||
var res = await wait(testFuture100(), 500.milliseconds)
|
||||
result = 6
|
||||
except:
|
||||
result = -6
|
||||
|
@ -83,6 +86,8 @@ proc test1(): bool =
|
|||
var fut = testFuture1()
|
||||
poll()
|
||||
poll()
|
||||
if not fut.finished:
|
||||
poll()
|
||||
result = fut.finished
|
||||
|
||||
proc test2(): bool =
|
||||
|
@ -138,106 +143,106 @@ proc testAllVarargs(): int =
|
|||
var completedFutures = 0
|
||||
|
||||
proc vlient1() {.async.} =
|
||||
await sleepAsync(100)
|
||||
await sleepAsync(100.milliseconds)
|
||||
inc(completedFutures)
|
||||
|
||||
proc vlient2() {.async.} =
|
||||
await sleepAsync(200)
|
||||
await sleepAsync(200.milliseconds)
|
||||
inc(completedFutures)
|
||||
|
||||
proc vlient3() {.async.} =
|
||||
await sleepAsync(300)
|
||||
await sleepAsync(300.milliseconds)
|
||||
inc(completedFutures)
|
||||
|
||||
proc vlient4() {.async.} =
|
||||
await sleepAsync(400)
|
||||
await sleepAsync(400.milliseconds)
|
||||
inc(completedFutures)
|
||||
|
||||
proc vlient5() {.async.} =
|
||||
await sleepAsync(500)
|
||||
await sleepAsync(500.milliseconds)
|
||||
inc(completedFutures)
|
||||
|
||||
proc vlient1f() {.async.} =
|
||||
await sleepAsync(100)
|
||||
await sleepAsync(100.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc vlient2f() {.async.} =
|
||||
await sleepAsync(100)
|
||||
await sleepAsync(100.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc vlient3f() {.async.} =
|
||||
await sleepAsync(100)
|
||||
await sleepAsync(100.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc vlient4f() {.async.} =
|
||||
await sleepAsync(100)
|
||||
await sleepAsync(100.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc vlient5f() {.async.} =
|
||||
await sleepAsync(100)
|
||||
await sleepAsync(100.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc client1(): Future[int] {.async.} =
|
||||
await sleepAsync(100)
|
||||
await sleepAsync(100.milliseconds)
|
||||
inc(completedFutures)
|
||||
result = 1
|
||||
|
||||
proc client2(): Future[int] {.async.} =
|
||||
await sleepAsync(200)
|
||||
await sleepAsync(200.milliseconds)
|
||||
inc(completedFutures)
|
||||
result = 1
|
||||
|
||||
proc client3(): Future[int] {.async.} =
|
||||
await sleepAsync(300)
|
||||
await sleepAsync(300.milliseconds)
|
||||
inc(completedFutures)
|
||||
result = 1
|
||||
|
||||
proc client4(): Future[int] {.async.} =
|
||||
await sleepAsync(400)
|
||||
await sleepAsync(400.milliseconds)
|
||||
inc(completedFutures)
|
||||
result = 1
|
||||
|
||||
proc client5(): Future[int] {.async.} =
|
||||
await sleepAsync(500)
|
||||
await sleepAsync(500.milliseconds)
|
||||
inc(completedFutures)
|
||||
result = 1
|
||||
|
||||
proc client1f(): Future[int] {.async.} =
|
||||
await sleepAsync(100)
|
||||
await sleepAsync(100.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc client2f(): Future[int] {.async.} =
|
||||
await sleepAsync(200)
|
||||
await sleepAsync(200.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc client3f(): Future[int] {.async.} =
|
||||
await sleepAsync(300)
|
||||
await sleepAsync(300.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc client4f(): Future[int] {.async.} =
|
||||
await sleepAsync(400)
|
||||
await sleepAsync(400.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc client5f(): Future[int] {.async.} =
|
||||
await sleepAsync(500)
|
||||
await sleepAsync(500.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
@ -284,106 +289,106 @@ proc testAllSeq(): int =
|
|||
var nfutures = newSeq[Future[int]]()
|
||||
|
||||
proc vlient1() {.async.} =
|
||||
await sleepAsync(100)
|
||||
await sleepAsync(100.milliseconds)
|
||||
inc(completedFutures)
|
||||
|
||||
proc vlient2() {.async.} =
|
||||
await sleepAsync(200)
|
||||
await sleepAsync(200.milliseconds)
|
||||
inc(completedFutures)
|
||||
|
||||
proc vlient3() {.async.} =
|
||||
await sleepAsync(300)
|
||||
await sleepAsync(300.milliseconds)
|
||||
inc(completedFutures)
|
||||
|
||||
proc vlient4() {.async.} =
|
||||
await sleepAsync(400)
|
||||
await sleepAsync(400.milliseconds)
|
||||
inc(completedFutures)
|
||||
|
||||
proc vlient5() {.async.} =
|
||||
await sleepAsync(500)
|
||||
await sleepAsync(500.milliseconds)
|
||||
inc(completedFutures)
|
||||
|
||||
proc vlient1f() {.async.} =
|
||||
await sleepAsync(100)
|
||||
await sleepAsync(100.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc vlient2f() {.async.} =
|
||||
await sleepAsync(100)
|
||||
await sleepAsync(100.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc vlient3f() {.async.} =
|
||||
await sleepAsync(100)
|
||||
await sleepAsync(100.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc vlient4f() {.async.} =
|
||||
await sleepAsync(100)
|
||||
await sleepAsync(100.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc vlient5f() {.async.} =
|
||||
await sleepAsync(100)
|
||||
await sleepAsync(100.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc client1(): Future[int] {.async.} =
|
||||
await sleepAsync(100)
|
||||
await sleepAsync(100.milliseconds)
|
||||
inc(completedFutures)
|
||||
result = 1
|
||||
|
||||
proc client2(): Future[int] {.async.} =
|
||||
await sleepAsync(200)
|
||||
await sleepAsync(200.milliseconds)
|
||||
inc(completedFutures)
|
||||
result = 1
|
||||
|
||||
proc client3(): Future[int] {.async.} =
|
||||
await sleepAsync(300)
|
||||
await sleepAsync(300.milliseconds)
|
||||
inc(completedFutures)
|
||||
result = 1
|
||||
|
||||
proc client4(): Future[int] {.async.} =
|
||||
await sleepAsync(400)
|
||||
await sleepAsync(400.milliseconds)
|
||||
inc(completedFutures)
|
||||
result = 1
|
||||
|
||||
proc client5(): Future[int] {.async.} =
|
||||
await sleepAsync(500)
|
||||
await sleepAsync(500.milliseconds)
|
||||
inc(completedFutures)
|
||||
result = 1
|
||||
|
||||
proc client1f(): Future[int] {.async.} =
|
||||
await sleepAsync(100)
|
||||
await sleepAsync(100.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc client2f(): Future[int] {.async.} =
|
||||
await sleepAsync(200)
|
||||
await sleepAsync(200.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc client3f(): Future[int] {.async.} =
|
||||
await sleepAsync(300)
|
||||
await sleepAsync(300.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc client4f(): Future[int] {.async.} =
|
||||
await sleepAsync(400)
|
||||
await sleepAsync(400.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc client5f(): Future[int] {.async.} =
|
||||
await sleepAsync(500)
|
||||
await sleepAsync(500.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
@ -464,51 +469,51 @@ proc testAsyncDiscard(): int =
|
|||
var completedFutures = 0
|
||||
|
||||
proc client1() {.async.} =
|
||||
await sleepAsync(100)
|
||||
await sleepAsync(100.milliseconds)
|
||||
inc(completedFutures)
|
||||
|
||||
proc client2() {.async.} =
|
||||
await sleepAsync(200)
|
||||
await sleepAsync(200.milliseconds)
|
||||
inc(completedFutures)
|
||||
|
||||
proc client3() {.async.} =
|
||||
await sleepAsync(300)
|
||||
await sleepAsync(300.milliseconds)
|
||||
inc(completedFutures)
|
||||
|
||||
proc client4() {.async.} =
|
||||
await sleepAsync(400)
|
||||
await sleepAsync(400.milliseconds)
|
||||
inc(completedFutures)
|
||||
|
||||
proc client5() {.async.} =
|
||||
await sleepAsync(500)
|
||||
await sleepAsync(500.milliseconds)
|
||||
inc(completedFutures)
|
||||
|
||||
proc client1f() {.async.} =
|
||||
await sleepAsync(100)
|
||||
await sleepAsync(100.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc client2f() {.async.} =
|
||||
await sleepAsync(200)
|
||||
await sleepAsync(200.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc client3f() {.async.} =
|
||||
await sleepAsync(300)
|
||||
await sleepAsync(300.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc client4f() {.async.} =
|
||||
await sleepAsync(400)
|
||||
await sleepAsync(400.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc client5f() {.async.} =
|
||||
await sleepAsync(500)
|
||||
await sleepAsync(500.milliseconds)
|
||||
inc(completedFutures)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
@ -524,7 +529,7 @@ proc testAsyncDiscard(): int =
|
|||
asyncDiscard client5()
|
||||
asyncDiscard client5f()
|
||||
|
||||
waitFor(sleepAsync(2000))
|
||||
waitFor(sleepAsync(2000.milliseconds))
|
||||
result = completedFutures
|
||||
|
||||
proc testAllZero(): bool =
|
||||
|
|
|
@ -20,7 +20,7 @@ when not defined(windows):
|
|||
removeSignal(int(cdata.fd))
|
||||
|
||||
proc asyncProc() {.async.} =
|
||||
await sleepAsync(500)
|
||||
await sleepAsync(500.milliseconds)
|
||||
|
||||
proc test(signal, value: int): bool =
|
||||
discard addSignal(signal, signalProc, cast[pointer](value))
|
||||
|
|
|
@ -41,7 +41,7 @@ proc test1(): uint =
|
|||
|
||||
proc testProc() {.async.} =
|
||||
for i in 1..CallSoonTests:
|
||||
await sleepAsync(100)
|
||||
await sleepAsync(100.milliseconds)
|
||||
timeoutsTest1 += 1
|
||||
|
||||
proc callbackProc(udata: pointer) {.gcsafe.} =
|
||||
|
|
|
@ -6,16 +6,16 @@
|
|||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
|
||||
import unittest
|
||||
import os, unittest
|
||||
import ../chronos, ../chronos/timer
|
||||
|
||||
const TimersCount = 10
|
||||
|
||||
proc timeWorker(time: int): Future[int] {.async.} =
|
||||
var st = fastEpochTime()
|
||||
proc timeWorker(time: Duration): Future[Duration] {.async.} =
|
||||
var st = Moment.now()
|
||||
await sleepAsync(time)
|
||||
var et = fastEpochTime()
|
||||
result = int(et - st)
|
||||
var et = Moment.now()
|
||||
result = et - st
|
||||
|
||||
proc waitAll[T](futs: seq[Future[T]]): Future[void] =
|
||||
var counter = len(futs)
|
||||
|
@ -28,25 +28,34 @@ proc waitAll[T](futs: seq[Future[T]]): Future[void] =
|
|||
fut.addCallback(cb)
|
||||
return retFuture
|
||||
|
||||
proc test(timeout: int): Future[int64] {.async.} =
|
||||
var workers = newSeq[Future[int]](TimersCount)
|
||||
proc test(timeout: Duration): Future[Duration] {.async.} =
|
||||
var workers = newSeq[Future[Duration]](TimersCount)
|
||||
for i in 0..<TimersCount:
|
||||
workers[i] = timeWorker(timeout)
|
||||
await waitAll(workers)
|
||||
var sum = 0'i64
|
||||
var sum: Duration
|
||||
for i in 0..<TimersCount:
|
||||
var time = workers[i].read()
|
||||
sum = sum + time
|
||||
result = sum div 10'i64
|
||||
|
||||
proc testTimer(): bool =
|
||||
let a = Moment.now()
|
||||
waitFor(sleepAsync(1000.milliseconds))
|
||||
let b = Moment.now()
|
||||
let d = b - a
|
||||
result = (d >= 1000.milliseconds) and (d <= 2_000.milliseconds)
|
||||
|
||||
when isMainModule:
|
||||
suite "Asynchronous timers test suite":
|
||||
test "Timer reliability test [" & asyncTimer & "]":
|
||||
check testTimer() == true
|
||||
test $TimersCount & " timers with 10ms timeout":
|
||||
var res = waitFor(test(10))
|
||||
check (res >= 10) and (res <= 100)
|
||||
var res = waitFor(test(10.milliseconds))
|
||||
check (res >= 10.milliseconds) and (res <= 100.milliseconds)
|
||||
test $TimersCount & " timers with 100ms timeout":
|
||||
var res = waitFor(test(100))
|
||||
check (res >= 100) and (res <= 1000)
|
||||
var res = waitFor(test(100.milliseconds))
|
||||
check (res >= 100.milliseconds) and (res <= 1000.milliseconds)
|
||||
test $TimersCount & " timers with 1000ms timeout":
|
||||
var res = waitFor(test(1000))
|
||||
check (res >= 1000) and (res <= 5000)
|
||||
var res = waitFor(test(1000.milliseconds))
|
||||
check (res >= 1000.milliseconds) and (res <= 5000.milliseconds)
|
||||
|
|
Loading…
Reference in New Issue