diff --git a/ext/em.cpp b/ext/em.cpp index 9844d2814..4a065f98d 100644 --- a/ext/em.cpp +++ b/ext/em.cpp @@ -514,12 +514,28 @@ bool EventMachine_t::_RunEpollOnce() assert (epfd != -1); int s; + timeval tv = _TimeTilNextEvent(); + #ifdef BUILD_FOR_RUBY + int ret = 0; + fd_set fdreads; + + FD_ZERO(&fdreads); + FD_SET(epfd, &fdreads); + + while ((ret = rb_thread_select(epfd + 1, &fdreads, NULL, NULL, &tv)) < 1) { + if (ret == -1) continue; + if (ret == 0) return true; + } + TRAP_BEG; - #endif - s = epoll_wait (epfd, epoll_events, MaxEvents, 50); - #ifdef BUILD_FOR_RUBY + s = epoll_wait (epfd, epoll_events, MaxEvents, 0); TRAP_END; + #else + int duration = 0; + duration = duration + (tv.tv_sec * 1000); + duration = duration + (tv.tv_usec / 1000); + s = epoll_wait (epfd, epoll_events, MaxEvents, duration); #endif if (s > 0) { @@ -548,12 +564,6 @@ bool EventMachine_t::_RunEpollOnce() EmSelect (0, NULL, NULL, NULL, &tv); } - #ifdef BUILD_FOR_RUBY - if (!rb_thread_alone()) { - rb_thread_schedule(); - } - #endif - return true; #else throw std::runtime_error ("epoll is not implemented on this platform"); @@ -628,6 +638,33 @@ bool EventMachine_t::_RunKqueueOnce() } +/********************************* +EventMachine_t::_TimeTilNextEvent +*********************************/ + +timeval EventMachine_t::_TimeTilNextEvent() +{ + multimap::iterator heartbeats = Heartbeats.begin(); + multimap::iterator timers = Timers.begin(); + + uint64_t next_event = heartbeats->first; + + if (timers->first != 0 && timers->first < next_event) + next_event = timers->first; + + timeval tv; + + if (next_event == 0) { + tv = Quantum; + } else { + uint64_t duration = next_event - MyCurrentLoopTime; + tv.tv_sec = duration / 1000000; + tv.tv_usec = duration % 1000000; + } + + return tv; +} + /******************************* EventMachine_t::_CleanupSockets *******************************/ diff --git a/ext/em.h b/ext/em.h index 800f0c399..5e2aa5604 100644 --- a/ext/em.h +++ b/ext/em.h @@ -156,6 +156,7 @@ class EventMachine_t void _ModifyEpollEvent (EventableDescriptor*); void _DispatchHeartbeats(); + timeval _TimeTilNextEvent(); public: void _ReadLoopBreaker();