2023-12-26 22:12:47 +02:00
|
|
|
use core::{
|
|
|
|
pin::Pin,
|
2023-12-28 22:32:33 +02:00
|
|
|
sync::atomic::{AtomicU32, Ordering},
|
2023-12-26 22:12:47 +02:00
|
|
|
task::{Context, Poll},
|
|
|
|
};
|
|
|
|
|
|
|
|
use alloc::{
|
|
|
|
boxed::Box,
|
|
|
|
collections::{BTreeMap, VecDeque},
|
|
|
|
string::String,
|
|
|
|
sync::Arc,
|
|
|
|
};
|
|
|
|
use futures_util::{task::AtomicWaker, Future};
|
2024-02-05 12:35:09 +02:00
|
|
|
use libk_util::sync::{IrqSafeSpinlock, LockMethod};
|
2024-03-12 14:46:54 +02:00
|
|
|
use yggdrasil_abi::{
|
|
|
|
error::Error,
|
|
|
|
io::{ChannelPublisherId, MessageDestination},
|
|
|
|
};
|
2023-12-26 22:12:47 +02:00
|
|
|
|
2024-03-13 19:14:54 +02:00
|
|
|
use crate::{
|
|
|
|
task::sync::Mutex,
|
|
|
|
vfs::{FileReadiness, FileRef},
|
|
|
|
};
|
2023-12-26 22:12:47 +02:00
|
|
|
|
2024-01-22 14:39:06 +02:00
|
|
|
/// Describes a channel over which messages can be sent to [Subscription]s
|
2023-12-26 22:12:47 +02:00
|
|
|
pub struct Channel {
|
2023-12-28 22:32:33 +02:00
|
|
|
last_id: AtomicU32,
|
|
|
|
subscriptions: Mutex<BTreeMap<u32, Arc<Subscription>>>,
|
2023-12-26 22:12:47 +02:00
|
|
|
}
|
|
|
|
|
2023-12-31 01:53:43 +02:00
|
|
|
/// Describes message payload
|
|
|
|
pub enum MessagePayload {
|
|
|
|
/// Payload contains a file
|
|
|
|
File(FileRef),
|
|
|
|
/// Payload contains byte data
|
|
|
|
Data(Box<[u8]>),
|
|
|
|
}
|
|
|
|
|
2024-01-22 14:39:06 +02:00
|
|
|
/// Describes a message sent over a channel
|
2023-12-26 22:12:47 +02:00
|
|
|
pub struct Message {
|
2024-01-22 14:39:06 +02:00
|
|
|
/// Channel descriptor ID from which the message came
|
2024-03-12 14:46:54 +02:00
|
|
|
pub source: ChannelPublisherId,
|
2024-01-22 14:39:06 +02:00
|
|
|
/// Data of the message
|
2023-12-31 01:53:43 +02:00
|
|
|
pub payload: MessagePayload,
|
2023-12-26 22:12:47 +02:00
|
|
|
}
|
|
|
|
|
2024-01-22 14:39:06 +02:00
|
|
|
/// Describes a single subscription so some [Channel]
|
2023-12-26 22:12:47 +02:00
|
|
|
pub struct Subscription {
|
|
|
|
queue: Mutex<VecDeque<Arc<Message>>>,
|
|
|
|
notify: AtomicWaker,
|
|
|
|
}
|
|
|
|
|
2024-01-22 14:39:06 +02:00
|
|
|
/// Describes a pair of a [Channel] descriptor plus an optional [Subscription]
|
2023-12-26 22:12:47 +02:00
|
|
|
pub struct ChannelDescriptor {
|
2023-12-28 22:32:33 +02:00
|
|
|
id: u32,
|
2023-12-26 22:12:47 +02:00
|
|
|
tx: Arc<Channel>,
|
|
|
|
rx: Option<Arc<Subscription>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ChannelDescriptor {
|
2024-01-22 14:39:06 +02:00
|
|
|
/// Opens a channel descriptor, optionally creating a subscription to it
|
2023-12-26 22:12:47 +02:00
|
|
|
pub fn open(name: &str, subscribe: bool) -> ChannelDescriptor {
|
|
|
|
let tx = Channel::get_or_create(name.into());
|
2023-12-28 22:32:33 +02:00
|
|
|
// NOTE The first one to open the channel is guaranteed to get an ID of 0
|
|
|
|
let id = tx.last_id.fetch_add(1, Ordering::SeqCst);
|
2023-12-26 22:12:47 +02:00
|
|
|
let rx = if subscribe {
|
2023-12-28 22:32:33 +02:00
|
|
|
Some(tx.subscribe(id))
|
2023-12-26 22:12:47 +02:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2023-12-28 22:32:33 +02:00
|
|
|
Self { tx, rx, id }
|
2023-12-26 22:12:47 +02:00
|
|
|
}
|
|
|
|
|
2024-01-22 14:39:06 +02:00
|
|
|
/// Receives a message from the subscription
|
2023-12-31 01:53:43 +02:00
|
|
|
pub fn receive_message(&self) -> Result<Arc<Message>, Error> {
|
2023-12-26 22:12:47 +02:00
|
|
|
let Some(rx) = self.rx.as_ref() else {
|
|
|
|
return Err(Error::InvalidOperation);
|
|
|
|
};
|
|
|
|
|
2023-12-31 01:53:43 +02:00
|
|
|
rx.receive_message_inner()
|
2023-12-26 22:12:47 +02:00
|
|
|
}
|
|
|
|
|
2024-01-22 14:39:06 +02:00
|
|
|
/// Asynchronously receives a message from the subscription
|
|
|
|
pub async fn receive_message_async(&self) -> Result<Arc<Message>, Error> {
|
|
|
|
let rx = self.rx.as_ref().ok_or(Error::InvalidOperation)?;
|
|
|
|
rx.receive_message_async().await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sends a message to the channel
|
2023-12-31 01:53:43 +02:00
|
|
|
pub fn send_message(
|
|
|
|
&self,
|
|
|
|
payload: MessagePayload,
|
|
|
|
dst: MessageDestination,
|
|
|
|
) -> Result<(), Error> {
|
2023-12-26 22:12:47 +02:00
|
|
|
let message = Arc::new(Message {
|
2024-03-12 14:46:54 +02:00
|
|
|
source: unsafe { ChannelPublisherId::from_raw(self.id) },
|
2023-12-31 01:53:43 +02:00
|
|
|
payload,
|
2023-12-26 22:12:47 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
let lock = self.tx.subscriptions.lock()?;
|
2023-12-28 22:32:33 +02:00
|
|
|
|
|
|
|
match dst {
|
|
|
|
MessageDestination::Specific(id) => {
|
|
|
|
if let Some(sub) = lock.get(&id) {
|
|
|
|
sub.push_message(message)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MessageDestination::AllExceptSelf => {
|
|
|
|
for (&id, sub) in lock.iter() {
|
|
|
|
if id == self.id {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub.push_message(message.clone())?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MessageDestination::All => todo!(),
|
2023-12-26 22:12:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Channel {
|
|
|
|
fn new() -> Arc<Channel> {
|
|
|
|
Arc::new(Self {
|
2023-12-28 22:32:33 +02:00
|
|
|
last_id: AtomicU32::new(0),
|
|
|
|
subscriptions: Mutex::new(BTreeMap::new()),
|
2023-12-26 22:12:47 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-01-22 14:39:06 +02:00
|
|
|
fn get_or_create(name: String) -> Arc<Channel> {
|
2023-12-26 22:12:47 +02:00
|
|
|
let mut channels = CHANNELS.lock();
|
|
|
|
|
|
|
|
channels.entry(name).or_insert_with(Self::new).clone()
|
|
|
|
}
|
|
|
|
|
2023-12-28 22:32:33 +02:00
|
|
|
fn subscribe(&self, id: u32) -> Arc<Subscription> {
|
2023-12-26 22:12:47 +02:00
|
|
|
let mut lock = self.subscriptions.lock().unwrap();
|
|
|
|
|
|
|
|
let sub = Arc::new(Subscription {
|
|
|
|
queue: Mutex::new(VecDeque::new()),
|
|
|
|
notify: AtomicWaker::new(),
|
|
|
|
});
|
|
|
|
|
2023-12-28 22:32:33 +02:00
|
|
|
lock.insert(id, sub.clone());
|
2023-12-26 22:12:47 +02:00
|
|
|
|
|
|
|
sub
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Subscription {
|
|
|
|
fn receive_message_async(&self) -> impl Future<Output = Result<Arc<Message>, Error>> + '_ {
|
|
|
|
struct F<'f> {
|
|
|
|
rx: &'f Subscription,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'f> Future for F<'f> {
|
|
|
|
type Output = Result<Arc<Message>, Error>;
|
|
|
|
|
|
|
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
|
|
let mut lock = self.rx.queue.lock()?;
|
|
|
|
if let Some(msg) = lock.pop_front() {
|
|
|
|
return Poll::Ready(Ok(msg));
|
|
|
|
}
|
|
|
|
drop(lock);
|
|
|
|
|
|
|
|
self.rx.notify.register(cx.waker());
|
|
|
|
|
|
|
|
let mut lock = self.rx.queue.lock()?;
|
|
|
|
if let Some(msg) = lock.pop_front() {
|
|
|
|
Poll::Ready(Ok(msg))
|
|
|
|
} else {
|
|
|
|
Poll::Pending
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
F { rx: self }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn receive_message_inner(&self) -> Result<Arc<Message>, Error> {
|
|
|
|
block!(self.receive_message_async().await)?
|
|
|
|
}
|
|
|
|
|
|
|
|
fn push_message(&self, msg: Arc<Message>) -> Result<(), Error> {
|
|
|
|
self.queue.lock()?.push_back(msg);
|
|
|
|
self.notify.wake();
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FileReadiness for ChannelDescriptor {
|
|
|
|
fn poll_read(&self, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
|
|
|
|
let Some(rx) = self.rx.as_ref() else {
|
|
|
|
return Poll::Ready(Err(Error::InvalidOperation));
|
|
|
|
};
|
|
|
|
|
|
|
|
if !rx.queue.lock()?.is_empty() {
|
|
|
|
return Poll::Ready(Ok(()));
|
|
|
|
}
|
|
|
|
|
|
|
|
rx.notify.register(cx.waker());
|
|
|
|
|
|
|
|
if !rx.queue.lock()?.is_empty() {
|
|
|
|
Poll::Ready(Ok(()))
|
|
|
|
} else {
|
|
|
|
Poll::Pending
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static CHANNELS: IrqSafeSpinlock<BTreeMap<String, Arc<Channel>>> =
|
|
|
|
IrqSafeSpinlock::new(BTreeMap::new());
|