2

Use case is the need to mask SIGPIPE in pthreads that do their own write() and/or SSL_write() and have it compile on current POSIX-ish systems like Linux, macOS, BSD, etc. The typical approach on Linux is explained quite nicely here, and there is lots of good additional discussion on the topic here.

The typical signal(SIGPIPE, SIG_IGN) does work everywhere I have tried, but (I believe) there should be a more surgical solution that avoids globally ignoring SIGPIPE. It would also be nice to avoid platform specific pragma if possible.

The sigtimedwait() function does not appear to exist in (current?) versions of macOS, so a cross platform solution does not look likely using that approach.

The sigwait() function seems to exist everywhere, but that will block forever if the particular signal is not actually pending. So the next best approach appears to be to use sigpending() to see what is pending, and then sigwait() to service it, which both appear to be available.

What has me concerned is that there is virtually nothing (that I can find) written on this particular problem, which is usually a sign that I am missing something painfully obvious.

So, is pthread_sigmask() / sigpending() / sigwait() / pthread_sigmask() a good choice for the above use case? Or are there (non?)obvious pitfalls I should be aware of?

Chuck Wolber
  • 519
  • 7
  • 15
  • *there should be a more surgical solution that avoids globally ignoring `SIGPIPE`* Why? If you're properly handling errors, `SIGPIPE` is pretty useless in most situations. See [**How to prevent SIGPIPEs (or handle them properly)**](https://stackoverflow.com/questions/108183/how-to-prevent-sigpipes-or-handle-them-properly) and [**Why does SIGPIPE exist?**](https://stackoverflow.com/questions/8369506/why-does-sigpipe-exist) – Andrew Henle Aug 02 '20 at 22:39
  • Why not just handle the signal? Let the handler set a "sigpipe occurred" flag and exit. Check the flag later. – n. m. could be an AI Aug 03 '20 at 00:06
  • @n.'pronouns'm. - I suspect you are referring to the use of ```sigaction()```. That function is per-process, and not per-thread. I was hoping for a more surgical approach that let me abstract behavior away into a library that had as few global effects as possible. – Chuck Wolber Aug 03 '20 at 04:23
  • @AndrewHenle - I am leaning towards that at this point. You are correct that there is little use for SIGPIPE if one does proper return checking. And yet I am still surprised at how limited the options are for portable per-thread signal handling; but that is a different question than the one I originally asked. – Chuck Wolber Aug 03 '20 at 04:27

1 Answers1

1

So, is pthread_sigmask() / sigpending() / sigwait() / pthread_sigmask() a good choice for the above use case? Or are there (non?)obvious pitfalls I should be aware of?

There's the fact that sigwait() and sigtimedwait() were released in the same version of POSIX. If you're looking to achieve portability by relying on standards, and if macOS fails to conform by omitting the latter, then you should be concerned about how else it fails to conform. Indeed, there are other areas of nonconformance that may bite you, though not necessarily with your particular proposed series of function calls.

For best portability I would suggest going for the simplest solutions possible. In this case I would simply ignore the signal (that is, set its disposition to SIG_IGN). I infer that you understand that signal dispositions are per-process characteristics, not per-thread characteristics, but so what? All of your write()s should be checking their return values to detect short writes and error conditions anyway, and if they do that correctly then they will take appropriate action without any need to receive a signal.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • I was hoping to abstract in a clean way and avoid global behavior, but I agree that SIG_IGN is probably the right approach when it comes to SIGPIPE behavior. I am still wrestling with the general question of portable signal handling in pthread applications. Perhaps it is one of those things that ultimately "evaporates" upon rigorous inspection. – Chuck Wolber Aug 03 '20 at 04:21
  • 2
    It's perhaps worth noting that a [conforming `sigpending()` cannot distinguish](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigpending.html) between an async SIGPIPE (pending on the process) and a synchronous SIGPIPE (pending on the calling thread). Thus, the OP's original thought wouldn't work on a conforming implementation. (Interestingly, OS X looks decidedly non-conforming to me: only _one_ of _N_ eligible threads will have `sigpending()` return true for an async pending signal, though any of those _N_ can successfully call `sigwait()`.) – pilcrow Aug 03 '20 at 19:32