time: use `Duration(C.INT64_MAX)` as infinite (#10539)

pull/10495/head
Uwe Krüger 2021-06-22 11:17:44 +02:00 committed by GitHub
parent dd6591b2f5
commit 72358833e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 49 additions and 24 deletions

View File

@ -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 // infinite_timeout should be given to functions when an infinite_timeout is wanted (i.e. functions
// only ever return with data) // 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 // Shutdown shutsdown a socket and closes it
fn shutdown(handle int) ? { fn shutdown(handle int) ? {
@ -34,7 +34,7 @@ fn @select(handle int, test Select, timeout time.Duration) ?bool {
C.FD_ZERO(&set) C.FD_ZERO(&set)
C.FD_SET(handle, &set) C.FD_SET(handle, &set)
seconds := timeout.milliseconds() / 1000 seconds := timeout / time.second
microseconds := time.Duration(timeout - (seconds * time.second)).microseconds() microseconds := time.Duration(timeout - (seconds * time.second)).microseconds()
mut tt := C.timeval{ 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 // wait_for_common wraps the common wait code
fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test Select) ? { fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test Select) ? {
if deadline.unix == 0 { if deadline.unix == 0 {
// only accept infinite_timeout as a valid // do not accept negative timeout
// negative timeout - it is handled in @select however if timeout < 0 {
if timeout < 0 && timeout != net.infinite_timeout {
return err_timed_out return err_timed_out
} }
ready := select_with_retry(handle, test, timeout) ? ready := select_with_retry(handle, test, timeout) ?

View File

@ -29,8 +29,8 @@ fn @select(handle int, test Select, timeout time.Duration) ?bool {
C.FD_ZERO(&set) C.FD_ZERO(&set)
C.FD_SET(handle, &set) C.FD_SET(handle, &set)
seconds := timeout.milliseconds() / 1000 seconds := timeout / time.second
microseconds := timeout - (seconds * time.second) microseconds := time.Duration(timeout - (seconds * time.second)).microseconds()
mut tt := C.timeval{ mut tt := C.timeval{
tv_sec: u64(seconds) 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 // wait_for_common wraps the common wait code
fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test Select) ? { fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test Select) ? {
if deadline.unix == 0 { if deadline.unix == 0 {
// only accept infinite_timeout as a valid // do not accept negative timeout
// negative timeout - it is handled in @select however if timeout < 0 {
if timeout < 0 && timeout != unix.infinite_timeout {
return net.err_timed_out return net.err_timed_out
} }
ready := @select(handle, test, timeout) ? 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 // infinite_timeout should be given to functions when an infinite_timeout is wanted (i.e. functions
// only ever return with data) // only ever return with data)
const ( const (
infinite_timeout = time.Duration(-1) infinite_timeout = time.infinite
) )
[inline] [inline]

View File

@ -107,10 +107,7 @@ fn (mut en EpollNotifier) wait(timeout time.Duration) []FdEvent {
// the added bonus of making EpollNotifier thread safe // the added bonus of making EpollNotifier thread safe
events := [512]C.epoll_event{} events := [512]C.epoll_event{}
// populate events with the new events // populate events with the new events
to := match timeout { to := timeout.sys_milliseconds()
time.infinite { -1 }
else { int(timeout / time.millisecond) }
}
count := C.epoll_wait(en.epoll_fd, &events[0], events.len, to) count := C.epoll_wait(en.epoll_fd, &events[0], events.len, to)
if count > 0 { if count > 0 {

View File

@ -8,6 +8,8 @@
module sync module sync
import time
fn do_rec_i64(mut ch Channel) { fn do_rec_i64(mut ch Channel) {
mut sum := i64(0) mut sum := i64(0)
for _ in 0 .. 300 { for _ in 0 .. 300 {
@ -56,7 +58,7 @@ fn test_select() {
mut sl := i64(0) mut sl := i64(0)
mut objs := [voidptr(&ri), &sl, &rl, &rb] mut objs := [voidptr(&ri), &sl, &rl, &rb]
for _ in 0 .. 1200 { 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 { match idx {
0 { 0 {
sum += ri sum += ri

View File

@ -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`) // 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 // object referenced by `objrefs[i]`. `timeout = time.infinite` means wait unlimited time. `timeout <= 0` means return
// if no transaction can be performed without waiting. // immediately if no transaction can be performed without waiting.
// return value: the index of the channel on which a transaction has taken place // return value: the index of the channel on which a transaction has taken place
// -1 if waiting for a transaction has exceeded timeout // -1 if waiting for a transaction has exceeded timeout
// -2 if all channels are closed // -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)) 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` mut event_idx := -1 // negative index means `timed out`
outer: for { outer: for {
@ -679,10 +683,10 @@ pub fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []vo
event_idx = -2 event_idx = -2
break outer break outer
} }
if timeout == 0 { if timeout <= 0 {
break outer break outer
} }
if timeout > 0 { if timeout != time.infinite {
remaining := timeout - stopwatch.elapsed() remaining := timeout - stopwatch.elapsed()
if !sem.timed_wait(remaining) { if !sem.timed_wait(remaining) {
break outer break outer

View File

@ -176,7 +176,7 @@ pub fn (mut sem Semaphore) timed_wait(timeout time.Duration) bool {
C.GetSystemTimeAsFileTime(&ft_start) C.GetSystemTimeAsFileTime(&ft_start)
time_end := ((u64(ft_start.dwHighDateTime) << 32) | ft_start.dwLowDateTime) + time_end := ((u64(ft_start.dwHighDateTime) << 32) | ft_start.dwLowDateTime) +
u64(timeout / (100 * time.nanosecond)) u64(timeout / (100 * time.nanosecond))
mut t_ms := u32(timeout / time.millisecond) mut t_ms := timeout.sys_milliseconds()
C.AcquireSRWLockExclusive(&sem.mtx) C.AcquireSRWLockExclusive(&sem.mtx)
mut res := 0 mut res := 0
c = C.atomic_load_u32(&sem.count) c = C.atomic_load_u32(&sem.count)

View File

@ -394,7 +394,7 @@ pub const (
second = Duration(1000 * millisecond) second = Duration(1000 * millisecond)
minute = Duration(60 * second) minute = Duration(60 * second)
hour = Duration(60 * minute) hour = Duration(60 * minute)
infinite = Duration(-1) infinite = Duration(C.INT64_MAX)
) )
// nanoseconds returns the duration as an integer number of nanoseconds. // nanoseconds returns the duration as an integer number of nanoseconds.

View File

@ -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)
}
}

View File

@ -225,3 +225,15 @@ pub fn wait(duration Duration) {
pub fn sleep(duration Duration) { pub fn sleep(duration Duration) {
C.Sleep(int(duration / millisecond)) 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)
}
}

View File

@ -4102,7 +4102,7 @@ fn (mut g Gen) select_expr(node ast.SelectExpr) {
} else if has_else { } else if has_else {
g.write('0') g.write('0')
} else { } else {
g.write('-1') g.write('_const_time__infinite')
} }
g.writeln(');') g.writeln(');')
// free the temps that were created // free the temps that were created