net: select with deadlines (#14369)
parent
d2eef45612
commit
50ab19d136
|
@ -65,56 +65,51 @@ fn @select(handle int, test Select, timeout time.Duration) ?bool {
|
|||
return C.FD_ISSET(handle, &set)
|
||||
}
|
||||
|
||||
// select_with_retry will retry the select if select is failing
|
||||
// due to interrupted system call. This can happen on signals
|
||||
// for example the GC Boehm uses signals internally on garbage
|
||||
// collection
|
||||
[inline]
|
||||
fn select_with_retry(handle int, test Select, timeout time.Duration) ?bool {
|
||||
mut retries := 10
|
||||
for retries > 0 {
|
||||
fn select_deadline(handle int, test Select, deadline time.Time) ?bool {
|
||||
// if we have a 0 deadline here then the timeout that was passed was infinite...
|
||||
infinite := deadline.unix_time() == 0
|
||||
for infinite || time.now() <= deadline {
|
||||
timeout := if infinite { net.infinite_timeout } else { deadline - time.now() }
|
||||
ready := @select(handle, test, timeout) or {
|
||||
if err.code() == 4 {
|
||||
// signal! lets retry max 10 times
|
||||
// suspend thread with sleep to let the gc get
|
||||
// cycles in the case the Bohem gc is interupting
|
||||
time.sleep(1 * time.millisecond)
|
||||
retries -= 1
|
||||
// Spurious wakeup from signal, keep waiting
|
||||
continue
|
||||
}
|
||||
// we got other error
|
||||
|
||||
// NOT a spurious wakeup
|
||||
return err
|
||||
}
|
||||
|
||||
return ready
|
||||
}
|
||||
return error('failed to @select more that three times due to interrupted system call')
|
||||
|
||||
// Deadline elapsed
|
||||
return false
|
||||
}
|
||||
|
||||
// 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 {
|
||||
// do not accept negative timeout
|
||||
if timeout < 0 {
|
||||
return err_timed_out
|
||||
// Convert timeouts to deadlines
|
||||
real_deadline := if timeout == net.infinite_timeout {
|
||||
time.unix(0)
|
||||
} else if timeout == 0 {
|
||||
// No timeout set, so assume deadline
|
||||
deadline
|
||||
} else if timeout < 0 {
|
||||
// TODO(emily): Do something nicer here :)
|
||||
panic('invalid negative timeout')
|
||||
} else {
|
||||
// timeout
|
||||
time.now().add(timeout)
|
||||
}
|
||||
ready := select_with_retry(handle, test, timeout) ?
|
||||
if ready {
|
||||
return
|
||||
}
|
||||
return err_timed_out
|
||||
}
|
||||
// Convert the deadline into a timeout
|
||||
// and use that
|
||||
d_timeout := deadline.unix - time.now().unix
|
||||
if d_timeout < 0 {
|
||||
// deadline is in the past so this has already
|
||||
// timed out
|
||||
return err_timed_out
|
||||
}
|
||||
ready := select_with_retry(handle, test, timeout) ?
|
||||
|
||||
ready := select_deadline(handle, test, real_deadline) ?
|
||||
|
||||
if ready {
|
||||
return
|
||||
}
|
||||
|
||||
return err_timed_out
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue