NPRPC docs

protocol PoaExecutor

Swift

protocol PoaExecutor : AnyObject, Sendable

A serial execution context that is a thread with its own event loop rather than a DispatchQueue.

.main and .queue cover everything GCD owns, but they cannot express the case they are most wanted for: a thread that blocks in someone else's wait — a GLFW/X11 pump, an epoll loop, a game loop — and that owns state which may only be touched from that thread. GCD cannot pin a serial queue to a chosen thread (only .main is pinned, and draining it means the loop can never block), so such a loop can neither be a hop target nor be woken by one.

Conforming types supply the two things the C DispatchExecutor needs:

final class RenderLoop: PoaExecutor {
    func post(_ work: @escaping @Sendable () -> Void) {
        queue.append(work)     // drained once per loop iteration
        wakeTheLoop()          // must unblock the loop's wait
    }
    var isRunningOnExecutor: Bool { Thread.current === loopThread }
}

post must wake the loop. The ring fires and forgets: nothing else will tell the loop that work is waiting, so a post that only enqueues leaves the servant unrun until the loop happens to wake for its own reasons — on an idle process, never.

The loop must be serial and must drain in FIFO order, for the same reason .queue demands a serial queue: a shared-memory session matches replies by ring slot order.

isRunningOnExecutor keeps invoke_sync from posting to a loop it is already on, which would wait for a drain that cannot happen until it returns.

nprpc_swift/Sources/NPRPC/Poa.swift:143

Properties

var isRunningOnExecutor: Bool { get }

True when the calling thread is the loop's own.

nprpc_swift/Sources/NPRPC/Poa.swift:147

Methods

func post(_ work: @escaping @Sendable () -> Void)

Enqueue work on the loop and wake it.

nprpc_swift/Sources/NPRPC/Poa.swift:145