bio
 
Loading...
Searching...
No Matches
Mailbox

Message passing between coroutines. More...

Macros

#define BIO_MAILBOX(T)   union { bio_handle_t bio__handle; T* bio__message; }
 Define a mailbox type.
 
#define bio_open_mailbox(ptr, capacity)    bio__mailbox_open(&(ptr)->bio__handle, sizeof(*(ptr)->bio__message), capacity)
 Create a new mailbox.
 
#define bio_close_mailbox(mailbox)    bio__mailbox_close((mailbox).bio__handle)
 Close a mailbox.
 
#define bio_is_mailbox_open(mailbox)    bio__mailbox_is_open((mailbox).bio__handle)
 Check whether a mailbox is open.
 
#define bio_send_message(mailbox, message)
 Attempt to send a message to a mailbox.
 
#define bio_wait_and_send_message(condition, mailbox, message)
 A more reliable way to send message.
 
#define bio_recv_message(mailbox, message)
 Attempt to receive from a mailbox.
 
#define bio_can_recv_message(mailbox)    bio__mailbox_can_recv((mailbox).bio__handle)
 Check whether a mailbox can be immediately received from.
 
#define bio_can_send_message(mailbox)    bio__mailbox_can_send((mailbox).bio__handle)
 Check whether a mailbox can be immediately sent to.
 
#define bio_foreach_message(msg, mailbox)
 Convenient message loop macro.
 

Detailed Description

Message passing between coroutines.

Inspired by Erlang, bio provides a way for coroutines to message one another.

This module also makes use of macro to enforce compile-time type checking.

Example:

// A mailbox can receive different types of messages
typedef enum {
TYPE_A,
TYPE_B,
} msg_type_t;
// Tagged union for message type
typedef struct {
msg_type_t type;
union {
struct {
int foo;
} a;
struct {
int bar;
} b;
};
} msg_t;
// Define the mailbox type
typedef BIO_MAILBOX(msg_t) mailbox_t;
void entry(void* userdata) {
mailbox_t mailbox;
bio_open_mailbox(mailbox, 16); // 16 messages in queue
// Pass this to other coroutines
bio_coro_t child_coro = bio_spawn(child_entry, &mailbox);
// Message loop
msg_t message;
while (bio_recv_message(mailbox, &message)) {
// Process message
}
bio_join(child_coro);
}
static bio_coro_t bio_spawn(bio_entrypoint_t entrypoint, void *userdata)
Spawn a new coroutine.
Definition bio.h:731
#define BIO_MAILBOX(T)
Define a mailbox type.
Definition mailbox.h:97
#define bio_open_mailbox(ptr, capacity)
Create a new mailbox.
Definition mailbox.h:108
#define bio_recv_message(mailbox, message)
Attempt to receive from a mailbox.
Definition mailbox.h:203
#define bio_close_mailbox(mailbox)
Close a mailbox.
Definition mailbox.h:120
static void bio_join(bio_coro_t coro)
Convenient function to wait for a coroutine to terminate.
Definition bio.h:947
Handle to a coroutine.
Definition bio.h:137
See also
Service

Macro Definition Documentation

◆ bio_can_recv_message

#define bio_can_recv_message (   mailbox)     bio__mailbox_can_recv((mailbox).bio__handle)

Check whether a mailbox can be immediately received from.

Return whether all of the following are true:

  • The mailbox is not closed
  • The mailbox is not empty

◆ bio_can_send_message

#define bio_can_send_message (   mailbox)     bio__mailbox_can_send((mailbox).bio__handle)

Check whether a mailbox can be immediately sent to.

Return whether all of the following are true:

  • The mailbox is not closed
  • The mailbox is not full

◆ bio_close_mailbox

#define bio_close_mailbox (   mailbox)     bio__mailbox_close((mailbox).bio__handle)

Close a mailbox.

As with all resources in bio, closing an already closed mailbox is not an error. In fact, it is idiomatic to close a mailbox that another coroutine is waiting on to tell it to terminate.

See also
Handle

◆ bio_foreach_message

#define bio_foreach_message (   msg,
  mailbox 
)
Value:
for ( \
BIO__TYPEOF(*(mailbox).bio__message) msg; \
bio_recv_message(mailbox, &msg); \
)

Convenient message loop macro.

mailbox_t mailbox;
bio_open_mailbox(mailbox, 16);
bio_foreach_message(message, mailbox) { // message is declared in this scope
if (message.type == MSG_QUIT) { break; }
}
#define bio_foreach_message(msg, mailbox)
Convenient message loop macro.
Definition mailbox.h:245

◆ bio_is_mailbox_open

#define bio_is_mailbox_open (   mailbox)     bio__mailbox_is_open((mailbox).bio__handle)

Check whether a mailbox is open.

◆ BIO_MAILBOX

#define BIO_MAILBOX (   T)    union { bio_handle_t bio__handle; T* bio__message; }

Define a mailbox type.

Parameters
Tthe type of message for this mailbox

◆ bio_open_mailbox

#define bio_open_mailbox (   ptr,
  capacity 
)     bio__mailbox_open(&(ptr)->bio__handle, sizeof(*(ptr)->bio__message), capacity)

Create a new mailbox.

A mailbox holds all of its messages by copy. When not needed, it should be closed with bio_close_mailbox.

Parameters
ptrPointer to a mailbox handle
capacityHow many messages can this mailbox hold before senders are blocked

◆ bio_recv_message

#define bio_recv_message (   mailbox,
  message 
)
Value:
( \
BIO__TYPECHECK_EXP(*(message), *(mailbox.bio__message)), \
bio__mailbox_recv(mailbox.bio__handle, (message), sizeof(*(message))) \
)

Attempt to receive from a mailbox.

This will dequeue a message from the mailbox.

If the mailbox is empty, the calling coroutine will be suspended. It will be resumed once a message is sent to the mailbox. Otherwise, this would return immediately without context switching.

If the mailbox is already closed, this will immediately return false.

If a mailbox is closed while a coroutine is waiting on it, the coroutine will be resumed with this returning false. Closing a mailbox is an idiomatic way to ask a coroutine to terminate.

Parameters
mailboxThe mailbox to receive from
messagePointer to a message
Returns
Whether a message was received

◆ bio_send_message

#define bio_send_message (   mailbox,
  message 
)
Value:
( \
BIO__TYPECHECK_EXP(message, *mailbox.bio__message), \
bio__mailbox_send(mailbox.bio__handle, &message, sizeof(message)) \
)

Attempt to send a message to a mailbox.

The message will be copied into the mailbox. Upon return, it is safe to invalidate/reuse/free the message.

A mailbox has limited capacity so when it is full, this will return false and the message was not actually sent.

A mailbox can also already be closed. In that case, this will also return false.

Parameters
mailboxThe mailbox to send to
messageThe message, must be of the same accepted type as the declared mailbox. This will be checked at compile-time.
Returns
Whether the message was actually sent.
See also
BIO_MAILBOX
bio_wait_and_send_message

◆ bio_wait_and_send_message

#define bio_wait_and_send_message (   condition,
  mailbox,
  message 
)
Value:
do { \
while ((bio_is_mailbox_open(mailbox)) && (condition)) { \
if (bio_send_message((mailbox), (message))) { break; } \
bio_yield(); \
} \
} while (0)
#define bio_send_message(mailbox, message)
Attempt to send a message to a mailbox.
Definition mailbox.h:147
#define bio_is_mailbox_open(mailbox)
Check whether a mailbox is open.
Definition mailbox.h:124

A more reliable way to send message.

This will attempt to send to a mailbox and busy wait if the mailbox is full. If the mailbox is already closed, it will stop trying.

// Main loop
while (!should_terminate) {
// ...
!should_terminate, // Do not retry if we received a termination signal
mailbox,
message
);
}
#define bio_wait_and_send_message(condition, mailbox, message)
A more reliable way to send message.
Definition mailbox.h:176
Parameters
conditionA boolean expression
mailboxThe mailbox to send to
messageThe message