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