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/QSocketNotifier>
19 #include <QtCore/QThread>
20
21 #include <sys/eventfd.h>
22
23 #include "eventdispatcher_epoll.h"
24 #include "eventdispatcher_epoll_p.h"
25
EventDispatcherEPoll(QObject * parent)26 EventDispatcherEPoll::EventDispatcherEPoll(QObject* parent)
27 : QAbstractEventDispatcher(parent), d_ptr(new EventDispatcherEPollPrivate(this))
28 {
29 }
30
~EventDispatcherEPoll()31 EventDispatcherEPoll::~EventDispatcherEPoll()
32 {
33 delete d_ptr;
34 }
35
processEvents(QEventLoop::ProcessEventsFlags flags)36 bool EventDispatcherEPoll::processEvents(QEventLoop::ProcessEventsFlags flags)
37 {
38 Q_D(EventDispatcherEPoll);
39 return d->processEvents(flags);
40 }
41
registerSocketNotifier(QSocketNotifier * notifier)42 void EventDispatcherEPoll::registerSocketNotifier(QSocketNotifier* notifier)
43 {
44 #ifndef QT_NO_DEBUG
45 if (notifier->socket() < 0) {
46 qWarning("QSocketNotifier: Internal error: sockfd < 0");
47 return;
48 }
49
50 if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
51 qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
52 return;
53 }
54 #endif
55
56 Q_D(EventDispatcherEPoll);
57 d->registerSocketNotifier(notifier);
58 }
59
unregisterSocketNotifier(QSocketNotifier * notifier)60 void EventDispatcherEPoll::unregisterSocketNotifier(QSocketNotifier* notifier)
61 {
62 #ifndef QT_NO_DEBUG
63 if (notifier->socket() < 0) {
64 qWarning("QSocketNotifier: Internal error: sockfd < 0");
65 return;
66 }
67
68 if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
69 qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
70 return;
71 }
72 #endif
73
74 Q_D(EventDispatcherEPoll);
75 d->unregisterSocketNotifier(notifier);
76 }
77
unregisterTimer(int timerId)78 bool EventDispatcherEPoll::unregisterTimer(int timerId)
79 {
80 #ifndef QT_NO_DEBUG
81 if (timerId < 1) {
82 qWarning("%s: invalid arguments", Q_FUNC_INFO);
83 return false;
84 }
85
86 if (thread() != QThread::currentThread()) {
87 qWarning("%s: timers cannot be stopped from another thread", Q_FUNC_INFO);
88 return false;
89 }
90 #endif
91
92 Q_D(EventDispatcherEPoll);
93 return d->unregisterTimer(timerId);
94 }
95
unregisterTimers(QObject * object)96 bool EventDispatcherEPoll::unregisterTimers(QObject *object)
97 {
98 #ifndef QT_NO_DEBUG
99 if (!object) {
100 qWarning("%s: invalid arguments", Q_FUNC_INFO);
101 return false;
102 }
103
104 if (object->thread() != thread() && thread() != QThread::currentThread()) {
105 qWarning("%s: timers cannot be stopped from another thread", Q_FUNC_INFO);
106 return false;
107 }
108 #endif
109
110 Q_D(EventDispatcherEPoll);
111 return d->unregisterTimers(object);
112 }
113
registeredTimers(QObject * object) const114 QList<QAbstractEventDispatcher::TimerInfo> EventDispatcherEPoll::registeredTimers(QObject *object) const
115 {
116 if (!object) {
117 qWarning("%s: invalid argument", Q_FUNC_INFO);
118 return QList<QAbstractEventDispatcher::TimerInfo>();
119 }
120
121 Q_D(const EventDispatcherEPoll);
122 return d->registeredTimers(object);
123 }
124
remainingTime(int timerId)125 int EventDispatcherEPoll::remainingTime(int timerId)
126 {
127 Q_D(const EventDispatcherEPoll);
128 return d->remainingTime(timerId);
129 }
130
wakeUp()131 void EventDispatcherEPoll::wakeUp()
132 {
133 Q_D(EventDispatcherEPoll);
134
135 if (d->m_wakeups.testAndSetAcquire(0, 1)) {
136 const eventfd_t value = 1;
137 int res;
138
139 do {
140 res = eventfd_write(d->m_event_fd, value);
141 } while (Q_UNLIKELY(-1 == res && EINTR == errno));
142
143 if (Q_UNLIKELY(-1 == res)) {
144 qErrnoWarning("%s: eventfd_write() failed", Q_FUNC_INFO);
145 }
146 }
147 }
148
interrupt()149 void EventDispatcherEPoll::interrupt()
150 {
151 Q_D(EventDispatcherEPoll);
152 d->m_interrupt = true;
153 wakeUp();
154 }
155
156 extern uint qGlobalPostedEventsCount();
157
hasPendingEvents()158 bool EventDispatcherEPoll::hasPendingEvents()
159 {
160 return qGlobalPostedEventsCount() > 0;
161 }
162
163 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
registerTimer(int timerId,int interval,Qt::TimerType timerType,QObject * object)164 void EventDispatcherEPoll::registerTimer(
165 int timerId,
166 int interval,
167 Qt::TimerType timerType,
168 QObject *object
169 )
170 {
171 #ifndef QT_NO_DEBUG
172 if (timerId < 1 || interval < 0 || !object) {
173 qWarning("%s: invalid arguments", Q_FUNC_INFO);
174 return;
175 }
176
177 if (object->thread() != thread() && thread() != QThread::currentThread()) {
178 qWarning("%s: timers cannot be started from another thread", Q_FUNC_INFO);
179 return;
180 }
181 #endif
182
183 Q_D(EventDispatcherEPoll);
184 if (interval) {
185 d->registerTimer(timerId, interval, timerType, object);
186 } else {
187 d->registerZeroTimer(timerId, object);
188 }
189 }
190
flush()191 void EventDispatcherEPoll::flush()
192 {
193 Q_D(EventDispatcherEPoll);
194 d->createEpoll();
195 }
196 #else
registerTimer(int timerId,qint64 interval,Qt::TimerType timerType,QObject * object)197 void EventDispatcherEPoll::registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object)
198 {
199 #ifndef QT_NO_DEBUG
200 if (timerId < 1 || interval < 0 || !object) {
201 qWarning("%s: invalid arguments", Q_FUNC_INFO);
202 return;
203 }
204
205 if (object->thread() != thread() && thread() != QThread::currentThread()) {
206 qWarning("%s: timers cannot be started from another thread", Q_FUNC_INFO);
207 return;
208 }
209 #endif
210
211 Q_D(EventDispatcherEPoll);
212 if (interval) {
213 d->registerTimer(timerId, interval, timerType, object);
214 } else {
215 d->registerZeroTimer(timerId, object);
216 }
217 }
218 #endif
219
220 #include "moc_eventdispatcher_epoll.cpp"
221