Fix: Java agent protocol network endianness consistency
[lttng-ust.git] / libringbuffer / shm.c
... / ...
CommitLineData
1/*
2 * libringbuffer/shm.c
3 *
4 * Copyright (C) 2005-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 *
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
19 */
20
21#include "shm.h"
22#include <unistd.h>
23#include <fcntl.h>
24#include <sys/mman.h>
25#include <sys/types.h>
26#include <sys/stat.h> /* For mode constants */
27#include <fcntl.h> /* For O_* constants */
28#include <assert.h>
29#include <stdio.h>
30#include <signal.h>
31#include <dirent.h>
32#include <lttng/align.h>
33#include <limits.h>
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}
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 if (!table)
81 return NULL;
82 table->size = max_nb_obj;
83 return table;
84}
85
86static
87struct shm_object *_shm_object_table_alloc_shm(struct shm_object_table *table,
88 size_t memory_map_size,
89 int stream_fd)
90{
91 int shmfd, waitfd[2], ret, i;
92 struct shm_object *obj;
93 char *memory_map;
94
95 if (stream_fd < 0)
96 return NULL;
97 if (table->allocated_len >= table->size)
98 return NULL;
99 obj = &table->objects[table->allocated_len];
100
101 /* wait_fd: create pipe */
102 ret = pipe(waitfd);
103 if (ret < 0) {
104 PERROR("pipe");
105 goto error_pipe;
106 }
107 for (i = 0; i < 2; i++) {
108 ret = fcntl(waitfd[i], F_SETFD, FD_CLOEXEC);
109 if (ret < 0) {
110 PERROR("fcntl");
111 goto error_fcntl;
112 }
113 }
114 /* The write end of the pipe needs to be non-blocking */
115 ret = fcntl(waitfd[1], F_SETFL, O_NONBLOCK);
116 if (ret < 0) {
117 PERROR("fcntl");
118 goto error_fcntl;
119 }
120 memcpy(obj->wait_fd, waitfd, sizeof(waitfd));
121
122 /* create shm */
123
124 shmfd = stream_fd;
125 ret = zero_file(shmfd, memory_map_size);
126 if (ret) {
127 PERROR("zero_file");
128 goto error_zero_file;
129 }
130 ret = ftruncate(shmfd, memory_map_size);
131 if (ret) {
132 PERROR("ftruncate");
133 goto error_ftruncate;
134 }
135 obj->shm_fd_ownership = 0;
136 obj->shm_fd = shmfd;
137
138 /* memory_map: mmap */
139 memory_map = mmap(NULL, memory_map_size, PROT_READ | PROT_WRITE,
140 MAP_SHARED, shmfd, 0);
141 if (memory_map == MAP_FAILED) {
142 PERROR("mmap");
143 goto error_mmap;
144 }
145 obj->type = SHM_OBJECT_SHM;
146 obj->memory_map = memory_map;
147 obj->memory_map_size = memory_map_size;
148 obj->allocated_len = 0;
149 obj->index = table->allocated_len++;
150
151 return obj;
152
153error_mmap:
154error_ftruncate:
155error_zero_file:
156error_fcntl:
157 for (i = 0; i < 2; i++) {
158 ret = close(waitfd[i]);
159 if (ret) {
160 PERROR("close");
161 assert(0);
162 }
163 }
164error_pipe:
165 return NULL;
166}
167
168static
169struct shm_object *_shm_object_table_alloc_mem(struct shm_object_table *table,
170 size_t memory_map_size)
171{
172 struct shm_object *obj;
173 void *memory_map;
174 int waitfd[2], i, ret;
175
176 if (table->allocated_len >= table->size)
177 return NULL;
178 obj = &table->objects[table->allocated_len];
179
180 memory_map = zmalloc(memory_map_size);
181 if (!memory_map)
182 goto alloc_error;
183
184 /* wait_fd: create pipe */
185 ret = pipe(waitfd);
186 if (ret < 0) {
187 PERROR("pipe");
188 goto error_pipe;
189 }
190 for (i = 0; i < 2; i++) {
191 ret = fcntl(waitfd[i], F_SETFD, FD_CLOEXEC);
192 if (ret < 0) {
193 PERROR("fcntl");
194 goto error_fcntl;
195 }
196 }
197 /* The write end of the pipe needs to be non-blocking */
198 ret = fcntl(waitfd[1], F_SETFL, O_NONBLOCK);
199 if (ret < 0) {
200 PERROR("fcntl");
201 goto error_fcntl;
202 }
203 memcpy(obj->wait_fd, waitfd, sizeof(waitfd));
204
205 /* no shm_fd */
206 obj->shm_fd = -1;
207 obj->shm_fd_ownership = 0;
208
209 obj->type = SHM_OBJECT_MEM;
210 obj->memory_map = memory_map;
211 obj->memory_map_size = memory_map_size;
212 obj->allocated_len = 0;
213 obj->index = table->allocated_len++;
214
215 return obj;
216
217error_fcntl:
218 for (i = 0; i < 2; i++) {
219 ret = close(waitfd[i]);
220 if (ret) {
221 PERROR("close");
222 assert(0);
223 }
224 }
225error_pipe:
226 free(memory_map);
227alloc_error:
228 return NULL;
229}
230
231struct shm_object *shm_object_table_alloc(struct shm_object_table *table,
232 size_t memory_map_size,
233 enum shm_object_type type,
234 int stream_fd)
235{
236 switch (type) {
237 case SHM_OBJECT_SHM:
238 return _shm_object_table_alloc_shm(table, memory_map_size,
239 stream_fd);
240 case SHM_OBJECT_MEM:
241 return _shm_object_table_alloc_mem(table, memory_map_size);
242 default:
243 assert(0);
244 }
245 return NULL;
246}
247
248struct shm_object *shm_object_table_append_shm(struct shm_object_table *table,
249 int shm_fd, int wakeup_fd, uint32_t stream_nr,
250 size_t memory_map_size)
251{
252 struct shm_object *obj;
253 char *memory_map;
254 int ret;
255
256 if (table->allocated_len >= table->size)
257 return NULL;
258 /* streams _must_ be received in sequential order, else fail. */
259 if (stream_nr + 1 != table->allocated_len)
260 return NULL;
261
262 obj = &table->objects[table->allocated_len];
263
264 /* wait_fd: set write end of the pipe. */
265 obj->wait_fd[0] = -1; /* read end is unset */
266 obj->wait_fd[1] = wakeup_fd;
267 obj->shm_fd = shm_fd;
268 obj->shm_fd_ownership = 1;
269
270 ret = fcntl(obj->wait_fd[1], F_SETFD, FD_CLOEXEC);
271 if (ret < 0) {
272 PERROR("fcntl");
273 goto error_fcntl;
274 }
275 /* The write end of the pipe needs to be non-blocking */
276 ret = fcntl(obj->wait_fd[1], F_SETFL, O_NONBLOCK);
277 if (ret < 0) {
278 PERROR("fcntl");
279 goto error_fcntl;
280 }
281
282 /* memory_map: mmap */
283 memory_map = mmap(NULL, memory_map_size, PROT_READ | PROT_WRITE,
284 MAP_SHARED, shm_fd, 0);
285 if (memory_map == MAP_FAILED) {
286 PERROR("mmap");
287 goto error_mmap;
288 }
289 obj->type = SHM_OBJECT_SHM;
290 obj->memory_map = memory_map;
291 obj->memory_map_size = memory_map_size;
292 obj->allocated_len = memory_map_size;
293 obj->index = table->allocated_len++;
294
295 return obj;
296
297error_fcntl:
298error_mmap:
299 return NULL;
300}
301
302/*
303 * Passing ownership of mem to object.
304 */
305struct shm_object *shm_object_table_append_mem(struct shm_object_table *table,
306 void *mem, size_t memory_map_size, int wakeup_fd)
307{
308 struct shm_object *obj;
309 int ret;
310
311 if (table->allocated_len >= table->size)
312 return NULL;
313 obj = &table->objects[table->allocated_len];
314
315 obj->wait_fd[0] = -1; /* read end is unset */
316 obj->wait_fd[1] = wakeup_fd;
317 obj->shm_fd = -1;
318 obj->shm_fd_ownership = 0;
319
320 ret = fcntl(obj->wait_fd[1], F_SETFD, FD_CLOEXEC);
321 if (ret < 0) {
322 PERROR("fcntl");
323 goto error_fcntl;
324 }
325 /* The write end of the pipe needs to be non-blocking */
326 ret = fcntl(obj->wait_fd[1], F_SETFL, O_NONBLOCK);
327 if (ret < 0) {
328 PERROR("fcntl");
329 goto error_fcntl;
330 }
331
332 obj->type = SHM_OBJECT_MEM;
333 obj->memory_map = mem;
334 obj->memory_map_size = memory_map_size;
335 obj->allocated_len = memory_map_size;
336 obj->index = table->allocated_len++;
337
338 return obj;
339
340error_fcntl:
341 return NULL;
342}
343
344static
345void shmp_object_destroy(struct shm_object *obj)
346{
347 switch (obj->type) {
348 case SHM_OBJECT_SHM:
349 {
350 int ret, i;
351
352 ret = munmap(obj->memory_map, obj->memory_map_size);
353 if (ret) {
354 PERROR("umnmap");
355 assert(0);
356 }
357 if (obj->shm_fd_ownership) {
358 ret = close(obj->shm_fd);
359 if (ret) {
360 PERROR("close");
361 assert(0);
362 }
363 }
364 for (i = 0; i < 2; i++) {
365 if (obj->wait_fd[i] < 0)
366 continue;
367 ret = close(obj->wait_fd[i]);
368 if (ret) {
369 PERROR("close");
370 assert(0);
371 }
372 }
373 break;
374 }
375 case SHM_OBJECT_MEM:
376 {
377 int ret, i;
378
379 for (i = 0; i < 2; i++) {
380 if (obj->wait_fd[i] < 0)
381 continue;
382 ret = close(obj->wait_fd[i]);
383 if (ret) {
384 PERROR("close");
385 assert(0);
386 }
387 }
388 free(obj->memory_map);
389 break;
390 }
391 default:
392 assert(0);
393 }
394}
395
396void shm_object_table_destroy(struct shm_object_table *table)
397{
398 int i;
399
400 for (i = 0; i < table->allocated_len; i++)
401 shmp_object_destroy(&table->objects[i]);
402 free(table);
403}
404
405/*
406 * zalloc_shm - allocate memory within a shm object.
407 *
408 * Shared memory is already zeroed by shmget.
409 * *NOT* multithread-safe (should be protected by mutex).
410 * Returns a -1, -1 tuple on error.
411 */
412struct shm_ref zalloc_shm(struct shm_object *obj, size_t len)
413{
414 struct shm_ref ref;
415 struct shm_ref shm_ref_error = { -1, -1 };
416
417 if (obj->memory_map_size - obj->allocated_len < len)
418 return shm_ref_error;
419 ref.index = obj->index;
420 ref.offset = obj->allocated_len;
421 obj->allocated_len += len;
422 return ref;
423}
424
425void align_shm(struct shm_object *obj, size_t align)
426{
427 size_t offset_len = offset_align(obj->allocated_len, align);
428 obj->allocated_len += offset_len;
429}
This page took 0.024767 seconds and 4 git commands to generate.