Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions core/libs/prx/libkernel/Equeue/Equeue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ bool KernelEqueuePrivate::NextTimerWaitMicros(uint64_t nowNs, uint32_t* out) con
bool KernelEqueuePrivate::PollEvents() {
bool polled = false;
for (auto& ev : m_events) {
if (ev.filter.pollFunc != nullptr) {
if (ev.filter.pollFunc != nullptr && !ev.disabled) {
ev.triggered = ev.filter.pollFunc(&ev);
polled = true;
}
Expand All @@ -99,7 +99,7 @@ void KernelEqueuePrivate::WakePollers() {
void KernelEqueuePrivate::WaitForDescriptors(std::unique_lock<std::mutex>& lock, std::uint64_t deadlineNanos) {
std::vector<GuestSockets::Interest> interests;
for (const auto& e : m_events) {
if (e.filter.pollFunc != nullptr) {
if (e.filter.pollFunc != nullptr && !e.disabled) {
interests.push_back({static_cast<int>(e.event.ident), e.event.filter == EVFILT_WRITE});
}
}
Expand Down Expand Up @@ -152,7 +152,7 @@ int KernelEqueuePrivate::CollectOncePerWait(KernelEvent* ev, int num) {
std::list<KernelEqueueEvent> requeued;
for (auto it = m_events.begin(); it != m_events.end() && ret < num;) {
auto& e = *it;
if (!e.triggered) {
if (!e.triggered || e.disabled) {
++it;
continue;
}
Expand Down
3 changes: 2 additions & 1 deletion core/libs/prx/libkernel/Equeue/Equeue.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ struct KernelFilter {

struct KernelEqueueEvent {
bool triggered = false;
bool disabled = false;
uint64_t deadlineNs = 0;
uint64_t intervalNs = 0;
KernelEvent event;
Expand Down Expand Up @@ -114,7 +115,7 @@ bool IsKqueueDescriptor(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);
int AddVnodeEvent(const KernelEqueueRef& queue, int descriptor, uint32_t fflags, uint16_t flags, void* udata, bool disabled = false);
extern "C" {

KernelEqueueRef EqueuePin_nid_postfix(KernelEqueue eq);
Expand Down
3 changes: 2 additions & 1 deletion core/libs/prx/libkernel/Equeue/src/FileEvent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ void SetVnodeNotes(KernelEqueueEvent& event, std::uint32_t fflags) {
static_cast<VnodeWatch*>(event.filter.data)->SetInterest(fflags);
}

int AddVnodeEvent(const KernelEqueueRef& queue, int descriptor, std::uint32_t fflags, std::uint16_t flags, void* udata) {
int AddVnodeEvent(const KernelEqueueRef& queue, int descriptor, std::uint32_t fflags, std::uint16_t flags, void* udata, bool disabled) {
RequireVnodeNotes(fflags);
if (const int error = VnodeDescriptorError(descriptor)) {
return error;
Expand All @@ -597,6 +597,7 @@ int AddVnodeEvent(const KernelEqueueRef& queue, int descriptor, std::uint32_t ff
throw;
}
KernelEqueueEvent event{};
event.disabled = disabled;
event.event.ident = static_cast<std::uintptr_t>(descriptor);
event.event.filter = EVFILT_VNODE;
event.event.flags = flags;
Expand Down
13 changes: 10 additions & 3 deletions core/libs/prx/libkernel/Equeue/src/Kqueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ int AddDescriptorKnote(const KernelEqueueRef& queue, KernelEvent& change, std::u
NotImplemented_nid_no_patch("kevent: EV_CLEAR on a socket");
}
auto event = EqueueDescriptorEvent(descriptor, change.filter, flags, change.udata);
event.disabled = (change.flags & EV_DISABLE) != 0;
change.fflags = 0;
change.data = 0;
return GuestErrno(queue->AddEvent(event));
Expand Down Expand Up @@ -180,6 +181,7 @@ int AddTimerKnote(const KernelEqueueRef& queue, KernelEvent& change, std::uint16

int AddUserKnote(const KernelEqueueRef& queue, KernelEvent& change, std::uint16_t flags) {
KernelEqueueEvent event{};
event.disabled = (change.flags & EV_DISABLE) != 0;
event.event = change;
event.event.flags = flags;
event.filter.resetFunc = [](KernelEqueueEvent* e) {
Expand Down Expand Up @@ -228,6 +230,11 @@ int ModifyKnote(const KernelEqueueRef& queue, KernelEvent& change) {
} else if (change.filter == EVFILT_VNODE) {
SetVnodeNotes(event, change.fflags);
}
if ((change.flags & EV_ENABLE) != 0) {
event.disabled = false;
} else if ((change.flags & EV_DISABLE) != 0) {
event.disabled = true;
}
}));
}

Expand All @@ -241,8 +248,8 @@ int Register(const KernelEqueueRef& queue, int kqueueDescriptor, KernelEvent& ch
if (change.filter != EVFILT_READ && change.filter != EVFILT_WRITE && change.filter != EVFILT_VNODE && change.filter != EVFILT_TIMER && change.filter != EVFILT_USER) {
NotImplemented_nid_no_patch(("kevent: filter " + std::to_string(change.filter)).c_str());
}
if ((change.flags & EV_DISABLE) != 0) {
NotImplemented_nid_no_patch("kevent: EV_DISABLE");
if ((change.flags & EV_DISABLE) != 0 && change.filter == EVFILT_TIMER) {
NotImplemented_nid_no_patch("kevent: EV_DISABLE on EVFILT_TIMER");
}
if ((change.flags & EV_DISPATCH) != 0) {
NotImplemented_nid_no_patch("kevent: EV_DISPATCH");
Expand Down Expand Up @@ -270,7 +277,7 @@ int Register(const KernelEqueueRef& queue, int kqueueDescriptor, KernelEvent& ch
const std::uint32_t notes = change.fflags;
change.fflags = 0;
change.data = 0;
return AddVnodeEvent(queue, static_cast<int>(change.ident), notes, flags, change.udata);
return AddVnodeEvent(queue, static_cast<int>(change.ident), notes, flags, change.udata, (change.flags & EV_DISABLE) != 0);
}
return AddDescriptorKnote(queue, change, flags);
}
Expand Down
77 changes: 76 additions & 1 deletion core/libs/tests/GuestKqueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ static void Errors() {
RequireFailure(Apply(kq, Change(static_cast<std::uintptr_t>(kq), EvfiltRead, EvAdd)), GuestEinval);
RequireFailure(Apply(kq, Change(1, 1, EvAdd)), GuestEinval);
Require(Throws([kq] { Apply(kq, Change(1, EvfiltProc, EvAdd)); }));
Require(Throws([kq] { Apply(kq, Change(1, EvfiltUser, EvAdd | EvDisable)); }));
Require(Throws([kq] { Apply(kq, Change(1, EvfiltTimer, EvAdd | EvDisable, 0, 5)); }));
int pipe[2];
Require(pipe_nid_postfix(pipe) == 0);
Require(Throws([kq, &pipe] { Apply(kq, Change(static_cast<std::uintptr_t>(pipe[0]), EvfiltRead, EvAdd)); }));
Expand Down Expand Up @@ -400,6 +400,80 @@ static void DirectoryWatch() {
Require(std::filesystem::remove_all(path) == 1);
}

static void DisabledEvents() {
const int kq = kqueue_nid_postfix();
int marker = 0;
KernelEvent events[4]{};
RequireFailure(Apply(kq, Change(20, EvfiltUser, EvEnable)), GuestEnoent);
RequireFailure(Apply(kq, Change(20, EvfiltUser, EvDisable)), GuestEnoent);

Require(Apply(kq, Change(20, EvfiltUser, EvAdd | EvDisable, 0, 0, &marker)) == 0);
Require(Apply(kq, Change(20, EvfiltUser, 0, NoteTrigger, 0, &marker)) == 0);
Require(Poll(kq, events, 4) == 0);
Require(Apply(kq, Change(20, EvfiltUser, EvEnable, 0, 0, &marker)) == 0);
Require(Poll(kq, events, 4) == 1 && events[0].ident == 20 && events[0].flags == 0 && events[0].udata == &marker);
Require(Apply(kq, Change(20, EvfiltUser, EvDisable, 0, 0, &marker)) == 0);
Require(Poll(kq, events, 4) == 0);
Require(Apply(kq, Change(20, EvfiltUser, EvAdd, 0, 0, &marker)) == 0);
Require(Poll(kq, events, 4) == 0);
Require(Apply(kq, Change(20, EvfiltUser, EvEnable, 0, 0, &marker)) == 0);
Require(Poll(kq, events, 4) == 1 && events[0].ident == 20);
Require(Apply(kq, Change(20, EvfiltUser, EvDelete | EvDisable)) == 0);
RequireFailure(Apply(kq, Change(20, EvfiltUser, EvDelete)), GuestEnoent);

Require(Apply(kq, Change(21, EvfiltUser, EvAdd | EvClear)) == 0);
Require(Apply(kq, Change(21, EvfiltUser, EvDisable, NoteTrigger | NoteFfcopy | 0x7, 5)) == 0);
Require(Poll(kq, events, 4) == 0);
Require(Apply(kq, Change(21, EvfiltUser, EvEnable, NoteFfor | 0x8, 6)) == 0);
Require(Poll(kq, events, 4) == 1 && events[0].ident == 21 && events[0].fflags == 0xf && events[0].data == 6 && events[0].flags == EvClear);
Require(Poll(kq, events, 4) == 0);
Require(Apply(kq, Change(21, EvfiltUser, EvDelete)) == 0);

Require(Apply(kq, Change(22, EvfiltUser, EvAdd | EvOneshot | EvDisable)) == 0);
Require(Apply(kq, Change(22, EvfiltUser, 0, NoteTrigger)) == 0);
Require(Poll(kq, events, 4) == 0);
std::thread enable([kq] {
std::this_thread::sleep_for(std::chrono::milliseconds(20));
Require(Apply(kq, Change(22, EvfiltUser, EvEnable)) == 0);
});
Require(kevent_nid_postfix(kq, nullptr, 0, events, 4, nullptr) == 1);
enable.join();
Require(events[0].ident == 22 && events[0].flags == EvOneshot);
RequireFailure(Apply(kq, Change(22, EvfiltUser, EvDelete)), GuestEnoent);

int pair[2];
Require(socketpair_nid_postfix(Unix, Stream, 0, pair) == 0);
const auto reader = static_cast<std::uintptr_t>(pair[0]);
Require(Apply(kq, Change(reader, EvfiltRead, EvAdd | EvDisable)) == 0);
Require(send_nid_postfix(pair[1], "abc", 3, 0) == 3);
const KernelTimespec timeout{0, 30000000};
const auto start = std::chrono::steady_clock::now();
Require(kevent_nid_postfix(kq, nullptr, 0, events, 4, &timeout) == 0);
Require(std::chrono::steady_clock::now() - start >= std::chrono::milliseconds(29));
Require(Apply(kq, Change(reader, EvfiltRead, EvEnable)) == 0);
Require(Wait(kq, events, 4) == 1 && events[0].ident == reader && events[0].filter == EvfiltRead && events[0].data == 3 && events[0].flags == 0);
Require(Apply(kq, Change(reader, EvfiltRead, EvDisable)) == 0);
Require(Poll(kq, events, 4) == 0);
Require(Apply(kq, Change(reader, EvfiltRead, EvEnable)) == 0);
Require(Poll(kq, events, 4) == 1 && events[0].data == 3);
Require(close_nid_postfix(pair[0]) == 0 && close_nid_postfix(pair[1]) == 0);

const auto path = TemporaryName("disabled");
const int file = open_nid_postfix(path.c_str(), ReadWrite | Create, 0644);
Require(file >= 0);
const auto ident = static_cast<std::uintptr_t>(file);
Require(Apply(kq, Change(ident, EvfiltVnode, EvAdd | EvClear | EvDisable, NoteWrite | NoteExtend)) == 0);
Require(write_nid_postfix(file, "abc", 3) == 3);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
Require(Poll(kq, events, 4) == 0);
Require(Apply(kq, Change(ident, EvfiltVnode, EvEnable, NoteWrite | NoteExtend)) == 0);
Require(Poll(kq, events, 4) == 1 && events[0].ident == ident && events[0].fflags == (NoteWrite | NoteExtend) && events[0].flags == EvClear);
Require(Poll(kq, events, 4) == 0);
Require(close_nid_postfix(file) == 0);
Require(std::filesystem::remove(path));
Require(close_nid_postfix(kq) == 0);
}

static void Timeout() {
const int kq = kqueue_nid_postfix();
KernelEvent event{};
Expand All @@ -423,6 +497,7 @@ int main() {
MoveDirectoryEntries();
#endif
DirectoryWatch();
DisabledEvents();
Timeout();
return 0;
}
Loading
Loading