Disable build of libraries/tests that rely on the RTLD_NEXT GNU extension
[lttng-ust.git] / libringbuffer / shm.c
CommitLineData
1d498196
MD
1/*
2 * libringbuffer/shm.c
3 *
e92f3e28 4 * Copyright (C) 2005-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
1d498196 5 *
e92f3e28
MD
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; only
9 * version 2.1 of the License.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1d498196
MD
19 */
20
21#include "shm.h"
22#include <unistd.h>
23#include <fcntl.h>
24#include <sys/mman.h>
25#include <sys/stat.h> /* For mode constants */
26#include <fcntl.h> /* For O_* constants */
27#include <assert.h>
8da6cd6d
MD
28#include <stdio.h>
29#include <signal.h>
30#include <dirent.h>
4318ae1b 31#include <lttng/align.h>
35897f8b 32#include <helper.h>
96e80018 33#include <limits.h>
ac64486f
MD
34#include <helper.h>
35
36/*
37 * Ensure we have the required amount of space available by writing 0
38 * into the entire buffer. Not doing so can trigger SIGBUS when going
39 * beyond the available shm space.
40 */
41static
42int zero_file(int fd, size_t len)
43{
44 ssize_t retlen;
45 size_t written = 0;
46 char *zeropage;
47 long pagelen;
48 int ret;
49
50 pagelen = sysconf(_SC_PAGESIZE);
51 if (pagelen < 0)
52 return (int) pagelen;
53 zeropage = calloc(pagelen, 1);
54 if (!zeropage)
55 return -ENOMEM;
56
57 while (len > written) {
58 do {
59 retlen = write(fd, zeropage,
60 min_t(size_t, pagelen, len - written));
61 } while (retlen == -1UL && errno == EINTR);
62 if (retlen < 0) {
63 ret = (int) retlen;
64 goto error;
65 }
66 written += retlen;
67 }
68 ret = 0;
69error:
70 free(zeropage);
71 return ret;
72}
1d498196
MD
73
74struct shm_object_table *shm_object_table_create(size_t max_nb_obj)
75{
76 struct shm_object_table *table;
77
78 table = zmalloc(sizeof(struct shm_object_table) +
79 max_nb_obj * sizeof(table->objects[0]));
80 table->size = max_nb_obj;
81 return table;
82}
83
84struct shm_object *shm_object_table_append(struct shm_object_table *table,
85 size_t memory_map_size)
86{
5a61337d 87 int shmfd, waitfd[2], ret, i, sigblocked = 0;
1d498196
MD
88 struct shm_object *obj;
89 char *memory_map;
8da6cd6d
MD
90 char tmp_name[NAME_MAX] = "ust-shm-tmp-XXXXXX";
91 sigset_t all_sigs, orig_sigs;
1d498196
MD
92
93 if (table->allocated_len >= table->size)
94 return NULL;
7a9c21bd 95 obj = &table->objects[table->allocated_len];
1d498196
MD
96
97 /* wait_fd: create pipe */
98 ret = pipe(waitfd);
99 if (ret < 0) {
100 PERROR("pipe");
101 goto error_pipe;
102 }
103 for (i = 0; i < 2; i++) {
104 ret = fcntl(waitfd[i], F_SETFD, FD_CLOEXEC);
105 if (ret < 0) {
106 PERROR("fcntl");
107 goto error_fcntl;
108 }
109 }
5d61a504
MD
110 /* The write end of the pipe needs to be non-blocking */
111 ret = fcntl(waitfd[1], F_SETFL, O_NONBLOCK);
112 if (ret < 0) {
113 PERROR("fcntl");
114 goto error_fcntl;
115 }
7a9c21bd 116 memcpy(obj->wait_fd, waitfd, sizeof(waitfd));
1d498196
MD
117
118 /* shm_fd: create shm */
119
8da6cd6d
MD
120 /*
121 * Theoretically, we could leak a shm if the application crashes
122 * between open and unlink. Disable signals on this thread for
123 * increased safety against this scenario.
124 */
125 sigfillset(&all_sigs);
126 ret = pthread_sigmask(SIG_BLOCK, &all_sigs, &orig_sigs);
127 if (ret == -1) {
128 PERROR("pthread_sigmask");
129 goto error_pthread_sigmask;
130 }
5a61337d 131 sigblocked = 1;
8da6cd6d 132
1d498196
MD
133 /*
134 * Allocate shm, and immediately unlink its shm oject, keeping
135 * only the file descriptor as a reference to the object. If it
136 * already exists (caused by short race window during which the
137 * global object exists in a concurrent shm_open), simply retry.
138 * We specifically do _not_ use the / at the beginning of the
139 * pathname so that some OS implementations can keep it local to
140 * the process (POSIX leaves this implementation-defined).
141 */
142 do {
8da6cd6d
MD
143 /*
144 * Using mktemp filename with O_CREAT | O_EXCL open
145 * flags.
146 */
147 mktemp(tmp_name);
148 if (tmp_name[0] == '\0') {
149 PERROR("mktemp");
150 goto error_shm_open;
a8803897 151 }
8da6cd6d 152 shmfd = shm_open(tmp_name,
1d498196 153 O_CREAT | O_EXCL | O_RDWR, 0700);
8da6cd6d 154 } while (shmfd < 0 && (errno == EEXIST || errno == EACCES));
1d498196
MD
155 if (shmfd < 0) {
156 PERROR("shm_open");
157 goto error_shm_open;
158 }
8da6cd6d 159 ret = shm_unlink(tmp_name);
a8803897
MD
160 if (ret < 0 && errno != ENOENT) {
161 PERROR("shm_unlink");
162 goto error_shm_release;
163 }
5a61337d 164 sigblocked = 0;
8da6cd6d
MD
165 ret = pthread_sigmask(SIG_SETMASK, &orig_sigs, NULL);
166 if (ret == -1) {
167 PERROR("pthread_sigmask");
5a61337d 168 goto error_sigmask_release;
8da6cd6d 169 }
ac64486f
MD
170 ret = zero_file(shmfd, memory_map_size);
171 if (ret) {
172 PERROR("zero_file");
173 goto error_zero_file;
174 }
1d498196
MD
175 ret = ftruncate(shmfd, memory_map_size);
176 if (ret) {
177 PERROR("ftruncate");
178 goto error_ftruncate;
179 }
180 obj->shm_fd = shmfd;
181
182 /* memory_map: mmap */
183 memory_map = mmap(NULL, memory_map_size, PROT_READ | PROT_WRITE,
184 MAP_SHARED, shmfd, 0);
185 if (memory_map == MAP_FAILED) {
186 PERROR("mmap");
187 goto error_mmap;
188 }
189 obj->memory_map = memory_map;
190 obj->memory_map_size = memory_map_size;
191 obj->allocated_len = 0;
dc613eb9 192 obj->index = table->allocated_len++;
7a9c21bd 193
1d498196
MD
194 return obj;
195
196error_mmap:
197error_ftruncate:
a8803897 198error_shm_release:
ac64486f 199error_zero_file:
5a61337d 200error_sigmask_release:
1d498196
MD
201 ret = close(shmfd);
202 if (ret) {
203 PERROR("close");
204 assert(0);
205 }
206error_shm_open:
5a61337d
MD
207 if (sigblocked) {
208 ret = pthread_sigmask(SIG_SETMASK, &orig_sigs, NULL);
209 if (ret == -1) {
210 PERROR("pthread_sigmask");
211 }
212 }
8da6cd6d 213error_pthread_sigmask:
1d498196
MD
214error_fcntl:
215 for (i = 0; i < 2; i++) {
216 ret = close(waitfd[i]);
217 if (ret) {
218 PERROR("close");
219 assert(0);
220 }
221 }
222error_pipe:
1d498196
MD
223 return NULL;
224
225}
226
193183fb
MD
227struct shm_object *shm_object_table_append_shadow(struct shm_object_table *table,
228 int shm_fd, int wait_fd, size_t memory_map_size)
229{
230 struct shm_object *obj;
231 char *memory_map;
232
233 if (table->allocated_len >= table->size)
234 return NULL;
235 obj = &table->objects[table->allocated_len];
236
237 /* wait_fd: set read end of the pipe. */
238 obj->wait_fd[0] = wait_fd;
239 obj->wait_fd[1] = -1; /* write end is unset. */
240 obj->shm_fd = shm_fd;
241
242 /* memory_map: mmap */
243 memory_map = mmap(NULL, memory_map_size, PROT_READ | PROT_WRITE,
244 MAP_SHARED, shm_fd, 0);
245 if (memory_map == MAP_FAILED) {
246 PERROR("mmap");
247 goto error_mmap;
248 }
249 obj->memory_map = memory_map;
250 obj->memory_map_size = memory_map_size;
251 obj->allocated_len = memory_map_size;
252 obj->index = table->allocated_len++;
253
254 return obj;
255
256error_mmap:
257 return NULL;
258}
259
1d498196
MD
260static
261void shmp_object_destroy(struct shm_object *obj)
262{
263 int ret, i;
264
7a784989
MD
265 if (!obj->is_shadow) {
266 ret = munmap(obj->memory_map, obj->memory_map_size);
267 if (ret) {
268 PERROR("umnmap");
269 assert(0);
270 }
271 }
ef9ff354
MD
272 if (obj->shm_fd >= 0) {
273 ret = close(obj->shm_fd);
274 if (ret) {
275 PERROR("close");
276 assert(0);
277 }
1d498196
MD
278 }
279 for (i = 0; i < 2; i++) {
824f40b8
MD
280 if (obj->wait_fd[i] < 0)
281 continue;
1d498196
MD
282 ret = close(obj->wait_fd[i]);
283 if (ret) {
284 PERROR("close");
285 assert(0);
286 }
287 }
288}
289
290void shm_object_table_destroy(struct shm_object_table *table)
291{
292 int i;
293
294 for (i = 0; i < table->allocated_len; i++)
295 shmp_object_destroy(&table->objects[i]);
296 free(table);
297}
298
299/*
300 * zalloc_shm - allocate memory within a shm object.
301 *
302 * Shared memory is already zeroed by shmget.
303 * *NOT* multithread-safe (should be protected by mutex).
304 * Returns a -1, -1 tuple on error.
305 */
306struct shm_ref zalloc_shm(struct shm_object *obj, size_t len)
307{
308 struct shm_ref ref;
309 struct shm_ref shm_ref_error = { -1, -1 };
310
311 if (obj->memory_map_size - obj->allocated_len < len)
312 return shm_ref_error;
313 ref.index = obj->index;
314 ref.offset = obj->allocated_len;
315 obj->allocated_len += len;
316 return ref;
317}
318
319void align_shm(struct shm_object *obj, size_t align)
320{
321 size_t offset_len = offset_align(obj->allocated_len, align);
322 obj->allocated_len += offset_len;
323}
This page took 0.036748 seconds and 4 git commands to generate.