Force usage of assert() condition when NDEBUG is defined
[lttng-tools.git] / src / common / pipe.c
1 /*
2 * Copyright (C) 2013 David Goulet <dgoulet@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8 #define _LGPL_SOURCE
9 #include <fcntl.h>
10 #include <unistd.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13
14 #include <common/common.h>
15
16 #include "pipe.h"
17
18 /*
19 * Lock read side of a pipe.
20 */
21 static void lock_read_side(struct lttng_pipe *pipe)
22 {
23 pthread_mutex_lock(&pipe->read_mutex);
24 }
25
26 /*
27 * Unlock read side of a pipe.
28 */
29 static void unlock_read_side(struct lttng_pipe *pipe)
30 {
31 pthread_mutex_unlock(&pipe->read_mutex);
32 }
33
34 /*
35 * Lock write side of a pipe.
36 */
37 static void lock_write_side(struct lttng_pipe *pipe)
38 {
39 pthread_mutex_lock(&pipe->write_mutex);
40 }
41
42 /*
43 * Unlock write side of a pipe.
44 */
45 static void unlock_write_side(struct lttng_pipe *pipe)
46 {
47 pthread_mutex_unlock(&pipe->write_mutex);
48 }
49
50 /*
51 * Internal function. Close read side of pipe WITHOUT locking the mutex.
52 *
53 * Return 0 on success else a negative errno from close(2).
54 */
55 static int _pipe_read_close(struct lttng_pipe *pipe)
56 {
57 int ret, ret_val = 0;
58
59 LTTNG_ASSERT(pipe);
60
61 if (!lttng_pipe_is_read_open(pipe)) {
62 goto end;
63 }
64
65 do {
66 ret = close(pipe->fd[0]);
67 } while (ret < 0 && errno == EINTR);
68 if (ret < 0) {
69 PERROR("close lttng read pipe");
70 ret_val = -errno;
71 }
72 pipe->r_state = LTTNG_PIPE_STATE_CLOSED;
73
74 end:
75 return ret_val;
76 }
77
78 /*
79 * Internal function. Close write side of pipe WITHOUT locking the mutex.
80 *
81 * Return 0 on success else a negative errno from close(2).
82 */
83 static int _pipe_write_close(struct lttng_pipe *pipe)
84 {
85 int ret, ret_val = 0;
86
87 LTTNG_ASSERT(pipe);
88
89 if (!lttng_pipe_is_write_open(pipe)) {
90 goto end;
91 }
92
93 do {
94 ret = close(pipe->fd[1]);
95 } while (ret < 0 && errno == EINTR);
96 if (ret < 0) {
97 PERROR("close lttng write pipe");
98 ret_val = -errno;
99 }
100 pipe->w_state = LTTNG_PIPE_STATE_CLOSED;
101
102 end:
103 return ret_val;
104 }
105
106 static struct lttng_pipe *_pipe_create(void)
107 {
108 int ret;
109 struct lttng_pipe *p;
110
111 p = zmalloc(sizeof(*p));
112 if (!p) {
113 PERROR("zmalloc pipe create");
114 goto end;
115 }
116 p->fd[0] = p->fd[1] = -1;
117
118 ret = pthread_mutex_init(&p->read_mutex, NULL);
119 if (ret) {
120 PERROR("pthread_mutex_init read lock pipe create");
121 goto error_destroy;
122 }
123 ret = pthread_mutex_init(&p->write_mutex, NULL);
124 if (ret) {
125 PERROR("pthread_mutex_init write lock pipe create");
126 goto error_destroy_rmutex;
127 }
128 end:
129 return p;
130 error_destroy_rmutex:
131 (void) pthread_mutex_destroy(&p->read_mutex);
132 error_destroy:
133 free(p);
134 return NULL;
135 }
136
137 static int _pipe_set_flags(struct lttng_pipe *pipe, int flags)
138 {
139 int i, ret = 0;
140
141 if (!flags) {
142 goto end;
143 }
144
145 for (i = 0; i < 2; i++) {
146 if (flags & O_NONBLOCK) {
147 ret = fcntl(pipe->fd[i], F_SETFL, O_NONBLOCK);
148 if (ret < 0) {
149 PERROR("fcntl lttng pipe %d", flags);
150 goto end;
151 }
152 }
153 if (flags & FD_CLOEXEC) {
154 ret = fcntl(pipe->fd[i], F_SETFD, FD_CLOEXEC);
155 if (ret < 0) {
156 PERROR("fcntl lttng pipe %d", flags);
157 goto end;
158 }
159 }
160 /*
161 * We only check for O_NONBLOCK or FD_CLOEXEC, if another flag is
162 * needed, we can add it, but for now just make sure we don't make
163 * mistakes with the parameters we pass.
164 */
165 if (!(flags & O_NONBLOCK) && !(flags & FD_CLOEXEC)) {
166 fprintf(stderr, "Unsupported flag\n");
167 ret = -1;
168 goto end;
169 }
170 }
171 end:
172 return ret;
173 }
174
175 /*
176 * Open a new lttng pipe and set flags using fcntl().
177 *
178 * Return a newly allocated lttng pipe on success or else NULL.
179 */
180 LTTNG_HIDDEN
181 struct lttng_pipe *lttng_pipe_open(int flags)
182 {
183 int ret;
184 struct lttng_pipe *p;
185
186 p = _pipe_create();
187 if (!p) {
188 goto error;
189 }
190
191 ret = pipe(p->fd);
192 if (ret < 0) {
193 PERROR("lttng pipe");
194 goto error;
195 }
196 p->r_state = LTTNG_PIPE_STATE_OPENED;
197 p->w_state = LTTNG_PIPE_STATE_OPENED;
198
199 ret = _pipe_set_flags(p, flags);
200 if (ret) {
201 goto error;
202 }
203
204 p->flags = flags;
205
206 return p;
207 error:
208 lttng_pipe_destroy(p);
209 return NULL;
210 }
211
212 /*
213 * Open a new lttng pipe at path and set flags using fcntl().
214 *
215 * Return a newly allocated lttng pipe on success or else NULL.
216 */
217 LTTNG_HIDDEN
218 struct lttng_pipe *lttng_pipe_named_open(const char *path, mode_t mode,
219 int flags)
220 {
221 int ret, fd_r, fd_w;
222 struct lttng_pipe *pipe;
223
224 pipe = _pipe_create();
225 if (!pipe) {
226 goto error;
227 }
228
229 ret = mkfifo(path, mode);
230 if (ret) {
231 PERROR("mkfifo");
232 goto error;
233 }
234
235 fd_r = open(path, O_RDONLY | O_NONBLOCK);
236 if (fd_r < 0) {
237 PERROR("open fifo");
238 goto error;
239 }
240 pipe->fd[0] = fd_r;
241 pipe->r_state = LTTNG_PIPE_STATE_OPENED;
242
243 fd_w = open(path, O_WRONLY | O_NONBLOCK);
244 if (fd_w < 0) {
245 PERROR("open fifo");
246 goto error;
247 }
248 pipe->fd[1] = fd_w;
249 pipe->w_state = LTTNG_PIPE_STATE_OPENED;
250
251 ret = _pipe_set_flags(pipe, flags);
252 if (ret) {
253 goto error;
254 }
255 pipe->flags = flags;
256
257 return pipe;
258 error:
259 lttng_pipe_destroy(pipe);
260 return NULL;
261 }
262
263 /*
264 * Close read side of a lttng pipe.
265 *
266 * Return 0 on success else a negative value.
267 */
268 LTTNG_HIDDEN
269 int lttng_pipe_read_close(struct lttng_pipe *pipe)
270 {
271 int ret;
272
273 LTTNG_ASSERT(pipe);
274
275 /* Handle read side first. */
276 lock_read_side(pipe);
277 ret = _pipe_read_close(pipe);
278 unlock_read_side(pipe);
279
280 return ret;
281 }
282
283 /*
284 * Close write side of a lttng pipe.
285 *
286 * Return 0 on success else a negative value.
287 */
288 LTTNG_HIDDEN
289 int lttng_pipe_write_close(struct lttng_pipe *pipe)
290 {
291 int ret;
292
293 LTTNG_ASSERT(pipe);
294
295 lock_write_side(pipe);
296 ret = _pipe_write_close(pipe);
297 unlock_write_side(pipe);
298
299 return ret;
300 }
301
302 /*
303 * Close both read and write side of a lttng pipe.
304 *
305 * Return 0 on success else a negative value.
306 */
307 LTTNG_HIDDEN
308 int lttng_pipe_close(struct lttng_pipe *pipe)
309 {
310 int ret, ret_val = 0;
311
312 LTTNG_ASSERT(pipe);
313
314 ret = lttng_pipe_read_close(pipe);
315 if (ret < 0) {
316 ret_val = ret;
317 }
318
319 ret = lttng_pipe_write_close(pipe);
320 if (ret < 0) {
321 ret_val = ret;
322 }
323
324 return ret_val;
325 }
326
327 /*
328 * Close and destroy a lttng pipe object. Finally, pipe is freed.
329 */
330 LTTNG_HIDDEN
331 void lttng_pipe_destroy(struct lttng_pipe *pipe)
332 {
333 int ret;
334
335 if (!pipe) {
336 return;
337 }
338
339 /*
340 * Destroy should *never* be called with a locked mutex. These must always
341 * succeed so we unlock them after the close pipe below.
342 */
343 ret = pthread_mutex_trylock(&pipe->read_mutex);
344 LTTNG_ASSERT(!ret);
345 ret = pthread_mutex_trylock(&pipe->write_mutex);
346 LTTNG_ASSERT(!ret);
347
348 /* Close pipes WITHOUT trying to lock the pipes. */
349 (void) _pipe_read_close(pipe);
350 (void) _pipe_write_close(pipe);
351
352 unlock_read_side(pipe);
353 unlock_write_side(pipe);
354
355 (void) pthread_mutex_destroy(&pipe->read_mutex);
356 (void) pthread_mutex_destroy(&pipe->write_mutex);
357
358 free(pipe);
359 }
360
361 /*
362 * Read on a lttng pipe and put the data in buf of at least size count.
363 *
364 * Return "count" on success. Return < count on error. errno can be used
365 * to check the actual error.
366 */
367 LTTNG_HIDDEN
368 ssize_t lttng_pipe_read(struct lttng_pipe *pipe, void *buf, size_t count)
369 {
370 ssize_t ret;
371
372 LTTNG_ASSERT(pipe);
373 LTTNG_ASSERT(buf);
374
375 lock_read_side(pipe);
376 if (!lttng_pipe_is_read_open(pipe)) {
377 ret = -1;
378 errno = EBADF;
379 goto error;
380 }
381 ret = lttng_read(pipe->fd[0], buf, count);
382 error:
383 unlock_read_side(pipe);
384 return ret;
385 }
386
387 /*
388 * Write on a lttng pipe using the data in buf and size of count.
389 *
390 * Return "count" on success. Return < count on error. errno can be used
391 * to check the actual error.
392 */
393 LTTNG_HIDDEN
394 ssize_t lttng_pipe_write(struct lttng_pipe *pipe, const void *buf,
395 size_t count)
396 {
397 ssize_t ret;
398
399 LTTNG_ASSERT(pipe);
400 LTTNG_ASSERT(buf);
401
402 lock_write_side(pipe);
403 if (!lttng_pipe_is_write_open(pipe)) {
404 ret = -1;
405 errno = EBADF;
406 goto error;
407 }
408 ret = lttng_write(pipe->fd[1], buf, count);
409 error:
410 unlock_write_side(pipe);
411 return ret;
412 }
413
414 /*
415 * Return and release the read end of the pipe.
416 *
417 * This call transfers the ownership of the read fd of the underlying pipe
418 * to the caller if it is still open.
419 *
420 * Returns the fd of the read end of the pipe, or -1 if it was already closed or
421 * released.
422 */
423 LTTNG_HIDDEN
424 int lttng_pipe_release_readfd(struct lttng_pipe *pipe)
425 {
426 int ret;
427
428 if (!pipe) {
429 ret = -1;
430 goto end;
431 }
432
433 lock_read_side(pipe);
434 if (!lttng_pipe_is_read_open(pipe)) {
435 ret = -1;
436 goto end_unlock;
437 }
438 ret = pipe->fd[0];
439 pipe->fd[0] = -1;
440 pipe->r_state = LTTNG_PIPE_STATE_CLOSED;
441 end_unlock:
442 unlock_read_side(pipe);
443 end:
444 return ret;
445 }
446
447 /*
448 * Return and release the write end of the pipe.
449 *
450 * This call transfers the ownership of the write fd of the underlying pipe
451 * to the caller if it is still open.
452 *
453 * Returns the fd of the write end of the pipe, or -1 if it was alwritey closed
454 * or released.
455 */
456 LTTNG_HIDDEN
457 int lttng_pipe_release_writefd(struct lttng_pipe *pipe)
458 {
459 int ret;
460
461 if (!pipe) {
462 ret = -1;
463 goto end;
464 }
465
466 lock_write_side(pipe);
467 if (!lttng_pipe_is_write_open(pipe)) {
468 ret = -1;
469 goto end_unlock;
470 }
471 ret = pipe->fd[1];
472 pipe->fd[1] = -1;
473 pipe->w_state = LTTNG_PIPE_STATE_CLOSED;
474 end_unlock:
475 unlock_write_side(pipe);
476 end:
477 return ret;
478 }
This page took 0.05458 seconds and 4 git commands to generate.