<commit_before>#include <system_error>
#include <mutex>
#include <type_traits>
#include <unordered_map>
#include <vector>

#ifdef __OpenBSD__
#include <sys/signal.h> // for __thrsigdivert aka sigtimedwait
#include <sys/syscall.h>
extern "C" { 
    int __thrsigdivert(sigset_t set, siginfo_t *info, const struct timespec * timeout);
}
#endif

#include <sys/event.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>

#include <unistd.h>
#include <signal.h>

namespace dasynq {

template <class Base> class KqueueLoop;

class KqueueTraits
{
    template <class Base> friend class KqueueLoop;

    public:

    class SigInfo
    {
        template <class Base> friend class KqueueLoop;
        
        siginfo_t info;
        
        public:
        int get_signo() { return info.si_signo; }
        int get_sicode() { return info.si_code; }
        void * get_ssiaddr() { return info.si_addr; }
        
        void set_signo(int signo) { info.si_signo = signo; }
    };    

    class FD_r;

    // File descriptor optional storage. If the mechanism can return the file descriptor, this
    // class will be empty, otherwise it can hold a file descriptor.
    class FD_s {
        // Epoll doesn't return the file descriptor (it can, but it can't return both file
        // descriptor and user data).
        // TODO make true empty.
    };

    // File descriptor reference (passed to event callback). If the mechanism can return the
    // file descriptor, this class holds the file descriptor. Otherwise, the file descriptor
    // must be stored in an FD_s instance.
    class FD_r {
        int fd;
        public:
        int getFd(FD_s ss)
        {
            return fd;
        }
        FD_r(int nfd) : fd(nfd)
        {
        }
    };
    
    const static bool has_bidi_fd_watch = false;
    const static bool has_separate_rw_fd_watches = true;
    const static bool supports_childwatch_reservation = true;
};

#if defined(__OpenBSD__)
// OpenBSD has no sigtimedwait (or sigwaitinfo) but does have "__thrsigdivert", which is
// essentially an incomplete version of the same thing. Discussion with OpenBSD developer
// <NAME> suggested that the siginfo_t structure returned might not always have all
// fields set correctly. Furthermore there is a bug such that specifying a zero timeout (or
// indeed any timeout less than a tick) results in NO timeout. We get around this by instead
// specifying an *invalid* timeout, which won't error out if a signal is pending.
static inline int sigtimedwait(const sigset_t *ssp, siginfo_t *info, struct timespec *timeout)
{
    // We know that we're only called with a timeout of 0 (which doesn't work properly) and
    // that we safely overwrite the timeout. So, we set tv_nsec to an invalid value, which
    // will cause EINVAL to be returned, but will still pick up any pending signals *first*.
    timeout->tv_nsec = 1000000001;
    return __thrsigdivert(*ssp, info, timeout);
}

static inline void prepare_signal(int signo) { }
static inline void unprep_signal(int signo) { }

static bool get_siginfo(int signo, siginfo_t *siginfo)
{
    struct timespec timeout;
    timeout.tv_sec = 0;
    timeout.tv_nsec = 0;

    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, signo);
    return (sigtimedwait(&mask, siginfo, &timeout) != -1);
}

#elif defined(__APPLE__)

static siginfo_t * siginfo_p;

static void signalHandler(int signo, siginfo_t *siginfo, void *v)
{
    *siginfo_p = *siginfo;
}

static inline void prepare_signal(int signo)
{
    struct sigaction the_action;
    the_action.sa_sigaction = signalHandler;
    the_action.sa_flags = SA_SIGINFO;
    sigfillset(&the_action.sa_mask);

    sigaction(signo, &the_action, nullptr);
}

static inline void unprep_signal(int signo)
{
    signal(signo, SIG_DFL);
}

static bool get_siginfo(int signo, siginfo_t *siginfo)
{
    siginfo_p = siginfo;

    sigset_t mask;
    sigfillset(&mask);
    sigdelset(&mask, signo);
    sigsuspend(&mask);
    return true;
}

#endif

template <class Base> class KqueueLoop : public Base
{
    int kqfd; // kqueue fd
    sigset_t sigmask; // enabled signal watch mask

    // Map of signal number to user data pointer. If kqueue had been better thought-through,
    // we shouldn't need this. Although we can associate user data with an EVFILT_SIGNAL kqueue
    // filter, the problem is that the kqueue signal report *coexists* with the regular signal
    // delivery mechanism without having any connection to it. Whereas regular signals can be
    // queued (especially "realtime" signals, via sigqueue()), kqueue just maintains a counter
    // of delivery attempts and clears this when we read the event. What this means is that
    // kqueue won't necessarily tell us if signals are pending, in the case that:
    //  1) it already reported the attempted signal delivery and
    //  2) more than one of the same signal was pending at that time and
    //  3) no more deliveries of the same signal have been attempted in the meantime.<commit_msg>Silence compiler warning (and avoid technically UB).<commit_after>#include <system_error>
#include <mutex>
#include <type_traits>
#include <unordered_map>
#include <vector>

#ifdef __OpenBSD__
#include <sys/signal.h> // for __thrsigdivert aka sigtimedwait
#include <sys/syscall.h>
extern "C" { 
    int __thrsigdivert(sigset_t set, siginfo_t *info, const struct timespec * timeout);
}
#endif

#include <sys/event.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>

#include <unistd.h>
#include <signal.h>

namespace dasynq {

template <class Base> class KqueueLoop;

class KqueueTraits
{
    template <class Base> friend class KqueueLoop;

    public:

    class SigInfo
    {
        template <class Base> friend class KqueueLoop;
        
        siginfo_t info;
        
        public:
        int get_signo() { return info.si_signo; }
        int get_sicode() { return info.si_code; }
        void * get_ssiaddr() { return info.si_addr; }
        
        void set_signo(int signo) { info.si_signo = signo; }
    };    

    class FD_r;

    // File descriptor optional storage. If the mechanism can return the file descriptor, this
    // class will be empty, otherwise it can hold a file descriptor.
    class FD_s {
        // Epoll doesn't return the file descriptor (it can, but it can't return both file
        // descriptor and user data).
        // TODO make true empty.
    };

    // File descriptor reference (passed to event callback). If the mechanism can return the
    // file descriptor, this class holds the file descriptor. Otherwise, the file descriptor
    // must be stored in an FD_s instance.
    class FD_r {
        int fd;
        public:
        int getFd(FD_s ss)
        {
            return fd;
        }
        FD_r(int nfd) : fd(nfd)
        {
        }
    };
    
    const static bool has_bidi_fd_watch = false;
    const static bool has_separate_rw_fd_watches = true;
    const static bool supports_childwatch_reservation = true;
};

#if defined(__OpenBSD__)
// OpenBSD has no sigtimedwait (or sigwaitinfo) but does have "__thrsigdivert", which is
// essentially an incomplete version of the same thing. Discussion with OpenBSD developer
// <NAME> suggested that the siginfo_t structure returned might not always have all
// fields set correctly. Furthermore there is a bug such that specifying a zero timeout (or
// indeed any timeout less than a tick) results in NO timeout. We get around this by instead
// specifying an *invalid* timeout, which won't error out if a signal is pending.
static inline int sigtimedwait(const sigset_t *ssp, siginfo_t *info, struct timespec *timeout)
{
    // We know that we're only called with a timeout of 0 (which doesn't work properly) and
    // that we safely overwrite the timeout. So, we set tv_nsec to an invalid value, which
    // will cause EINVAL to be returned, but will still pick up any pending signals *first*.
    timeout->tv_nsec = 1000000001;
    return __thrsigdivert(*ssp, info, timeout);
}

static inline void prepare_signal(int signo) { }
static inline void unprep_signal(int signo) { }

static bool get_siginfo(int signo, siginfo_t *siginfo)
{
    struct timespec timeout;
    timeout.tv_sec = 0;
    timeout.tv_nsec = 0;

    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, signo);
    return (sigtimedwait(&mask, siginfo, &timeout) != -1);
}

#elif defined(__APPLE__)

static siginfo_t * siginfo_p;

static void signalHandler(int signo, siginfo_t *siginfo, void *v)
{
    *siginfo_p = *siginfo;
}

static inline void prepare_signal(int signo)
{
    struct sigaction the_action;
    the_action.sa_sigaction = signalHandler;
    the_action.sa_flags = SA_SIGINFO;
    sigfillset(&the_action.sa_mask);

    sigaction(signo, &the_action, nullptr);
}

static inline void unprep_signal(int signo)
{
    signal(signo, SIG_DFL);
}

static inline bool get_siginfo(int signo, siginfo_t *siginfo)
{
    siginfo_p = siginfo;

    sigset_t mask;
    sigfillset(&mask);
    sigdelset(&mask, signo);
    sigsuspend(&mask);
    return true;
}

#endif

template <class Base> class KqueueLoop : public Base
{
    int kqfd; // kqueue fd
    sigset_t sigmask; // enabled signal watch mask

    // Map of signal number to user data pointer. If kqueue had been better thought-through,
    // we shouldn't need this. Although we can associate user data with an EVFILT_SIGNAL kqueue
    // filter, the problem is that the kqueue signal report *coexists* with the regular signal
    // delivery mechanism without having any connection to it. Whereas regular signals can be
    // queued (especially "realtime" signals, via sigqueue()), kqueue just maintains a counter
    // of delivery attempts and clears this when we read the event. What this means is that
    // kqueue won't necessarily tell us if signals are pending, in the case that:
    //  1) it already reported the attempted signal delivery and
    //  2) more than one of the same signal was pending at that time and
    //  3) no more deliveries of the same signal have been attempted in the meantime.
{'fraction_non_alphanumeric': 0.08224465558194774, 'fraction_numerical': 0.0033650039588281866, 'mean_word_length': 3.1363078182562423, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2432897', 'n_tokens_mistral': 3119, 'n_tokens_neox': 3018, 'n_words': 1168}