diff --git a/options/internal/generic/sigset.cpp b/options/internal/generic/sigset.cpp index ed4b7cb56..f3434bc27 100644 --- a/options/internal/generic/sigset.cpp +++ b/options/internal/generic/sigset.cpp @@ -3,6 +3,45 @@ #include #include #include +#include + +namespace { + +template struct remove_reference { typedef T type; }; +template struct remove_reference { typedef T type; }; + +// Assume that the struct has a member named 'sig'. +template +struct sigset_type_helper { + using type = typename remove_reference::type; + static_assert(offsetof(T, sig) == 0); +}; + +template<> +struct sigset_type_helper { using type = unsigned long; }; + +template<> +struct sigset_type_helper { using type = unsigned long long; }; + +template<> +struct sigset_type_helper { using type = long; }; + +template<> +struct sigset_type_helper { using type = long long; }; + +// Some ABIs define sigset_t as a simple integer (e.g unsigned long), +// while others define it as a struct containing an array of integers. +using sigset_underlying_type = sigset_type_helper::type; + +size_t signo_to_field(int signo) { + return signo / (sizeof(sigset_underlying_type) * CHAR_BIT); +} + +size_t signo_to_bit(int signo) { + return signo % (sizeof(sigset_underlying_type) * CHAR_BIT); +} + +} // namespace int sigemptyset(sigset_t *sigset) { memset(sigset, 0, sizeof(*sigset)); @@ -20,9 +59,9 @@ int sigaddset(sigset_t *sigset, int sig) { errno = EINVAL; return -1; } - auto ptr = reinterpret_cast(sigset); - int field = signo / (sizeof(unsigned long) * CHAR_BIT); - int bit = signo % (sizeof(unsigned long) * CHAR_BIT); + auto ptr = reinterpret_cast(sigset); + auto field = signo_to_field(signo); + auto bit = signo_to_bit(signo); ptr[field] |= (1UL << bit); return 0; } @@ -33,9 +72,9 @@ int sigdelset(sigset_t *sigset, int sig) { errno = EINVAL; return -1; } - auto ptr = reinterpret_cast(sigset); - int field = signo / (sizeof(unsigned long) * CHAR_BIT); - int bit = signo % (sizeof(unsigned long) * CHAR_BIT); + auto ptr = reinterpret_cast(sigset); + auto field = signo_to_field(signo); + auto bit = signo_to_bit(signo); ptr[field] &= ~(1UL << bit); return 0; } @@ -46,8 +85,8 @@ int sigismember(const sigset_t *sigset, int sig) { errno = EINVAL; return -1; } - auto ptr = reinterpret_cast(sigset); - int field = signo / (sizeof(unsigned long) * CHAR_BIT); - int bit = signo % (sizeof(unsigned long) * CHAR_BIT); + auto ptr = reinterpret_cast(sigset); + auto field = signo_to_field(signo); + auto bit = signo_to_bit(signo); return (ptr[field] & (1UL << bit)) != 0; }