Skip to content

Commit

Permalink
options/internal: detect underlying type of sigset_t
Browse files Browse the repository at this point in the history
  • Loading branch information
64 committed Oct 13, 2024
1 parent 2c41220 commit 80bcdab
Showing 1 changed file with 46 additions and 9 deletions.
55 changes: 46 additions & 9 deletions options/internal/generic/sigset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,43 @@
#include <errno.h>
#include <limits.h>
#include <string.h>
#include <stddef.h>

namespace {

template<class T> struct remove_reference { typedef T type; };
template<class T> struct remove_reference<T&> { typedef T type; };

// Assume that the struct has a member named 'sig'.
template<typename T>
struct sigset_type_helper {
using type = typename remove_reference<decltype(T::sig[0])>::type;
static_assert(offsetof(T, sig) == 0);
};

template<>
struct sigset_type_helper<unsigned long> {
using type = unsigned long;
};

template<>
struct sigset_type_helper<long> {
using type = 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<sigset_t>::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));
Expand All @@ -20,9 +57,9 @@ int sigaddset(sigset_t *sigset, int sig) {
errno = EINVAL;
return -1;
}
auto ptr = reinterpret_cast<unsigned long *>(sigset);
int field = signo / (sizeof(unsigned long) * CHAR_BIT);
int bit = signo % (sizeof(unsigned long) * CHAR_BIT);
auto ptr = reinterpret_cast<sigset_underlying_type *>(sigset);
auto field = signo_to_field(signo);
auto bit = signo_to_bit(signo);
ptr[field] |= (1UL << bit);
return 0;
}
Expand All @@ -33,9 +70,9 @@ int sigdelset(sigset_t *sigset, int sig) {
errno = EINVAL;
return -1;
}
auto ptr = reinterpret_cast<unsigned long *>(sigset);
int field = signo / (sizeof(unsigned long) * CHAR_BIT);
int bit = signo % (sizeof(unsigned long) * CHAR_BIT);
auto ptr = reinterpret_cast<sigset_underlying_type *>(sigset);
auto field = signo_to_field(signo);
auto bit = signo_to_bit(signo);
ptr[field] &= ~(1UL << bit);
return 0;
}
Expand All @@ -46,8 +83,8 @@ int sigismember(const sigset_t *sigset, int sig) {
errno = EINVAL;
return -1;
}
auto ptr = reinterpret_cast<const unsigned long *>(sigset);
int field = signo / (sizeof(unsigned long) * CHAR_BIT);
int bit = signo % (sizeof(unsigned long) * CHAR_BIT);
auto ptr = reinterpret_cast<const sigset_underlying_type *>(sigset);
auto field = signo_to_field(signo);
auto bit = signo_to_bit(signo);
return (ptr[field] & (1UL << bit)) != 0;
}

0 comments on commit 80bcdab

Please sign in to comment.