#thread #message-passing #sync #channel

ump-server

Server message dispatch loop for ump

4 releases (breaking)

0.4.0 Sep 10, 2024
0.3.0 Feb 20, 2024
0.2.1 Feb 20, 2024
0.2.0 Jan 28, 2024
0.1.0 Oct 3, 2023

#1167 in Concurrency


Used in umpx

0BSD license

18KB
219 lines

Server message dispatch loop for ump

The ump-server crate is a server message dispatch abstraction for ump.


lib.rs:

ump-server is an abstraction on top of [ump] that is used to hide boilerplate code used to implement intra-process message passing servers.

Dispatch loop

The core functionality of ump-server is a dispatch loop, whose role it is to pull messages off the message queue and pass them to the application-supplied message handler.

There are two different ways to run the dispatcher loop: On a non-async thread or as an async task. The former is launched using [thread::spawn()] and the latter [task::spawn()] (only available using the tokio feature).

The spawn() functions return a tuple containing a Client (that can be used to send pass messages to the server) and a JoinHandle that can be used to wait for the dispatch loop thread/task to terminate (and retreive its return value).

The returned JoinHandle will, once joined, return an Option<RV>. If this is None the server was terminated because all the Client endpoints were dropped. If this is Some(RV) the server was terminated because a callback requested its termination by returning ControlFlow::Break(RV).

There are two ways to terminate the dispatch loop:

  • The message processing handler returns ControlFlow::Break(RV) (rather than ControlFlow::Continue(())). This would cause the thread/task to return Some(RV).
  • The message queue is empty and all the associated Clients have been released. This would cause the thread to return None.

Application message handlers

Message handlers are implemented using the thread::Handler trait (for the threaded dispatch loop) and task::Handler (for the async dispatch loop).

There are cases where the handler needs to store a clone of the client end-point of the message passing channel used to issue requests to the server (so that message handlers can issue new requests). In order to facilitate this, the application must pass a Handler-construction closure to spawn(). The closure will be called after the message passing channel has been created so it can be passed a reference to the client end-point.

If the dispatch loop should terminate once all the application's client end-points have been dropped, then the handler can store a WeakClient instead (as storing a cloned Client object will preventing the dispatch loop from terminating due to all clients being lost). The examples in the task and thread modules illustrate how to do this.

Dependencies

~3–9MB
~77K SLoC