Rename "tsc" to "timestamp"
[lttng-ust.git] / src / common / counter / shm.c
CommitLineData
ebabbf58 1/*
c0c0989a 2 * SPDX-License-Identifier: LGPL-2.1-only
ebabbf58
MD
3 *
4 * Copyright (C) 2005-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
ebabbf58
MD
5 */
6
7#define _LGPL_SOURCE
ebabbf58
MD
8#include "shm.h"
9#include <unistd.h>
10#include <fcntl.h>
11#include <sys/mman.h>
12#include <sys/types.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>
ebabbf58
MD
19#include <limits.h>
20#include <stdbool.h>
21#include <stdint.h>
3d3a2bb8 22
ebabbf58
MD
23#ifdef HAVE_LIBNUMA
24#include <numa.h>
25#include <numaif.h>
26#endif
3d3a2bb8 27
eae3c729 28#include <lttng/ust-utils.h>
3d3a2bb8 29
9d315d6d
MJ
30#include "common/macros.h"
31#include "common/ust-fd.h"
1be43539 32#include "common/compat/mmap.h"
ebabbf58
MD
33
34/*
35 * Ensure we have the required amount of space available by writing 0
36 * into the entire buffer. Not doing so can trigger SIGBUS when going
37 * beyond the available shm space.
38 */
39static
40int zero_file(int fd, size_t len)
41{
42 ssize_t retlen;
43 size_t written = 0;
44 char *zeropage;
45 long pagelen;
46 int ret;
47
48 pagelen = sysconf(_SC_PAGESIZE);
49 if (pagelen < 0)
50 return (int) pagelen;
51 zeropage = calloc(pagelen, 1);
52 if (!zeropage)
53 return -ENOMEM;
54
55 while (len > written) {
56 do {
57 retlen = write(fd, zeropage,
58 min_t(size_t, pagelen, len - written));
59 } while (retlen == -1UL && errno == EINTR);
60 if (retlen < 0) {
61 ret = (int) retlen;
62 goto error;
63 }
64 written += retlen;
65 }
66 ret = 0;
67error:
68 free(zeropage);
69 return ret;
70}
71
97572c04 72struct lttng_counter_shm_object_table *lttng_counter_shm_object_table_create(size_t max_nb_obj, bool populate)
ebabbf58
MD
73{
74 struct lttng_counter_shm_object_table *table;
75
97572c04
MD
76 table = zmalloc_populate(sizeof(struct lttng_counter_shm_object_table) +
77 max_nb_obj * sizeof(table->objects[0]), populate);
ebabbf58
MD
78 if (!table)
79 return NULL;
80 table->size = max_nb_obj;
81 return table;
82}
83
84static
85struct lttng_counter_shm_object *_lttng_counter_shm_object_table_alloc_shm(struct lttng_counter_shm_object_table *table,
86 size_t memory_map_size,
97572c04 87 int cpu_fd, bool populate)
ebabbf58 88{
ebabbf58 89 struct lttng_counter_shm_object *obj;
97572c04
MD
90 int flags = MAP_SHARED;
91 int shmfd, ret;
ebabbf58
MD
92 char *memory_map;
93
94 if (cpu_fd < 0)
95 return NULL;
96 if (table->allocated_len >= table->size)
97 return NULL;
98 obj = &table->objects[table->allocated_len];
99
100 /* create shm */
101
102 shmfd = cpu_fd;
103 ret = zero_file(shmfd, memory_map_size);
104 if (ret) {
105 PERROR("zero_file");
106 goto error_zero_file;
107 }
108 ret = ftruncate(shmfd, memory_map_size);
109 if (ret) {
110 PERROR("ftruncate");
111 goto error_ftruncate;
112 }
113 /*
114 * Also ensure the file metadata is synced with the storage by using
115 * fsync(2).
116 */
117 ret = fsync(shmfd);
118 if (ret) {
119 PERROR("fsync");
120 goto error_fsync;
121 }
122 obj->shm_fd_ownership = 0;
123 obj->shm_fd = shmfd;
124
97572c04
MD
125 if (populate)
126 flags |= LTTNG_MAP_POPULATE;
ebabbf58
MD
127 /* memory_map: mmap */
128 memory_map = mmap(NULL, memory_map_size, PROT_READ | PROT_WRITE,
97572c04 129 flags, shmfd, 0);
ebabbf58
MD
130 if (memory_map == MAP_FAILED) {
131 PERROR("mmap");
132 goto error_mmap;
133 }
134 obj->type = LTTNG_COUNTER_SHM_OBJECT_SHM;
135 obj->memory_map = memory_map;
136 obj->memory_map_size = memory_map_size;
137 obj->allocated_len = 0;
138 obj->index = table->allocated_len++;
139
140 return obj;
141
142error_mmap:
143error_fsync:
144error_ftruncate:
145error_zero_file:
146 return NULL;
147}
148
149static
150struct lttng_counter_shm_object *_lttng_counter_shm_object_table_alloc_mem(struct lttng_counter_shm_object_table *table,
97572c04 151 size_t memory_map_size, bool populate)
ebabbf58
MD
152{
153 struct lttng_counter_shm_object *obj;
154 void *memory_map;
155
156 if (table->allocated_len >= table->size)
157 return NULL;
158 obj = &table->objects[table->allocated_len];
159
97572c04 160 memory_map = zmalloc_populate(memory_map_size, populate);
ebabbf58
MD
161 if (!memory_map)
162 goto alloc_error;
163
164 /* no shm_fd */
165 obj->shm_fd = -1;
166 obj->shm_fd_ownership = 0;
167
168 obj->type = LTTNG_COUNTER_SHM_OBJECT_MEM;
169 obj->memory_map = memory_map;
170 obj->memory_map_size = memory_map_size;
171 obj->allocated_len = 0;
172 obj->index = table->allocated_len++;
173
174 return obj;
175
176alloc_error:
177 return NULL;
178}
179
180/*
181 * libnuma prints errors on the console even for numa_available().
182 * Work-around this limitation by using get_mempolicy() directly to
183 * check whether the kernel supports mempolicy.
184 */
185#ifdef HAVE_LIBNUMA
186static bool lttng_is_numa_available(void)
187{
188 int ret;
189
190 ret = get_mempolicy(NULL, NULL, 0, NULL, 0);
191 if (ret && errno == ENOSYS) {
192 return false;
193 }
194 return numa_available() > 0;
195}
196#endif
197
c494c0f1 198#ifdef HAVE_LIBNUMA
ebabbf58
MD
199struct lttng_counter_shm_object *lttng_counter_shm_object_table_alloc(struct lttng_counter_shm_object_table *table,
200 size_t memory_map_size,
201 enum lttng_counter_shm_object_type type,
202 int cpu_fd,
97572c04
MD
203 int cpu,
204 bool populate)
c494c0f1
MJ
205#else
206struct lttng_counter_shm_object *lttng_counter_shm_object_table_alloc(struct lttng_counter_shm_object_table *table,
207 size_t memory_map_size,
208 enum lttng_counter_shm_object_type type,
209 int cpu_fd,
97572c04
MD
210 int cpu __attribute__((unused)),
211 bool populate)
c494c0f1 212#endif
ebabbf58
MD
213{
214 struct lttng_counter_shm_object *shm_object;
215#ifdef HAVE_LIBNUMA
216 int oldnode = 0, node;
217 bool numa_avail;
218
219 numa_avail = lttng_is_numa_available();
220 if (numa_avail) {
221 oldnode = numa_preferred();
222 if (cpu >= 0) {
223 node = numa_node_of_cpu(cpu);
224 if (node >= 0)
225 numa_set_preferred(node);
226 }
227 if (cpu < 0 || node < 0)
228 numa_set_localalloc();
229 }
230#endif /* HAVE_LIBNUMA */
231 switch (type) {
232 case LTTNG_COUNTER_SHM_OBJECT_SHM:
233 shm_object = _lttng_counter_shm_object_table_alloc_shm(table, memory_map_size,
97572c04 234 cpu_fd, populate);
ebabbf58
MD
235 break;
236 case LTTNG_COUNTER_SHM_OBJECT_MEM:
97572c04
MD
237 shm_object = _lttng_counter_shm_object_table_alloc_mem(table, memory_map_size,
238 populate);
ebabbf58
MD
239 break;
240 default:
241 assert(0);
242 }
243#ifdef HAVE_LIBNUMA
244 if (numa_avail)
245 numa_set_preferred(oldnode);
246#endif /* HAVE_LIBNUMA */
247 return shm_object;
248}
249
250struct lttng_counter_shm_object *lttng_counter_shm_object_table_append_shm(struct lttng_counter_shm_object_table *table,
97572c04 251 int shm_fd, size_t memory_map_size, bool populate)
ebabbf58
MD
252{
253 struct lttng_counter_shm_object *obj;
97572c04 254 int flags = MAP_SHARED;
ebabbf58
MD
255 char *memory_map;
256
257 if (table->allocated_len >= table->size)
258 return NULL;
259
260 obj = &table->objects[table->allocated_len];
261
262 obj->shm_fd = shm_fd;
263 obj->shm_fd_ownership = 1;
264
97572c04
MD
265 if (populate)
266 flags |= LTTNG_MAP_POPULATE;
ebabbf58
MD
267 /* memory_map: mmap */
268 memory_map = mmap(NULL, memory_map_size, PROT_READ | PROT_WRITE,
97572c04 269 flags, shm_fd, 0);
ebabbf58
MD
270 if (memory_map == MAP_FAILED) {
271 PERROR("mmap");
272 goto error_mmap;
273 }
274 obj->type = LTTNG_COUNTER_SHM_OBJECT_SHM;
275 obj->memory_map = memory_map;
276 obj->memory_map_size = memory_map_size;
277 obj->allocated_len = memory_map_size;
278 obj->index = table->allocated_len++;
279
280 return obj;
281
282error_mmap:
283 return NULL;
284}
285
286/*
287 * Passing ownership of mem to object.
288 */
289struct lttng_counter_shm_object *lttng_counter_shm_object_table_append_mem(struct lttng_counter_shm_object_table *table,
290 void *mem, size_t memory_map_size)
291{
292 struct lttng_counter_shm_object *obj;
293
294 if (table->allocated_len >= table->size)
295 return NULL;
296 obj = &table->objects[table->allocated_len];
297
298 obj->shm_fd = -1;
299 obj->shm_fd_ownership = 0;
300
301 obj->type = LTTNG_COUNTER_SHM_OBJECT_MEM;
302 obj->memory_map = mem;
303 obj->memory_map_size = memory_map_size;
304 obj->allocated_len = memory_map_size;
305 obj->index = table->allocated_len++;
306
307 return obj;
308
309 return NULL;
310}
311
312static
313void lttng_counter_shmp_object_destroy(struct lttng_counter_shm_object *obj, int consumer)
314{
315 switch (obj->type) {
316 case LTTNG_COUNTER_SHM_OBJECT_SHM:
317 {
318 int ret;
319
320 ret = munmap(obj->memory_map, obj->memory_map_size);
321 if (ret) {
322 PERROR("umnmap");
323 assert(0);
324 }
325
326 if (obj->shm_fd_ownership) {
327 /* Delete FDs only if called from app (not consumer). */
328 if (!consumer) {
329 lttng_ust_lock_fd_tracker();
330 ret = close(obj->shm_fd);
331 if (!ret) {
332 lttng_ust_delete_fd_from_tracker(obj->shm_fd);
333 } else {
334 PERROR("close");
335 assert(0);
336 }
337 lttng_ust_unlock_fd_tracker();
338 } else {
339 ret = close(obj->shm_fd);
340 if (ret) {
341 PERROR("close");
342 assert(0);
343 }
344 }
345 }
346 break;
347 }
348 case LTTNG_COUNTER_SHM_OBJECT_MEM:
349 {
350 free(obj->memory_map);
351 break;
352 }
353 default:
354 assert(0);
355 }
356}
357
358void lttng_counter_shm_object_table_destroy(struct lttng_counter_shm_object_table *table, int consumer)
359{
360 int i;
361
362 for (i = 0; i < table->allocated_len; i++)
363 lttng_counter_shmp_object_destroy(&table->objects[i], consumer);
364 free(table);
365}
366
367/*
368 * lttng_counter_zalloc_shm - allocate memory within a shm object.
369 *
370 * Shared memory is already zeroed by shmget.
371 * *NOT* multithread-safe (should be protected by mutex).
372 * Returns a -1, -1 tuple on error.
373 */
374struct lttng_counter_shm_ref lttng_counter_zalloc_shm(struct lttng_counter_shm_object *obj, size_t len)
375{
376 struct lttng_counter_shm_ref ref;
377 struct lttng_counter_shm_ref shm_ref_error = { -1, -1 };
378
379 if (obj->memory_map_size - obj->allocated_len < len)
380 return shm_ref_error;
381 ref.index = obj->index;
382 ref.offset = obj->allocated_len;
383 obj->allocated_len += len;
384 return ref;
385}
386
387void lttng_counter_align_shm(struct lttng_counter_shm_object *obj, size_t align)
388{
cd61d9bf 389 size_t offset_len = lttng_ust_offset_align(obj->allocated_len, align);
ebabbf58
MD
390 obj->allocated_len += offset_len;
391}
This page took 0.045405 seconds and 4 git commands to generate.