共享内存文件的应用-sysrepo笔记(2)

742 阅读2分钟

上一篇讲了sysrepo使用管道做事件通知,至于处理数据则通过共享内存文件来保存。sysrepo号称是共享内存型的数据库,主要就是由于其数据都是通过共享内存文件保存的。

创建的共享内存文件,默认都是在/dev/shm目录下,正常情况下,系统会以/dev/shm目录为根路径组织文件的路径,然后创建。

具体的操作流程就是:

  1. 打开文件 使用shm_open打开一个文件
  2. 设置初始大小 使用ftruncate设置文件的大小为要写的内容的大小
  3. 映射到内存 调用mmap映射到内存中,获取地址
  4. 写数据 强制转换地址类型,然后设置数据
  5. 追加数据 把之前的地址 munmap掉。根据计算的大小重新mmap, 然后获取到新地址后,计算偏移 写入内容。
  6. 读数据 根据地址,计算偏移后 使用指针强转类型,直接读取数据
  7. 清理共享内存 使用munmap卸载映射的关系,close最初使用shm_open获得的fd

sysrepo中,封装了几个函数, open_map, remap, clean_map。根据使用的场景调用。

示例代码

github.com/fishmwei/bl…

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/stat.h>


typedef struct {
    int request_id;
    int event;
    unsigned int pripority;
    unsigned int count;
} content_t;


typedef struct {
    int request_id;
    int event;
    unsigned int pripority;
    unsigned int count;
    char data[4];
} excontent_t;


typedef struct {
    int fd;
    size_t size;
    void *addr;
} shm_t;

int file_get_size(int fd, size_t *size) 
{
    struct stat st;
    if (fstat(fd, &st) == -1) {
        printf("fstat error\r\n");
        return -1;
    }

    *size = st.st_size;
    return 0;
}

int get_file_path(const char *name, char **path)
{
    int ret = asprintf(path, "/sub2_%s", name);
    if (ret == -1) {
        return -1;
    }

    return 0;
}


int remap(shm_t *shm, size_t new_shm_size)
{
    size_t file_size;
    if (!new_shm_size && (file_get_size(shm->fd, &file_size)))
    {
        return -1;
    }

    // size not changed.
    if ((!new_shm_size && (new_shm_size == file_size)) || (new_shm_size &&new_shm_size == file_size)) {
        return 0;
    }

    if (shm->addr) {
        munmap(shm->addr, shm->size);
        printf("munmap\r\n");
    }

    // resize file 
    if (new_shm_size && (ftruncate(shm->fd, new_shm_size) == -1)) {
        shm->addr = NULL;
        printf("ftruncate error\r\n");
        return -1;
    }

    shm->size = new_shm_size ? new_shm_size : file_size;

    shm->addr = mmap(NULL, shm->size, PROT_READ | PROT_WRITE, MAP_SHARED, shm->fd, 0);
    if (shm->addr == MAP_FAILED) {
        shm->addr = NULL;
        printf("mmap error\r\n");
        return -1;
    }
    printf("get addr %p\r\n", shm->addr);
    return 0;
}

void clear_map(shm_t *shm)
{
    if (shm->addr)
    {
        munmap(shm->addr, shm->size);
        shm->addr = NULL;
    }

    if (shm->fd > -1) {
        close(shm->fd);
        shm->fd = -1;
    }
    shm->size =  0;
}

int open_map(const char *name, shm_t *shm, size_t struct_size)
{
    int created = 1;
    char *path;

    if (get_file_path(name, &path)) {
        printf("get_file_path error\r\n");
        return -1;
    }

    mode_t um = umask(0);
    shm->fd = shm_open(path, O_RDWR | O_CREAT | O_EXCL, 00666);
    umask(um);
    if ((shm->fd == -1) && (errno == EEXIST)) {
        created = 0;
        shm->fd = shm_open(path, O_RDWR, 00666);
        printf("file exist %s, open agine\r\n", path);
    }
    free(path);
    if (shm->fd == -1) {
        printf("open map file error\r\n");
        return -1;
    }

    if (created) {
        // remap struct_size
        if (remap(shm, struct_size)) {
            return -1;
        }

    } else {
        // remap size 0 
        if (remap(shm, 0)) {
            return -1;
        }
    }

    return 0;
}

void main()
{
    shm_t first, second;
    size_t struct_size = sizeof(content_t);
    memset(&first, 0, sizeof(shm_t));
    memset(&second, 0, sizeof(shm_t));
    
    int ret = open_map("hello", &first, struct_size);
    if (ret < 0) {
        return;
    }

    content_t *pData = first.addr;
    pData->count = 100;

    ret = open_map("hello", &second, struct_size);
    if (ret < 0) {
        clear_map(&first);
        return;
    }

    pData = second.addr;
    printf("count is %d\r\n", pData->count);

    ret = remap(&second, sizeof(excontent_t));
    if (0 == ret) {
        excontent_t *pex = second.addr;
        printf("ext count is %d\n", pex->count);
    }

    sleep(10);
    clear_map(&first);
    clear_map(&second);
}



/*
gcc map_test.c -o map -lrt


strace ./map 

shm_open will create file in /dev/shm 

*/

行动,才不会被动!

欢迎关注个人公众号 微信 -> 搜索 -> fishmwei,沟通交流。