上一篇讲了sysrepo使用管道做事件通知,至于处理数据则通过共享内存文件来保存。sysrepo号称是共享内存型的数据库,主要就是由于其数据都是通过共享内存文件保存的。
创建的共享内存文件,默认都是在/dev/shm目录下,正常情况下,系统会以/dev/shm目录为根路径组织文件的路径,然后创建。
具体的操作流程就是:
- 打开文件 使用shm_open打开一个文件
- 设置初始大小 使用ftruncate设置文件的大小为要写的内容的大小
- 映射到内存 调用mmap映射到内存中,获取地址
- 写数据 强制转换地址类型,然后设置数据
- 追加数据 把之前的地址 munmap掉。根据计算的大小重新mmap, 然后获取到新地址后,计算偏移 写入内容。
- 读数据 根据地址,计算偏移后 使用指针强转类型,直接读取数据
- 清理共享内存 使用munmap卸载映射的关系,close最初使用shm_open获得的fd
在sysrepo中,封装了几个函数, open_map, remap, clean_map。根据使用的场景调用。
示例代码
#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,沟通交流。