[kernel] Replace endpoint with new mailbox API

The new mailbox kernel object API offers asynchronous message-based IPC
for sending data and handles between threads, as opposed to endpoint's
synchronous model.
This commit is contained in:
Justin C. Miller
2022-02-22 00:06:14 -08:00
parent f7ae2e2220
commit 30aed15090
17 changed files with 647 additions and 364 deletions

View File

@@ -0,0 +1,235 @@
#include <j6/errors.h>
#include <j6/flags.h>
#include <util/util.h>
#include "objects/mailbox.h"
#include "objects/thread.h"
#include "syscalls/helpers.h"
using namespace obj;
namespace syscalls {
j6_status_t
mailbox_create(j6_handle_t *self)
{
construct_handle<mailbox>(self);
return j6_status_ok;
}
j6_status_t
mailbox_close(mailbox *self)
{
if (self->closed())
return j6_status_closed;
self->close();
return j6_status_ok;
}
j6_status_t
prep_send(
mailbox::message *msg,
uint64_t tag,
uint64_t badge,
const void *data,
size_t data_len,
const j6_handle_t *handles,
size_t handle_count)
{
if (!msg ||
data_len > mailbox::max_data_length ||
handle_count > mailbox::max_handle_count)
return j6_err_invalid_arg;
msg->tag = tag;
msg->badge = badge;
msg->handle_count = handle_count;
for (unsigned i = 0; i < handle_count; ++i) {
handle *h = get_handle<kobject>(handles[i]);
if (!h)
return j6_err_invalid_arg;
msg->handles[i] = *h;
}
msg->data_len = data_len;
memcpy(msg->data, data, data_len);
return j6_status_ok;
}
void
prep_receive(
mailbox::message *msg,
uint64_t *tag,
uint64_t *badge,
uint16_t *reply_tag,
void *data,
size_t *data_len,
j6_handle_t *handles,
size_t *handle_count)
{
if (tag) *tag = msg->tag;
if (badge) *badge = msg->badge;
if (reply_tag) *reply_tag = msg->reply_tag;
*data_len = msg->data_len;
memcpy(data, msg->data, msg->data_len);
*handle_count = msg->handle_count;
process &proc = process::current();
for (size_t i = 0; i < msg->handle_count; ++i)
handles[i] = proc.add_handle(msg->handles[i]);
delete msg;
}
j6_status_t
mailbox_send(
handle *self_handle,
uint64_t tag,
const void * data,
size_t data_len,
j6_handle_t * handles,
size_t handle_count)
{
mailbox *self = self_handle->as<mailbox>();
mailbox::message *msg = new mailbox::message;
j6_status_t s = prep_send(msg,
tag, self_handle->badge,
data, data_len,
handles, handle_count);
if (s != j6_status_ok) {
delete msg;
return s;
}
self->send(msg);
return j6_status_ok;
}
j6_status_t
mailbox_receive(
mailbox *self,
uint64_t * tag,
void * data,
size_t * data_len,
j6_handle_t * handles,
size_t * handle_count,
uint16_t * reply_tag,
uint64_t * badge,
uint64_t flags)
{
if (*data_len < mailbox::max_data_length ||
*handle_count < mailbox::max_handle_count)
return j6_err_insufficient;
mailbox::message *msg = nullptr;
bool block = flags & j6_mailbox_block;
if (!self->receive(msg, block)) {
// No message received
return self->closed() ? j6_status_closed :
block ? j6_status_would_block :
j6_err_unexpected;
}
prep_receive(msg,
tag, badge, reply_tag,
data, data_len,
handles, handle_count);
return j6_status_ok;
}
j6_status_t
mailbox_call(
handle *self_handle,
uint64_t * tag,
void * data,
size_t * data_len,
j6_handle_t * handles,
size_t * handle_count)
{
mailbox *self = self_handle->as<mailbox>();
mailbox::message *msg = new mailbox::message;
j6_status_t s = prep_send(msg,
*tag, self_handle->badge,
data, *data_len,
handles, *handle_count);
if (s != j6_status_ok) {
delete msg;
return s;
}
if (!self->call(msg)) {
delete msg;
return self->closed() ? j6_status_closed :
j6_err_unexpected;
}
prep_receive(msg,
tag, nullptr, nullptr,
data, data_len,
handles, handle_count);
delete msg;
return j6_status_ok;
}
j6_status_t
mailbox_respond(
mailbox *self,
uint64_t tag,
const void * data,
size_t data_len,
j6_handle_t * handles,
size_t handle_count,
uint16_t reply_tag)
{
mailbox::replyer reply = self->reply(reply_tag);
if (!reply.valid())
return j6_err_invalid_arg;
j6_status_t s = prep_send(reply.msg, tag, 0,
data, data_len,
handles, handle_count);
if (s != j6_status_ok) {
reply.error(s);
return s;
}
return j6_status_ok;
}
j6_status_t
mailbox_respond_receive(
mailbox *self,
uint64_t * tag,
void * data,
size_t * data_len,
j6_handle_t * handles,
size_t * handle_count,
uint16_t * reply_tag,
uint64_t * badge,
uint64_t flags)
{
j6_status_t s = mailbox_respond(self, *tag, data, *data_len, handles, *handle_count, *reply_tag);
if (s != j6_status_ok)
return s;
return mailbox_receive(self, tag, data, data_len, handles, handle_count, reply_tag, badge, flags);
}
} // namespace syscalls