邮箱是一种典型的任务间通信机制。邮箱每次可以传递固定字节大小的邮件,且邮箱有缓冲区,可以缓存一定数量的邮件。邮箱没满的情况下,可以一直往邮箱里面发送邮件,邮箱满了可以选择超时等待;邮箱有邮件的情况下,可以从邮箱里面接收邮件,如果没有邮件,可以选择超时等待。
在本操作系统中,一封邮件的大小固定为4byte,所有可以直接发送32位数据。在32位系统上,一个指针大小是4byte,所以可以用邮箱来发送指针,而收发双方都按照相同的方式去解析指针指向的内容,就可以达到传送各种类型数据的功能。
struct os_mailbox
{
struct os_ipc_object parent; /* Inherit from ipc_object. */
os_uint32_t *msg_pool; /* Start address of message buffer. */
os_uint16_t size; /* Size of message pool. */
os_uint16_t entry; /* Index of messages in msg_pool. */
os_uint16_t in_offset; /* Input offset of the message buffer. */
os_uint16_t out_offset; /* Output offset of the message buffer. */
os_list_node_t suspend_sender_task; /* Sender thread suspended on this mailbox. */
};
struct os_mailbox重要参数 | 说明 |
---|---|
msg_pool | 邮箱缓冲区的起始地址 |
size | 邮箱缓冲区的大小,以byte为单位 |
entry | 邮箱中邮件的个数 |
in_offset | 邮箱缓冲区中的输入偏移 |
out_offset | 邮箱缓冲区中的输出偏移 |
suspend_sender_task | 挂起在该邮箱上的发送任务 |
接口 | 说明 |
---|---|
os_mb_init | 以静态方式初始化邮箱,邮箱对象由使用者提供 |
os_mb_deinit | 反初始化邮箱,与os_mb_init()匹配使用 |
os_mb_create | 以动态方式创建并初始化邮箱,邮箱对象采用动态申请内存的方式获得 |
os_mb_destroy | 销毁邮箱,与os_mb_create()匹配使用 |
os_mb_send | 发送邮件 |
os_mb_recv | 接收邮件 |
os_mb_control | 控制或更改邮箱的行为属性 |
该函数以静态的方式初始化邮箱,邮箱对象的内存空间和邮箱缓冲区都由使用者提供,函数原型如下:
os_err_t os_mb_init(os_mailbox_t *mb,
const char *name,
void *msg_pool,
os_size_t msg_pool_size,
os_ipc_flag_t flag);
参数 | 说明 |
---|---|
mb | 邮箱句柄 |
name | 邮箱名字 |
msg_pool | 邮箱缓冲区的起始地址 |
msg_pool_size | 邮箱缓冲区的大小,以byte为单位 |
flag | 标志,可以取OS_IPC_FLAG_FIFO和OS_IPC_FLAG_PRIO;当取值为OS_IPC_FLAG_FIFO时,等待的任务将按照先进先出的方式排队,先进入的任务先被唤醒;当取值为OS_IPC_FLAG_PRIO时,等待的任务将按照任务优先级排队,优先级高的任务先被唤醒 |
返回 | 说明 |
OS_EOK | 初始化成功 |
OS_ERROR | 初始化错误 |
该函数用于反初始化邮箱,与os_mb_init()匹配使用,函数原型如下:
os_err_t os_mb_deinit(os_mailbox_t *mb);
参数 | 说明 |
---|---|
mb | 邮箱句柄 |
返回 | 说明 |
OS_EOK | 反初始化成功 |
该函数以动态的方式创建并初始化邮箱,其邮箱对象的内存空间和邮箱缓冲区都是通过动态申请内存获得,函数原型如下:
os_mailbox_t *os_mb_create(const char *name, os_size_t max_mails, os_ipc_flag_t flag);
参数 | 说明 |
---|---|
name | 邮箱名字 |
max_mails | 此邮箱支持的最大邮件个数 |
flag | 标志,可以取OS_IPC_FLAG_FIFO和OS_IPC_FLAG_PRIO;当取值为OS_IPC_FLAG_FIFO时,等待的任务将按照先进先出的方式排队,先进入的任务先被唤醒;当取值为OS_IPC_FLAG_PRIO时,等待的任务将按照任务优先级排队,优先级高的任务先被唤醒 |
返回 | 说明 |
非OS_NULL | 创建成功,返回邮箱句柄 |
OS_NULL | 创建失败 |
该函数用于销毁邮箱,并释放邮箱对象的内存空间和邮箱缓冲区的空间,函数原型如下:
os_err_t os_mb_destroy(os_mailbox_t *mb);
参数 | 说明 |
---|---|
mb | 邮箱句柄 |
返回 | 说明 |
OS_EOK | 销毁成功 |
该函数用于发送邮件,若邮箱已满且设定了等待时间,则当前发送任务阻塞,函数原型如下:
os_err_t os_mb_send(os_mailbox_t *mb, os_uint32_t value, os_tick_t timeout);
参数 | 说明 |
---|---|
mb | 邮箱句柄 |
value | 邮件内容 |
timeout | 当邮箱已满时,发送任务等待的超时时间;若为OS_IPC_WAITING_NO,则直接返回OS_EFULL;若为OS_IPC_WAITING_FOREVER,则永久等待直到邮箱有可用空间;若为其它值,则等待timeout时间或者直到邮箱有可用空间 |
返回 | 说明 |
OS_EOK | 邮件发送成功 |
OS_EFULL | 邮箱已满且未等待 |
OS_ETIMEOUT | 邮箱已满且等待超时 |
该函数用于接收邮件,若邮箱为空且设定了等待时间,则当前接收任务阻塞,函数原型如下:
os_err_t os_mb_recv(os_mailbox_t *mb, os_uint32_t *value, os_tick_t timeout);
参数 | 说明 |
---|---|
mb | 邮箱句柄 |
value | 指向接收的邮件内容 |
timeout | 当邮箱为空时,接收任务等待的超时时间;若为OS_IPC_WAITING_NO,则直接返回OS_EEMPTY;若为OS_IPC_WAITING_FOREVER,则永久等待直到邮箱中有邮件;若为其它值,则等待timeout时间或者直到邮箱中有邮件 |
返回 | 说明 |
OS_EOK | 邮件接收成功 |
OS_EEMPTY | 邮箱为空且未等待 |
OS_ETIMEOUT | 邮箱为空且等待超时 |
该函数用于控制或改变邮箱的行为属性,函数原型如下:
os_err_t os_mb_control(os_mailbox_t *mb, os_ipc_cmd_t cmd, void *arg);
参数 | 说明 |
---|---|
mb | 邮箱句柄 |
cmd | 控制命令,目前支持OS_IPC_CMD_RESET,该命令会唤醒所有阻塞在该邮箱上的任务,并重新初始化邮箱信息 |
返回 | 说明 |
OS_EOK | 成功 |
OS_ERROR | 失败 |
本例采用静态方式初始化了一个邮箱。然后创建了任务1,每隔一段时间发送一封邮件(32位整型数据),当邮箱满了之后,发送任务阻塞;之后创建任务2接收邮件,当读取邮件后,发送任务被唤醒可以继续发送邮件;当邮件被全部接收完成后,再次接收邮件时,接收任务会阻塞;后续发送任务每发送一封邮件,接收任务就被唤醒一次。
#include <oneos_config.h>
#include <os_dbg.h>
#include <os_errno.h>
#include <os_task.h>
#include <shell.h>
#include <os_mailbox.h>
#define TEST_TAG "TEST"
#define TASK_STACK_SIZE 1024
#define TASK1_PRIORITY 15
#define TASK2_PRIORITY 16
#define TASK_TIMESLICE 10
#define MB_MAX_MAILS 10
#define MB_POLL_SIZE (MB_MAX_MAILS * sizeof(os_uint32_t))
static char mb_pool[MB_POLL_SIZE];
static os_mailbox_t mb_static;
void task1_entry(void *para)
{
os_uint32_t send_data = 0;
while (1)
{
send_data++;
LOG_W(TEST_TAG, "task1 send_data:%d", send_data);
if(OS_EOK == os_mb_send(&mb_static, send_data, OS_IPC_WAITING_FOREVER))
{
LOG_W(TEST_TAG, "task1 send OK");
}
else
{
LOG_W(TEST_TAG, "task1 send err");
}
os_task_sleep(100);
}
}
void task2_entry(void *para)
{
os_uint32_t recv_data = 0;
while (1)
{
if (OS_EOK == os_mb_recv(&mb_static, &recv_data, OS_IPC_WAITING_FOREVER))
{
LOG_W(TEST_TAG, "task2 recv_data:%d", recv_data);
}
}
}
void mailbox_static_sample(void)
{
os_task_t *task1 = OS_NULL;
os_task_t *task2 = OS_NULL;
os_mb_init(&mb_static, "mailbox_static", &mb_pool[0], MB_POLL_SIZE, OS_IPC_FLAG_FIFO);
task1 = os_task_create("task1",
task1_entry,
OS_NULL,
TASK_STACK_SIZE,
TASK1_PRIORITY,
TASK_TIMESLICE);
if (task1)
{
LOG_W(TEST_TAG, "mailbox_static_sample startup task1");
os_task_startup(task1);
}
os_task_sleep(1200);
task2 = os_task_create("task2",
task2_entry,
OS_NULL,
TASK_STACK_SIZE,
TASK2_PRIORITY,
TASK_TIMESLICE);
if (task2)
{
LOG_W(TEST_TAG, "mailbox_static_sample startup task2");
os_task_startup(task2);
}
}
SH_CMD_EXPORT(static_mailbox, mailbox_static_sample, "test staitc mailbox");
运行结果如下:
sh />static_mailbox
W/TEST: mailbox_static_sample startup task1
W/TEST: task1 send_data:1
W/TEST: task1 send OK
W/TEST: task1 send_data:2
W/TEST: task1 send OK
W/TEST: task1 send_data:3
W/TEST: task1 send OK
W/TEST: task1 send_data:4
W/TEST: task1 send OK
W/TEST: task1 send_data:5
W/TEST: task1 send OK
W/TEST: task1 send_data:6
W/TEST: task1 send OK
W/TEST: task1 send_data:7
W/TEST: task1 send OK
W/TEST: task1 send_data:8
W/TEST: task1 send OK
W/TEST: task1 send_data:9
W/TEST: task1 send OK
W/TEST: task1 send_data:10
W/TEST: task1 send OK
W/TEST: task1 send_data:11
W/TEST: mailbox_static_sample startup task2
W/TEST: task1 send OK
W/TEST: task2 recv_data:1
W/TEST: task2 recv_data:2
W/TEST: task2 recv_data:3
W/TEST: task2 recv_data:4
W/TEST: task2 recv_data:5
W/TEST: task2 recv_data:6
W/TEST: task2 recv_data:7
W/TEST: task2 recv_data:8
W/TEST: task2 recv_data:9
W/TEST: task2 recv_data:10
W/TEST: task2 recv_data:11
W/TEST: task1 send_data:12
W/TEST: task1 send OK
W/TEST: task2 recv_data:12
W/TEST: task1 send_data:13
W/TEST: task1 send OK
W/TEST: task2 recv_data:13
W/TEST: task1 send_data:14
W/TEST: task1 send OK
W/TEST: task2 recv_data:14
W/TEST: task1 send_data:15
W/TEST: task1 send OK
W/TEST: task2 recv_data:15
本例采用动态的方式创建并初始化了一个邮箱;本例所展示的发送邮件的方式更为通用和更加灵活。在任务1中申请了一块空间,填充好要发送的数据后,将数据区域的指针作为邮件内容发送出去;在任务2中,接收到邮件内容后,将指针指向的数据按照相同的方式解析,之后释放申请的空间。
#include <oneos_config.h>
#include <os_dbg.h>
#include <os_errno.h>
#include <os_task.h>
#include <shell.h>
#include <string.h>
#include <os_memory.h>
#include <os_mailbox.h>
#define TEST_TAG "TEST"
#define TASK_STACK_SIZE 1024
#define TASK1_PRIORITY 15
#define TASK2_PRIORITY 16
#define TASK_TIMESLICE 10
#define MB_MAX_MAILS 10
#define TEST_NAME_MAX 16
#define STUDENT_NUM 5
static os_mailbox_t *mb_dynamic;
struct student_score
{
char name[TEST_NAME_MAX];
os_uint32_t score;
};
void task1_entry(void *para)
{
os_uint32_t i = 0;
struct student_score *student_data = OS_NULL;
char *name[STUDENT_NUM] = {"xiaoming", "xiaohua", "xiaoqiang", "xiaoli", "xiaofang"};
os_uint32_t score[STUDENT_NUM] = {80, 85, 90, 95, 96};
for (i = 0; i < STUDENT_NUM; i++)
{
student_data = os_malloc(sizeof(struct student_score));
LOG_W(TEST_TAG, "task1 malloc ptr:%p", student_data);
if (student_data)
{
memset(student_data->name, 0, TEST_NAME_MAX);
strncpy(student_data->name, name[i], TEST_NAME_MAX);
student_data->score = score[i];
if(OS_EOK == os_mb_send(mb_dynamic, (os_uint32_t)student_data, OS_IPC_WAITING_FOREVER))
{
LOG_W(TEST_TAG, "task1 send -- name:%s score:%d", student_data->name, student_data->score);
}
}
os_task_sleep(100);
}
}
void task2_entry(void *para)
{
os_uint32_t recv_data = 0;
while (1)
{
if (OS_EOK == os_mb_recv(mb_dynamic, &recv_data, OS_IPC_WAITING_FOREVER))
{
LOG_W(TEST_TAG, "task2 recv -- name:%s score:%d", ((struct student_score *)recv_data)->name, ((struct student_score *)recv_data)->score);
LOG_W(TEST_TAG, "task2 free ptr :%p", (void*)recv_data);
os_free((void*)recv_data);
}
}
}
void mailbox_dynamic_sample(void)
{
os_task_t *task1 = OS_NULL;
os_task_t *task2 = OS_NULL;
mb_dynamic = os_mb_create("mailbox_dynamic", MB_MAX_MAILS, OS_IPC_FLAG_FIFO);
if(!mb_dynamic)
{
LOG_W(TEST_TAG, "mailbox_dynamic_sample mailbox create ERR");
return;
}
task1 = os_task_create("task1",
task1_entry,
OS_NULL,
TASK_STACK_SIZE,
TASK1_PRIORITY,
TASK_TIMESLICE);
if (task1)
{
LOG_W(TEST_TAG, "mailbox_dynamic_sample startup task1");
os_task_startup(task1);
}
os_task_sleep(200);
task2 = os_task_create("task2",
task2_entry,
OS_NULL,
TASK_STACK_SIZE,
TASK2_PRIORITY,
TASK_TIMESLICE);
if (task2)
{
LOG_W(TEST_TAG, "mailbox_dynamic_sample startup task2");
os_task_startup(task2);
}
}
SH_CMD_EXPORT(dynamic_mailbox, mailbox_dynamic_sample, "test dynamic mailbox");
运行结果如下:
sh />dynamic_mailbox
W/TEST: mailbox_dynamic_sample startup task1
W/TEST: task1 malloc ptr:20007744
W/TEST: task1 send -- name:xiaoming score:80
W/TEST: task1 malloc ptr:20007768
W/TEST: task1 send -- name:xiaohua score:85
W/TEST: mailbox_dynamic_sample startup task2
W/TEST: task2 recv -- name:xiaoming score:80
W/TEST: task1 malloc ptr:20007a44
W/TEST: task1 send -- name:xiaoqiang score:90
W/TEST: task2 free ptr :20007744
W/TEST: task2 recv -- name:xiaohua score:85
W/TEST: task2 free ptr :20007768
W/TEST: task2 recv -- name:xiaoqiang score:90
W/TEST: task2 free ptr :20007a44
W/TEST: task1 malloc ptr:20007744
W/TEST: task1 send -- name:xiaoli score:95
W/TEST: task2 recv -- name:xiaoli score:95
W/TEST: task2 free ptr :20007744
W/TEST: task1 malloc ptr:20007744
W/TEST: task1 send -- name:xiaofang score:96
W/TEST: task2 recv -- name:xiaofang score:96
W/TEST: task2 free ptr :20007744