pharos icon indicating copy to clipboard operation
pharos copied to clipboard

seL4 style bounded non-blocking notifications

Open ratmice opened this issue 6 years ago • 4 comments

   /// A channel with a limited buffer (the usize parameter). Creates back pressure when the buffer is full.
   /// This means that producer tasks may block if consumers can't process fast enough.
   //
   Bounded(usize),

overvable.rs

It would be nice to introduce a mechanism similar to seL4 asynchronous notifications, These can be viewed as each event representing a bit in bounded channel, sending an event sets the bit to 1, consuming it resets it to 0, if the producer is outpacing the consumer (or regardless), the consumer cannot distinguish between receiving a single event of a type from multiple events of the type.

This would have somewhat of a different behavior than the proposed ring buffer. We receive only one message for a given event, so dropping messages will still produce that event. But similar to the ring buffer the producer tasks would not block on the consumer.

ratmice avatar Sep 24 '19 16:09 ratmice

Hi, I'm sorry, somehow I wasn't "watching" my own repository, even though I thought that was the default, so I only saw your message now.

This shouldn't be very complicated to implement, but could you describe the specific use case above a ringchannel size 1? Also if all you do is set a bit, why use something like pharos at all? Sounds like a tiny future around an AtomicBool would cover this use case?

najamelan avatar Oct 02 '19 06:10 najamelan

This is a good question, and part of it is just my familiarity with the sel4 style, and relative infamiliarity with rusts async. With pharos being roughly familiar in ways, and the discussion of denial of service instigated me to mention it. Perhaps it may be better to use futures directly. The assumptions surrounding the 2 systems are fairly different that a 1:1 mapping of their API's may in fact be awkward.

generally in sel4 at least asynchronous notifications are the only way you get poll() style of blocking on multiple endpoints. In that sense it acts like a Sink for multiple producers, and a Source for a consumer at the final endpoint.

Most messaging in sel4 is in fact sync (the ability to Reply is also async) while Send through which you initiate a Reply is sync, (The sender blocks until receiving the reply). What the async notifications allow you to do then, is Send notifications asynchronously/without blocking (To the previously mentioned Sink) -- but only for a single bit.

Example, lets say there is a Driver a Mux and clients client 1, ... client n, Mux is blocked on Driver, client 1 ... n are blocked on Mux. Mux takes care only to Reply to clients, so does not block on client.

If we wish to introduce a second party to any client for instance a timer. We now have the case that Mux won't block on client, and client won't block on Mux. To resolve this situation, Mux needs an async send, Timer needs an async send, client polls both, and only Send's to Mux when Mux has notified the client that it is in position to Reply instantly.

It seems to me, that the ringchannel > 1, is because it has a bunch of async but it's only under the hood and it's wrapping this up in a sync API so you only really await one future. And somewhat compounded by being the equivalent of a no_std + no alloc environment, with an a priori known fixed number of futures.

I believe in large part ringbuffer > 1, is just a way to know exactly the total size of all potential incoming futures with local reasoning, where if you split these across different AtomicBool's You'll have to add the size of all the futures created up.

Anyhow it's certainly deserving of it's own API, but I just wanted to mention it since you were investigating things like denial of service etc. It's a rather resilient little mechanism.

ratmice avatar Oct 02 '19 17:10 ratmice

ok, do you have a reference to the se4L API to which you refer? I looked a bit at the docs, but didn't find it exactly.

I feel like a ring_channel of size 1 with a message type bool would provide the functionality that you describe, but the reason to not do that in pharos might be performance.

The advantage of pharos is that you don't need to use bool as your message type, and that you can use other richer message types like enums. But for the very elemental functionality of just signaling a bool, it's surely not the most performant implementation.

There is also other interesting paradigms which would perform better than pharos for their specific use case, like the lmax-destructor.

najamelan avatar Oct 04 '19 09:10 najamelan

Sorry it has taken me a bit to get back to this, currently the only documentation which I believe is readily readable is chapter 5 of manual-latest.

I had been hoping to find a simple example using them I could show, but I haven't found one readily linkable. There is this: notifications tutorial, but the sources of the tutorial are built from a templated version of markdown, and thus you'd really need to go through the install/setup phase to read the sources.

And my own sources which are using notifications are still on an older version of the kernel.

ratmice avatar Oct 11 '19 23:10 ratmice