IPC
Header File
#include <resea/ipc.h>
Message Structure
A message is fixed-sized. It contains the message type (or an error), the sender task ID, and the message payload (arbitrary bytes, defined by IDL).
/// Message.
struct message {
/// The type of message. If it's negative, this field represents an error
/// (error_t).
int type;
/// The sender task of this message.
task_t src;
/// The message contents. Note that it's a union, not struct!
union {
// The message contents as raw bytes.
uint8_t raw[MESSAGE_SIZE - sizeof(int) - sizeof(task_t)];
// The common header of message fields.
struct {
/// The ool pointer to be sent. Used if MSG_OOL is set.
void *ool_ptr;
/// The size of ool payload in bytes.
size_t ool_len;
};
// Auto-generated message fields:
//
// struct { notifcations_t data; } notifcations;
// struct { task_t task; ... } page_fault;
// struct { paddr_t paddr; } page_reply_fault;
// ...
//
IDL_MESSAGE_FIELDS
};
};
Sending a Message
In Resea, IPC operations are sychronous. The destination is specified by a task ID. For simplicity, we don't provide indirect IPC mechanism so-called channel.
error_t ipc_send(task_t dst, struct message *m);
error_t ipc_send_err(task_t dst, error_t error);
error_t ipc_send_noblock(task_t dst, struct message *m);
ipc_send_err
is a wrapper function which sets error
to m.type
and then
sends the error message.
ipc_send_noblock
tries to send a message. If the desitnation task is not
ready for receiving a message, it immediately returns ERR_WOULD_BLOCK
instead of blocking the sender task.
Receiving a Message
On a receive operation, you have two options, open receive and closed receive:
- open receive (when
src == IPC_ANY
): accepts a message from any tasks. - closed receive (otherwise): accepts a message from the specific task (
src
). Other sender tasks are blocked.
error_t ipc_recv(task_t src, struct message *m);
Replying a Message from a Server
In case the sender task does not wait for a reply message, use the following
wrapper functions (they wrap ipc_send_noblock
). If the client calls the server with
ipc_call
, these APIs should success.
void ipc_reply(task_t dst, struct message *m);
void ipc_reply_err(task_t dst, error_t error);
Sending Notifications
Notifications is a asynchronous IPC like signals in UNIX. Each task has its
own notifications bitfield. When a task tries to receive a meesage and pending
notifications exist (i.e. the bitfield is not zero), the kernel constructs and
returns NOTIFICATIONS_MSG
with the notifications.
error_t ipc_notify(task_t dst, notifications_t notifications);
ipc_notify
does bitwise-OR operation on the destination task's
notifications bitfield and the given bits, i.e. dst->notifications |= notifications
.
Send and Receive a Message at once
error_t ipc_call(task_t dst, struct message *m);
error_t ipc_replyrecv(task_t dst, struct message *m);
ipc_call
is same as ipc_send(dst, m)
and then ipc_recv(dst, m)
. Clients
should use this API instead of calling those two APIs or ipc_reply
from the
server may fail.
Both APIs overwrite the message buffer m
with the received message.
ipc_replyrecv
is same as ipc_reply(dst, m)
and then ipc_recv(IPC_ANY, m)
. With this API, you can reduce the number of system calls in the server.