Skip to content

Commit

Permalink
fix: corrected an error in the event loop handling that could lead to…
Browse files Browse the repository at this point in the history
… a crash in certain circumstances
  • Loading branch information
jacopodl committed May 13, 2024
1 parent e3caab1 commit 09657e3
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 15 deletions.
17 changes: 12 additions & 5 deletions argon/vm/loop2/epoll.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@
using namespace argon::vm::loop2;

bool argon::vm::loop2::AddEvent(EvLoop *loop, EvLoopQueue *ev_queue, Event *event, EvLoopQueueDirection direction,
unsigned int timeout) {
unsigned int timeout) {
epoll_event ep_event{};

event->fiber = vm::GetFiber();

std::unique_lock _(ev_queue->lock);

if (ev_queue->in_events.Count() == 0 && ev_queue->out_events.Count() == 0) {
if (!ev_queue->in_set && !ev_queue->out_set) {
ep_event.events = EPOLLOUT | EPOLLIN | EPOLLET;
ep_event.data.ptr = ev_queue;

Expand All @@ -35,6 +35,9 @@ bool argon::vm::loop2::AddEvent(EvLoop *loop, EvLoopQueue *ev_queue, Event *even

return false;
}

ev_queue->in_set = true;
ev_queue->out_set = true;
}

if (timeout > 0) {
Expand Down Expand Up @@ -104,9 +107,13 @@ bool argon::vm::loop2::IOPoll(EvLoop *loop, unsigned long timeout) {

std::unique_lock _(ev_queue->lock);

if (ev_queue->in_events.Count() == 0 && ev_queue->out_events.Count() == 0 &&
epoll_ctl(loop->handle, EPOLL_CTL_DEL, ev_queue->handle, nullptr) < 0)
assert(false); // Never get here!
if (ev_queue->in_events.Count() == 0 && ev_queue->out_events.Count() == 0) {
if (epoll_ctl(loop->handle, EPOLL_CTL_DEL, ev_queue->handle, nullptr) < 0)
assert(false); // Never get here!

ev_queue->in_set = false;
ev_queue->out_set = false;
}
}

return true;
Expand Down
16 changes: 14 additions & 2 deletions argon/vm/loop2/evloop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,9 @@ Event *argon::vm::loop2::EventNew(EvLoop *loop, ArObject *initiator) {
event = (Event *) memory::Calloc(sizeof(Event));
if (event == nullptr)
return nullptr;
}

new(&event->lock)std::mutex();
new(&event->lock)std::mutex();
}

event->initiator = IncRef(initiator);

Expand Down Expand Up @@ -198,6 +198,16 @@ void argon::vm::loop2::EventDel(Event *event) {
std::unique_lock _(loop->lock);

if (loop->free_events.Count() + 1 <= kMaxFreeEvents) {
event->callback = nullptr;
event->user_callback = nullptr;

event->aux = nullptr;
event->initiator = nullptr;

event->timeout = 0;
event->id = 0;
event->discard_on_timeout = false;

loop->free_events.Push(event);

return;
Expand Down Expand Up @@ -229,6 +239,8 @@ void argon::vm::loop2::QueueDel(EvLoopQueue **ev_queue) {
while ((event = queue->out_events.Dequeue()) != nullptr)
EventDel(event);

printf("Chiusa coda: %d\n", (*ev_queue)->handle);

queue->lock.~mutex();

argon::vm::memory::Free(queue);
Expand Down
4 changes: 4 additions & 0 deletions argon/vm/loop2/evloop.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ namespace argon::vm::loop2 {

EventQueue out_events;

bool in_set;

bool out_set;

EvHandle handle;
};

Expand Down
48 changes: 40 additions & 8 deletions argon/vm/loop2/kqueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,40 @@ using namespace argon::vm::loop2;
bool argon::vm::loop2::AddEvent(EvLoop *loop, EvLoopQueue *ev_queue, Event *event, EvLoopQueueDirection direction,
unsigned int timeout) {
struct kevent kev[2];
int changes = 0;

bool in_selected = false;

event->fiber = vm::GetFiber();

std::unique_lock _(ev_queue->lock);

if (ev_queue->in_events.Count() == 0 && ev_queue->out_events.Count() == 0) {
if (direction == EvLoopQueueDirection::IN && !ev_queue->in_set) {
EV_SET(kev, ev_queue->handle, EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, ev_queue);
EV_SET(kev + 1, ev_queue->handle, EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, ev_queue);
ev_queue->in_set = true;
in_selected = true;
changes++;
}

if (direction == EvLoopQueueDirection::OUT && !ev_queue->out_set) {
EV_SET(kev + changes, ev_queue->handle, EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, ev_queue);
ev_queue->out_set = true;
changes++;
}

if (changes > 0) {
auto res = kevent(loop->handle, kev, changes, nullptr, 0, nullptr);
if (res < 0) {
if (changes > 1) {
ev_queue->in_set = false;
ev_queue->out_set = false;
} else {
if (in_selected)
ev_queue->in_set = false;
else
ev_queue->out_set = false;
}

if (kevent(loop->handle, kev, 2, nullptr, 0, nullptr) < 0) {
_.unlock();

vm::SetFiberStatus(FiberStatus::RUNNING);
Expand Down Expand Up @@ -84,8 +108,8 @@ bool argon::vm::loop2::EvLoopInit(EvLoop *loop) {
bool argon::vm::loop2::IOPoll(EvLoop *loop, unsigned long timeout) {
struct kevent events[kMaxEvents];
struct kevent kev[2];
timespec ts{};

timespec ts{};
ts.tv_sec = (long) timeout / 1000;
ts.tv_nsec = (long) ((timeout % 1000) * 1000000);

Expand All @@ -108,13 +132,21 @@ bool argon::vm::loop2::IOPoll(EvLoop *loop, unsigned long timeout) {

std::unique_lock _(ev_queue->lock);

if (ev_queue->in_events.Count() == 0 && ev_queue->out_events.Count() == 0) {
int changes = 0;
if (events[i].filter == EVFILT_READ && ev_queue->in_events.Count() == 0) {
EV_SET(kev, ev_queue->handle, EVFILT_READ, EV_DELETE, 0, 0, nullptr);
EV_SET(kev + 1, ev_queue->handle, EVFILT_WRITE, EV_DELETE, 0, 0, nullptr);
ev_queue->in_set = false;
changes++;
}

if (kevent(loop->handle, kev, 2, nullptr, 0, nullptr) < 0)
assert(false); // Never get here!
if (events[i].filter == EVFILT_WRITE && ev_queue->out_events.Count() == 0) {
EV_SET(kev + changes, ev_queue->handle, EVFILT_WRITE, EV_DELETE, 0, 0, nullptr);
ev_queue->out_set = false;
changes++;
}

if (changes > 0 && kevent(loop->handle, kev, changes, nullptr, 0, nullptr) < 0)
assert(false); // Never get here!
}

return true;
Expand Down

0 comments on commit 09657e3

Please sign in to comment.