void pony_asio_event_subscribe(asio_event_t* ev) { if((ev == NULL) || (ev->flags == ASIO_DISPOSABLE) || (ev->flags == ASIO_DESTROYED)) return; asio_backend_t* b = ponyint_asio_get_backend(); if(ev->noisy) ponyint_asio_noisy_add(); struct epoll_event ep; ep.data.ptr = ev; ep.events = EPOLLRDHUP | EPOLLET; if(ev->flags & ASIO_READ) ep.events |= EPOLLIN; if(ev->flags & ASIO_WRITE) ep.events |= EPOLLOUT; if(ev->flags & ASIO_TIMER) { ev->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); timer_set_nsec(ev->fd, ev->nsec); ep.events |= EPOLLIN; } if(ev->flags & ASIO_SIGNAL) { int sig = (int)ev->nsec; asio_event_t* prev = NULL; if((sig < MAX_SIGNAL) && atomic_compare_exchange_strong_explicit(&b->sighandlers[sig], &prev, ev, memory_order_release, memory_order_relaxed)) { signal(sig, signal_handler); ev->fd = eventfd(0, EFD_NONBLOCK); ep.events |= EPOLLIN; } else { return; } } epoll_ctl(b->epfd, EPOLL_CTL_ADD, ev->fd, &ep); }
PONY_API void pony_asio_event_subscribe(asio_event_t* ev) { if((ev == NULL) || (ev->flags == ASIO_DISPOSABLE) || (ev->flags == ASIO_DESTROYED)) { pony_assert(0); return; } asio_backend_t* b = ponyint_asio_get_backend(); pony_assert(b != NULL); if(ev->noisy) { uint64_t old_count = ponyint_asio_noisy_add(); // tell scheduler threads that asio has at least one noisy actor // if the old_count was 0 if (old_count == 0) ponyint_sched_noisy_asio(SPECIAL_THREADID_EPOLL); } struct epoll_event ep; ep.data.ptr = ev; ep.events = EPOLLRDHUP; if(ev->flags & ASIO_READ) ep.events |= EPOLLIN; if(ev->flags & ASIO_WRITE) ep.events |= EPOLLOUT; if(ev->flags & ASIO_TIMER) { ev->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); timer_set_nsec(ev->fd, ev->nsec); ep.events |= EPOLLIN; } if(ev->flags & ASIO_SIGNAL) { int sig = (int)ev->nsec; asio_event_t* prev = NULL; #ifdef USE_VALGRIND ANNOTATE_HAPPENS_BEFORE(&b->sighandlers[sig]); #endif if((sig < MAX_SIGNAL) && atomic_compare_exchange_strong_explicit(&b->sighandlers[sig], &prev, ev, memory_order_release, memory_order_relaxed)) { struct sigaction new_action; new_action.sa_handler = signal_handler; sigemptyset (&new_action.sa_mask); // ask to restart interrupted syscalls to match `signal` behavior new_action.sa_flags = SA_RESTART; sigaction(sig, &new_action, NULL); ev->fd = eventfd(0, EFD_NONBLOCK); ep.events |= EPOLLIN; } else { return; } } if(ev->flags & ASIO_ONESHOT) { ep.events |= EPOLLONESHOT; } else { // Only use edge triggering if one shot isn't enabled. // This is because of how the runtime gets notifications // from epoll in this ASIO thread and then notifies the // appropriate actor to read/write as necessary. // specifically, it seems there's an edge case/race condition // with edge triggering where if there is already data waiting // on the socket, then epoll might not be triggering immediately // when an edge triggered epoll request is made. ep.events |= EPOLLET; } epoll_ctl(b->epfd, EPOLL_CTL_ADD, ev->fd, &ep); }