stuff
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
#include <zinnia/status.h>
|
||||
#include <kernel/alloc.h>
|
||||
#include <kernel/channel.h>
|
||||
#include <kernel/namespace.h>
|
||||
#include <kernel/percpu.h>
|
||||
#include <kernel/sched.h>
|
||||
#include <kernel/tailq.h>
|
||||
#include <kernel/wait.h>
|
||||
#include <stdatomic.h>
|
||||
|
||||
zn_status_t channel_create(struct channel** ep0, struct channel** ep1) {
|
||||
struct channel* a = mem_alloc(sizeof(struct channel), 0);
|
||||
if (!a)
|
||||
return ZN_ERR_NO_MEMORY;
|
||||
|
||||
struct channel* b = mem_alloc(sizeof(struct channel), 0);
|
||||
if (!b) {
|
||||
mem_free(a);
|
||||
return ZN_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
a->peer = b;
|
||||
a->lock = (struct spinlock){0};
|
||||
TAILQ_INIT(&a->messages);
|
||||
wait_queue_init(&a->waiters);
|
||||
|
||||
b->peer = a;
|
||||
b->lock = (struct spinlock){0};
|
||||
TAILQ_INIT(&b->messages);
|
||||
wait_queue_init(&b->waiters);
|
||||
|
||||
*ep0 = a;
|
||||
*ep1 = b;
|
||||
return ZN_OK;
|
||||
}
|
||||
|
||||
void channel_msg_free(struct channel_msg* msg) {
|
||||
mem_free(msg->data);
|
||||
mem_free(msg->descs);
|
||||
mem_free(msg);
|
||||
}
|
||||
|
||||
zn_status_t channel_write(
|
||||
struct channel* ch,
|
||||
void* data,
|
||||
size_t num_bytes,
|
||||
struct namespace_desc* descs,
|
||||
size_t num_handles
|
||||
) {
|
||||
// Check that the peer is still alive.
|
||||
struct channel* peer = atomic_load_explicit(&ch->peer, memory_order_acquire);
|
||||
if (!peer)
|
||||
return ZN_ERR_BAD_HANDLE;
|
||||
|
||||
// Allocate the message.
|
||||
struct channel_msg* msg = mem_alloc(sizeof(struct channel_msg), 0);
|
||||
if (!msg)
|
||||
return ZN_ERR_NO_MEMORY;
|
||||
|
||||
msg->data = data;
|
||||
msg->num_bytes = num_bytes;
|
||||
msg->descs = descs;
|
||||
msg->num_handles = num_handles;
|
||||
|
||||
// Enqueue on the peer's message queue and wake a waiter.
|
||||
spin_lock(&peer->lock);
|
||||
TAILQ_INSERT_TAIL(&peer->messages, msg, next);
|
||||
spin_unlock(&peer->lock);
|
||||
|
||||
struct sched_percpu* sched = &percpu_get()->sched;
|
||||
sched_wake(sched, &peer->waiters);
|
||||
|
||||
return ZN_OK;
|
||||
}
|
||||
|
||||
zn_status_t channel_read(struct channel* ch, struct channel_msg** msg_out) {
|
||||
spin_lock(&ch->lock);
|
||||
struct channel_msg* msg = TAILQ_FIRST(&ch->messages);
|
||||
|
||||
if (msg != nullptr) {
|
||||
TAILQ_REMOVE(&ch->messages, msg, next);
|
||||
spin_unlock(&ch->lock);
|
||||
*msg_out = msg;
|
||||
return ZN_OK;
|
||||
}
|
||||
|
||||
// No message and peer is gone — nothing will ever arrive.
|
||||
if (!ch->peer) {
|
||||
spin_unlock(&ch->lock);
|
||||
return ZN_ERR_BAD_HANDLE;
|
||||
}
|
||||
|
||||
spin_unlock(&ch->lock);
|
||||
return ZN_ERR_INVALID;
|
||||
}
|
||||
|
||||
zn_status_t channel_poll(struct channel* ch) {
|
||||
spin_lock(&ch->lock);
|
||||
|
||||
if (!TAILQ_EMPTY(&ch->messages)) {
|
||||
spin_unlock(&ch->lock);
|
||||
return ZN_OK;
|
||||
}
|
||||
|
||||
if (!ch->peer) {
|
||||
spin_unlock(&ch->lock);
|
||||
return ZN_ERR_BAD_HANDLE;
|
||||
}
|
||||
|
||||
spin_unlock(&ch->lock);
|
||||
return ZN_ERR_INVALID;
|
||||
}
|
||||
Reference in New Issue
Block a user