Add wrappers for pipe
[lttng-tools.git] / src / common / pipe.c
... / ...
CommitLineData
1/*
2 * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License, version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18#define _GNU_SOURCE
19#include <assert.h>
20#include <fcntl.h>
21#include <unistd.h>
22
23#include <common/common.h>
24
25#include "pipe.h"
26
27/*
28 * Lock read side of a pipe.
29 */
30static void lock_read_side(struct lttng_pipe *pipe)
31{
32 pthread_mutex_lock(&pipe->read_mutex);
33}
34
35/*
36 * Unlock read side of a pipe.
37 */
38static void unlock_read_side(struct lttng_pipe *pipe)
39{
40 pthread_mutex_unlock(&pipe->read_mutex);
41}
42
43/*
44 * Lock write side of a pipe.
45 */
46static void lock_write_side(struct lttng_pipe *pipe)
47{
48 pthread_mutex_lock(&pipe->write_mutex);
49}
50
51/*
52 * Unlock write side of a pipe.
53 */
54static void unlock_write_side(struct lttng_pipe *pipe)
55{
56 pthread_mutex_unlock(&pipe->write_mutex);
57}
58
59/*
60 * Internal function. Close read side of pipe WITHOUT locking the mutex.
61 *
62 * Return 0 on success else a negative errno from close(2).
63 */
64static int _pipe_read_close(struct lttng_pipe *pipe)
65{
66 int ret, ret_val = 0;
67
68 assert(pipe);
69
70 if (!lttng_pipe_is_read_open(pipe)) {
71 goto end;
72 }
73
74 do {
75 ret = close(pipe->fd[0]);
76 } while (ret < 0 && errno == EINTR);
77 if (ret < 0) {
78 PERROR("close lttng read pipe");
79 ret_val = -errno;
80 }
81 pipe->r_state = LTTNG_PIPE_STATE_CLOSED;
82
83end:
84 return ret_val;
85}
86
87/*
88 * Internal function. Close write side of pipe WITHOUT locking the mutex.
89 *
90 * Return 0 on success else a negative errno from close(2).
91 */
92static int _pipe_write_close(struct lttng_pipe *pipe)
93{
94 int ret, ret_val = 0;
95
96 assert(pipe);
97
98 if (!lttng_pipe_is_write_open(pipe)) {
99 goto end;
100 }
101
102 do {
103 ret = close(pipe->fd[1]);
104 } while (ret < 0 && errno == EINTR);
105 if (ret < 0) {
106 PERROR("close lttng write pipe");
107 ret_val = -errno;
108 }
109 pipe->w_state = LTTNG_PIPE_STATE_CLOSED;
110
111end:
112 return ret_val;
113}
114
115
116/*
117 * Open a new lttng pipe and set flags using fcntl().
118 *
119 * Return a newly allocated lttng pipe on success or else NULL.
120 */
121struct lttng_pipe *lttng_pipe_open(int flags)
122{
123 int ret;
124 struct lttng_pipe *p;
125
126 p = zmalloc(sizeof(*p));
127 if (!p) {
128 PERROR("zmalloc pipe open");
129 goto error;
130 }
131
132 ret = pipe(p->fd);
133 if (ret < 0) {
134 PERROR("lttng pipe");
135 goto error;
136 }
137
138 if (flags) {
139 int i;
140
141 for (i = 0; i < 2; i++) {
142 ret = fcntl(p->fd[i], F_SETFD, flags);
143 if (ret < 0) {
144 PERROR("fcntl lttng pipe %d", flags);
145 goto error;
146 }
147 }
148 }
149
150 pthread_mutex_init(&p->read_mutex, NULL);
151 pthread_mutex_init(&p->write_mutex, NULL);
152 p->r_state = LTTNG_PIPE_STATE_OPENED;
153 p->w_state = LTTNG_PIPE_STATE_OPENED;
154 p->flags = flags;
155
156 return p;
157
158error:
159 lttng_pipe_destroy(p);
160 return NULL;
161}
162
163/*
164 * Close read side of a lttng pipe.
165 *
166 * Return 0 on success else a negative value.
167 */
168int lttng_pipe_read_close(struct lttng_pipe *pipe)
169{
170 int ret;
171
172 assert(pipe);
173
174 /* Handle read side first. */
175 lock_read_side(pipe);
176 ret = _pipe_read_close(pipe);
177 unlock_read_side(pipe);
178
179 return ret;
180}
181
182/*
183 * Close write side of a lttng pipe.
184 *
185 * Return 0 on success else a negative value.
186 */
187int lttng_pipe_write_close(struct lttng_pipe *pipe)
188{
189 int ret;
190
191 assert(pipe);
192
193 lock_write_side(pipe);
194 ret = _pipe_write_close(pipe);
195 unlock_write_side(pipe);
196
197 return ret;
198}
199
200/*
201 * Close both read and write side of a lttng pipe.
202 *
203 * Return 0 on success else a negative value.
204 */
205int lttng_pipe_close(struct lttng_pipe *pipe)
206{
207 int ret, ret_val = 0;
208
209 assert(pipe);
210
211 ret = lttng_pipe_read_close(pipe);
212 if (ret < 0) {
213 ret_val = ret;
214 }
215
216 ret = lttng_pipe_write_close(pipe);
217 if (ret < 0) {
218 ret_val = ret;
219 }
220
221 return ret_val;
222}
223
224/*
225 * Close and destroy a lttng pipe object. Finally, pipe is freed.
226 */
227void lttng_pipe_destroy(struct lttng_pipe *pipe)
228{
229 int ret;
230
231 if (!pipe) {
232 return;
233 }
234
235 /*
236 * Destroy should *never* be called with a locked mutex. These must always
237 * succeed so we unlock them after the close pipe below.
238 */
239 ret = pthread_mutex_trylock(&pipe->read_mutex);
240 assert(!ret);
241 ret = pthread_mutex_trylock(&pipe->write_mutex);
242 assert(!ret);
243
244 /* Close pipes WITHOUT trying to lock the pipes. */
245 (void) _pipe_read_close(pipe);
246 (void) _pipe_write_close(pipe);
247
248 unlock_read_side(pipe);
249 unlock_write_side(pipe);
250
251 (void) pthread_mutex_destroy(&pipe->read_mutex);
252 (void) pthread_mutex_destroy(&pipe->write_mutex);
253
254 free(pipe);
255}
256
257/*
258 * Read on a lttng pipe and put the data in buf of at least size count.
259 *
260 * Return 0 on success or else a negative errno message from read(2).
261 */
262ssize_t lttng_pipe_read(struct lttng_pipe *pipe, void *buf, size_t count)
263{
264 ssize_t ret, read_len, read_left, index;
265
266 assert(pipe);
267 assert(buf);
268
269 lock_read_side(pipe);
270
271 if (!lttng_pipe_is_read_open(pipe)) {
272 ret = -EBADF;
273 goto error;
274 }
275
276 read_left = count;
277 index = 0;
278 do {
279 read_len = read(pipe->fd[0], buf + index, read_left);
280 if (read_len < 0) {
281 ret = -errno;
282 if (errno == EINTR) {
283 /* Read again. */
284 continue;
285 } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
286 /*
287 * Return the number of bytes read up to this point if any.
288 */
289 if (index) {
290 ret = index;
291 }
292 goto error;
293 } else {
294 PERROR("lttng pipe read");
295 goto error;
296 }
297 }
298 read_left -= read_len;
299 index += read_len;
300 } while (read_left > 0);
301
302 /* Everything went fine. */
303 ret = index;
304
305error:
306 unlock_read_side(pipe);
307 return ret;
308}
309
310/*
311 * Write on a lttng pipe using the data in buf and size of count.
312 *
313 * Return 0 on success or else a negative errno message from write(2).
314 */
315ssize_t lttng_pipe_write(struct lttng_pipe *pipe, const void *buf,
316 size_t count)
317{
318 ssize_t ret, write_len, write_left, index;
319
320 assert(pipe);
321 assert(buf);
322
323 lock_write_side(pipe);
324
325 if (!lttng_pipe_is_write_open(pipe)) {
326 ret = -EBADF;
327 goto error;
328 }
329
330 write_left = count;
331 index = 0;
332 do {
333 write_len = write(pipe->fd[1], buf + index, write_left);
334 if (write_len < 0) {
335 ret = -errno;
336 if (errno == EINTR) {
337 /* Read again. */
338 continue;
339 } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
340 /*
341 * Return the number of bytes read up to this point if any.
342 */
343 if (index) {
344 ret = index;
345 }
346 goto error;
347 } else {
348 PERROR("lttng pipe write");
349 goto error;
350 }
351 }
352 write_left -= write_len;
353 index += write_len;
354 } while (write_left > 0);
355
356 /* Everything went fine. */
357 ret = index;
358
359error:
360 unlock_write_side(pipe);
361 return ret;
362}
This page took 0.023382 seconds and 4 git commands to generate.