1. 引入
本节介绍的内容原理很简单,就是著名的环形缓冲区,关于环形缓冲区的诸多介绍网上比比皆是,但是为了后面更加深入的学习SylixOS,我觉得有必要提一下这部分内容。在这里推荐一个开源库liblcthw网址是: https://github.com/zedshaw/liblcthw这个库用c代码实现了一些常用的数据结构,适合学习c语言的人看看。接下来我们来学习一下SylixOS中块消息缓冲区实现上的一些技术细节。
2. 块消息缓冲区结构
这是从SylixOS源码中截取的一个图,从图中看块消息缓冲区结构中包含5个成员:
- BM_pucBuffer指向消息缓冲区的首地址(也即环形缓冲区);
-
BM_stSize是消息缓冲区的总大小;
-
BM_stLeft是这个消息缓冲区中剩余的可用空间大小;
-
BM_pucPut向缓冲区中放入消息指针;
-
BM_pucGet从缓冲区中取出消息指针。
之所以称为块消息缓冲区是因为在缓冲区中的每个消息前都保留了2个字节的空间来保存消息的长度,这样一个完整的消息就包括了消息内容和消息长度。由此可见缓冲区的剩余空间不能小于2个字节,否则视为缓冲区满。同样SylixOS规定了缓冲区最小空间不能小于64字节。
3. 块消息缓冲区函数
下面我们简单的介绍缓冲区操作的一些函数:
PLW_BMSG _bmsgCreate(size_t stSize);
VOID _bmsgDelete(PLW_BMSG pbmsg);
INT _bmsgPut(PLW_BMSG pbmsg, CPVOID pvMsg, size_t stSize);
INT _bmsgGet(PLW_BMSG pbmsg, PVOID pvMsg, size_t stBufferSize);
VOID _bmsgFlush(PLW_BMSG pbmsg);
INT _bmsgIsEmpty(PLW_BMSG pbmsg);
INT _bmsgIsFull(PLW_BMSG pbmsg);
INT _bmsgSizeGet(PLW_BMSG pbmsg);
INT _bmsgFreeByte(PLW_BMSG pbmsg);
INT _bmsgNBytes(PLW_BMSG pbmsg);
INT _bmsgNBytesNext(PLW_BMSG pbmsg);
块消息缓冲区操作函数基本上就包括了上面的一组函数,我们重点看一下_bmsgPut 、_bmsgGet两个函数,这两个函数是缓冲区操作的核心,从名字看我们也可以想到_bmsgPut是往缓冲区中放入一条消息而_bmsgGet是从缓冲区中取出一条消息,这里值得我们注意的是放入的消息长度最大不得超过65536(也即2个字节的最大长度)下面是源码中部分片段:
INT _bmsgPut (PLW_BMSG pbmsg, CPVOID pvMsg, size_t stSize)
{
#define LW_BMSG_ADJUST_PUT() \
if (pbmsg->BM_pucPut >= (pbmsg->BM_pucBuffer + pbmsg->BM_stSize)) { \
pbmsg->BM_pucPut = pbmsg->BM_pucBuffer; \
}
...
*pbmsg->BM_pucPut = (UCHAR)(stSize >> 8); /* 保存两个字节长度信息 */
pbmsg->BM_pucPut++;
LW_BMSG_ADJUST_PUT();
*pbmsg->BM_pucPut = (UCHAR)(stSize & 0xff);
pbmsg->BM_pucPut++;
LW_BMSG_ADJUST_PUT();
...
}
从源码中我们可以看出消息长度的低16位作为有效长度保存在了BM_pucPut前两个字节中。
宏LW_BMSG_ADJUST_PUT()实现了缓冲区的环形操作,其他的技术问题在这里就不再赘述了,都是一些缓冲区的常规处理问题了,具体可参考SylixOS源码。
4. 应用实例
下面的实例仅供说明SylixOS块消息缓冲区函数的使用方法,在SylixOS开发中不建议这样用,因为下面这段程序使用了许多SylixOS中不建议在这里用的函数或方法。同样这段程序也存在着许多问题,如互斥访问等。
#define __SYLIXOS_KERNEL
#include <SylixOS.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
static LW_HANDLE sync_lock;
static char *msg = "Testing SylixOS bmsg.";
void *thread_putmsg (void *arg)
{
PLW_BMSG pbmsg = (PLW_BMSG)arg;
_bmsgPut(pbmsg, msg, strlen(msg));
API_SemaphoreBPost(sync_lock);
while (1) {
sleep(10);
}
return NULL;
}
void *thread_getmsg (void *arg)
{
PLW_BMSG pbmsg = (PLW_BMSG)arg;
char buf[64] = {0};
API_SemaphoreBPend(sync_lock, LW_OPTION_WAIT_INFINITE);
_bmsgGet(pbmsg, buf, strlen(msg));
fprintf(stdout, "Recv msg: %s\n", buf);
while (1) {
sleep(10);
}
return NULL;
}
int main (int argc, char *argv[])
{
PLW_BMSG pbmsg;
pthread_t tid1, tid2;
pbmsg = _bmsgCreate(2048);
if (!pbmsg) {
fprintf(stderr, "bmsg create failed.\n");
return -1;
}
sync_lock = API_SemaphoreBCreate("bmsg_sync", LW_FALSE, LW_OPTION_OBJECT_GLOBAL, LW_NULL);
if (!sync_lock) {
fprintf(stdout, "Create semaphore failed.\n");
return -1;
}
pthread_create(&tid1, NULL, thread_putmsg, (void *)pbmsg);
pthread_create(&tid2, NULL, thread_getmsg, (void *)pbmsg);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
return (0);
}
(本节完)