aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSeebs <seebs@seebs.net>2018-12-15 14:28:19 -0600
committerSeebs <seebs@seebs.net>2018-12-15 14:28:44 -0600
commit416240273bfd987cbddac7b6439d99c29f7b67ba (patch)
tree27c3a23d3715aef3ddb56c9f3c7c366c79d578b9
parent6c8651cf361531ebc9633ea3e0486ec048e6ac13 (diff)
downloadpseudo-416240273bfd987cbddac7b6439d99c29f7b67ba.tar.gz
pseudo-416240273bfd987cbddac7b6439d99c29f7b67ba.tar.bz2
pseudo-416240273bfd987cbddac7b6439d99c29f7b67ba.zip
Use MSG_NOSIGNAL if available.
MSG_NOSIGNAL has been in Linux since 2.2, and has been standardized in POSIX 2008. Using that when available avoids the overhead of the two syscalls to set and restore the SIGPIPE handler. Moreover, we can eliminate one write() call by making use of sendmsg() to do scatter-gather I/O. Signed-off-by: Rasmus Villemoes <rasmus.villemoes@prevas.dk> Signed-off-by: Seebs <seebs@seebs.net>
-rw-r--r--ChangeLog.txt3
-rw-r--r--pseudo_ipc.c63
2 files changed, 53 insertions, 13 deletions
diff --git a/ChangeLog.txt b/ChangeLog.txt
index e7f84a8..6664517 100644
--- a/ChangeLog.txt
+++ b/ChangeLog.txt
@@ -1,3 +1,6 @@
+2018-12-15:
+ * (seebs) Import IPC patch from Rasmus Villemoes.
+
2018-11-29:
* (seebs) add missing <stdint.h> to pseudo_db.c. Thanks to
Bernhard Hartleb <bernhard.hartleb@gmail.com> for pointing
diff --git a/pseudo_ipc.c b/pseudo_ipc.c
index 82c6f70..7786880 100644
--- a/pseudo_ipc.c
+++ b/pseudo_ipc.c
@@ -26,13 +26,17 @@
#include <ctype.h>
#include <errno.h>
#include <sys/stat.h>
+#include <sys/socket.h>
#include "pseudo.h"
#include "pseudo_ipc.h"
-/* Short reads or writes can cause a sigpipe, killing the program, so we
- * trap it and report that something happened.
+/* Short reads or writes can cause a sigpipe, killing the program, so
+ * we trap it and report that something happened. We can avoid the
+ * overhead of setting/restoring the SIGPIPE handler if MSG_NOSIGNAL
+ * is available.
*/
+#ifndef MSG_NOSIGNAL
static sig_atomic_t pipe_error = 0;
static void (*old_handler)(int) = SIG_DFL;
@@ -51,6 +55,9 @@ static void
allow_sigpipe(void) {
signal(SIGPIPE, old_handler);
}
+#else
+#define pipe_error 0
+#endif
#if 0
/* useful only when debugging crazy stuff */
@@ -66,6 +73,36 @@ display_msg_header(pseudo_msg_t *msg) {
}
#endif
+#ifdef MSG_NOSIGNAL
+static int
+do_send(int fd, struct iovec *iov, int iovlen)
+{
+ struct msghdr hdr;
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.msg_iov = iov;
+ hdr.msg_iovlen = iovlen;
+
+ return sendmsg(fd, &hdr, MSG_NOSIGNAL);
+}
+#else
+static int
+do_send(int fd, struct iovec *iov, int iovlen)
+{
+ int r, s = 0, i;
+
+ ignore_sigpipe();
+ for (i = 0; i < iovlen; ++i) {
+ r = write(fd, iov[i].iov_base, iov[i].iov_len);
+ s += r;
+ if (r != (int)iov[i].iov_len)
+ break;
+ }
+ allow_sigpipe();
+ return s;
+}
+#endif
+
/*
* send message on fd
* return:
@@ -75,6 +112,7 @@ display_msg_header(pseudo_msg_t *msg) {
*/
int
pseudo_msg_send(int fd, pseudo_msg_t *msg, size_t len, const char *path) {
+ struct iovec iov[2];
int r;
if (!msg)
@@ -89,14 +127,13 @@ pseudo_msg_send(int fd, pseudo_msg_t *msg, size_t len, const char *path) {
if (len == (size_t) -1)
len = strlen(path) + 1;
msg->pathlen = len;
- ignore_sigpipe();
- r = write(fd, msg, PSEUDO_HEADER_SIZE);
- if (r == PSEUDO_HEADER_SIZE) {
- r += write(fd, path, len);
- }
- allow_sigpipe();
+ iov[0].iov_base = msg;
+ iov[0].iov_len = PSEUDO_HEADER_SIZE;
+ iov[1].iov_base = (void*)path;
+ iov[1].iov_len = len;
+ r = do_send(fd, iov, 2);
pseudo_debug(PDBGF_IPC | PDBGF_VERBOSE, "wrote %d bytes\n", r);
- if (pipe_error || (r == -1 && errno == EBADF))
+ if (pipe_error || (r == -1 && (errno == EBADF || errno == EPIPE)))
return -1;
return ((size_t) r != PSEUDO_HEADER_SIZE + len);
} else {
@@ -105,11 +142,11 @@ pseudo_msg_send(int fd, pseudo_msg_t *msg, size_t len, const char *path) {
msg->result, pseudo_res_name(msg->result),
msg->pathlen, msg->path, (int) msg->mode);
// display_msg_header(msg);
- ignore_sigpipe();
- r = write(fd, msg, PSEUDO_HEADER_SIZE + msg->pathlen);
- allow_sigpipe();
+ iov[0].iov_base = msg;
+ iov[0].iov_len = PSEUDO_HEADER_SIZE + msg->pathlen;
+ r = do_send(fd, iov, 1);
pseudo_debug(PDBGF_IPC | PDBGF_VERBOSE, "wrote %d bytes\n", r);
- if (pipe_error || (r == -1 && errno == EBADF))
+ if (pipe_error || (r == -1 && (errno == EBADF || errno == EPIPE)))
return -1;
return ((size_t) r != PSEUDO_HEADER_SIZE + msg->pathlen);
}