Fix error handling
[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>
16#include <ust/align.h>
17
18struct shm_object_table *shm_object_table_create(size_t max_nb_obj)
19{
20 struct shm_object_table *table;
21
22 table = zmalloc(sizeof(struct shm_object_table) +
23 max_nb_obj * sizeof(table->objects[0]));
24 table->size = max_nb_obj;
25 return table;
26}
27
28struct shm_object *shm_object_table_append(struct shm_object_table *table,
29 size_t memory_map_size)
30{
31 int shmfd, waitfd[2], ret, i;
32 struct shm_object *obj;
33 char *memory_map;
34
35 if (table->allocated_len >= table->size)
36 return NULL;
7a9c21bd 37 obj = &table->objects[table->allocated_len];
1d498196
MD
38
39 /* wait_fd: create pipe */
40 ret = pipe(waitfd);
41 if (ret < 0) {
42 PERROR("pipe");
43 goto error_pipe;
44 }
45 for (i = 0; i < 2; i++) {
46 ret = fcntl(waitfd[i], F_SETFD, FD_CLOEXEC);
47 if (ret < 0) {
48 PERROR("fcntl");
49 goto error_fcntl;
50 }
51 }
5d61a504
MD
52 /* The write end of the pipe needs to be non-blocking */
53 ret = fcntl(waitfd[1], F_SETFL, O_NONBLOCK);
54 if (ret < 0) {
55 PERROR("fcntl");
56 goto error_fcntl;
57 }
7a9c21bd 58 memcpy(obj->wait_fd, waitfd, sizeof(waitfd));
1d498196
MD
59
60 /* shm_fd: create shm */
61
62 /*
63 * Allocate shm, and immediately unlink its shm oject, keeping
64 * only the file descriptor as a reference to the object. If it
65 * already exists (caused by short race window during which the
66 * global object exists in a concurrent shm_open), simply retry.
67 * We specifically do _not_ use the / at the beginning of the
68 * pathname so that some OS implementations can keep it local to
69 * the process (POSIX leaves this implementation-defined).
616d144a
MD
70 * Ignore the shm_unlink errors, because we handle leaks that
71 * could occur by applications crashing between shm_open and
72 * shm_unlink by unlinking the shm before every open. Therefore,
73 * we can only leak one single shm (and only if the application
74 * crashes between shm_open and the following shm_unlink).
1d498196
MD
75 */
76 do {
a8803897
MD
77 ret = shm_unlink("ust-shm-tmp");
78 if (ret < 0 && errno != ENOENT) {
79 PERROR("shm_unlink");
80 goto error_shm_unlink;
81 }
1d498196
MD
82 shmfd = shm_open("ust-shm-tmp",
83 O_CREAT | O_EXCL | O_RDWR, 0700);
84 } while (shmfd < 0 && errno == EEXIST);
85 if (shmfd < 0) {
86 PERROR("shm_open");
87 goto error_shm_open;
88 }
a8803897
MD
89 ret = shm_unlink("ust-shm-tmp");
90 if (ret < 0 && errno != ENOENT) {
91 PERROR("shm_unlink");
92 goto error_shm_release;
93 }
1d498196
MD
94 ret = ftruncate(shmfd, memory_map_size);
95 if (ret) {
96 PERROR("ftruncate");
97 goto error_ftruncate;
98 }
99 obj->shm_fd = shmfd;
100
101 /* memory_map: mmap */
102 memory_map = mmap(NULL, memory_map_size, PROT_READ | PROT_WRITE,
103 MAP_SHARED, shmfd, 0);
104 if (memory_map == MAP_FAILED) {
105 PERROR("mmap");
106 goto error_mmap;
107 }
108 obj->memory_map = memory_map;
109 obj->memory_map_size = memory_map_size;
110 obj->allocated_len = 0;
dc613eb9 111 obj->index = table->allocated_len++;
7a9c21bd 112
1d498196
MD
113 return obj;
114
115error_mmap:
116error_ftruncate:
a8803897 117error_shm_release:
1d498196
MD
118 ret = close(shmfd);
119 if (ret) {
120 PERROR("close");
121 assert(0);
122 }
a8803897 123error_shm_unlink:
1d498196
MD
124error_shm_open:
125error_fcntl:
126 for (i = 0; i < 2; i++) {
127 ret = close(waitfd[i]);
128 if (ret) {
129 PERROR("close");
130 assert(0);
131 }
132 }
133error_pipe:
1d498196
MD
134 return NULL;
135
136}
137
138static
139void shmp_object_destroy(struct shm_object *obj)
140{
141 int ret, i;
142
143 ret = munmap(obj->memory_map, obj->memory_map_size);
144 if (ret) {
145 PERROR("umnmap");
146 assert(0);
147 }
148 ret = close(obj->shm_fd);
149 if (ret) {
150 PERROR("close");
151 assert(0);
152 }
153 for (i = 0; i < 2; i++) {
154 ret = close(obj->wait_fd[i]);
155 if (ret) {
156 PERROR("close");
157 assert(0);
158 }
159 }
160}
161
162void shm_object_table_destroy(struct shm_object_table *table)
163{
164 int i;
165
166 for (i = 0; i < table->allocated_len; i++)
167 shmp_object_destroy(&table->objects[i]);
168 free(table);
169}
170
171/*
172 * zalloc_shm - allocate memory within a shm object.
173 *
174 * Shared memory is already zeroed by shmget.
175 * *NOT* multithread-safe (should be protected by mutex).
176 * Returns a -1, -1 tuple on error.
177 */
178struct shm_ref zalloc_shm(struct shm_object *obj, size_t len)
179{
180 struct shm_ref ref;
181 struct shm_ref shm_ref_error = { -1, -1 };
182
183 if (obj->memory_map_size - obj->allocated_len < len)
184 return shm_ref_error;
185 ref.index = obj->index;
186 ref.offset = obj->allocated_len;
187 obj->allocated_len += len;
188 return ref;
189}
190
191void align_shm(struct shm_object *obj, size_t align)
192{
193 size_t offset_len = offset_align(obj->allocated_len, align);
194 obj->allocated_len += offset_len;
195}
This page took 0.030112 seconds and 4 git commands to generate.