不同容器(ECS)间使用信号量同步方案

不同容器(ECS)间使用信号量同步方案

1、概述
      在 SylixOS 容器版本中由于容器间存在命名空间隔离的问题因此无法直接使用信号量进行同步操作,这在某些场合下可能无法完成实际需求,如共享内存通信时。本文介绍一种在容器间实现信号量同步功能的解决方案。

2、解决方案
      此解决方案思路是在 SylixOS 标准信号量的基础上封装一层字符设备,在内核层创建信号量并提供相关接口使容器内的 APP 可以通过字符设备接口获取内核信号量句柄,再通过标准信号量 API 进行操作。实现不同容器间的 APP 同步操作。基本框架如下图所示。


3、代码
字符设备:
  1. /*********************************************************************************************************
    **
    **                                    中国软件开源组织
    **
    **                                   嵌入式实时操作系统
    **
    **                                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:
  1. #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 个优先级; 支持虚拟进程; ...