Cleanup: remove unused label 'end'
[babeltrace.git] / include / babeltrace / compat / send.h
index 5654d95f4fe17e8a091a1053ae6b0a4c6415505b..39986945fab9fbd66085ca73ea86757f8991ba42 100644 (file)
@@ -5,6 +5,7 @@
  * babeltrace/compat/send.h
  *
  * Copyright (C) 2015  Michael Jeanson <mjeanson@efficios.com>
+ *               2015  Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * SOFTWARE.
  */
 
-#include <config.h>
-
 /*
  * This wrapper is used on platforms that have no way of ignoring SIGPIPE
- * during a send(). Instead, we set the signal action to ignore. This is OK
- * in a single-threaded app, but would be problematic in a multi-threaded app
- * since sigaction applies to all threads.
+ * during a send().
  */
 
 #ifndef MSG_NOSIGNAL
@@ -47,35 +44,72 @@ ssize_t bt_send_nosigpipe(int fd, const void *buffer, size_t size)
        return send(fd, buffer, size, MSG_NOSIGNAL);
 }
 #else
+
+#include <signal.h>
+
 static inline
 ssize_t bt_send_nosigpipe(int fd, const void *buffer, size_t size)
 {
        ssize_t sent;
        int saved_err;
-       struct sigaction act, oldact;
+       sigset_t sigpipe_set, pending_set, old_set;
+       int sigpipe_was_pending;
 
-       /* Set SIGPIPE action to ignore and save current signal action */
-       act.sa_handler = SIG_IGN;
-       if (sigaction(SIGPIPE, &act, &oldact)) {
-               perror("sigaction");
-               sent = -1;
-               goto end;
+       /*
+        * Discard the SIGPIPE from send(), not disturbing any SIGPIPE
+        * that might be already pending. If a bogus SIGPIPE is sent to
+        * the entire process concurrently by a malicious user, it may
+        * be simply discarded.
+        */
+       if (sigemptyset(&pending_set)) {
+               return -1;
+       }
+       /*
+        * sigpending returns the mask of signals that are _both_
+        * blocked for the thread _and_ pending for either the thread or
+        * the entire process.
+        */
+       if (sigpending(&pending_set)) {
+               return -1;
+       }
+       sigpipe_was_pending = sigismember(&pending_set, SIGPIPE);
+       /*
+        * If sigpipe was pending, it means it was already blocked, so
+        * no need to block it.
+        */
+       if (!sigpipe_was_pending) {
+               if (sigemptyset(&sigpipe_set)) {
+                       return -1;
+               }
+               if (sigaddset(&sigpipe_set, SIGPIPE)) {
+                       return -1;
+               }
+               if (pthread_sigmask(SIG_BLOCK, &sigpipe_set, &old_set)) {
+                       return -1;
+               }
        }
 
-       /* Send and save errno */
+       /* Send and save errno. */
        sent = send(fd, buffer, size, 0);
        saved_err = errno;
 
-       /* Restore original signal action */
-       if (sigaction(SIGPIPE, &oldact, NULL)) {
-               perror("sigaction");
-               sent = -1;
-               goto end;
-       }
+       if (sent == -1 && errno == EPIPE && !sigpipe_was_pending) {
+               struct timespec timeout = { 0, 0 };
+               int ret;
 
+               do {
+                       ret = sigtimedwait(&sigpipe_set, NULL,
+                               &timeout);
+               } while (ret == -1 && errno == EINTR);
+       }
+       if (!sigpipe_was_pending) {
+               if (pthread_sigmask(SIG_SETMASK, &old_set, NULL)) {
+                       return -1;
+               }
+       }
        /* Restore send() errno */
        errno = saved_err;
-end:
+
        return sent;
 }
 #endif
This page took 0.025509 seconds and 4 git commands to generate.