1 /*
2  * Copyright (C) 2017 Daniel Nicoletti <dantti12@gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 #include <QtCore/QCoreApplication>
19 #include <QPointer>
20 #include <QSocketNotifier>
21 #include <QVector>
22 
23 #include <unistd.h>
24 #include <sys/epoll.h>
25 #include <sys/eventfd.h>
26 #include <sys/timerfd.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include "eventdispatcher_epoll.h"
30 #include "eventdispatcher_epoll_p.h"
31 
EventDispatcherEPollPrivate(EventDispatcherEPoll * const q)32 EventDispatcherEPollPrivate::EventDispatcherEPollPrivate(EventDispatcherEPoll* const q)
33     : q_ptr(q)
34 {
35     createEpoll();
36 }
37 
~EventDispatcherEPollPrivate()38 EventDispatcherEPollPrivate::~EventDispatcherEPollPrivate()
39 {
40     close(m_event_fd);
41     close(m_epoll_fd);
42 
43     auto it = m_handles.constBegin();
44     while (it != m_handles.constEnd()) {
45         delete it.value();
46         ++it;
47     }
48     delete m_event_fd_info;
49 }
50 
createEpoll()51 void EventDispatcherEPollPrivate::createEpoll()
52 {
53     m_epoll_fd = epoll_create1(EPOLL_CLOEXEC);
54     if (Q_UNLIKELY(-1 == m_epoll_fd)) {
55         qErrnoWarning("epoll_create1() failed");
56         abort();
57     }
58 
59     m_event_fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
60     if (Q_UNLIKELY(-1 == m_event_fd)) {
61         qErrnoWarning("eventfd() failed");
62         abort();
63     }
64 
65     struct epoll_event e;
66     e.events = EPOLLIN;
67     m_event_fd_info = new EventFdInfo(m_event_fd, this);
68     e.data.ptr = m_event_fd_info;
69     if (Q_UNLIKELY(-1 == epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, m_event_fd, &e))) {
70         qErrnoWarning("%s: epoll_ctl() failed", Q_FUNC_INFO);
71     }
72 }
73 
processEvents(QEventLoop::ProcessEventsFlags flags)74 bool EventDispatcherEPollPrivate::processEvents(QEventLoop::ProcessEventsFlags flags)
75 {
76     Q_Q(EventDispatcherEPoll);
77 
78     const bool exclude_notifiers = (flags & QEventLoop::ExcludeSocketNotifiers);
79     const bool exclude_timers    = (flags & QEventLoop::X11ExcludeTimers);
80 
81     exclude_notifiers && disableSocketNotifiers(true);
82     exclude_timers    && disableTimers(true);
83 
84     m_interrupt = false;
85     Q_EMIT q->awake();
86 
87     bool result = q->hasPendingEvents();
88 
89     QCoreApplication::sendPostedEvents();
90 
91     bool can_wait =
92             !m_interrupt
93             && (flags & QEventLoop::WaitForMoreEvents)
94             && !result
95             ;
96 
97     int n_events = 0;
98 
99     if (!m_interrupt) {
100         int timeout = 0;
101 
102         if (!exclude_timers && !m_zero_timers.isEmpty()) {
103             QVector<ZeroTimer*> timers;
104             auto it = m_zero_timers.constBegin();
105             while (it != m_zero_timers.constEnd()) {
106                 ZeroTimer *data = it.value();
107                 data->ref();
108                 timers.push_back(data);
109                 ++it;
110             }
111 
112             for (ZeroTimer *data : timers) {
113                 if (data->canProcess() && data->active) {
114                     data->active = false;
115 
116                     QTimerEvent event(data->timerId);
117                     QCoreApplication::sendEvent(data->object, &event);
118 
119                     result = true;
120                     if (!data->active) {
121                         data->active = true;
122                     }
123                 }
124 
125                 data->deref();
126             }
127         }
128 
129         if (can_wait && !result) {
130             Q_EMIT q->aboutToBlock();
131             timeout = -1;
132         }
133 
134         struct epoll_event events[10024];
135         do {
136             n_events = epoll_wait(m_epoll_fd, events, 10024, timeout);
137         } while (Q_UNLIKELY(-1 == n_events && errno == EINTR));
138 
139         for (int i = 0; i < n_events; ++i) {
140             struct epoll_event &e = events[i];
141             auto data = static_cast<EpollAbastractEvent*>(e.data.ptr);
142             data->ref();
143         }
144 
145         for (int i = 0; i < n_events; ++i) {
146             struct epoll_event &e = events[i];
147             auto data = static_cast<EpollAbastractEvent*>(e.data.ptr);
148             if (data->canProcess()) {
149                 data->process(e.events);
150             }
151 
152             data->deref();
153         }
154     }
155 
156     exclude_notifiers && disableSocketNotifiers(false);
157     exclude_timers    && disableTimers(false);
158 
159     return result || n_events > 0;
160 }
161 
wake_up_handler()162 void EventDispatcherEPollPrivate::wake_up_handler()
163 {
164     eventfd_t value;
165     int res;
166     do {
167         res = eventfd_read(m_event_fd, &value);
168     } while (Q_UNLIKELY(-1 == res && EINTR == errno));
169 
170     if (Q_UNLIKELY(-1 == res)) {
171         qErrnoWarning("%s: eventfd_read() failed", Q_FUNC_INFO);
172     }
173 
174     if (Q_UNLIKELY(!m_wakeups.testAndSetRelease(1, 0))) {
175         qCritical("%s: internal error, testAndSetRelease(1, 0) failed!", Q_FUNC_INFO);
176     }
177 }
178 
process(quint32 events)179 void SocketNotifierInfo::process(quint32 events)
180 {
181     QEvent e(QEvent::SockAct);
182 
183     if (r && (events & EPOLLIN)) {
184         QCoreApplication::sendEvent(r, &e);
185     }
186 
187     if (w && (events & EPOLLOUT)) {
188         QCoreApplication::sendEvent(w, &e);
189     }
190 
191     if (x && (events & EPOLLPRI)) {
192         QCoreApplication::sendEvent(x, &e);
193     }
194 }
195 
process(quint32 events)196 void EventFdInfo::process(quint32 events)
197 {
198     if (Q_LIKELY(events & EPOLLIN)) {
199         epPriv->wake_up_handler();
200     }
201 }
202 
process(quint32 events)203 void TimerInfo::process(quint32 events)
204 {
205     Q_UNUSED(events)
206 
207     uint64_t value;
208     int res;
209     do {
210         res = read(fd, &value, sizeof(value));
211     } while (-1 == res && EINTR == errno);
212 
213     if (Q_UNLIKELY(-1 == res)) {
214         qErrnoWarning("%s: read() failed", Q_FUNC_INFO);
215     }
216 
217     QTimerEvent event(timerId);
218     QCoreApplication::sendEvent(object, &event);
219 
220     // Check if we are NOT going to be deleted
221     if (canProcess()) {
222         struct timeval now;
223         struct timeval delta;
224         struct itimerspec spec;
225 
226         spec.it_interval.tv_sec  = 0;
227         spec.it_interval.tv_nsec = 0;
228 
229         gettimeofday(&now, 0);
230         EventDispatcherEPollPrivate::calculateNextTimeout(this, now, delta);
231         TIMEVAL_TO_TIMESPEC(&delta, &spec.it_value);
232         if (0 == spec.it_value.tv_sec && 0 == spec.it_value.tv_nsec) {
233             spec.it_value.tv_nsec = 500;
234         }
235 
236         if (-1 == timerfd_settime(fd, 0, &spec, 0)) {
237             qErrnoWarning("%s: timerfd_settime() failed", Q_FUNC_INFO);
238         }
239     }
240 }
241 
process(quint32 events)242 void ZeroTimer::process(quint32 events)
243 {
244     Q_UNUSED(events)
245 }
246