Genode: add scheduleCallbacks to asyncdispatch (#20708)

* Genode: add native signal handler

* Genode: add scheduleCallbacks to asyncdispatch

This resolves some awkwardness where an RPC server may or may not
use callSoon while dispatching RPC but without scheduling timers
or I/O.
This commit is contained in:
ehmry 2022-10-31 13:24:57 -05:00 • committed by GitHub
commit 0b262e9496
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 188 additions and 3 deletions

View file

@ -281,6 +281,8 @@ proc adjustTimeout(
result = max(nextTimer.get(), 0)
result = min(pollTimeout, result)
proc runOnce(timeout: int): bool {.gcsafe.}
proc callSoon*(cbproc: proc () {.gcsafe.}) {.gcsafe.}
## Schedule `cbproc` to be called as soon as possible.
## The callback is called when control returns to the event loop.
@ -390,7 +392,7 @@ when defined(windows) or defined(nimdoc):
let p = getGlobalDispatcher()
p.handles.len != 0 or p.timers.len != 0 or p.callbacks.len != 0
proc runOnce(timeout = 500): bool =
proc runOnce(timeout: int): bool =
let p = getGlobalDispatcher()
if p.handles.len == 0 and p.timers.len == 0 and p.callbacks.len == 0:
raise newException(ValueError,
@ -1169,6 +1171,9 @@ else:
MSG_NOSIGNAL
when declared(posix.accept4):
from posix import accept4, SOCK_CLOEXEC
when defined(genode):
include genode/env # get the implicit Genode env
import genode/signals
const
InitCallbackListSize = 4 # initial size of callbacks sequence,
@ -1187,6 +1192,8 @@ else:
PDispatcher* = ref object of PDispatcherBase
selector: Selector[AsyncData]
when defined(genode):
signalHandler: SignalHandler
proc `==`*(x, y: AsyncFD): bool {.borrow.}
proc `==`*(x, y: AsyncEvent): bool {.borrow.}
@ -1202,6 +1209,10 @@ else:
result.selector = newSelector[AsyncData]()
result.timers.clear()
result.callbacks = initDeque[proc () {.closure, gcsafe.}](InitDelayedCallbackListSize)
when defined(genode):
let entrypoint = ep(cast[GenodeEnv](runtimeEnv))
result.signalHandler = newSignalHandler(entrypoint):
discard runOnce(0)
var gDisp{.threadvar.}: owned PDispatcher ## Global dispatcher
@ -1371,10 +1382,11 @@ else:
ValueError, "Expecting async operations to stop when fd has closed."
)
proc runOnce(timeout = 500): bool =
proc runOnce(timeout: int): bool =
let p = getGlobalDispatcher()
if p.selector.isEmpty() and p.timers.len == 0 and p.callbacks.len == 0:
when defined(genode):
if timeout == 0: return
raise newException(ValueError,
"No handles or timers registered in dispatcher.")
@ -2025,3 +2037,17 @@ when defined(linux) or defined(windows) or defined(macosx) or defined(bsd) or
if getrlimit(RLIMIT_NOFILE, fdLim) < 0:
raiseOSError(osLastError())
result = int(fdLim.rlim_cur) - 1
when defined(genode):
proc scheduleCallbacks*(): bool {.discardable.} =
## *Genode only.*
## Schedule callback processing and return immediately.
## Returns `false` if there is nothing to schedule.
## RPC servers should call this to dispatch `callSoon`
## bodies after retiring an RPC to its client.
## This is effectively a non-blocking `poll(…)` and is
## equivalent to scheduling a momentary no-op timeout
## but faster and with less overhead.
let dis = getGlobalDispatcher()
result = dis.callbacks.len > 0
if result: submit(dis.signalHandler.cap)