2020-05-03

I was looking for a way to express the following C-language macro, as found in a #ifdef __USE_GNU section of #include <unistd.h> in modern C++
# define TEMP_FAILURE_RETRY(expression) \
  (__extension__                                                              \
    ({ long int __result;                                                     \
       do __result = (long int) (expression);                                 \
       while (__result == -1L && errno == EINTR);                             \
       __result; }))
#endif
and it wasn't exactly easy to find the pieces to get that done by googling (Nor was it particularly easy to get blogger to display this article correctly!). I did eventually find it and present it here for reference by my future-self, in a template function I called uninterrupted. Instead of
return TEMP_FAILURE_RETRY(read(sockFd, buf, len, flags));
you would write
return uninterrupted(read, sockFd, buf, len, flags);
The glue that gets it done looks like this:
template< class F, class... Args >
inline auto uninterrupted(F&& f, Args&&...args) ->
    decltype(std::forward<F>(f)(std::forward<Args>(args)...))
{
    decltype(std::forward<F>(f)(std::forward<Args>(args)...)) rc;
    do
    {
        rc = std::forward<F>(f)(std::forward<Args>(args)...);
    }
    while(rc == static_cast<decltype(rc)>(-1) && errno == EINTR);
    return rc;
}
It's type-safe. It's easy to use. It's concise. And a modern compiler will optimize it down to assembler that's as tight or more so, as what C could produce with the macro that inspired it. And you don't have to worry about getting all the trailing back-slashes right when you write it!

If that's "too geeky for you", fine... just keep moving.

No comments: