| 1 |
/**************************************************************************** |
| 2 |
** |
| 3 |
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). |
| 4 |
** All rights reserved. |
| 5 |
** Contact: Nokia Corporation (qt-info@nokia.com) |
| 6 |
** |
| 7 |
** This file is part of the QtCore module of the Qt Toolkit. |
| 8 |
** |
| 9 |
** $QT_BEGIN_LICENSE:LGPL$ |
| 10 |
** GNU Lesser General Public License Usage |
| 11 |
** This file may be used under the terms of the GNU Lesser General Public |
| 12 |
** License version 2.1 as published by the Free Software Foundation and |
| 13 |
** appearing in the file LICENSE.LGPL included in the packaging of this |
| 14 |
** file. Please review the following information to ensure the GNU Lesser |
| 15 |
** General Public License version 2.1 requirements will be met: |
| 16 |
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
| 17 |
** |
| 18 |
** In addition, as a special exception, Nokia gives you certain additional |
| 19 |
** rights. These rights are described in the Nokia Qt LGPL Exception |
| 20 |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
| 21 |
** |
| 22 |
** GNU General Public License Usage |
| 23 |
** Alternatively, this file may be used under the terms of the GNU General |
| 24 |
** Public License version 3.0 as published by the Free Software Foundation |
| 25 |
** and appearing in the file LICENSE.GPL included in the packaging of this |
| 26 |
** file. Please review the following information to ensure the GNU General |
| 27 |
** Public License version 3.0 requirements will be met: |
| 28 |
** http://www.gnu.org/copyleft/gpl.html. |
| 29 |
** |
| 30 |
** Other Usage |
| 31 |
** Alternatively, this file may be used in accordance with the terms and |
| 32 |
** conditions contained in a signed written agreement between you and Nokia. |
| 33 |
** |
| 34 |
** |
| 35 |
** |
| 36 |
** |
| 37 |
** |
| 38 |
** $QT_END_LICENSE$ |
| 39 |
** |
| 40 |
****************************************************************************/ |
| 41 |
|
| 42 |
#include "qplatformdefs.h" |
| 43 |
|
| 44 |
#include "qcoreapplication.h" |
| 45 |
#include "qpair.h" |
| 46 |
#include "qsocketnotifier.h" |
| 47 |
#include "qthread.h" |
| 48 |
#include "qelapsedtimer.h" |
| 49 |
|
| 50 |
#include "qeventdispatcher_unix_p.h" |
| 51 |
#include <private/qthread_p.h> |
| 52 |
#include <private/qcoreapplication_p.h> |
| 53 |
#include <private/qcore_unix_p.h> |
| 54 |
|
| 55 |
#include <errno.h> |
| 56 |
#include <stdio.h> |
| 57 |
#include <stdlib.h> |
| 58 |
|
| 59 |
// VxWorks doesn't correctly set the _POSIX_... options |
| 60 |
#if defined(Q_OS_VXWORKS) |
| 61 |
# if defined(_POSIX_MONOTONIC_CLOCK) && (_POSIX_MONOTONIC_CLOCK <= 0) |
| 62 |
# undef _POSIX_MONOTONIC_CLOCK |
| 63 |
# define _POSIX_MONOTONIC_CLOCK 1 |
| 64 |
# endif |
| 65 |
# include <pipeDrv.h> |
| 66 |
# include <selectLib.h> |
| 67 |
#endif |
| 68 |
|
| 69 |
#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) || defined(QT_BOOTSTRAPPED) |
| 70 |
# include <sys/times.h> |
| 71 |
#endif |
| 72 |
|
| 73 |
QT_BEGIN_NAMESPACE |
| 74 |
|
| 75 |
Q_CORE_EXPORT bool qt_disable_lowpriority_timers=false; |
| 76 |
|
| 77 |
/***************************************************************************** |
| 78 |
UNIX signal handling |
| 79 |
*****************************************************************************/ |
| 80 |
|
| 81 |
static sig_atomic_t signal_received; |
| 82 |
static sig_atomic_t signals_fired[NSIG]; |
| 83 |
|
| 84 |
static void signalHandler(int sig) |
| 85 |
{ |
| 86 |
signals_fired[sig] = 1; |
| 87 |
signal_received = 1; |
| 88 |
} |
| 89 |
|
| 90 |
|
| 91 |
#if defined(Q_OS_INTEGRITY) || defined(Q_OS_VXWORKS) |
| 92 |
static void initThreadPipeFD(int fd) |
| 93 |
{ |
| 94 |
int ret = fcntl(fd, F_SETFD, FD_CLOEXEC); |
| 95 |
if (ret == -1) |
| 96 |
perror("QEventDispatcherUNIXPrivate: Unable to init thread pipe"); |
| 97 |
|
| 98 |
int flags = fcntl(fd, F_GETFL); |
| 99 |
if (flags == -1) |
| 100 |
perror("QEventDispatcherUNIXPrivate: Unable to get flags on thread pipe"); |
| 101 |
|
| 102 |
ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK); |
| 103 |
if (ret == -1) |
| 104 |
perror("QEventDispatcherUNIXPrivate: Unable to set flags on thread pipe"); |
| 105 |
} |
| 106 |
#endif |
| 107 |
|
| 108 |
QEventDispatcherUNIXPrivate::QEventDispatcherUNIXPrivate() |
| 109 |
{ |
| 110 |
extern Qt::HANDLE qt_application_thread_id; |
| 111 |
mainThread = (QThread::currentThreadId() == qt_application_thread_id); |
| 112 |
bool pipefail = false; |
| 113 |
|
| 114 |
// initialize the common parts of the event loop |
| 115 |
#if defined(Q_OS_NACL) |
| 116 |
// do nothing. |
| 117 |
#elif defined(Q_OS_INTEGRITY) |
| 118 |
// INTEGRITY doesn't like a "select" on pipes, so use socketpair instead |
| 119 |
if (socketpair(AF_INET, SOCK_STREAM, 0, thread_pipe) == -1) { |
| 120 |
perror("QEventDispatcherUNIXPrivate(): Unable to create socket pair"); |
| 121 |
pipefail = true; |
| 122 |
} else { |
| 123 |
initThreadPipeFD(thread_pipe[0]); |
| 124 |
initThreadPipeFD(thread_pipe[1]); |
| 125 |
} |
| 126 |
#elif defined(Q_OS_VXWORKS) |
| 127 |
char name[20]; |
| 128 |
qsnprintf(name, sizeof(name), "/pipe/qt_%08x", int(taskIdCurrent)); |
| 129 |
|
| 130 |
// make sure there is no pipe with this name |
| 131 |
pipeDevDelete(name, true); |
| 132 |
// create the pipe |
| 133 |
if (pipeDevCreate(name, 128 /*maxMsg*/, 1 /*maxLength*/) != OK) { |
| 134 |
perror("QEventDispatcherUNIXPrivate(): Unable to create thread pipe device"); |
| 135 |
pipefail = true; |
| 136 |
} else { |
| 137 |
if ((thread_pipe[0] = open(name, O_RDWR, 0)) < 0) { |
| 138 |
perror("QEventDispatcherUNIXPrivate(): Unable to create thread pipe"); |
| 139 |
pipefail = true; |
| 140 |
} else { |
| 141 |
initThreadPipeFD(thread_pipe[0]); |
| 142 |
thread_pipe[1] = thread_pipe[0]; |
| 143 |
} |
| 144 |
} |
| 145 |
#else |
| 146 |
if (qt_safe_pipe(thread_pipe, O_NONBLOCK) == -1) { |
| 147 |
perror("QEventDispatcherUNIXPrivate(): Unable to create thread pipe"); |
| 148 |
pipefail = true; |
| 149 |
} |
| 150 |
#endif |
| 151 |
|
| 152 |
if (pipefail) |
| 153 |
qFatal("QEventDispatcherUNIXPrivate(): Can not continue without a thread pipe"); |
| 154 |
|
| 155 |
sn_highest = -1; |
| 156 |
|
| 157 |
interrupt = false; |
| 158 |
} |
| 159 |
|
| 160 |
QEventDispatcherUNIXPrivate::~QEventDispatcherUNIXPrivate() |
| 161 |
{ |
| 162 |
#if defined(Q_OS_NACL) |
| 163 |
// do nothing. |
| 164 |
#elif defined(Q_OS_VXWORKS) |
| 165 |
close(thread_pipe[0]); |
| 166 |
|
| 167 |
char name[20]; |
| 168 |
qsnprintf(name, sizeof(name), "/pipe/qt_%08x", int(taskIdCurrent)); |
| 169 |
|
| 170 |
pipeDevDelete(name, true); |
| 171 |
#else |
| 172 |
// cleanup the common parts of the event loop |
| 173 |
close(thread_pipe[0]); |
| 174 |
close(thread_pipe[1]); |
| 175 |
#endif |
| 176 |
|
| 177 |
// cleanup timers |
| 178 |
qDeleteAll(timerList); |
| 179 |
} |
| 180 |
|
| 181 |
int QEventDispatcherUNIXPrivate::doSelect(QEventLoop::ProcessEventsFlags flags, timeval *timeout) |
| 182 |
{ |
| 183 |
Q_Q(QEventDispatcherUNIX); |
| 184 |
|
| 185 |
// needed in QEventDispatcherUNIX::select() |
| 186 |
timerList.updateCurrentTime(); |
| 187 |
|
| 188 |
int nsel; |
| 189 |
do { |
| 190 |
if (mainThread) { |
| 191 |
while (signal_received) { |
| 192 |
signal_received = 0; |
| 193 |
for (int i = 0; i < NSIG; ++i) { |
| 194 |
if (signals_fired[i]) { |
| 195 |
signals_fired[i] = 0; |
| 196 |
emit QCoreApplication::instance()->unixSignal(i); |
| 197 |
} |
| 198 |
} |
| 199 |
} |
| 200 |
} |
| 201 |
|
| 202 |
// Process timers and socket notifiers - the common UNIX stuff |
| 203 |
int highest = 0; |
| 204 |
if (! (flags & QEventLoop::ExcludeSocketNotifiers) && (sn_highest >= 0)) { |
| 205 |
// return the highest fd we can wait for input on |
| 206 |
sn_vec[0].select_fds = sn_vec[0].enabled_fds; |
| 207 |
sn_vec[1].select_fds = sn_vec[1].enabled_fds; |
| 208 |
sn_vec[2].select_fds = sn_vec[2].enabled_fds; |
| 209 |
highest = sn_highest; |
| 210 |
} else { |
| 211 |
FD_ZERO(&sn_vec[0].select_fds); |
| 212 |
FD_ZERO(&sn_vec[1].select_fds); |
| 213 |
FD_ZERO(&sn_vec[2].select_fds); |
| 214 |
} |
| 215 |
|
| 216 |
FD_SET(thread_pipe[0], &sn_vec[0].select_fds); |
| 217 |
highest = qMax(highest, thread_pipe[0]); |
| 218 |
|
| 219 |
nsel = q->select(highest + 1, |
| 220 |
&sn_vec[0].select_fds, |
| 221 |
&sn_vec[1].select_fds, |
| 222 |
&sn_vec[2].select_fds, |
| 223 |
timeout); |
| 224 |
} while (nsel == -1 && (errno == EINTR || errno == EAGAIN)); |
| 225 |
|
| 226 |
if (nsel == -1) { |
| 227 |
if (errno == EBADF) { |
| 228 |
// it seems a socket notifier has a bad fd... find out |
| 229 |
// which one it is and disable it |
| 230 |
fd_set fdset; |
| 231 |
timeval tm; |
| 232 |
tm.tv_sec = tm.tv_usec = 0l; |
| 233 |
|
| 234 |
for (int type = 0; type < 3; ++type) { |
| 235 |
QSockNotType::List &list = sn_vec[type].list; |
| 236 |
if (list.size() == 0) |
| 237 |
continue; |
| 238 |
|
| 239 |
for (int i = 0; i < list.size(); ++i) { |
| 240 |
QSockNot *sn = list[i]; |
| 241 |
|
| 242 |
FD_ZERO(&fdset); |
| 243 |
FD_SET(sn->fd, &fdset); |
| 244 |
|
| 245 |
int ret = -1; |
| 246 |
do { |
| 247 |
switch (type) { |
| 248 |
case 0: // read |
| 249 |
ret = select(sn->fd + 1, &fdset, 0, 0, &tm); |
| 250 |
break; |
| 251 |
case 1: // write |
| 252 |
ret = select(sn->fd + 1, 0, &fdset, 0, &tm); |
| 253 |
break; |
| 254 |
case 2: // except |
| 255 |
ret = select(sn->fd + 1, 0, 0, &fdset, &tm); |
| 256 |
break; |
| 257 |
} |
| 258 |
} while (ret == -1 && (errno == EINTR || errno == EAGAIN)); |
| 259 |
|
| 260 |
if (ret == -1 && errno == EBADF) { |
| 261 |
// disable the invalid socket notifier |
| 262 |
static const char *t[] = { "Read", "Write", "Exception" }; |
| 263 |
qWarning("QSocketNotifier: Invalid socket %d and type '%s', disabling...", |
| 264 |
sn->fd, t[type]); |
| 265 |
sn->obj->setEnabled(false); |
| 266 |
} |
| 267 |
} |
| 268 |
} |
| 269 |
} else { |
| 270 |
// EINVAL... shouldn't happen, so let's complain to stderr |
| 271 |
// and hope someone sends us a bug report |
| 272 |
perror("select"); |
| 273 |
} |
| 274 |
} |
| 275 |
|
| 276 |
// some other thread woke us up... consume the data on the thread pipe so that |
| 277 |
// select doesn't immediately return next time |
| 278 |
int nevents = 0; |
| 279 |
if (nsel > 0 && FD_ISSET(thread_pipe[0], &sn_vec[0].select_fds)) { |
| 280 |
#if defined(Q_OS_VXWORKS) |
| 281 |
char c[16]; |
| 282 |
::read(thread_pipe[0], c, sizeof(c)); |
| 283 |
::ioctl(thread_pipe[0], FIOFLUSH, 0); |
| 284 |
#else |
| 285 |
char c[16]; |
| 286 |
while (::read(thread_pipe[0], c, sizeof(c)) > 0) |
| 287 |
; |
| 288 |
#endif |
| 289 |
if (!wakeUps.testAndSetRelease(1, 0)) { |
| 290 |
// hopefully, this is dead code |
| 291 |
qWarning("QEventDispatcherUNIX: internal error, wakeUps.testAndSetRelease(1, 0) failed!"); |
| 292 |
} |
| 293 |
++nevents; |
| 294 |
} |
| 295 |
|
| 296 |
// activate socket notifiers |
| 297 |
if (! (flags & QEventLoop::ExcludeSocketNotifiers) && nsel > 0 && sn_highest >= 0) { |
| 298 |
// if select says data is ready on any socket, then set the socket notifier |
| 299 |
// to pending |
| 300 |
for (int i=0; i<3; i++) { |
| 301 |
QSockNotType::List &list = sn_vec[i].list; |
| 302 |
for (int j = 0; j < list.size(); ++j) { |
| 303 |
QSockNot *sn = list[j]; |
| 304 |
if (FD_ISSET(sn->fd, &sn_vec[i].select_fds)) |
| 305 |
q->setSocketNotifierPending(sn->obj); |
| 306 |
} |
| 307 |
} |
| 308 |
} |
| 309 |
return (nevents + q->activateSocketNotifiers()); |
| 310 |
} |
| 311 |
|
| 312 |
/* |
| 313 |
* Internal functions for manipulating timer data structures. The |
| 314 |
* timerBitVec array is used for keeping track of timer identifiers. |
| 315 |
*/ |
| 316 |
|
| 317 |
QTimerInfoList::QTimerInfoList() |
| 318 |
{ |
| 319 |
#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC) && !defined(Q_OS_NACL) |
| 320 |
if (!QElapsedTimer::isMonotonic()) { |
| 321 |
// not using monotonic timers, initialize the timeChanged() machinery |
| 322 |
previousTime = qt_gettime(); |
| 323 |
|
| 324 |
tms unused; |
| 325 |
previousTicks = times(&unused); |
| 326 |
|
| 327 |
ticksPerSecond = sysconf(_SC_CLK_TCK); |
| 328 |
msPerTick = 1000/ticksPerSecond; |
| 329 |
} else { |
| 330 |
// detected monotonic timers |
| 331 |
previousTime.tv_sec = previousTime.tv_usec = 0; |
| 332 |
previousTicks = 0; |
| 333 |
ticksPerSecond = 0; |
| 334 |
msPerTick = 0; |
| 335 |
} |
| 336 |
#endif |
| 337 |
|
| 338 |
firstTimerInfo = 0; |
| 339 |
} |
| 340 |
|
| 341 |
timeval QTimerInfoList::updateCurrentTime() |
| 342 |
{ |
| 343 |
return (currentTime = qt_gettime()); |
| 344 |
} |
| 345 |
|
| 346 |
#if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC) && !defined(Q_OS_INTEGRITY)) || defined(QT_BOOTSTRAPPED) |
| 347 |
|
| 348 |
template <> |
| 349 |
timeval qAbs(const timeval &t) |
| 350 |
{ |
| 351 |
timeval tmp = t; |
| 352 |
if (tmp.tv_sec < 0) { |
| 353 |
tmp.tv_sec = -tmp.tv_sec - 1; |
| 354 |
tmp.tv_usec -= 1000000; |
| 355 |
} |
| 356 |
if (tmp.tv_sec == 0 && tmp.tv_usec < 0) { |
| 357 |
tmp.tv_usec = -tmp.tv_usec; |
| 358 |
} |
| 359 |
return normalizedTimeval(tmp); |
| 360 |
} |
| 361 |
|
| 362 |
/* |
| 363 |
Returns true if the real time clock has changed by more than 10% |
| 364 |
relative to the processor time since the last time this function was |
| 365 |
called. This presumably means that the system time has been changed. |
| 366 |
|
| 367 |
If /a delta is nonzero, delta is set to our best guess at how much the system clock was changed. |
| 368 |
*/ |
| 369 |
bool QTimerInfoList::timeChanged(timeval *delta) |
| 370 |
{ |
| 371 |
#ifdef Q_OS_NACL |
| 372 |
Q_UNUSED(delta) |
| 373 |
return false; // Calling "times" crashes. |
| 374 |
#endif |
| 375 |
struct tms unused; |
| 376 |
clock_t currentTicks = times(&unused); |
| 377 |
|
| 378 |
clock_t elapsedTicks = currentTicks - previousTicks; |
| 379 |
timeval elapsedTime = currentTime - previousTime; |
| 380 |
|
| 381 |
timeval elapsedTimeTicks; |
| 382 |
elapsedTimeTicks.tv_sec = elapsedTicks / ticksPerSecond; |
| 383 |
elapsedTimeTicks.tv_usec = (((elapsedTicks * 1000) / ticksPerSecond) % 1000) * 1000; |
| 384 |
|
| 385 |
timeval dummy; |
| 386 |
if (!delta) |
| 387 |
delta = &dummy; |
| 388 |
*delta = elapsedTime - elapsedTimeTicks; |
| 389 |
|
| 390 |
previousTicks = currentTicks; |
| 391 |
previousTime = currentTime; |
| 392 |
|
| 393 |
// If tick drift is more than 10% off compared to realtime, we assume that the clock has |
| 394 |
// been set. Of course, we have to allow for the tick granularity as well. |
| 395 |
timeval tickGranularity; |
| 396 |
tickGranularity.tv_sec = 0; |
| 397 |
tickGranularity.tv_usec = msPerTick * 1000; |
| 398 |
return elapsedTimeTicks < ((qAbs(*delta) - tickGranularity) * 10); |
| 399 |
} |
| 400 |
|
| 401 |
void QTimerInfoList::repairTimersIfNeeded() |
| 402 |
{ |
| 403 |
if (QElapsedTimer::isMonotonic()) |
| 404 |
return; |
| 405 |
timeval delta; |
| 406 |
if (timeChanged(&delta)) |
| 407 |
timerRepair(delta); |
| 408 |
} |
| 409 |
|
| 410 |
#else // !(_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(QT_BOOTSTRAPPED) |
| 411 |
|
| 412 |
void QTimerInfoList::repairTimersIfNeeded() |
| 413 |
{ |
| 414 |
} |
| 415 |
|
| 416 |
#endif |
| 417 |
|
| 418 |
/* |
| 419 |
insert timer info into list |
| 420 |
*/ |
| 421 |
void QTimerInfoList::timerInsert(QTimerInfo *ti) |
| 422 |
{ |
| 423 |
int index = size(); |
| 424 |
while (index--) { |
| 425 |
register const QTimerInfo * const t = at(index); |
| 426 |
if (!(ti->timeout < t->timeout)) |
| 427 |
break; |
| 428 |
} |
| 429 |
insert(index+1, ti); |
| 430 |
} |
| 431 |
|
| 432 |
/* |
| 433 |
repair broken timer |
| 434 |
*/ |
| 435 |
void QTimerInfoList::timerRepair(const timeval &diff) |
| 436 |
{ |
| 437 |
// repair all timers |
| 438 |
for (int i = 0; i < size(); ++i) { |
| 439 |
register QTimerInfo *t = at(i); |
| 440 |
t->timeout = t->timeout + diff; |
| 441 |
} |
| 442 |
} |
| 443 |
|
| 444 |
/* |
| 445 |
Returns the time to wait for the next timer, or null if no timers |
| 446 |
are waiting. |
| 447 |
*/ |
| 448 |
bool QTimerInfoList::timerWait(timeval &tm) |
| 449 |
{ |
| 450 |
timeval currentTime = updateCurrentTime(); |
| 451 |
repairTimersIfNeeded(); |
| 452 |
|
| 453 |
// Find first waiting timer not already active |
| 454 |
QTimerInfo *t = 0; |
| 455 |
for (QTimerInfoList::const_iterator it = constBegin(); it != constEnd(); ++it) { |
| 456 |
if (!(*it)->activateRef) { |
| 457 |
t = *it; |
| 458 |
break; |
| 459 |
} |
| 460 |
} |
| 461 |
|
| 462 |
if (!t) |
| 463 |
return false; |
| 464 |
|
| 465 |
if (currentTime < t->timeout) { |
| 466 |
// time to wait |
| 467 |
tm = t->timeout - currentTime; |
| 468 |
} else { |
| 469 |
// no time to wait |
| 470 |
tm.tv_sec = 0; |
| 471 |
tm.tv_usec = 0; |
| 472 |
} |
| 473 |
|
| 474 |
return true; |
| 475 |
} |
| 476 |
|
| 477 |
void QTimerInfoList::registerTimer(int timerId, int interval, QObject *object) |
| 478 |
{ |
| 479 |
QTimerInfo *t = new QTimerInfo; |
| 480 |
t->id = timerId; |
| 481 |
t->interval.tv_sec = interval / 1000; |
| 482 |
t->interval.tv_usec = (interval % 1000) * 1000; |
| 483 |
t->timeout = updateCurrentTime() + t->interval; |
| 484 |
t->obj = object; |
| 485 |
t->activateRef = 0; |
| 486 |
|
| 487 |
timerInsert(t); |
| 488 |
} |
| 489 |
|
| 490 |
bool QTimerInfoList::unregisterTimer(int timerId) |
| 491 |
{ |
| 492 |
// set timer inactive |
| 493 |
for (int i = 0; i < count(); ++i) { |
| 494 |
register QTimerInfo *t = at(i); |
| 495 |
if (t->id == timerId) { |
| 496 |
// found it |
| 497 |
removeAt(i); |
| 498 |
if (t == firstTimerInfo) |
| 499 |
firstTimerInfo = 0; |
| 500 |
if (t->activateRef) |
| 501 |
*(t->activateRef) = 0; |
| 502 |
|
| 503 |
// release the timer id |
| 504 |
if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent) |
| 505 |
QAbstractEventDispatcherPrivate::releaseTimerId(timerId); |
| 506 |
|
| 507 |
delete t; |
| 508 |
return true; |
| 509 |
} |
| 510 |
} |
| 511 |
// id not found |
| 512 |
return false; |
| 513 |
} |
| 514 |
|
| 515 |
bool QTimerInfoList::unregisterTimers(QObject *object) |
| 516 |
{ |
| 517 |
if (isEmpty()) |
| 518 |
return false; |
| 519 |
for (int i = 0; i < count(); ++i) { |
| 520 |
register QTimerInfo *t = at(i); |
| 521 |
if (t->obj == object) { |
| 522 |
// object found |
| 523 |
removeAt(i); |
| 524 |
if (t == firstTimerInfo) |
| 525 |
firstTimerInfo = 0; |
| 526 |
if (t->activateRef) |
| 527 |
*(t->activateRef) = 0; |
| 528 |
|
| 529 |
// release the timer id |
| 530 |
if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent) |
| 531 |
QAbstractEventDispatcherPrivate::releaseTimerId(t->id); |
| 532 |
|
| 533 |
delete t; |
| 534 |
// move back one so that we don't skip the new current item |
| 535 |
--i; |
| 536 |
} |
| 537 |
} |
| 538 |
return true; |
| 539 |
} |
| 540 |
|
| 541 |
QList<QPair<int, int> > QTimerInfoList::registeredTimers(QObject *object) const |
| 542 |
{ |
| 543 |
QList<QPair<int, int> > list; |
| 544 |
for (int i = 0; i < count(); ++i) { |
| 545 |
register const QTimerInfo * const t = at(i); |
| 546 |
if (t->obj == object) |
| 547 |
list << QPair<int, int>(t->id, t->interval.tv_sec * 1000 + t->interval.tv_usec / 1000); |
| 548 |
} |
| 549 |
return list; |
| 550 |
} |
| 551 |
|
| 552 |
/* |
| 553 |
Activate pending timers, returning how many where activated. |
| 554 |
*/ |
| 555 |
int QTimerInfoList::activateTimers() |
| 556 |
{ |
| 557 |
if (qt_disable_lowpriority_timers || isEmpty()) |
| 558 |
return 0; // nothing to do |
| 559 |
|
| 560 |
int n_act = 0, maxCount = 0; |
| 561 |
firstTimerInfo = 0; |
| 562 |
|
| 563 |
timeval currentTime = updateCurrentTime(); |
| 564 |
repairTimersIfNeeded(); |
| 565 |
|
| 566 |
|
| 567 |
// Find out how many timer have expired |
| 568 |
for (QTimerInfoList::const_iterator it = constBegin(); it != constEnd(); ++it) { |
| 569 |
if (currentTime < (*it)->timeout) |
| 570 |
break; |
| 571 |
maxCount++; |
| 572 |
} |
| 573 |
|
| 574 |
//fire the timers. |
| 575 |
while (maxCount--) { |
| 576 |
if (isEmpty()) |
| 577 |
break; |
| 578 |
|
| 579 |
QTimerInfo *currentTimerInfo = first(); |
| 580 |
if (currentTime < currentTimerInfo->timeout) |
| 581 |
break; // no timer has expired |
| 582 |
|
| 583 |
if (!firstTimerInfo) { |
| 584 |
firstTimerInfo = currentTimerInfo; |
| 585 |
} else if (firstTimerInfo == currentTimerInfo) { |
| 586 |
// avoid sending the same timer multiple times |
| 587 |
break; |
| 588 |
} else if (currentTimerInfo->interval < firstTimerInfo->interval |
| 589 |
|| currentTimerInfo->interval == firstTimerInfo->interval) { |
| 590 |
firstTimerInfo = currentTimerInfo; |
| 591 |
} |
| 592 |
|
| 593 |
// remove from list |
| 594 |
removeFirst(); |
| 595 |
|
| 596 |
// determine next timeout time |
| 597 |
currentTimerInfo->timeout += currentTimerInfo->interval; |
| 598 |
if (currentTimerInfo->timeout < currentTime) |
| 599 |
currentTimerInfo->timeout = currentTime + currentTimerInfo->interval; |
| 600 |
|
| 601 |
// reinsert timer |
| 602 |
timerInsert(currentTimerInfo); |
| 603 |
if (currentTimerInfo->interval.tv_usec > 0 || currentTimerInfo->interval.tv_sec > 0) |
| 604 |
n_act++; |
| 605 |
|
| 606 |
if (!currentTimerInfo->activateRef) { |
| 607 |
// send event, but don't allow it to recurse |
| 608 |
currentTimerInfo->activateRef = ¤tTimerInfo; |
| 609 |
|
| 610 |
QTimerEvent e(currentTimerInfo->id); |
| 611 |
QCoreApplication::sendEvent(currentTimerInfo->obj, &e); |
| 612 |
|
| 613 |
if (currentTimerInfo) |
| 614 |
currentTimerInfo->activateRef = 0; |
| 615 |
} |
| 616 |
} |
| 617 |
|
| 618 |
firstTimerInfo = 0; |
| 619 |
return n_act; |
| 620 |
} |
| 621 |
|
| 622 |
QEventDispatcherUNIX::QEventDispatcherUNIX(QObject *parent) |
| 623 |
: QAbstractEventDispatcher(*new QEventDispatcherUNIXPrivate, parent) |
| 624 |
{ } |
| 625 |
|
| 626 |
QEventDispatcherUNIX::QEventDispatcherUNIX(QEventDispatcherUNIXPrivate &dd, QObject *parent) |
| 627 |
: QAbstractEventDispatcher(dd, parent) |
| 628 |
{ } |
| 629 |
|
| 630 |
QEventDispatcherUNIX::~QEventDispatcherUNIX() |
| 631 |
{ |
| 632 |
Q_D(QEventDispatcherUNIX); |
| 633 |
d->threadData->eventDispatcher = 0; |
| 634 |
} |
| 635 |
|
| 636 |
int QEventDispatcherUNIX::select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, |
| 637 |
timeval *timeout) |
| 638 |
{ |
| 639 |
return qt_safe_select(nfds, readfds, writefds, exceptfds, timeout); |
| 640 |
} |
| 641 |
|
| 642 |
/*! |
| 643 |
\internal |
| 644 |
*/ |
| 645 |
void QEventDispatcherUNIX::registerTimer(int timerId, int interval, QObject *obj) |
| 646 |
{ |
| 647 |
#ifndef QT_NO_DEBUG |
| 648 |
if (timerId < 1 || interval < 0 || !obj) { |
| 649 |
qWarning("QEventDispatcherUNIX::registerTimer: invalid arguments"); |
| 650 |
return; |
| 651 |
} else if (obj->thread() != thread() || thread() != QThread::currentThread()) { |
| 652 |
qWarning("QObject::startTimer: timers cannot be started from another thread"); |
| 653 |
return; |
| 654 |
} |
| 655 |
#endif |
| 656 |
|
| 657 |
Q_D(QEventDispatcherUNIX); |
| 658 |
d->timerList.registerTimer(timerId, interval, obj); |
| 659 |
} |
| 660 |
|
| 661 |
/*! |
| 662 |
\internal |
| 663 |
*/ |
| 664 |
bool QEventDispatcherUNIX::unregisterTimer(int timerId) |
| 665 |
{ |
| 666 |
#ifndef QT_NO_DEBUG |
| 667 |
if (timerId < 1) { |
| 668 |
qWarning("QEventDispatcherUNIX::unregisterTimer: invalid argument"); |
| 669 |
return false; |
| 670 |
} else if (thread() != QThread::currentThread()) { |
| 671 |
qWarning("QObject::killTimer: timers cannot be stopped from another thread"); |
| 672 |
return false; |
| 673 |
} |
| 674 |
#endif |
| 675 |
|
| 676 |
Q_D(QEventDispatcherUNIX); |
| 677 |
return d->timerList.unregisterTimer(timerId); |
| 678 |
} |
| 679 |
|
| 680 |
/*! |
| 681 |
\internal |
| 682 |
*/ |
| 683 |
bool QEventDispatcherUNIX::unregisterTimers(QObject *object) |
| 684 |
{ |
| 685 |
#ifndef QT_NO_DEBUG |
| 686 |
if (!object) { |
| 687 |
qWarning("QEventDispatcherUNIX::unregisterTimers: invalid argument"); |
| 688 |
return false; |
| 689 |
} else if (object->thread() != thread() || thread() != QThread::currentThread()) { |
| 690 |
qWarning("QObject::killTimers: timers cannot be stopped from another thread"); |
| 691 |
return false; |
| 692 |
} |
| 693 |
#endif |
| 694 |
|
| 695 |
Q_D(QEventDispatcherUNIX); |
| 696 |
return d->timerList.unregisterTimers(object); |
| 697 |
} |
| 698 |
|
| 699 |
QList<QEventDispatcherUNIX::TimerInfo> |
| 700 |
QEventDispatcherUNIX::registeredTimers(QObject *object) const |
| 701 |
{ |
| 702 |
if (!object) { |
| 703 |
qWarning("QEventDispatcherUNIX:registeredTimers: invalid argument"); |
| 704 |
return QList<TimerInfo>(); |
| 705 |
} |
| 706 |
|
| 707 |
Q_D(const QEventDispatcherUNIX); |
| 708 |
return d->timerList.registeredTimers(object); |
| 709 |
} |
| 710 |
|
| 711 |
/***************************************************************************** |
| 712 |
Socket notifier type |
| 713 |
*****************************************************************************/ |
| 714 |
QSockNotType::QSockNotType() |
| 715 |
{ |
| 716 |
FD_ZERO(&select_fds); |
| 717 |
FD_ZERO(&enabled_fds); |
| 718 |
FD_ZERO(&pending_fds); |
| 719 |
} |
| 720 |
|
| 721 |
QSockNotType::~QSockNotType() |
| 722 |
{ |
| 723 |
for (int i = 0; i < list.size(); ++i) |
| 724 |
delete list[i]; |
| 725 |
} |
| 726 |
|
| 727 |
/***************************************************************************** |
| 728 |
QEventDispatcher implementations for UNIX |
| 729 |
*****************************************************************************/ |
| 730 |
|
| 731 |
void QEventDispatcherUNIX::registerSocketNotifier(QSocketNotifier *notifier) |
| 732 |
{ |
| 733 |
Q_ASSERT(notifier); |
| 734 |
int sockfd = notifier->socket(); |
| 735 |
int type = notifier->type(); |
| 736 |
#ifndef QT_NO_DEBUG |
| 737 |
if (sockfd < 0 |
| 738 |
|| unsigned(sockfd) >= FD_SETSIZE) { |
| 739 |
qWarning("QSocketNotifier: Internal error"); |
| 740 |
return; |
| 741 |
} else if (notifier->thread() != thread() |
| 742 |
|| thread() != QThread::currentThread()) { |
| 743 |
qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread"); |
| 744 |
return; |
| 745 |
} |
| 746 |
#endif |
| 747 |
|
| 748 |
Q_D(QEventDispatcherUNIX); |
| 749 |
QSockNotType::List &list = d->sn_vec[type].list; |
| 750 |
fd_set *fds = &d->sn_vec[type].enabled_fds; |
| 751 |
QSockNot *sn; |
| 752 |
|
| 753 |
sn = new QSockNot; |
| 754 |
sn->obj = notifier; |
| 755 |
sn->fd = sockfd; |
| 756 |
sn->queue = &d->sn_vec[type].pending_fds; |
| 757 |
|
| 758 |
int i; |
| 759 |
for (i = 0; i < list.size(); ++i) { |
| 760 |
QSockNot *p = list[i]; |
| 761 |
if (p->fd < sockfd) |
| 762 |
break; |
| 763 |
if (p->fd == sockfd) { |
| 764 |
static const char *t[] = { "Read", "Write", "Exception" }; |
| 765 |
qWarning("QSocketNotifier: Multiple socket notifiers for " |
| 766 |
"same socket %d and type %s", sockfd, t[type]); |
| 767 |
} |
| 768 |
} |
| 769 |
list.insert(i, sn); |
| 770 |
|
| 771 |
FD_SET(sockfd, fds); |
| 772 |
d->sn_highest = qMax(d->sn_highest, sockfd); |
| 773 |
} |
| 774 |
|
| 775 |
void QEventDispatcherUNIX::unregisterSocketNotifier(QSocketNotifier *notifier) |
| 776 |
{ |
| 777 |
Q_ASSERT(notifier); |
| 778 |
int sockfd = notifier->socket(); |
| 779 |
int type = notifier->type(); |
| 780 |
#ifndef QT_NO_DEBUG |
| 781 |
if (sockfd < 0 |
| 782 |
|| unsigned(sockfd) >= FD_SETSIZE) { |
| 783 |
qWarning("QSocketNotifier: Internal error"); |
| 784 |
return; |
| 785 |
} else if (notifier->thread() != thread() |
| 786 |
|| thread() != QThread::currentThread()) { |
| 787 |
qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread"); |
| 788 |
return; |
| 789 |
} |
| 790 |
#endif |
| 791 |
|
| 792 |
Q_D(QEventDispatcherUNIX); |
| 793 |
QSockNotType::List &list = d->sn_vec[type].list; |
| 794 |
fd_set *fds = &d->sn_vec[type].enabled_fds; |
| 795 |
QSockNot *sn = 0; |
| 796 |
int i; |
| 797 |
for (i = 0; i < list.size(); ++i) { |
| 798 |
sn = list[i]; |
| 799 |
if(sn->obj == notifier && sn->fd == sockfd) |
| 800 |
break; |
| 801 |
} |
| 802 |
if (i == list.size()) // not found |
| 803 |
return; |
| 804 |
|
| 805 |
FD_CLR(sockfd, fds); // clear fd bit |
| 806 |
FD_CLR(sockfd, sn->queue); |
| 807 |
d->sn_pending_list.removeAll(sn); // remove from activation list |
| 808 |
list.removeAt(i); // remove notifier found above |
| 809 |
delete sn; |
| 810 |
|
| 811 |
if (d->sn_highest == sockfd) { // find highest fd |
| 812 |
d->sn_highest = -1; |
| 813 |
for (int i=0; i<3; i++) { |
| 814 |
if (!d->sn_vec[i].list.isEmpty()) |
| 815 |
d->sn_highest = qMax(d->sn_highest, // list is fd-sorted |
| 816 |
d->sn_vec[i].list[0]->fd); |
| 817 |
} |
| 818 |
} |
| 819 |
} |
| 820 |
|
| 821 |
void QEventDispatcherUNIX::setSocketNotifierPending(QSocketNotifier *notifier) |
| 822 |
{ |
| 823 |
Q_ASSERT(notifier); |
| 824 |
int sockfd = notifier->socket(); |
| 825 |
int type = notifier->type(); |
| 826 |
#ifndef QT_NO_DEBUG |
| 827 |
if (sockfd < 0 |
| 828 |
|| unsigned(sockfd) >= FD_SETSIZE) { |
| 829 |
qWarning("QSocketNotifier: Internal error"); |
| 830 |
return; |
| 831 |
} |
| 832 |
Q_ASSERT(notifier->thread() == thread() && thread() == QThread::currentThread()); |
| 833 |
#endif |
| 834 |
|
| 835 |
Q_D(QEventDispatcherUNIX); |
| 836 |
QSockNotType::List &list = d->sn_vec[type].list; |
| 837 |
QSockNot *sn = 0; |
| 838 |
int i; |
| 839 |
for (i = 0; i < list.size(); ++i) { |
| 840 |
sn = list[i]; |
| 841 |
if(sn->obj == notifier && sn->fd == sockfd) |
| 842 |
break; |
| 843 |
} |
| 844 |
if (i == list.size()) // not found |
| 845 |
return; |
| 846 |
|
| 847 |
// We choose a random activation order to be more fair under high load. |
| 848 |
// If a constant order is used and a peer early in the list can |
| 849 |
// saturate the IO, it might grab our attention completely. |
| 850 |
// Also, if we're using a straight list, the callback routines may |
| 851 |
// delete other entries from the list before those other entries are |
| 852 |
// processed. |
| 853 |
if (! FD_ISSET(sn->fd, sn->queue)) { |
| 854 |
if (d->sn_pending_list.isEmpty()) { |
| 855 |
d->sn_pending_list.append(sn); |
| 856 |
} else { |
| 857 |
d->sn_pending_list.insert((qrand() & 0xff) % |
| 858 |
(d->sn_pending_list.size()+1), sn); |
| 859 |
} |
| 860 |
FD_SET(sn->fd, sn->queue); |
| 861 |
} |
| 862 |
} |
| 863 |
|
| 864 |
int QEventDispatcherUNIX::activateTimers() |
| 865 |
{ |
| 866 |
Q_ASSERT(thread() == QThread::currentThread()); |
| 867 |
Q_D(QEventDispatcherUNIX); |
| 868 |
return d->timerList.activateTimers(); |
| 869 |
} |
| 870 |
|
| 871 |
int QEventDispatcherUNIX::activateSocketNotifiers() |
| 872 |
{ |
| 873 |
Q_D(QEventDispatcherUNIX); |
| 874 |
if (d->sn_pending_list.isEmpty()) |
| 875 |
return 0; |
| 876 |
|
| 877 |
// activate entries |
| 878 |
int n_act = 0; |
| 879 |
QEvent event(QEvent::SockAct); |
| 880 |
while (!d->sn_pending_list.isEmpty()) { |
| 881 |
QSockNot *sn = d->sn_pending_list.takeFirst(); |
| 882 |
if (FD_ISSET(sn->fd, sn->queue)) { |
| 883 |
FD_CLR(sn->fd, sn->queue); |
| 884 |
QCoreApplication::sendEvent(sn->obj, &event); |
| 885 |
++n_act; |
| 886 |
} |
| 887 |
} |
| 888 |
return n_act; |
| 889 |
} |
| 890 |
|
| 891 |
bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags) |
| 892 |
{ |
| 893 |
Q_D(QEventDispatcherUNIX); |
| 894 |
d->interrupt = false; |
| 895 |
|
| 896 |
// we are awake, broadcast it |
| 897 |
emit awake(); |
| 898 |
QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData); |
| 899 |
|
| 900 |
int nevents = 0; |
| 901 |
const bool canWait = (d->threadData->canWait |
| 902 |
&& !d->interrupt |
| 903 |
&& (flags & QEventLoop::WaitForMoreEvents)); |
| 904 |
|
| 905 |
if (canWait) |
| 906 |
emit aboutToBlock(); |
| 907 |
|
| 908 |
if (!d->interrupt) { |
| 909 |
// return the maximum time we can wait for an event. |
| 910 |
timeval *tm = 0; |
| 911 |
timeval wait_tm = { 0l, 0l }; |
| 912 |
if (!(flags & QEventLoop::X11ExcludeTimers)) { |
| 913 |
if (d->timerList.timerWait(wait_tm)) |
| 914 |
tm = &wait_tm; |
| 915 |
} |
| 916 |
|
| 917 |
if (!canWait) { |
| 918 |
if (!tm) |
| 919 |
tm = &wait_tm; |
| 920 |
|
| 921 |
// no time to wait |
| 922 |
tm->tv_sec = 0l; |
| 923 |
tm->tv_usec = 0l; |
| 924 |
} |
| 925 |
|
| 926 |
nevents = d->doSelect(flags, tm); |
| 927 |
|
| 928 |
// activate timers |
| 929 |
if (! (flags & QEventLoop::X11ExcludeTimers)) { |
| 930 |
nevents += activateTimers(); |
| 931 |
} |
| 932 |
} |
| 933 |
// return true if we handled events, false otherwise |
| 934 |
return (nevents > 0); |
| 935 |
} |
| 936 |
|
| 937 |
bool QEventDispatcherUNIX::hasPendingEvents() |
| 938 |
{ |
| 939 |
extern uint qGlobalPostedEventsCount(); // from qapplication.cpp |
| 940 |
return qGlobalPostedEventsCount(); |
| 941 |
} |
| 942 |
|
| 943 |
void QEventDispatcherUNIX::wakeUp() |
| 944 |
{ |
| 945 |
Q_D(QEventDispatcherUNIX); |
| 946 |
if (d->wakeUps.testAndSetAcquire(0, 1)) { |
| 947 |
char c = 0; |
| 948 |
qt_safe_write( d->thread_pipe[1], &c, 1 ); |
| 949 |
} |
| 950 |
} |
| 951 |
|
| 952 |
void QEventDispatcherUNIX::interrupt() |
| 953 |
{ |
| 954 |
Q_D(QEventDispatcherUNIX); |
| 955 |
d->interrupt = true; |
| 956 |
wakeUp(); |
| 957 |
} |
| 958 |
|
| 959 |
void QEventDispatcherUNIX::flush() |
| 960 |
{ } |
| 961 |
|
| 962 |
|
| 963 |
|
| 964 |
|
| 965 |
void QCoreApplication::watchUnixSignal(int sig, bool watch) |
| 966 |
{ |
| 967 |
if (sig < NSIG) { |
| 968 |
struct sigaction sa; |
| 969 |
sigemptyset(&(sa.sa_mask)); |
| 970 |
sa.sa_flags = 0; |
| 971 |
if (watch) |
| 972 |
sa.sa_handler = signalHandler; |
| 973 |
else |
| 974 |
sa.sa_handler = SIG_DFL; |
| 975 |
sigaction(sig, &sa, 0); |
| 976 |
} |
| 977 |
} |
| 978 |
|
| 979 |
QT_END_NAMESPACE |