mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 16:43:05 -05:00
A kqueue descriptor is readable while one of its events is triggered and is never writable or exceptional, as FreeBSD's kqueue_poll answers, on both hosts. On Windows select threw for it, and on Linux its /dev/null placeholder was reported readable and writable. A descriptor that stops being a socket, a kqueue or a pipe during the wait now fails the call with EBADF when it was closed and is selected again with the rest of the timeout when its number was reused, as FreeBSD's kern_select looks every descriptor up again in each pass, instead of throwing. On Windows a host descriptor that is not a pipe throws when select starts, before waiting. Depends on #7139. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
133 lines
4.8 KiB
C++
133 lines
4.8 KiB
C++
#ifndef CORE_LIBS_PRX_LIBKERNEL_EQUEUE_EQUEUE_HPP
|
|
#define CORE_LIBS_PRX_LIBKERNEL_EQUEUE_EQUEUE_HPP
|
|
|
|
#include <cstdint>
|
|
#include <deque>
|
|
#include <functional>
|
|
#include <list>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
#include "SceTypes.hpp"
|
|
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include "prx/libkernel/KernelErrors.hpp"
|
|
#include "prx/libkernel/Time/include/TimedWait.hpp"
|
|
|
|
static constexpr int16_t EVFILT_READ = -1;
|
|
static constexpr int16_t EVFILT_WRITE = -2;
|
|
static constexpr int16_t EVFILT_VNODE = -4;
|
|
static constexpr int16_t EVFILT_TIMER = -7;
|
|
static constexpr int16_t EVFILT_USER = -11;
|
|
static constexpr int16_t EVFILT_VIDEO_OUT = -13;
|
|
static constexpr int16_t EVFILT_HRTIMER = -15;
|
|
static constexpr int16_t EVFILT_AMPR = -25;
|
|
|
|
static constexpr uint16_t EV_ADD = 0x0001;
|
|
static constexpr uint16_t EV_DELETE = 0x0002;
|
|
static constexpr uint16_t EV_ENABLE = 0x0004;
|
|
static constexpr uint16_t EV_DISABLE = 0x0008;
|
|
static constexpr uint16_t EV_ONESHOT = 0x0010;
|
|
static constexpr uint16_t EV_CLEAR = 0x0020;
|
|
static constexpr uint16_t EV_RECEIPT = 0x0040;
|
|
static constexpr uint16_t EV_DISPATCH = 0x0080;
|
|
static constexpr uint16_t EV_FORCEONESHOT = 0x0100;
|
|
static constexpr uint16_t EV_SYSFLAGS = 0xF000;
|
|
static constexpr uint16_t EV_ERROR = 0x4000;
|
|
static constexpr uint16_t EV_EOF = 0x8000;
|
|
|
|
static constexpr int EQUEUE_OK = 0;
|
|
|
|
struct KernelEqueueEvent;
|
|
|
|
using EqueueTriggerFunc = void (*)(KernelEqueueEvent* event, void* triggerData);
|
|
using EqueueResetFunc = void (*)(KernelEqueueEvent* event);
|
|
using EqueueDeleteFunc = void (*)(KernelEqueue eq, KernelEqueueEvent* event);
|
|
using EqueuePollFunc = bool (*)(KernelEqueueEvent* event);
|
|
|
|
struct KernelFilter {
|
|
void* data = nullptr;
|
|
std::shared_ptr<void> owner;
|
|
EqueueTriggerFunc triggerFunc = nullptr;
|
|
EqueueResetFunc resetFunc = nullptr;
|
|
EqueueDeleteFunc deleteEventFunc = nullptr;
|
|
EqueuePollFunc pollFunc = nullptr;
|
|
};
|
|
|
|
struct KernelEqueueEvent {
|
|
bool triggered = false;
|
|
bool enabled = true;
|
|
uint64_t deadlineNs = 0;
|
|
uint64_t intervalNs = 0;
|
|
std::int64_t lowWater = 0;
|
|
KernelEvent event;
|
|
KernelFilter filter;
|
|
std::deque<KernelEvent> pendingEvents;
|
|
};
|
|
|
|
class KernelEqueuePrivate {
|
|
public:
|
|
explicit KernelEqueuePrivate(KernelEqueue handle, bool reportOncePerWait = false);
|
|
~KernelEqueuePrivate();
|
|
|
|
KernelEqueuePrivate(const KernelEqueuePrivate&) = delete;
|
|
KernelEqueuePrivate& operator=(const KernelEqueuePrivate&) = delete;
|
|
|
|
const std::string& GetName() const { return m_name; }
|
|
void SetName(std::string name) { m_name = std::move(name); }
|
|
|
|
int AddEvent(const KernelEqueueEvent& event);
|
|
int TriggerEvent(uintptr_t ident, int16_t filter, void* triggerData);
|
|
int DeleteEvent(uintptr_t ident, int16_t filter);
|
|
bool HasEvent(uintptr_t ident, int16_t filter);
|
|
int EditEvent(uintptr_t ident, int16_t filter, const std::function<void(KernelEqueueEvent&)>& edit);
|
|
int GetTriggeredEvents(KernelEvent* ev, int num);
|
|
bool HasTriggeredEvents();
|
|
int WaitForEvents(KernelEvent* ev, int num, uint32_t micros);
|
|
int WaitForEventsUntil(KernelEvent* ev, int num, std::uint64_t deadlineNanos);
|
|
void RemoveDescriptorEvents(uintptr_t ident);
|
|
void Close();
|
|
static uint64_t MonotonicNs();
|
|
|
|
private:
|
|
void TriggerExpiredTimers(uint64_t nowNs);
|
|
bool NextTimerWaitMicros(uint64_t nowNs, uint32_t* out) const;
|
|
int CollectTriggered(KernelEvent* ev, int num);
|
|
int CollectOncePerWait(KernelEvent* ev, int num);
|
|
bool PollEvents();
|
|
void WakePollers();
|
|
void WaitForDescriptors(std::unique_lock<std::mutex>& lock, std::uint64_t deadlineNanos);
|
|
|
|
std::list<KernelEqueueEvent> m_events;
|
|
std::vector<std::uintptr_t> m_pollers;
|
|
std::mutex m_mutex;
|
|
TimedWait::Condition m_cond;
|
|
std::string m_name;
|
|
KernelEqueue m_handle;
|
|
bool m_reportOncePerWait;
|
|
bool m_closed = false;
|
|
};
|
|
|
|
using KernelEqueueRef = std::shared_ptr<KernelEqueuePrivate>;
|
|
void EqueueDescriptorClosed(int descriptor);
|
|
void KqueueDescriptorClosed(int descriptor);
|
|
bool IsKqueueDescriptor(int descriptor);
|
|
std::optional<bool> KqueueReadable(int descriptor);
|
|
KernelEqueueEvent EqueueDescriptorEvent(int descriptor, int16_t filter, uint16_t flags, void* udata);
|
|
void RequireVnodeNotes(uint32_t fflags);
|
|
void SetVnodeNotes(KernelEqueueEvent& event, uint32_t fflags);
|
|
int AddVnodeEvent(const KernelEqueueRef& queue, int descriptor, uint32_t fflags, uint16_t flags, void* udata);
|
|
extern "C" {
|
|
|
|
KernelEqueueRef EqueuePin_nid_postfix(KernelEqueue eq);
|
|
int APS5_VABI EqueueAddEvent_nid_postfix(KernelEqueue eq, const KernelEqueueEvent& event);
|
|
int APS5_VABI EqueueTriggerEvent_nid_postfix(KernelEqueue eq, uintptr_t ident, int16_t filter, void* triggerData);
|
|
int APS5_VABI EqueueDeleteEvent_nid_postfix(KernelEqueue eq, uintptr_t ident, int16_t filter);
|
|
|
|
}
|
|
|
|
#endif
|