背景
总结下 ecos mbox这个通信机制。
ecos下面的通信机制真的很少,没有信号、消息队列、信号量、unix域…, 当然,我看到里面不少地方用到了 网络socket,如DHCP客户端的开启和关闭。
mbox我理解上应该就是Linux下消息队列吧,但是BRCM下面的 rc 中,用到的非常简单,仅仅使用这种机制来传递一个整数,哈哈,真是蛋碎。
经过扩展后,能传递字符串了。下面,走进去看下。
mbox的实现
tapf_sys_init->sys_main->(*sys_msg_init)()
这个函数指针封装的,目前未发现有什么备用选择。
->msg_init->cyg_mbox_create
关键就是这个函数了,其它封装后面说。
函数原型这样,很简单,一个ID, 一个结构体。
externC void cyg_mbox_create(
cyg_handle_t *handle,
cyg_mbox *mbox
) __THROW
{
CYG_ASSERT_SIZES( cyg_mbox, Cyg_Mbox );
Cyg_Mbox *t = new((void *)mbox) Cyg_Mbox();
t=t;
CYG_CHECK_DATA_PTR( handle, "Bad handle pointer" );
*handle = (cyg_handle_t)mbox;
}
这函数很坑,
- CYG_ASSERT_SIZES这宏检查下C中的这个结构体与 C++中的类大小是否相同。(类中的大小,就是成员变量的大小之各,这个类中使用模板创建的成员。)
- 实际上t就是mbox的一个别名,空间不是new出来的,而是直接使用这个结构体的地址空间。
3)handle保存mbox的地址,完全没必要在这赋值啊。
估计是一些设计上的兼容性,才导致了这么奇怪的写法。
第一个对象出场:Cyg_Mbox
构造函数为空,但它调用了模板类 Cyg_Mboxt2,
Cyg_Mboxt2<void *, CYGNUM_KERNEL_SYNCH_MBOX_QUEUE_SIZE> m;
这个模板中成员与C结构中的成员一致,其构建函数对 base , count成员赋 0 (mboxt2.inl) 。
获取mbox
cyg_mbox_get(rc_mbox_handle) & 0xffff) -> ((Cyg_Mbox *)mbox)->get()
为啥&0xffff, 把get出来的结果 取 低16位。
-> m.get( p ) 再调用模板方法。
get与set都是使用模板中方法实现的。
对于其中的每个条目操作,又有点环形队列 了。
这里很简单,仅仅是存储指针数组,然后返回其中的一个原素。
put时,找到一个位置,然后插入进去。
当然实现中会有些PV操作保证原子性、还有阻塞唤醒层面的操作。
再回头看现有的封装实现 。
struct msg_struct
{
cyg_handle_t mbox_msg_id;
cyg_mbox mbox;
PIU8 mbox_tag;
PI8 msg_info[MAX_MBOX_MSG_NUM][MAX_MBOX_MSG_LEN];
};
id / mbox同原来的调用函数。 msg_info用于存储传递的字符串,二维的个数等同于系统中 mbox的存储个数。
在操作时,要考虑获取到的消息与msg_info中的对应关系。
这种感觉,就像体制外,硬生生的附加上,当然它能work well ,但缺少层次。
思考
变长与定长 ,加入消息头(类UDP)。
消息仅传递malloc的指针,指向存储的消息,通过头部中的字段指定长度,来提取消息,完成后释放。不知为什么,很多人(包括我)都会觉得ecos下面使用动态内容就不安全,会产生莫名其妙的问题?会么?缺少独立进程、互不影响的分离机制(有了可能就不叫ecos了,会增加复杂度),导致其它任何一处的有问题,必将坏掉一锅汤。
但绝对不能“一朝被蛇咬,十年怕井绳”,这个机制是没有问题的。并且这样地是发挥了mbox的作用。(在机制上进行设计)
如何把存储空间放到消息对象的内部,减少 申请与释放内容的动作。
好吧,就能存储10条消息、定长,那么就去扩展struct 及class吧,注意其它使用mbox的地方。