5.3.1.2.4. sys_ipc, Inter-Proccess Communication¶
Contents
5.3.1.2.4.1. Synopsis¶
Inter-Process Communication is done using the sys_ipc()
syscall familly.
IPC can be either synchronous or asynchronous:
- synchronous IPC requests are blocking until the message has been sent and received
- asynchronous IPC are non blocking. They may return an error if the other side of the channel is not ready.
EwoK detects IPC mutual lock (two task sending IPC to each other), returning
SYS_E_BUSY
error but it does not detect cyclic deadlocks between multiple tasks
(more than 2). Be careful when designing your IPC automaton!
Note that IPC are half-duplex. For example, if task A can send messages to task B, the reciprocity is not always true and task B may have no permission to send any message to A.
5.3.1.2.4.2. Prerequisites¶
If a task A want to communicate with another task B, task A need
to retrieve B’s task id.
Getting a task identifier is done with sys_init(INIT_GETTASKID)
syscall:
uint8_t id;
e_syscall_ret ret;
ret = sys_init(INIT_GETTASKID, "task_b", &id);
if (ret != SYS_E_DONE) {
...
}
For more details, see sys_init, initializing devices.
Important
Notice that any attempt to receive or to send a message with an IPC during
the task init mode fails with SYS_E_DENIED
.
5.3.1.2.4.3. sys_ipc(SEND_SYNC)¶
A task can synchronously send data to another task.
The task is blocked until the other task emit either a
sys_ipc(RECV_SYNC)
or a sys_ipc(RECV_ASYNC)
syscall:
uint8_t id;
logsize_t size;
char *msg = "hello";
e_syscall_ret ret;
...
ret = sys_ipc(IPC_SEND_SYNC, id, sizeof(msg), msg);
if (ret != SYS_E_DONE) {
... /* Error handling */
}
The sys_ipc(IPC_SEND_SYNC,....)
can return:
SYS_E_DONE
: The message has been succesfully emittedSYS_E_DENIED
: The current task is not allowed to communicate with the other taskSYS_E_INVAL
: One of the syscall argument is invalid (invalid task id, pointer value, etc.)SYS_E_BUSY
: This happens only in the very rare condition of a synchronous send is emited after an asynchronous send and while the receiver has not emited any receive syscall.
5.3.1.2.4.4. sys_ipc(SEND_ASYNC)¶
Asynchronous send is used to send a message without waiting for it to be received. The message is kept in a kernel’s buffer until the receiver read it:
uint8_t id;
logsize_t size;
char *msg = "hello";
e_syscall_ret ret;
...
ret = sys_ipc(IPC_SEND_ASYNC, id, sizeof(msg), msg);
if (ret != SYS_E_DONE) {
... /* Error handling */
}
The sys_ipc(IPC_SEND_ASYNC,....)
can return:
SYS_E_DONE
: The message has been succesfully emittedSYS_E_DENIED
: the current task is not allowed to communicate with the other taskSYS_E_INVAL
: one of the syscall argument is invalid (invalid task id, pointer value, etc.)SYS_E_BUSY
: (only in rare occasion) only when the target has already a message from the current task that has not been read yet. This also happens if the target task has sent an IPC to the current task which is not yet received (communication channel already used)
Mixing synchronous and asynchronous IPC is possible but, of course, need some very careful thinking.
5.3.1.2.4.5. sys_ipc(RECV_SYNC)¶
- A task can synchronously wait for a message:
- from another specific task, by setting accordingly the task id
- from any task, by setting the task id to
ANY_APP
The task is blocked until a readable message is feed:
uint8_t id;
logsize_t size;
char buf[128];
e_syscall_ret ret;
id = ANY_APP; /* Waiting a msg from *any* task */
size = sizeof(buf); /* Receiving buffer max size */
ret = sys_ipc(IPC_RECV_SYNC, &id, &size, buf);
if (ret != SYS_E_DONE) {
... /* Error handling */
}
When a message is received, the kernel modify the following parameters (based on the example above):
id
: to know which task has sent the messagesize
: to set message’s sizebuf
: the message is copied into the receiving buffer
The sys_ipc(IPC_RECV_SYNC,....)
can return:
SYS_E_DONE
: The message has been succesfully receivedSYS_E_DENIED
: the current task is not allowed to communicate with the other task set as targetSYS_E_INVAL
: one of the syscall argument is invalid (invalid task id, pointer value, etc.) or the buffer size is too small to get back the message.SYS_E_BUSY
: (only in rare occasion) only when the target is already in receiving mode, waiting for the current task to send a message.
5.3.1.2.4.6. sys_ipc(RECV_ASYNC)¶
Asynchronous receive is used to read any pending message. The task is not blocked and directly returns:
ret = sys_ipc(IPC_RECV_ASYNC, &id, &size, buf);
This syscall returns the same values that is synchonous counterpart plus
SYS_E_BUSY
if there is no message to read.