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);
}
Related Articles
SylixOS 容器版本(ECS)添加 syscall 方式
1、配置 IDE 环境 这里配置的是 3.9.11 版本的 IDE,3.9.11 以后的版本中可能会集成此功能。 将下面两个插件拷贝到目录 ACOINFO\RealEvo\ide\plugins com.sylixos.realevo.devicemgr_3.0.0.jar com.sylixos.realevo.container_3.0.0.jar 将 syscallgen.rar 解压得到的 syscallgen 目录拷贝到 ACOINFO\RealEvo\tools 目录下,重启 IDE ...
RealEvo-IDE 6.x.x升级指南
RealEvo-IDE 6.x.x升级指南 RealEvo-IDE 6.x.x 兼容3.9.10及后续版本工程,可升级版本包括3.9.10、3.9.11、4.0.0、5.0.x; 兼容性说明: 1、多 arch 工程只能为6.0版本新建工程,旧版本导入的 base 工程不可设置多 arch。 2、旧版本 app 工程导入后,若依赖多 arch base ,则不能修改依赖 arch 选项,默认全选。 3、旧版本bsp工程导入后不可直接依赖多 arch base,如果使用多arch ...
RealEvo-IDE 5.x.x升级指南
RealEvo-IDE 5.x.x升级指南 RealEvo-IDE 5.x.x 兼容3.9.10及后续版本工程,可升级版本包括3.9.10、3.9.11、4.0.0; 升级过程如下: 如果安装了补丁(如浮动license、ECS、LTS等补丁),建议先卸载补丁,否则在卸载老版本 RealEvo-IDE 后可能会出现无效的快捷方式。 卸载老版本 RealEvo-IDE; 安装 RealEvo-IDE 5.0.0; 安装新版本补丁。注:老版本补丁和 RealEvo-IDE 5.0.0 ...
SylixOS 功能介绍及版本差异
SylixOS功能介绍及版本差异 SylixOS 标准版 SylixOS 标准版是 SylixOS 的基础版本,具备如下功能: 兼容 IEEE 1003(ISO/IEC 9945)操作系统接口规范; 兼容 POSIX 1003.1b(ISO/IEC 9945-1)实时编程标准; 支持国军标 GJB7714-2012 操作系统接口规范; 优秀的实时性能(任务调度与切换算法时间复杂度为 O(1)); 支持无限多任务; 抢占式调度支持 256 个优先级; 支持虚拟进程; ...