Add lttng_ust_ prefix before objd_unref
[lttng-ust.git] / libringbuffer / shm.c
1 /*
2 * libringbuffer/shm.c
3 *
4 * Copyright 2011 (c) - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 *
6 * Dual LGPL v2.1/GPL v2 license.
7 */
8
9 #include "shm.h"
10 #include <unistd.h>
11 #include <fcntl.h>
12 #include <sys/mman.h>
13 #include <sys/stat.h> /* For mode constants */
14 #include <fcntl.h> /* For O_* constants */
15 #include <assert.h>
16 #include <stdio.h>
17 #include <signal.h>
18 #include <dirent.h>
19 #include <ust/align.h>
20
21 struct shm_object_table *shm_object_table_create(size_t max_nb_obj)
22 {
23 struct shm_object_table *table;
24
25 table = zmalloc(sizeof(struct shm_object_table) +
26 max_nb_obj * sizeof(table->objects[0]));
27 table->size = max_nb_obj;
28 return table;
29 }
30
31 struct shm_object *shm_object_table_append(struct shm_object_table *table,
32 size_t memory_map_size)
33 {
34 int shmfd, waitfd[2], ret, i, sigblocked = 0;
35 struct shm_object *obj;
36 char *memory_map;
37 char tmp_name[NAME_MAX] = "ust-shm-tmp-XXXXXX";
38 sigset_t all_sigs, orig_sigs;
39
40 if (table->allocated_len >= table->size)
41 return NULL;
42 obj = &table->objects[table->allocated_len];
43
44 /* wait_fd: create pipe */
45 ret = pipe(waitfd);
46 if (ret < 0) {
47 PERROR("pipe");
48 goto error_pipe;
49 }
50 for (i = 0; i < 2; i++) {
51 ret = fcntl(waitfd[i], F_SETFD, FD_CLOEXEC);
52 if (ret < 0) {
53 PERROR("fcntl");
54 goto error_fcntl;
55 }
56 }
57 /* The write end of the pipe needs to be non-blocking */
58 ret = fcntl(waitfd[1], F_SETFL, O_NONBLOCK);
59 if (ret < 0) {
60 PERROR("fcntl");
61 goto error_fcntl;
62 }
63 memcpy(obj->wait_fd, waitfd, sizeof(waitfd));
64
65 /* shm_fd: create shm */
66
67 /*
68 * Theoretically, we could leak a shm if the application crashes
69 * between open and unlink. Disable signals on this thread for
70 * increased safety against this scenario.
71 */
72 sigfillset(&all_sigs);
73 ret = pthread_sigmask(SIG_BLOCK, &all_sigs, &orig_sigs);
74 if (ret == -1) {
75 PERROR("pthread_sigmask");
76 goto error_pthread_sigmask;
77 }
78 sigblocked = 1;
79
80 /*
81 * Allocate shm, and immediately unlink its shm oject, keeping
82 * only the file descriptor as a reference to the object. If it
83 * already exists (caused by short race window during which the
84 * global object exists in a concurrent shm_open), simply retry.
85 * We specifically do _not_ use the / at the beginning of the
86 * pathname so that some OS implementations can keep it local to
87 * the process (POSIX leaves this implementation-defined).
88 */
89 do {
90 /*
91 * Using mktemp filename with O_CREAT | O_EXCL open
92 * flags.
93 */
94 mktemp(tmp_name);
95 if (tmp_name[0] == '\0') {
96 PERROR("mktemp");
97 goto error_shm_open;
98 }
99 shmfd = shm_open(tmp_name,
100 O_CREAT | O_EXCL | O_RDWR, 0700);
101 } while (shmfd < 0 && (errno == EEXIST || errno == EACCES));
102 if (shmfd < 0) {
103 PERROR("shm_open");
104 goto error_shm_open;
105 }
106 ret = shm_unlink(tmp_name);
107 if (ret < 0 && errno != ENOENT) {
108 PERROR("shm_unlink");
109 goto error_shm_release;
110 }
111 sigblocked = 0;
112 ret = pthread_sigmask(SIG_SETMASK, &orig_sigs, NULL);
113 if (ret == -1) {
114 PERROR("pthread_sigmask");
115 goto error_sigmask_release;
116 }
117 ret = ftruncate(shmfd, memory_map_size);
118 if (ret) {
119 PERROR("ftruncate");
120 goto error_ftruncate;
121 }
122 obj->shm_fd = shmfd;
123
124 /* memory_map: mmap */
125 memory_map = mmap(NULL, memory_map_size, PROT_READ | PROT_WRITE,
126 MAP_SHARED, shmfd, 0);
127 if (memory_map == MAP_FAILED) {
128 PERROR("mmap");
129 goto error_mmap;
130 }
131 obj->memory_map = memory_map;
132 obj->memory_map_size = memory_map_size;
133 obj->allocated_len = 0;
134 obj->index = table->allocated_len++;
135
136 return obj;
137
138 error_mmap:
139 error_ftruncate:
140 error_shm_release:
141 error_sigmask_release:
142 ret = close(shmfd);
143 if (ret) {
144 PERROR("close");
145 assert(0);
146 }
147 error_shm_open:
148 if (sigblocked) {
149 ret = pthread_sigmask(SIG_SETMASK, &orig_sigs, NULL);
150 if (ret == -1) {
151 PERROR("pthread_sigmask");
152 }
153 }
154 error_pthread_sigmask:
155 error_fcntl:
156 for (i = 0; i < 2; i++) {
157 ret = close(waitfd[i]);
158 if (ret) {
159 PERROR("close");
160 assert(0);
161 }
162 }
163 error_pipe:
164 return NULL;
165
166 }
167
168 struct shm_object *shm_object_table_append_shadow(struct shm_object_table *table,
169 int shm_fd, int wait_fd, size_t memory_map_size)
170 {
171 struct shm_object *obj;
172 char *memory_map;
173
174 if (table->allocated_len >= table->size)
175 return NULL;
176 obj = &table->objects[table->allocated_len];
177
178 /* wait_fd: set read end of the pipe. */
179 obj->wait_fd[0] = wait_fd;
180 obj->wait_fd[1] = -1; /* write end is unset. */
181 obj->shm_fd = shm_fd;
182
183 /* memory_map: mmap */
184 memory_map = mmap(NULL, memory_map_size, PROT_READ | PROT_WRITE,
185 MAP_SHARED, shm_fd, 0);
186 if (memory_map == MAP_FAILED) {
187 PERROR("mmap");
188 goto error_mmap;
189 }
190 obj->memory_map = memory_map;
191 obj->memory_map_size = memory_map_size;
192 obj->allocated_len = memory_map_size;
193 obj->index = table->allocated_len++;
194
195 return obj;
196
197 error_mmap:
198 return NULL;
199 }
200
201 static
202 void shmp_object_destroy(struct shm_object *obj)
203 {
204 int ret, i;
205
206 ret = munmap(obj->memory_map, obj->memory_map_size);
207 if (ret) {
208 PERROR("umnmap");
209 assert(0);
210 }
211 ret = close(obj->shm_fd);
212 if (ret) {
213 PERROR("close");
214 assert(0);
215 }
216 for (i = 0; i < 2; i++) {
217 if (obj->wait_fd[i] < 0)
218 continue;
219 ret = close(obj->wait_fd[i]);
220 if (ret) {
221 PERROR("close");
222 assert(0);
223 }
224 }
225 }
226
227 void shm_object_table_destroy(struct shm_object_table *table)
228 {
229 int i;
230
231 for (i = 0; i < table->allocated_len; i++)
232 shmp_object_destroy(&table->objects[i]);
233 free(table);
234 }
235
236 /*
237 * zalloc_shm - allocate memory within a shm object.
238 *
239 * Shared memory is already zeroed by shmget.
240 * *NOT* multithread-safe (should be protected by mutex).
241 * Returns a -1, -1 tuple on error.
242 */
243 struct shm_ref zalloc_shm(struct shm_object *obj, size_t len)
244 {
245 struct shm_ref ref;
246 struct shm_ref shm_ref_error = { -1, -1 };
247
248 if (obj->memory_map_size - obj->allocated_len < len)
249 return shm_ref_error;
250 ref.index = obj->index;
251 ref.offset = obj->allocated_len;
252 obj->allocated_len += len;
253 return ref;
254 }
255
256 void align_shm(struct shm_object *obj, size_t align)
257 {
258 size_t offset_len = offset_align(obj->allocated_len, align);
259 obj->allocated_len += offset_len;
260 }
This page took 0.034268 seconds and 4 git commands to generate.