diff --git a/vlib/net/common.v b/vlib/net/common.v index da2ee28047..aab8f166b4 100644 --- a/vlib/net/common.v +++ b/vlib/net/common.v @@ -14,7 +14,7 @@ pub const no_timeout = time.Duration(0) // infinite_timeout should be given to functions when an infinite_timeout is wanted (i.e. functions // only ever return with data) -pub const infinite_timeout = time.Duration(-1) +pub const infinite_timeout = time.infinite // Shutdown shutsdown a socket and closes it fn shutdown(handle int) ? { @@ -34,7 +34,7 @@ fn @select(handle int, test Select, timeout time.Duration) ?bool { C.FD_ZERO(&set) C.FD_SET(handle, &set) - seconds := timeout.milliseconds() / 1000 + seconds := timeout / time.second microseconds := time.Duration(timeout - (seconds * time.second)).microseconds() mut tt := C.timeval{ @@ -93,9 +93,8 @@ fn select_with_retry(handle int, test Select, timeout time.Duration) ?bool { // wait_for_common wraps the common wait code fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test Select) ? { if deadline.unix == 0 { - // only accept infinite_timeout as a valid - // negative timeout - it is handled in @select however - if timeout < 0 && timeout != net.infinite_timeout { + // do not accept negative timeout + if timeout < 0 { return err_timed_out } ready := select_with_retry(handle, test, timeout) ? diff --git a/vlib/net/unix/common.v b/vlib/net/unix/common.v index 2463ec37d8..75e591f24c 100644 --- a/vlib/net/unix/common.v +++ b/vlib/net/unix/common.v @@ -29,8 +29,8 @@ fn @select(handle int, test Select, timeout time.Duration) ?bool { C.FD_ZERO(&set) C.FD_SET(handle, &set) - seconds := timeout.milliseconds() / 1000 - microseconds := timeout - (seconds * time.second) + seconds := timeout / time.second + microseconds := time.Duration(timeout - (seconds * time.second)).microseconds() mut tt := C.timeval{ tv_sec: u64(seconds) @@ -63,9 +63,8 @@ fn @select(handle int, test Select, timeout time.Duration) ?bool { // wait_for_common wraps the common wait code fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test Select) ? { if deadline.unix == 0 { - // only accept infinite_timeout as a valid - // negative timeout - it is handled in @select however - if timeout < 0 && timeout != unix.infinite_timeout { + // do not accept negative timeout + if timeout < 0 { return net.err_timed_out } ready := @select(handle, test, timeout) ? @@ -117,7 +116,7 @@ const ( // infinite_timeout should be given to functions when an infinite_timeout is wanted (i.e. functions // only ever return with data) const ( - infinite_timeout = time.Duration(-1) + infinite_timeout = time.infinite ) [inline] diff --git a/vlib/os/notify/backend_linux.c.v b/vlib/os/notify/backend_linux.c.v index 6b43df1f26..1913913881 100644 --- a/vlib/os/notify/backend_linux.c.v +++ b/vlib/os/notify/backend_linux.c.v @@ -107,10 +107,7 @@ fn (mut en EpollNotifier) wait(timeout time.Duration) []FdEvent { // the added bonus of making EpollNotifier thread safe events := [512]C.epoll_event{} // populate events with the new events - to := match timeout { - time.infinite { -1 } - else { int(timeout / time.millisecond) } - } + to := timeout.sys_milliseconds() count := C.epoll_wait(en.epoll_fd, &events[0], events.len, to) if count > 0 { diff --git a/vlib/sync/channel_select_test.v b/vlib/sync/channel_select_test.v index 71f5efccac..26ed641f52 100644 --- a/vlib/sync/channel_select_test.v +++ b/vlib/sync/channel_select_test.v @@ -8,6 +8,8 @@ module sync +import time + fn do_rec_i64(mut ch Channel) { mut sum := i64(0) for _ in 0 .. 300 { @@ -56,7 +58,7 @@ fn test_select() { mut sl := i64(0) mut objs := [voidptr(&ri), &sl, &rl, &rb] for _ in 0 .. 1200 { - idx := channel_select(mut channels, directions, mut objs, -1) + idx := channel_select(mut channels, directions, mut objs, time.infinite) match idx { 0 { sum += ri diff --git a/vlib/sync/channels.v b/vlib/sync/channels.v index 74b8bd4852..74d88a70bc 100644 --- a/vlib/sync/channels.v +++ b/vlib/sync/channels.v @@ -602,8 +602,8 @@ fn (mut ch Channel) try_pop_priv(dest voidptr, no_block bool) ChanState { } // Wait `timeout` on any of `channels[i]` until one of them can push (`is_push[i] = true`) or pop (`is_push[i] = false`) -// object referenced by `objrefs[i]`. `timeout < 0` means wait unlimited time. `timeout == 0` means return immediately -// if no transaction can be performed without waiting. +// object referenced by `objrefs[i]`. `timeout = time.infinite` means wait unlimited time. `timeout <= 0` means return +// immediately if no transaction can be performed without waiting. // return value: the index of the channel on which a transaction has taken place // -1 if waiting for a transaction has exceeded timeout // -2 if all channels are closed @@ -646,7 +646,11 @@ pub fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []vo C.atomic_store_u16(&ch.read_sub_mtx, u16(0)) } } - stopwatch := if timeout <= 0 { time.StopWatch{} } else { time.new_stopwatch({}) } + stopwatch := if timeout == time.infinite || timeout <= 0 { + time.StopWatch{} + } else { + time.new_stopwatch({}) + } mut event_idx := -1 // negative index means `timed out` outer: for { @@ -679,10 +683,10 @@ pub fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []vo event_idx = -2 break outer } - if timeout == 0 { + if timeout <= 0 { break outer } - if timeout > 0 { + if timeout != time.infinite { remaining := timeout - stopwatch.elapsed() if !sem.timed_wait(remaining) { break outer diff --git a/vlib/sync/sync_windows.c.v b/vlib/sync/sync_windows.c.v index b610baef4d..d0942b709c 100644 --- a/vlib/sync/sync_windows.c.v +++ b/vlib/sync/sync_windows.c.v @@ -176,7 +176,7 @@ pub fn (mut sem Semaphore) timed_wait(timeout time.Duration) bool { C.GetSystemTimeAsFileTime(&ft_start) time_end := ((u64(ft_start.dwHighDateTime) << 32) | ft_start.dwLowDateTime) + u64(timeout / (100 * time.nanosecond)) - mut t_ms := u32(timeout / time.millisecond) + mut t_ms := timeout.sys_milliseconds() C.AcquireSRWLockExclusive(&sem.mtx) mut res := 0 c = C.atomic_load_u32(&sem.count) diff --git a/vlib/time/time.v b/vlib/time/time.v index 0b80b26aac..43b5511e32 100644 --- a/vlib/time/time.v +++ b/vlib/time/time.v @@ -394,7 +394,7 @@ pub const ( second = Duration(1000 * millisecond) minute = Duration(60 * second) hour = Duration(60 * minute) - infinite = Duration(-1) + infinite = Duration(C.INT64_MAX) ) // nanoseconds returns the duration as an integer number of nanoseconds. diff --git a/vlib/time/time_nix.c.v b/vlib/time/time_nix.c.v index d9efe4b521..438b72d44f 100644 --- a/vlib/time/time_nix.c.v +++ b/vlib/time/time_nix.c.v @@ -149,3 +149,15 @@ pub fn sleep(duration Duration) { } } } + +// some *nix system functions (e.g. `C.poll()`, C.epoll_wait()) accept an `int` +// value as *timeout in milliseconds* with the special value `-1` meaning "infinite" +pub fn (d Duration) sys_milliseconds() int { + if d > C.INT32_MAX * millisecond { // treat 2147483647000001 .. C.INT64_MAX as "infinite" + return -1 + } else if d <= 0 { + return 0 // treat negative timeouts as 0 - consistent with Unix behaviour + } else { + return int(d / millisecond) + } +} diff --git a/vlib/time/time_windows.c.v b/vlib/time/time_windows.c.v index eb8845eb44..363bede08d 100644 --- a/vlib/time/time_windows.c.v +++ b/vlib/time/time_windows.c.v @@ -225,3 +225,15 @@ pub fn wait(duration Duration) { pub fn sleep(duration Duration) { C.Sleep(int(duration / millisecond)) } + +// some Windows system functions (e.g. `C.WaitForSingleObject()`) accept an `u32` +// value as *timeout in milliseconds* with the special value `u32(-1)` meaning "infinite" +pub fn (d Duration) sys_milliseconds() u32 { + if d >= u32(-1) * millisecond { // treat 4294967295000000 .. C.INT64_MAX as "infinite" + return u32(-1) + } else if d <= 0 { + return 0 // treat negative timeouts as 0 - consistent with Unix behaviour + } else { + return u32(d / millisecond) + } +} diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index d30402d58d..9802de9033 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -4102,7 +4102,7 @@ fn (mut g Gen) select_expr(node ast.SelectExpr) { } else if has_else { g.write('0') } else { - g.write('-1') + g.write('_const_time__infinite') } g.writeln(');') // free the temps that were created