0%

共享内存文件的应用-sysrepo笔记(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。根据使用的场景调用。

示例代码

https://github.com/fishmwei/blog_code/tree/master/sysrepo/map_test.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#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,沟通交流。