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)
|
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]
|
[inline]
|
||||||
fn select_with_retry(handle int, test Select, timeout time.Duration) ?bool {
|
fn select_deadline(handle int, test Select, deadline time.Time) ?bool {
|
||||||
mut retries := 10
|
// if we have a 0 deadline here then the timeout that was passed was infinite...
|
||||||
for retries > 0 {
|
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 {
|
ready := @select(handle, test, timeout) or {
|
||||||
if err.code() == 4 {
|
if err.code() == 4 {
|
||||||
// signal! lets retry max 10 times
|
// Spurious wakeup from signal, keep waiting
|
||||||
// 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
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// we got other error
|
|
||||||
|
// NOT a spurious wakeup
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return ready
|
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
|
// 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 {
|
// Convert timeouts to deadlines
|
||||||
// do not accept negative timeout
|
real_deadline := if timeout == net.infinite_timeout {
|
||||||
if timeout < 0 {
|
time.unix(0)
|
||||||
return err_timed_out
|
} 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 {
|
ready := select_deadline(handle, test, real_deadline) ?
|
||||||
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) ?
|
|
||||||
if ready {
|
if ready {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return err_timed_out
|
return err_timed_out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue