shm creation: use temporary name with O_CREAT | O_EXCL
[lttng-ust.git] / libringbuffer / shm.c
CommitLineData
1d498196
MD
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>
8da6cd6d
MD
16#include <stdio.h>
17#include <signal.h>
18#include <dirent.h>
1d498196
MD
19#include <ust/align.h>
20
21struct 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
31struct 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;
35 struct shm_object *obj;
36 char *memory_map;
8da6cd6d
MD
37 char tmp_name[NAME_MAX] = "ust-shm-tmp-XXXXXX";
38 sigset_t all_sigs, orig_sigs;
1d498196
MD
39
40 if (table->allocated_len >= table->size)
41 return NULL;
7a9c21bd 42 obj = &table->objects[table->allocated_len];
1d498196
MD
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 }
5d61a504
MD
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 }
7a9c21bd 63 memcpy(obj->wait_fd, waitfd, sizeof(waitfd));
1d498196
MD
64
65 /* shm_fd: create shm */
66
8da6cd6d
MD
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
1d498196
MD
79 /*
80 * Allocate shm, and immediately unlink its shm oject, keeping
81 * only the file descriptor as a reference to the object. If it
82 * already exists (caused by short race window during which the
83 * global object exists in a concurrent shm_open), simply retry.
84 * We specifically do _not_ use the / at the beginning of the
85 * pathname so that some OS implementations can keep it local to
86 * the process (POSIX leaves this implementation-defined).
87 */
88 do {
8da6cd6d
MD
89 /*
90 * Using mktemp filename with O_CREAT | O_EXCL open
91 * flags.
92 */
93 mktemp(tmp_name);
94 if (tmp_name[0] == '\0') {
95 PERROR("mktemp");
96 goto error_shm_open;
a8803897 97 }
8da6cd6d 98 shmfd = shm_open(tmp_name,
1d498196 99 O_CREAT | O_EXCL | O_RDWR, 0700);
8da6cd6d 100 } while (shmfd < 0 && (errno == EEXIST || errno == EACCES));
1d498196
MD
101 if (shmfd < 0) {
102 PERROR("shm_open");
103 goto error_shm_open;
104 }
8da6cd6d 105 ret = shm_unlink(tmp_name);
a8803897
MD
106 if (ret < 0 && errno != ENOENT) {
107 PERROR("shm_unlink");
108 goto error_shm_release;
109 }
8da6cd6d
MD
110 ret = pthread_sigmask(SIG_SETMASK, &orig_sigs, NULL);
111 if (ret == -1) {
112 PERROR("pthread_sigmask");
113 goto error_shm_release;
114 }
1d498196
MD
115 ret = ftruncate(shmfd, memory_map_size);
116 if (ret) {
117 PERROR("ftruncate");
118 goto error_ftruncate;
119 }
120 obj->shm_fd = shmfd;
121
122 /* memory_map: mmap */
123 memory_map = mmap(NULL, memory_map_size, PROT_READ | PROT_WRITE,
124 MAP_SHARED, shmfd, 0);
125 if (memory_map == MAP_FAILED) {
126 PERROR("mmap");
127 goto error_mmap;
128 }
129 obj->memory_map = memory_map;
130 obj->memory_map_size = memory_map_size;
131 obj->allocated_len = 0;
dc613eb9 132 obj->index = table->allocated_len++;
7a9c21bd 133
1d498196
MD
134 return obj;
135
136error_mmap:
137error_ftruncate:
a8803897 138error_shm_release:
1d498196
MD
139 ret = close(shmfd);
140 if (ret) {
141 PERROR("close");
142 assert(0);
143 }
144error_shm_open:
8da6cd6d 145error_pthread_sigmask:
1d498196
MD
146error_fcntl:
147 for (i = 0; i < 2; i++) {
148 ret = close(waitfd[i]);
149 if (ret) {
150 PERROR("close");
151 assert(0);
152 }
153 }
154error_pipe:
1d498196
MD
155 return NULL;
156
157}
158
159static
160void shmp_object_destroy(struct shm_object *obj)
161{
162 int ret, i;
163
164 ret = munmap(obj->memory_map, obj->memory_map_size);
165 if (ret) {
166 PERROR("umnmap");
167 assert(0);
168 }
169 ret = close(obj->shm_fd);
170 if (ret) {
171 PERROR("close");
172 assert(0);
173 }
174 for (i = 0; i < 2; i++) {
175 ret = close(obj->wait_fd[i]);
176 if (ret) {
177 PERROR("close");
178 assert(0);
179 }
180 }
181}
182
183void shm_object_table_destroy(struct shm_object_table *table)
184{
185 int i;
186
187 for (i = 0; i < table->allocated_len; i++)
188 shmp_object_destroy(&table->objects[i]);
189 free(table);
190}
191
192/*
193 * zalloc_shm - allocate memory within a shm object.
194 *
195 * Shared memory is already zeroed by shmget.
196 * *NOT* multithread-safe (should be protected by mutex).
197 * Returns a -1, -1 tuple on error.
198 */
199struct shm_ref zalloc_shm(struct shm_object *obj, size_t len)
200{
201 struct shm_ref ref;
202 struct shm_ref shm_ref_error = { -1, -1 };
203
204 if (obj->memory_map_size - obj->allocated_len < len)
205 return shm_ref_error;
206 ref.index = obj->index;
207 ref.offset = obj->allocated_len;
208 obj->allocated_len += len;
209 return ref;
210}
211
212void align_shm(struct shm_object *obj, size_t align)
213{
214 size_t offset_len = offset_align(obj->allocated_len, align);
215 obj->allocated_len += offset_len;
216}
This page took 0.031295 seconds and 4 git commands to generate.