compat send no SIGPIPE: multithread-safe
[babeltrace.git] / include / babeltrace / compat / send.h
... / ...
CommitLineData
1#ifndef _BABELTRACE_COMPAT_SEND_H
2#define _BABELTRACE_COMPAT_SEND_H
3
4/*
5 * babeltrace/compat/send.h
6 *
7 * Copyright (C) 2015 Michael Jeanson <mjeanson@efficios.com>
8 * 2015 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
29/*
30 * This wrapper is used on platforms that have no way of ignoring SIGPIPE
31 * during a send().
32 */
33
34#ifndef MSG_NOSIGNAL
35# ifdef SO_NOSIGPIPE
36# define MSG_NOSIGNAL SO_NOSIGPIPE
37# endif
38#endif
39
40#if defined(MSG_NOSIGNAL)
41static inline
42ssize_t bt_send_nosigpipe(int fd, const void *buffer, size_t size)
43{
44 return send(fd, buffer, size, MSG_NOSIGNAL);
45}
46#else
47
48#include <signal.h>
49
50static inline
51ssize_t bt_send_nosigpipe(int fd, const void *buffer, size_t size)
52{
53 ssize_t sent;
54 int saved_err;
55 sigset_t sigpipe_set, pending_set, old_set;
56 int sigpipe_was_pending;
57
58 /*
59 * Discard the SIGPIPE from send(), not disturbing any SIGPIPE
60 * that might be already pending. If a bogus SIGPIPE is sent to
61 * the entire process concurrently by a malicious user, it may
62 * be simply discarded.
63 */
64 if (sigemptyset(&pending_set)) {
65 return -1;
66 }
67 /*
68 * sigpending returns the mask of signals that are _both_
69 * blocked for the thread _and_ pending for either the thread or
70 * the entire process.
71 */
72 if (sigpending(&pending_set)) {
73 return -1;
74 }
75 sigpipe_was_pending = sigismember(&pending_set, SIGPIPE);
76 /*
77 * If sigpipe was pending, it means it was already blocked, so
78 * no need to block it.
79 */
80 if (!sigpipe_was_pending) {
81 if (sigemptyset(&sigpipe_set)) {
82 return -1;
83 }
84 if (sigaddset(&sigpipe_set, SIGPIPE)) {
85 return -1;
86 }
87 if (pthread_sigmask(SIG_BLOCK, &sigpipe_set, &old_set)) {
88 return -1;
89 }
90 }
91
92 /* Send and save errno. */
93 sent = send(fd, buffer, size, 0);
94 saved_err = errno;
95
96 if (sent == -1 && errno == EPIPE && !sigpipe_was_pending) {
97 struct timespec timeout = { 0, 0 };
98 int ret;
99
100 do {
101 ret = sigtimedwait(&sigpipe_set, NULL,
102 &timeout);
103 } while (ret == -1 && errno == EINTR);
104 }
105 if (!sigpipe_was_pending) {
106 if (pthread_sigmask(SIG_SETMASK, &old_set, NULL)) {
107 return -1;
108 }
109 }
110 /* Restore send() errno */
111 errno = saved_err;
112end:
113 return sent;
114}
115#endif
116
117#endif /* _BABELTRACE_COMPAT_SEND_H */
This page took 0.023075 seconds and 4 git commands to generate.