fix timeoutmonitor loop (#463)

* fix timeoutmonitor loop

* Clarify that cancellation can happen while in timeoutMonitor
This commit is contained in:
Jacek Sieka 2020-11-29 13:34:19 +01:00 committed by GitHub
parent 18443dafc1
commit 5c2a54bdd9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 33 additions and 23 deletions

View File

@ -63,6 +63,7 @@ method closeImpl*(s: Connection): Future[void] =
trace "Closing connection", s trace "Closing connection", s
if not isNil(s.timerTaskFut) and not s.timerTaskFut.finished: if not isNil(s.timerTaskFut) and not s.timerTaskFut.finished:
s.timerTaskFut.cancel() s.timerTaskFut.cancel()
s.timerTaskFut = nil
trace "Closed connection", s trace "Closed connection", s
@ -71,6 +72,32 @@ method closeImpl*(s: Connection): Future[void] =
func hash*(p: Connection): Hash = func hash*(p: Connection): Hash =
cast[pointer](p).hash cast[pointer](p).hash
proc pollActivity(s: Connection): Future[bool] {.async.} =
if s.closed and s.atEof:
return false # Done, no more monitoring
if s.activity:
s.activity = false
return true
# Inactivity timeout happened, call timeout monitor
trace "Connection timed out", s
if not(isNil(s.timeoutHandler)):
trace "Calling timeout handler", s
try:
await s.timeoutHandler()
except CancelledError:
# timeoutHandler is expected to be fast, but it's still possible that
# cancellation will happen here - no need to warn about it - we do want to
# stop the polling however
debug "Timeout handler cancelled", s
except CatchableError as exc: # Shouldn't happen
warn "exception in timeout handler", s, exc = exc.msg
return false
proc timeoutMonitor(s: Connection) {.async, gcsafe.} = proc timeoutMonitor(s: Connection) {.async, gcsafe.} =
## monitor the channel for inactivity ## monitor the channel for inactivity
## ##
@ -80,31 +107,14 @@ proc timeoutMonitor(s: Connection) {.async, gcsafe.} =
## be reset ## be reset
## ##
try:
while true: while true:
try: # Sleep at least once!
await sleepAsync(s.timeout) await sleepAsync(s.timeout)
except CancelledError:
if s.closed and s.atEof:
return return
if s.activity: if not await s.pollActivity():
s.activity = false return
continue
break
# reset channel on inactivity timeout
trace "Connection timed out", s
if not(isNil(s.timeoutHandler)):
trace "Calling timeout handler", s
await s.timeoutHandler()
except CancelledError as exc:
raise exc
except CatchableError as exc: # Shouldn't happen
warn "exception in timeout", s, exc = exc.msg
finally:
s.timerTaskFut = nil
proc init*(C: type Connection, proc init*(C: type Connection,
peerInfo: PeerInfo, peerInfo: PeerInfo,