File syn_mailbox.h¶
File List > sched > syn_mailbox.h
Go to the documentation of this file
#ifndef SYN_MAILBOX_H
#define SYN_MAILBOX_H
#include "../common/syn_barrier.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
/* ── Mailbox instance ───────────────────────────────────────────────────── */
typedef struct {
uint8_t *buf;
size_t msg_size;
size_t capacity;
volatile size_t head;
volatile size_t tail;
uint32_t overflow;
#if defined(SYN_USE_MULTICORE) && SYN_USE_MULTICORE
bool notify;
#endif
} SYN_Mailbox;
#if defined(SYN_USE_MULTICORE) && SYN_USE_MULTICORE
#define SYN_MAILBOX_DEFINE(name, type, count) \
static uint8_t name##_buf[(count) * sizeof(type)]; \
static SYN_Mailbox name = { \
.buf = name##_buf, \
.msg_size = sizeof(type), \
.capacity = (count), \
.head = 0, \
.tail = 0, \
.overflow = 0, \
.notify = false, \
}
#else
#define SYN_MAILBOX_DEFINE(name, type, count) \
static uint8_t name##_buf[(count) * sizeof(type)]; \
static SYN_Mailbox name = { \
.buf = name##_buf, \
.msg_size = sizeof(type), \
.capacity = (count), \
.head = 0, \
.tail = 0, \
.overflow = 0, \
}
#endif
/* ── Forward declaration for IPC notify ────────────────────────────────── */
#if defined(SYN_USE_MULTICORE) && SYN_USE_MULTICORE
void syn_port_ipc_notify(void);
#endif
/* ── API ────────────────────────────────────────────────────────────────── */
static inline void syn_mailbox_init(SYN_Mailbox *mb, void *buf, size_t msg_size, size_t capacity)
{
mb->buf = (uint8_t *)buf;
mb->msg_size = msg_size;
mb->capacity = capacity;
mb->head = 0;
mb->tail = 0;
mb->overflow = 0;
#if defined(SYN_USE_MULTICORE) && SYN_USE_MULTICORE
mb->notify = false;
#endif
}
#if defined(SYN_USE_MULTICORE) && SYN_USE_MULTICORE
static inline void syn_mailbox_set_notify(SYN_Mailbox *mb, bool enable)
{
mb->notify = enable;
}
#endif
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wanalyzer-use-of-uninitialized-value"
#endif
static inline bool syn_mailbox_post(SYN_Mailbox *mb, const void *msg)
{
size_t head = mb->head;
size_t next = head + 1;
if (next >= mb->capacity)
next = 0;
if (next == SYN_LOAD_ACQUIRE(&mb->tail)) {
mb->overflow++;
return false;
}
memcpy(&mb->buf[head * mb->msg_size], msg, mb->msg_size);
SYN_STORE_RELEASE(&mb->head, next);
#if defined(SYN_USE_MULTICORE) && SYN_USE_MULTICORE
if (mb->notify) {
syn_port_ipc_notify();
}
#endif
return true;
}
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
static inline bool syn_mailbox_receive(SYN_Mailbox *mb, void *msg)
{
size_t head = SYN_LOAD_ACQUIRE(&mb->head);
size_t tail = mb->tail;
if (tail == head)
return false;
memcpy(msg, &mb->buf[tail * mb->msg_size], mb->msg_size);
size_t next = tail + 1;
if (next >= mb->capacity)
next = 0;
SYN_STORE_RELEASE(&mb->tail, next);
return true;
}
static inline const void *syn_mailbox_peek(const SYN_Mailbox *mb)
{
if (SYN_LOAD_ACQUIRE(&mb->head) == mb->tail)
return NULL;
return &mb->buf[mb->tail * mb->msg_size];
}
static inline bool syn_mailbox_empty(const SYN_Mailbox *mb)
{
return SYN_LOAD_ACQUIRE(&mb->head) == mb->tail;
}
static inline bool syn_mailbox_full(const SYN_Mailbox *mb)
{
size_t next = mb->head + 1;
if (next >= mb->capacity)
next = 0;
return next == SYN_LOAD_ACQUIRE(&mb->tail);
}
static inline size_t syn_mailbox_pending(const SYN_Mailbox *mb)
{
size_t h = SYN_LOAD_ACQUIRE(&mb->head);
size_t t = mb->tail;
return (h >= t) ? h - t : mb->capacity - t + h;
}
static inline size_t syn_mailbox_free(const SYN_Mailbox *mb)
{
/* One slot is always reserved as sentinel */
return mb->capacity - 1 - syn_mailbox_pending(mb);
}
static inline uint32_t syn_mailbox_overflows(const SYN_Mailbox *mb)
{
return mb->overflow;
}
static inline void syn_mailbox_flush(SYN_Mailbox *mb)
{
size_t head = SYN_LOAD_ACQUIRE(&mb->head);
SYN_STORE_RELEASE(&mb->tail, head);
}
#ifdef __cplusplus
}
#endif
#endif /* SYN_MAILBOX_H */