1、概述
在 SylixOS 容器版本中由于容器间存在命名空间隔离的问题因此无法直接使用信号量进行同步操作,这在某些场合下可能无法完成实际需求,如共享内存通信时。本文介绍一种在容器间实现信号量同步功能的解决方案。
2、解决方案
此解决方案思路是在 SylixOS 标准信号量的基础上封装一层字符设备,在内核层创建信号量并提供相关接口使容器内的 APP 可以通过字符设备接口获取内核信号量句柄,再通过标准信号量 API 进行操作。实现不同容器间的 APP 同步操作。基本框架如下图所示。
3、代码
字符设备:
/*********************************************************************************************************
**
** 中国软件开源组织
**
** 嵌入式实时操作系统
**
** SylixOS(TM) LW : long wing
**
** Copyright All Rights Reserved
**
**--------------文件信息--------------------------------------------------------------------------------
**
** 文 件 名: semc.c
**
** 创 建 人: Wang.Jingshi (王京石)
**
** 文件创建日期: 2021 年 07 月 13 日
**
** 描 述: 信号量设备(用于容器间资源同步)
*********************************************************************************************************/
#define __SYLIXOS_KERNEL
#include <SylixOS.h>
#include <linux/compat.h>
#include <sys/ioccom.h>
#include "semc.h"
/*********************************************************************************************************
设备结构
*********************************************************************************************************/
struct __semc_dev {
LW_DEV_HDR SEMC_devhdr; /* 设备头 */
LW_LIST_LINE_HEADER SEMC_fdNodeHeader; /* 文件节点链表头 */
LW_HANDLE SEMC_handle; /* 信号量句柄 */
ULONG SEMC_ulInitCounter; /* 信号量初值 */
ULONG SEMC_ulMaxCounter; /* 信号量最大值 */
ULONG SEMC_ulOption; /* 信号量选项 */
};
typedef struct __semc_dev __SEMC_DEV;
typedef __SEMC_DEV *__PSEMC_DEV;
/*********************************************************************************************************
全局变量
*********************************************************************************************************/
static __SEMC_DEV _G_semcDev; /* 信号量设备 */
static INT _G_iSemcDrvNum = 0; /* 信号量设备主设备号 */
/*********************************************************************************************************
** 函数名称: __semcOpen
** 功能描述: 打开 SEMC 设备
** 输 入 : pDev 设备
** pcName 设备名字
** iFlags 标志
** iMode 模式
** 输 出 : NONE
** 返 回 : ERROR_CODE
*********************************************************************************************************/
static LONG __semcOpen (__PSEMC_DEV pDev, CHAR *pcName, INT iFlags, INT iMode)
{
BOOL bIsNew;
PLW_FD_NODE pFdNode = LW_NULL;
if (LW_NULL == pcName) { /* 设备名称为空时,出错 */
_ErrorHandle(ERROR_IO_NO_DEVICE_NAME_IN_PATH);
return (PX_ERROR);
} else { /* 增加一个设备 */
pFdNode = API_IosFdNodeAdd(&pDev->SEMC_fdNodeHeader,
(dev_t)pDev,
0,
iFlags,
iMode,
0,
0,
0,
LW_NULL,
&bIsNew);
if (LW_NULL == pFdNode) { /* 判断节点是否为空 */
printk(KERN_ERR "[semc] failed to add fd node.\n");
return (PX_ERROR);
}
if (LW_DEV_INC_USE_COUNT(&pDev->SEMC_devhdr) == 1) {
CHAR cName[64];
snprintf(cName, sizeof(cName), "dev_%s", pcName);
pDev->SEMC_handle = API_SemaphoreCCreate(cName,
pDev->SEMC_ulInitCounter,
pDev->SEMC_ulMaxCounter,
pDev->SEMC_ulOption,
LW_NULL);
if (pDev->SEMC_handle == LW_OBJECT_HANDLE_INVALID) {
printk(KERN_ERR "[semc] semaphore create failded.\n");
goto __error;
}
}
}
return ((LONG)pFdNode);
__error:
LW_DEV_DEC_USE_COUNT(&pDev->SEMC_devhdr);
if (pFdNode) {
API_IosFdNodeDec(&pDev->SEMC_fdNodeHeader, pFdNode, LW_NULL);
}
return ((LONG)LW_NULL);
}
/*********************************************************************************************************
** 函数名称: __semcClose
** 功能描述: SEMC 设备关闭
** 输 入 : pFdentry 文件结构
** 输 出 : NONE
** 返 回 : ERROR_CODE
*********************************************************************************************************/
static INT __semcClose (PLW_FD_ENTRY pFdentry)
{
__PSEMC_DEV pDev = LW_NULL;
PLW_FD_NODE pfdNode = LW_NULL;
if (!pFdentry) {
return (PX_ERROR);
}
pDev = (__PSEMC_DEV)pFdentry->FDENTRY_pdevhdrHdr;
pfdNode = (PLW_FD_NODE)pFdentry->FDENTRY_pfdnode;
if (pfdNode) {
if (PX_ERROR == API_IosFdNodeDec(&pDev->SEMC_fdNodeHeader, pfdNode, LW_NULL)) {
/* 是否成功删除节点 */
return (PX_ERROR);
}
if (LW_DEV_DEC_USE_COUNT(&pDev->SEMC_devhdr) == 0) {
if (pDev->SEMC_handle) {
API_SemaphoreCDelete(&pDev->SEMC_handle);
pDev->SEMC_handle = LW_OBJECT_HANDLE_INVALID;
}
}
}
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函数名称: __semcIoctl
** 功能描述: SEMC ioctl 操作接口
** 输 入 : pFdEntry 文件结构
** iCmd 命令
** lArg 参数
** 输 出 : NONE
** 返 回 : ERROR_CODE
*********************************************************************************************************/
static INT __semcIoctl (PLW_FD_ENTRY pFdentry, INT iCmd, PVOID plArg)
{
__PSEMC_DEV pDev = LW_NULL;
if (LW_NULL == pFdentry) {
return (PX_ERROR);
}
pDev = (__PSEMC_DEV)pFdentry->FDENTRY_pdevhdrHdr;
switch (iCmd) {
case SEMC_CMD_GET_HANDLE:
if (plArg) {
*(LW_HANDLE *)plArg = pDev->SEMC_handle;
}
break;
default:
return (PX_ERROR);
}
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函数名称: semcDrvInstall
** 功能描述: 安装 SEMC 驱动
** 输 入 : NONE
** 输 出 : NONE
** 返 回 : ERROR_CODE
*********************************************************************************************************/
INT semcDrvInstall (VOID)
{
struct file_operations fileopFileOP;
if (_G_iSemcDrvNum) { /* 主设备号是否被注册 */
return (ERROR_NONE);
}
lib_memset(&fileopFileOP, 0, sizeof(struct file_operations));
fileopFileOP.owner = THIS_MODULE;
fileopFileOP.fo_create = __semcOpen;
fileopFileOP.fo_open = __semcOpen;
fileopFileOP.fo_close = __semcClose;
fileopFileOP.fo_ioctl = __semcIoctl;
_G_iSemcDrvNum = iosDrvInstallEx2(&fileopFileOP, LW_DRV_TYPE_NEW_1);/* 注册设备驱动程序 */
if (PX_ERROR == _G_iSemcDrvNum) {
printk(KERN_ERR "[semc] DrvInstall failed.\r\n");
return (PX_ERROR);
}
DRIVER_LICENSE(_G_iSemcDrvNum, "Dual BSD/GPL->Ver 1.0");
DRIVER_AUTHOR(_G_iSemcDrvNum, "WangJingshi");
DRIVER_DESCRIPTION(_G_iSemcDrvNum, "semc driver.");
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函数名称: semcDevCreate
** 功能描述: 创建 SEMC 设备
** 输 入 : cpcName 设备名称
** ulInitCounter 信号量初值
** ulMaxCounter 信号量最大值
** ulOption 信号量选项
** 输 出 : NONE
** 返 回 : ERROR_CODE
*********************************************************************************************************/
INT semcDevCreate (CPCHAR cpcName, ULONG ulInitCounter, ULONG ulMaxCounter, ULONG ulOption)
{
if (!cpcName) {
printk(KERN_ERR "[semc] dev name invalid\n");
return (PX_ERROR);
}
/*
* 信号量配置
*/
_G_semcDev.SEMC_ulInitCounter = ulInitCounter;
_G_semcDev.SEMC_ulMaxCounter = ulMaxCounter;
_G_semcDev.SEMC_ulOption = ulOption;
/*
* 向系统添加一个设备
*/
if (ERROR_NONE != API_IosDevAddEx(&_G_semcDev.SEMC_devhdr, cpcName, _G_iSemcDrvNum, DT_CHR)) {
printk(KERN_ERR "[semc] dev add failed.\n");
_ErrorHandle(ERROR_SYSTEM_LOW_MEMORY);
return (PX_ERROR);
}
_ErrorHandle(ERROR_NONE);
return (ERROR_NONE);
}
/*********************************************************************************************************
END
*********************************************************************************************************/
Demo:
#include <stdio.h>
#include "sys/ioctl.h"
#define SEMC_CMD_GET_HANDLE _IOR('c', 1, LW_HANDLE) /* 获取信号量句柄 */
int main (int argc, char **argv)
{
int fd;
LW_HANDLE semc = LW_OBJECT_HANDLE_INVALID;
INT iError;
INT i = 0;
printf("1\n");
fd = open("/dev/semc0", O_RDWR);
if (fd < 0) {
printf("open semc dev error.\n");
return PX_ERROR;
}
printf("fd = %d\n", fd);
if (ioctl(fd, SEMC_CMD_GET_HANDLE, &semc) < 0 || semc == LW_OBJECT_HANDLE_INVALID ) {
printf("get semc handle error.\n");
return PX_ERROR;
}
printf("semc = %d", semc);
while (1) {
iError = Lw_SemaphoreC_Wait(semc, LW_OPTION_WAIT_INFINITE);
if (iError != ERROR_NONE) {
printf("get semc handle error.iError = %d errno = %d\n", iError, errno);
return PX_ERROR;
}
printf("semc wait... %d\n", i++);
sleep(1);
printf("semc post\n");
Lw_SemaphoreC_Post(semc);
sleep(1);
}
close(fd);
return (0);
}