Hi Sid,
in our current project, the question of synchronous communications between processes comes up quite often. For background, our scenario processes numerous parallel requests, which requires, among other operations, verifying a signature of a request and signing its response. The signature verification and signing operations are encapsulated in separate processes. That way they do not need to understand the complex message format of requests and responses, but only binary hashes and signatures. Therefore, the component processing the request must send the input data to the verify or sign component and wait for the response before continuing processing. In our current solution we use Genode's basic synchronous RPC mechanism. This approach has the effect of creating new session types when more different functionalities such as verifying or signing are added. This seems to be in conflict with the Genode philosophy of using only few selected session types. On the other hand, building the scenario using the asynchronous report/rom mechanism would lead to significantly more complex code to avoid mixing up the many requests being processed in parallel.
there is no general answer but a few considerations.
First, your remark about Genode's philosophy is spot-on. Let me cite myself from Section "Components" of the Genode Foundations book:
"The versatility of a component-based system does not come from the existence of many components alone. Even more important is the composability of components. Components can be combined only if their interfaces match. To maximize composability, the number of interfaces throughout the system should be as low as possible, and all interfaces should be largely orthogonal to each other."
[1] https://genode.org/documentation/genode-foundations/20.05/components/index.h...
Therefore, before introducing a new session interface, one should ask the following questions:
"What if this service had a (*) session interface?" where (*) stands for the the usual candidates ROM, Report, File_system, Terminal, Block, and Nic.
E.g., when we were tempted with introducing a socket session interface, we ultimately ended up with modelling the socket API as a pseudo-file system, reusing the existing "File_system" session interface. This eventually enabled us to use the VFS server as multiplexer for the shared use of a single TCP/IP stack.
"Does the designated interface needs to be one interface, or can it be a combination of multiple simple ones?"
E.g., when thinking of an encryption component, the most intuitive interface may be an RPC interface with an "encrypt" function taking the plaintext as argument and producing the ciphertext as result.
A less intuitive approach would be to model the encryption component as a block service that offers two block sessions, one for submitting plaintext, and one for picking up ciphertext. This approach has the following benefits:
1. It does not block the caller while computing the encryption function. 2. It can scale better because multiple "block" requests can be submitted as a batch at once, using the block number as a token to tell them apart. 3. No session can observe both the plain and ciphertext but only one of them. This way, the information flow at the clint side can become better separated. 4. The component works similar to a physical device. That is, it could be replaced by a driver for an actual hardware device.
I have not fully thought it through but the example shows that the design space - even when sticking to the existing session interfaces - is sometimes larger than it appears at first.
"Could that feature be implemented as a VFS plugin?"
Recently, the default answer to this question has become YES! Implementing protocol-stack functionality as a VFS plugin gives two advantages over the implementation of a new server.
1. The decision of separating functionality out to a separate component can be taken at integration time. It is just the difference of mounting a VFS plugin locally at an application versus mounting it inside a shared VFS server. Performance can be traded against the granularity of separation by mere reconfiguration. 2. There is no need to write boiler-place server code. The VFS server exists and can be used as is.
This leads to quite unorthodox results. For example, the font renderer used by Sculpt's Leitzentrale GUI is implemented as a VFS plugin.
That said, let me share one note of caution. The VFS-internal interfaces are not completely fleshed out yet. They will be undergo changes in the next release cycles. There will be no fundamental disruption but you should be prepared for the need to adjust VFS plugins.
With all these considerations given, we should not be dogmatic. If none of the existing interfaces fits well, or if the use the existing interfaces feels highly unnatural, the introduction of a new interface is totally fine. In the best case, the new interface can one day be generalized to fill a real gap in the existing options.
After all, correctness is primarily important. And this is best achieved with simplicity. So if you say that the asynchronous combination of report and ROM sessions makes you feel uneasy, better take a different route you feel confident with.
Cheers Norman