- Timestamp:
- Jul 26, 2009, 1:19:03 AM (16 years ago)
- Location:
- trunk/src/corelib/kernel
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/corelib/kernel/qeventdispatcher_pm.cpp
r83 r84 49 49 #include "qmutex.h" 50 50 #include "qwaitcondition.h" 51 #include "qlist.h" 52 #include "qmap.h" 53 #include "qhash.h" 54 #include "qset.h" 51 55 52 56 #include "qabstracteventdispatcher_p.h" … … 59 63 60 64 #include <sys/socket.h> 65 #include <sys/times.h> // for times() 66 #include <unistd.h> // for sysconf() 61 67 62 68 QT_BEGIN_NAMESPACE 63 69 64 70 extern uint qGlobalPostedEventsCount(); 65 66 class QEventDispatcherPMPrivate;67 68 // @todo later: timers69 #if 070 71 struct WinTimerInfo { // internal timer info72 QObject *dispatcher;73 int timerId;74 int interval;75 QObject *obj; // - object to receive events76 bool inTimerEvent;77 int fastTimerId;78 };79 80 class QZeroTimerEvent : public QTimerEvent81 {82 public:83 inline QZeroTimerEvent(int timerId)84 : QTimerEvent(timerId)85 { t = QEvent::ZeroTimerEvent; }86 };87 88 typedef QList<WinTimerInfo*> WinTimerVec; // vector of TimerInfo structs89 typedef QHash<int, WinTimerInfo*> WinTimerDict; // fast dict of timers90 91 #if !defined(DWORD_PTR) && !defined(Q_WS_WIN64)92 #define DWORD_PTR DWORD93 #endif94 95 typedef MMRESULT(WINAPI *ptimeSetEvent)(UINT, UINT, LPTIMECALLBACK, DWORD_PTR, UINT);96 typedef MMRESULT(WINAPI *ptimeKillEvent)(UINT);97 98 static ptimeSetEvent qtimeSetEvent = 0;99 static ptimeKillEvent qtimeKillEvent = 0;100 101 LRESULT CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);102 103 static void resolveTimerAPI()104 {105 static bool triedResolve = false;106 if (!triedResolve) {107 #ifndef QT_NO_THREAD108 QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve));109 if (triedResolve)110 return;111 #endif112 triedResolve = true;113 #if !defined(Q_OS_WINCE)114 qtimeSetEvent = (ptimeSetEvent)QLibrary::resolve(QLatin1String("winmm"), "timeSetEvent");115 qtimeKillEvent = (ptimeKillEvent)QLibrary::resolve(QLatin1String("winmm"), "timeKillEvent");116 #else117 qtimeSetEvent = (ptimeSetEvent)QLibrary::resolve(QLatin1String("Mmtimer"), "timeSetEvent");118 qtimeKillEvent = (ptimeKillEvent)QLibrary::resolve(QLatin1String("Mmtimer"), "timeKillEvent");119 #endif120 }121 }122 123 #endif124 71 125 72 /***************************************************************************** … … 272 219 273 220 274 // socket select notification (highe stpriority)221 // socket select notification (higher priority) 275 222 #define WM_U_SEM_SELECT WM_SEM1 276 // zero timer notification (lowest priority) 277 #define WM_U_SEM_ZEROTIMER WM_SEM4 223 // timer notification (lower priority) 224 #define WM_U_SEM_TIMER WM_SEM3 // scheduled right before WM_TIMER 225 226 // Internal operator functions for timevals 227 228 inline bool operator<(const timeval &t1, const timeval &t2) 229 { 230 return t1.tv_sec < t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_usec < t2.tv_usec); 231 } 232 233 inline bool operator==(const timeval &t1, const timeval &t2) 234 { 235 return t1.tv_sec == t2.tv_sec && t1.tv_usec == t2.tv_usec; 236 } 237 238 inline timeval &operator+=(timeval &t1, const timeval &t2) 239 { 240 t1.tv_sec += t2.tv_sec; 241 if ((t1.tv_usec += t2.tv_usec) >= 1000000l) { 242 ++t1.tv_sec; 243 t1.tv_usec -= 1000000l; 244 } 245 return t1; 246 } 247 inline timeval operator+(const timeval &t1, const timeval &t2) 248 { 249 timeval tmp; 250 tmp.tv_sec = t1.tv_sec + t2.tv_sec; 251 if ((tmp.tv_usec = t1.tv_usec + t2.tv_usec) >= 1000000l) { 252 ++tmp.tv_sec; 253 tmp.tv_usec -= 1000000l; 254 } 255 return tmp; 256 } 257 inline timeval operator-(const timeval &t1, const timeval &t2) 258 { 259 timeval tmp; 260 tmp.tv_sec = t1.tv_sec - t2.tv_sec; 261 if ((tmp.tv_usec = t1.tv_usec - t2.tv_usec) < 0l) { 262 --tmp.tv_sec; 263 tmp.tv_usec += 1000000l; 264 } 265 return tmp; 266 } 278 267 279 268 /***************************************************************************** 280 socket select() thread269 socket select() and timer service thread 281 270 *****************************************************************************/ 282 271 283 272 #if !defined(QT_NO_THREAD) 284 273 285 class QS ockSelectThread : public QThread274 class QSelectThread : public QThread 286 275 { 287 276 public: 277 288 278 typedef QSocketNotifier::Type Type; 289 279 … … 292 282 static QSocketNotifier *getSocketNotifier(int key); 293 283 284 // timer support is based on QTimerInfoList from the Unix implementation 285 static void addTimer(int timerId, int interval, QObject *object, HWND hwnd); 286 static bool removeTimer(int timerId); 287 static bool removeTimers(QObject *object); 288 static QList<QPair<int, int> > knownTimers(QObject *object); 289 static QObject *getTimerObject(int timerId); 290 294 291 static void attachThread(); 295 292 static void detachThread(); 296 293 297 294 private: 298 QSockSelectThread() : finish(false), refcnt(0), maxSockfd(-1) {}; 295 QSelectThread(); 296 ~QSelectThread(); 299 297 300 298 void run(); 301 299 void cancelSelectOrIdle(); 300 301 struct TimerInfo; 302 303 bool timeChanged(timeval *delta); 304 void getTime(timeval &t); 305 void updateCurrentTime(); 306 void removeFromTimeoutMap(TimerInfo *ti); 307 308 bool timerWait(timeval &); 309 void timerRepair(const timeval &); 310 311 void activateTimers(); 302 312 303 313 bool finish; … … 305 315 QWaitCondition cond; 306 316 317 // socket stuff 318 307 319 typedef QHash<int, QSocketNotifier*> Sockets; 308 320 Sockets sockets; … … 310 322 311 323 enum Op { Add, Remove }; 312 struct Pending Op {324 struct PendingSockOp { 313 325 Op op; 314 326 int sockfd; … … 316 328 HWND hwnd; 317 329 }; 318 typedef QList<PendingOp> Pending; 319 Pending pending; 320 321 static int toKey(int sockfd, Type type) { 330 331 typedef QList<PendingSockOp> PendingSockets; 332 PendingSockets pendingSockets; 333 334 // timer stuff 335 336 struct TimerInfo { 337 int id; // - timer identifier 338 timeval interval; // - timer interval 339 timeval timeout; // - when to sent event 340 QObject *obj; // - object to receive event 341 HWND hwnd; // - where to post the timer message 342 }; 343 344 typedef QHash<int, TimerInfo*> TimerInfoMap; 345 TimerInfoMap timers; 346 347 typedef QMap<timeval, TimerInfo*> TimevalMap; 348 TimevalMap timersByTimeout; 349 350 timeval currentTime; 351 timeval previousTime; 352 clock_t previousTicks; 353 int ticksPerSecond; 354 int msPerTick; 355 356 static int toSockKey(int sockfd, Type type) { 322 357 // as a hash key, we use first two bits of int for the type and the rest 323 358 // for the sockfd which should be enough in the real world … … 325 360 return (sockfd << 2) + type; 326 361 } 327 // opposite to to Key()362 // opposite to toSockKey() 328 363 static int toSocket(int key) { return key >> 2; } 329 static Type to Type(int key) { return Type(key & 0x3); }330 331 static QS ockSelectThread *instance;364 static Type toSockType(int key) { return Type(key & 0x3); } 365 366 static QSelectThread *instance; 332 367 static QMutex mutex; 333 368 }; 334 369 335 370 // static 336 QS ockSelectThread *QSockSelectThread::instance = 0;337 QMutex QS ockSelectThread::mutex;371 QSelectThread *QSelectThread::instance = 0; 372 QMutex QSelectThread::mutex; 338 373 339 374 // static 340 void QS ockSelectThread::addSelect(QSocketNotifier *notifier, HWND hwnd)375 void QSelectThread::addSelect(QSocketNotifier *notifier, HWND hwnd) 341 376 { 342 377 Q_ASSERT(hwnd != NULLHANDLE); … … 346 381 int sockfd = notifier->socket(); 347 382 Type type = notifier->type(); 348 int key = to Key(sockfd, type);383 int key = toSockKey(sockfd, type); 349 384 350 385 QMutexLocker locker(&mutex); 351 386 Q_ASSERT(instance); 352 387 388 // lazy start 353 389 instance->start(); 354 390 … … 360 396 } 361 397 instance->sockets.insert(key, notifier); 362 Pending Op op = {Add, sockfd, type, hwnd};363 instance->pending .append(op);398 PendingSockOp op = {Add, sockfd, type, hwnd}; 399 instance->pendingSockets.append(op); 364 400 instance->cancelSelectOrIdle(); 365 401 } 366 402 367 403 // static 368 void QS ockSelectThread::removeSelect(QSocketNotifier *notifier)404 void QSelectThread::removeSelect(QSocketNotifier *notifier) 369 405 { 370 406 QMutexLocker locker(&mutex); … … 373 409 int sockfd = notifier->socket(); 374 410 Type type = notifier->type(); 375 int key = to Key(sockfd, notifier->type());411 int key = toSockKey(sockfd, notifier->type()); 376 412 377 413 if (instance->sockets.contains(key)) { 378 414 instance->sockets.remove(key); 379 Pending Op op = {Remove, sockfd, type};380 instance->pending .append(op);415 PendingSockOp op = {Remove, sockfd, type}; 416 instance->pendingSockets.append(op); 381 417 instance->cancelSelectOrIdle(); 382 418 } … … 389 425 390 426 May return 0 if the socket notifier object is disabled/deleted after 391 WM_U_SEM_SELECT is issued for it but before this message gets processed by427 WM_U_SEM_SELECT was issued for it but before this message gets processed by 392 428 the owning thread. 393 429 */ 394 430 // static 395 QSocketNotifier *QS ockSelectThread::getSocketNotifier(int key)431 QSocketNotifier *QSelectThread::getSocketNotifier(int key) 396 432 { 397 433 QMutexLocker locker(&mutex); … … 405 441 } 406 442 443 // static 444 void QSelectThread::addTimer(int timerId, int interval, QObject *object, HWND hwnd) 445 { 446 Q_ASSERT(hwnd != NULLHANDLE); 447 if (hwnd == NULLHANDLE) 448 return; 449 450 QMutexLocker locker(&mutex); 451 Q_ASSERT(instance); 452 453 // lazy start 454 instance->start(); 455 456 instance->updateCurrentTime(); 457 458 TimerInfo *t = new TimerInfo; 459 t->id = timerId; 460 t->interval.tv_sec = interval / 1000; 461 t->interval.tv_usec = (interval % 1000) * 1000; 462 t->timeout = instance->currentTime + t->interval; 463 t->obj = object; 464 t->hwnd = hwnd; 465 466 instance->timers.insert(t->id, t); 467 // QMap is sorted by key (timeval), which is exactly what we need 468 instance->timersByTimeout.insert(t->timeout, t); 469 470 instance->cancelSelectOrIdle(); 471 } 472 473 // static 474 bool QSelectThread::removeTimer(int timerId) 475 { 476 QMutexLocker locker(&mutex); 477 Q_ASSERT(instance); 478 479 // set timer inactive 480 TimerInfo *t = instance->timers.take(timerId); 481 if (t) { 482 // release the timer id 483 if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent) 484 QAbstractEventDispatcherPrivate::releaseTimerId(timerId); 485 instance->removeFromTimeoutMap(t); 486 487 delete t; 488 return true; 489 } 490 491 // id not found 492 return false; 493 } 494 495 // static 496 bool QSelectThread::removeTimers(QObject *object) 497 { 498 QMutexLocker locker(&mutex); 499 Q_ASSERT(instance); 500 501 if (instance->timers.isEmpty()) 502 return false; 503 for (TimerInfoMap::iterator it = instance->timers.begin(); 504 it != instance->timers.end();) { 505 register TimerInfo *t = it.value(); 506 if (t->obj == object) { 507 // object found 508 it = instance->timers.erase(it); 509 510 // release the timer id 511 if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent) 512 QAbstractEventDispatcherPrivate::releaseTimerId(t->id); 513 instance->removeFromTimeoutMap(t); 514 515 delete t; 516 } else { 517 ++it; 518 } 519 } 520 return true; 521 } 522 523 // static 524 QList<QPair<int, int> > QSelectThread::knownTimers(QObject *object) 525 { 526 QMutexLocker locker(&mutex); 527 Q_ASSERT(instance); 528 529 QList<QPair<int, int> > list; 530 for (TimerInfoMap::const_iterator it = instance->timers.constBegin(); 531 it != instance->timers.constEnd(); ++it) { 532 register const TimerInfo * const t = it.value(); 533 if (t->obj == object) 534 list << QPair<int, int>(t->id, t->interval.tv_sec * 1000 + t->interval.tv_usec / 1000); 535 } 536 return list; 537 } 538 407 539 /*! 408 Incrreases the usage count of the QSockSelectThread instance by one. If no 409 QSockSelectThread instance exists yet, creates it. Note that the thread is 540 Returns the timer object corresponding to the given timer ID from the 541 WM_U_SEM_TIMER message. The return value is only correct for the thread 542 that owns the timer (creates/registers/unregisters it). 543 544 May return 0 if the timer is stopped/deleted after WM_U_SEM_TIMER was issued 545 for it but before this message gets processed by the owning thread. 546 */ 547 // static 548 QObject *QSelectThread::getTimerObject(int timerId) 549 { 550 QMutexLocker locker(&mutex); 551 Q_ASSERT(instance); 552 553 TimerInfo *t = instance->timers.value(timerId); 554 if (t) 555 return t->obj; 556 557 return 0; 558 } 559 560 /*! 561 Incrreases the usage count of the QSelectThread instance by one. If no 562 QSelectThread instance exists yet, creates it. Note that the thread is 410 563 started on demand by addSelect(), not by this method. 411 564 … … 415 568 */ 416 569 // static 417 void QS ockSelectThread::attachThread()570 void QSelectThread::attachThread() 418 571 { 419 572 QMutexLocker locker(&mutex); 420 573 421 574 if (instance == 0) { 422 instance = new QS ockSelectThread();575 instance = new QSelectThread(); 423 576 instance->start(); 424 577 } … … 429 582 /*! 430 583 Removes all socket notifiers owned by the current thread and decreases the 431 usage count of the QS ockSelectThread instance by one. When the usage count584 usage count of the QSelectThread instance by one. When the usage count 432 585 goes to zero, the socket select thread is stopped and the instance is 433 586 deleted. … … 437 590 */ 438 591 // static 439 void QS ockSelectThread::detachThread()592 void QSelectThread::detachThread() 440 593 { 441 594 QMutexLocker locker(&mutex); 442 595 Q_ASSERT(instance); 443 596 597 // remove socket notifiers owned by this thread 444 598 for (Sockets::iterator it = instance->sockets.begin(); 445 599 it != instance->sockets.end();) { 446 600 QSocketNotifier *notifier = it.value(); 447 601 if (notifier->thread() == QThread::currentThread()) { 448 Pending Op op = {Remove, notifier->socket(), notifier->type()};449 instance->pending .append(op);602 PendingSockOp op = {Remove, notifier->socket(), notifier->type()}; 603 instance->pendingSockets.append(op); 450 604 it = instance->sockets.erase(it); 605 } else { 606 ++it; 607 } 608 } 609 610 // remove timers owned by this thread 611 for (TimerInfoMap::iterator it = instance->timers.begin(); 612 it != instance->timers.end();) { 613 register TimerInfo *t = it.value(); 614 if (t->obj->thread() == QThread::currentThread()) { 615 // object found 616 it = instance->timers.erase(it); 617 618 // release the timer id 619 if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent) 620 QAbstractEventDispatcherPrivate::releaseTimerId(t->id); 621 instance->removeFromTimeoutMap(t); 622 623 delete t; 451 624 } else { 452 625 ++it; … … 464 637 } 465 638 } 466 void QSockSelectThread::run() 639 640 QSelectThread::QSelectThread() : finish(false), refcnt(0) 641 { 642 // initialize socket stuff 643 maxSockfd = -1; 644 645 // initialize timer stuff 646 getTime(currentTime); 647 648 // initialize the timeChanged() machinery 649 previousTime = currentTime; 650 651 tms unused; 652 previousTicks = times(&unused); 653 654 ticksPerSecond = sysconf(_SC_CLK_TCK); 655 msPerTick = 1000 / ticksPerSecond; 656 } 657 658 QSelectThread::~QSelectThread() 659 { 660 // detachThread() calls must clean up sockets/timers they own 661 Q_ASSERT(sockets.isEmpty()); 662 Q_ASSERT(timers.isEmpty()); 663 Q_ASSERT(timersByTimeout.isEmpty()); 664 665 // but, still, be nice and cleanup timers (we allocate them with new) 666 qDeleteAll(timers); 667 } 668 669 void QSelectThread::run() 467 670 { 468 671 // maintain a separate hash for HWNDs to avoid mutex locking every time … … 476 679 FD_ZERO(&exS); 477 680 681 mutex.lock(); 682 478 683 do { 479 mutex.lock();480 481 684 while (!finish && sockets.isEmpty()) { 482 685 cond.wait(&mutex); 483 686 } 484 687 485 if (finish) { 486 mutex.unlock(); 688 if (finish) 487 689 break; 488 } 489 490 while (!pending .isEmpty()) {491 Pending Op p = pending.takeFirst();690 691 // process pending socket operations 692 while (!pendingSockets.isEmpty()) { 693 PendingSockOp p = pendingSockets.takeFirst(); 492 694 switch (p.op) { 493 695 case Add: … … 500 702 FD_SET(p.sockfd, &exS); break; 501 703 } 502 hwnds.insert(to Key(p.sockfd, p.type), p.hwnd);704 hwnds.insert(toSockKey(p.sockfd, p.type), p.hwnd); 503 705 maxSockfd = qMax(maxSockfd, p.sockfd); 504 706 break; … … 512 714 FD_CLR(p.sockfd, &exS); break; 513 715 } 514 hwnds.remove(to Key(p.sockfd, p.type));716 hwnds.remove(toSockKey(p.sockfd, p.type)); 515 717 if (maxSockfd == p.sockfd) { 516 718 // find the new hignest socket … … 528 730 } 529 731 732 // get the maximum time we can wait (for the closest timer) 733 timeval *timeout = 0; 734 timeval wait_tm = { 0l, 0l }; 735 if (timerWait(wait_tm)) 736 timeout = &wait_tm; 737 738 mutex.unlock(); 739 530 740 // do select 531 mutex.unlock(); 532 int nsel = ::select(maxSockfd + 1, &readS, &writeS, &exS, NULL); 741 int nsel = ::select(maxSockfd + 1, &readS, &writeS, &exS, timeout); 533 742 if (nsel > 0) { 534 743 for (Hwnds::const_iterator it = hwnds.constBegin(); … … 536 745 int sockfd = toSocket(it.key()); 537 746 bool isSet = false; 538 switch (to Type(it.key())) {747 switch (toSockType(it.key())) { 539 748 case QSocketNotifier::Read: 540 749 isSet = FD_ISSET(sockfd, &readS); break; … … 548 757 } 549 758 } 759 760 mutex.lock(); 761 762 if (nsel == 0 || (nsel == -1 && errno == EINTR)) { 763 // timeout, check if there are expired timers 764 activateTimers(); 765 } 550 766 } while(true); 551 } 552 553 // Must be called from under QSockSelectThread::mutex 554 void QSockSelectThread::cancelSelectOrIdle() 767 768 mutex.unlock(); 769 } 770 771 // Must be called from under QSelectThread::mutex 772 void QSelectThread::cancelSelectOrIdle() 555 773 { 556 774 if (maxSockfd >= 0) { … … 563 781 } 564 782 783 /* 784 Returns true if the real time clock has changed by more than 10% 785 relative to the processor time since the last time this function was 786 called. This presumably means that the system time has been changed. 787 788 If /a delta is nonzero, delta is set to our best guess at how much the system 789 clock was changed. 790 */ 791 bool QSelectThread::timeChanged(timeval *delta) 792 { 793 tms unused; 794 clock_t currentTicks = times(&unused); 795 796 int elapsedTicks = currentTicks - previousTicks; 797 timeval elapsedTime = currentTime - previousTime; 798 int elapsedMsecTicks = (elapsedTicks * 1000) / ticksPerSecond; 799 int deltaMsecs = (elapsedTime.tv_sec * 1000 + elapsedTime.tv_usec / 1000) 800 - elapsedMsecTicks; 801 802 if (delta) { 803 delta->tv_sec = deltaMsecs / 1000; 804 delta->tv_usec = (deltaMsecs % 1000) * 1000; 805 } 806 previousTicks = currentTicks; 807 previousTime = currentTime; 808 809 // If tick drift is more than 10% off compared to realtime, we assume that the clock has 810 // been set. Of course, we have to allow for the tick granularity as well. 811 812 return (qAbs(deltaMsecs) - msPerTick) * 10 > elapsedMsecTicks; 813 } 814 815 void QSelectThread::getTime(timeval &t) 816 { 817 gettimeofday(&t, 0); 818 // NTP-related fix 819 while (t.tv_usec >= 1000000l) { 820 t.tv_usec -= 1000000l; 821 ++t.tv_sec; 822 } 823 while (t.tv_usec < 0l) { 824 if (t.tv_sec > 0l) { 825 t.tv_usec += 1000000l; 826 --t.tv_sec; 827 } else { 828 t.tv_usec = 0l; 829 break; 830 } 831 } 832 } 833 834 void QSelectThread::updateCurrentTime() 835 { 836 getTime(currentTime); 837 838 // repair timers if needed 839 timeval delta; 840 if (timeChanged(&delta)) 841 timerRepair(delta); 842 } 843 844 void QSelectThread::removeFromTimeoutMap(TimerInfo *ti) 845 { 846 TimevalMap::iterator it = timersByTimeout.find(ti->timeout); 847 while (it != timersByTimeout.end() && it.value() != ti) 848 ++it; 849 Q_ASSERT(it != timersByTimeout.end()); 850 timersByTimeout.erase(it); 851 } 852 853 /* 854 repair broken timer 855 */ 856 void QSelectThread::timerRepair(const timeval &diff) 857 { 858 // repair all timers 859 for (TimerInfoMap::iterator it = instance->timers.begin(); 860 it != instance->timers.end(); ++it) { 861 register TimerInfo *t = it.value(); 862 t->timeout = t->timeout - diff; 863 } 864 } 865 866 /* 867 Returns the time to wait for the next timer, or null if no timers 868 are waiting. 869 */ 870 bool QSelectThread::timerWait(timeval &tm) 871 { 872 updateCurrentTime(); 873 874 if (timers.isEmpty()) 875 return false; 876 877 TimerInfo *t = timersByTimeout.begin().value(); // first waiting timer 878 if (currentTime < t->timeout) { 879 // time to wait 880 tm = t->timeout - currentTime; 881 } else { 882 // no time to wait 883 tm.tv_sec = 0; 884 tm.tv_usec = 0; 885 } 886 887 return true; 888 } 889 890 /* 891 Activates pending timers. 892 */ 893 void QSelectThread::activateTimers() 894 { 895 if (timers.isEmpty()) 896 return; // nothing to do 897 898 updateCurrentTime(); 899 900 while(true) { 901 TimerInfo *t = timersByTimeout.begin().value(); 902 903 if (currentTime < t->timeout) 904 break; // no timer has expired 905 906 // remove from map 907 timersByTimeout.erase(timersByTimeout.begin()); 908 909 // determine next timeout time 910 if (t->interval.tv_sec == 0 && t->interval.tv_usec == 0) { 911 // zero timer; make sure it won't fire again in this loop 912 t->timeout.tv_sec = 0; 913 t->timeout.tv_usec = 1; 914 t->timeout += currentTime; 915 } else { 916 // normal timer; also make sure it won't fire again in this loop 917 t->timeout += t->interval; 918 if (t->timeout < currentTime) 919 t->timeout = currentTime + t->interval; 920 } 921 922 // reinsert timer (in proper sort order) 923 timersByTimeout.insert(t->timeout, t); 924 925 // post the timer message 926 WinPostMsg(t->hwnd, WM_U_SEM_TIMER, MPFROMLONG(t->id), 0); 927 } 928 929 return; 930 } 931 565 932 #else 566 933 567 class QSockSelectThread 568 { 934 class QSelectThread 935 { 936 // dummy implementation 937 569 938 public: 570 939 static void addSelect(QSocketNotifier *notifier, HWND hwnd) { … … 577 946 static QSocketNotifier *getSocketNotifier(int key); { return 0; } 578 947 948 static void addTimer(int timerId, int interval, QObject *object, HWND hwnd) { 949 #ifndef QT_NO_DEBUG 950 qWarning("QObject::startTimer: timers require thread support but" 951 "QT_NO_THREAD was defined"); 952 #endif 953 } 954 static bool removeTimer(int timerId) { return false; } 955 static bool removeTimers(QObject *object) { return false; } 956 static QList<QPair<int, int> > knownTimers(QObject *object) const { 957 return QList<QPair<int, int> >(); 958 } 959 static QObject *getTimerObject(int timerId); 960 579 961 static void attachThread() {} 580 962 static void detachThread() {} … … 593 975 void createAuxWnd(); 594 976 595 // Auxiliary object window to process WM_U_SEM_SELECT and WM_ TIMER messages.977 // Auxiliary object window to process WM_U_SEM_SELECT and WM_U_SEM_TIMER messages. 596 978 // We need a dedicated window along with processing these messages directly in 597 979 // QEventLoop::processEvents() to make sure they are processed even if the … … 607 989 MRESULT message(ULONG msg, MPARAM mp1, MPARAM mp2); 608 990 QEventDispatcherPMPrivate *dispatcher; 991 private: 992 QSet<int> timersInSend; 609 993 } auxWnd; 610 994 … … 615 999 616 1000 // @todo later 617 //618 // // timers619 // WinTimerVec timerVec;620 // WinTimerDict timerDict;621 // void registerTimer(WinTimerInfo *t);622 // void unregisterTimer(WinTimerInfo *t);623 // void sendTimerEvent(int timerId);624 1001 // 625 1002 // QList<QMSG> queuedUserInputEvents; … … 685 1062 case WM_U_SEM_SELECT: { 686 1063 QSocketNotifier *notifier = 687 QS ockSelectThread::getSocketNotifier(LONGFROMMP(mp1));688 689 690 691 1064 QSelectThread::getSocketNotifier(LONGFROMMP(mp1)); 1065 if (notifier) { 1066 QEvent event(QEvent::SockAct); 1067 QCoreApplication::sendEvent(notifier, &event); 1068 } 692 1069 break; 693 1070 } 694 case WM_U_SEM_ZEROTIMER: { 695 // @todo later 696 // if (numZeroTimers) { 697 // activateZeroTimers(); 698 // // repost the message if there are still zero timers left 699 // if (numZeroTimers) 700 // WinPostMsg(hwnd(), WM_U_SEM_ZEROTIMER, 0, 0); 701 // } 1071 case WM_U_SEM_TIMER: { 1072 int timerId = LONGFROMMP(mp1); 1073 QObject *obj = QSelectThread::getTimerObject(timerId); 1074 1075 if (obj && !timersInSend.contains(timerId)) { 1076 // send event, but don't allow it to recurse 1077 timersInSend += timerId; 1078 1079 QTimerEvent e(timerId); 1080 QCoreApplication::sendEvent(obj, &e); 1081 1082 timersInSend -= timerId; 1083 } 702 1084 break; 703 1085 } 704 case WM_TIMER: { 705 // @todo later 706 // USHORT id = SHORT1FROMMP(mp1); 707 // dispatchTimer((uint) id, &qmsg); 1086 default: 708 1087 break; 709 }710 1088 } 711 1089 712 1090 return FALSE; 713 1091 } 714 715 // @todo remove716 #if 0717 718 LRESULT CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)719 {720 if (message == WM_NCCREATE) {721 return true;722 } else if (message == WM_USER) {723 724 // socket notifier message725 MSG msg;726 msg.hwnd = hwnd;727 msg.message = message;728 msg.wParam = wp;729 msg.lParam = lp;730 731 QCoreApplication *app = QCoreApplication::instance();732 long result;733 if (app && app->filterEvent(&msg, &result))734 return result;735 736 int type = -1;737 switch (WSAGETSELECTEVENT(lp)) {738 case FD_READ:739 case FD_CLOSE:740 case FD_ACCEPT:741 type = 0;742 break;743 case FD_WRITE:744 case FD_CONNECT:745 type = 1;746 break;747 case FD_OOB:748 type = 2;749 break;750 }751 if (type >= 0) {752 753 #ifdef GWLP_USERDATA754 QEventDispatcherPM *eventDispatcher =755 (QEventDispatcherPM *) GetWindowLongPtrA(hwnd, GWLP_USERDATA);756 #else757 QEventDispatcherPM *eventDispatcher =758 (QEventDispatcherPM *) GetWindowLongA(hwnd, GWL_USERDATA);759 #endif760 if (eventDispatcher) {761 QEventDispatcherPMPrivate *d = eventDispatcher->d_func();762 QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };763 QSNDict *dict = sn_vec[type];764 765 QSockNot *sn = dict ? dict->value(wp) : 0;766 if (sn) {767 QEvent event(QEvent::SockAct);768 QCoreApplication::sendEvent(sn->obj, &event);769 }770 }771 }772 return 0;773 774 } else if (message == WM_TIMER) {775 776 MSG msg;777 msg.hwnd = hwnd;778 msg.message = message;779 msg.wParam = wp;780 msg.lParam = lp;781 782 QCoreApplication *app = QCoreApplication::instance();783 Q_ASSERT_X(app, "qt_interal_proc", "Timer fired, but no QCoreApplication");784 if (!app) {785 KillTimer(hwnd, wp);786 return 0;787 }788 789 long result;790 if (app->filterEvent(&msg, &result))791 return result;792 793 QEventDispatcherPM *eventDispatcher =794 qobject_cast<QEventDispatcherPM *>(QAbstractEventDispatcher::instance());795 Q_ASSERT(eventDispatcher != 0);796 QEventDispatcherPMPrivate *d = eventDispatcher->d_func();797 d->sendTimerEvent(wp);798 return 0;799 }800 801 return DefWindowProc(hwnd, message, wp, lp);802 }803 804 void QEventDispatcherPMPrivate::registerTimer(WinTimerInfo *t)805 {806 Q_ASSERT(internalHwnd);807 808 Q_Q(QEventDispatcherPM);809 810 int ok = 0;811 812 if (t->interval > 10 || !t->interval || !qtimeSetEvent) {813 ok = 1;814 if (!t->interval) // optimization for single-shot-zero-timer815 QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId));816 else817 ok = SetTimer(internalHwnd, t->timerId, (uint) t->interval, 0);818 } else {819 ok = t->fastTimerId = qtimeSetEvent(t->interval, 1, qt_fast_timer_proc, (DWORD_PTR)t,820 TIME_CALLBACK_FUNCTION | TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);821 if (ok == 0) { // fall back to normal timer if no more multimedia timers avaiable822 ok = SetTimer(internalHwnd, t->timerId, (uint) t->interval, 0);823 }824 }825 826 if (ok == 0)827 qErrnoWarning("QEventDispatcherPM::registerTimer: Failed to create a timer");828 }829 830 void QEventDispatcherPMPrivate::unregisterTimer(WinTimerInfo *t)831 {832 // mark timer as unused833 if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent)834 QAbstractEventDispatcherPrivate::releaseTimerId(t->timerId);835 836 if (t->interval == 0) {837 QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);838 } else if (t->fastTimerId != 0) {839 qtimeKillEvent(t->fastTimerId);840 QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);841 } else if (internalHwnd) {842 KillTimer(internalHwnd, t->timerId);843 }844 delete t;845 }846 847 void QEventDispatcherPMPrivate::sendTimerEvent(int timerId)848 {849 WinTimerInfo *t = timerDict.value(timerId);850 if (t && !t->inTimerEvent) {851 // send event, but don't allow it to recurse852 t->inTimerEvent = true;853 854 QTimerEvent e(t->timerId);855 QCoreApplication::sendEvent(t->obj, &e);856 857 // timer could have been removed858 t = timerDict.value(timerId);859 if (t) {860 t->inTimerEvent = false;861 }862 }863 }864 865 void QEventDispatcherPM::createInternalHwnd()866 {867 Q_D(QEventDispatcherPM);868 869 Q_ASSERT(!d->internalHwnd);870 if (d->internalHwnd)871 return;872 d->internalHwnd = qt_create_internal_window(this);873 874 // register all socket notifiers875 QList<int> sockets = (d->sn_read.keys().toSet()876 + d->sn_write.keys().toSet()877 + d->sn_except.keys().toSet()).toList();878 for (int i = 0; i < sockets.count(); ++i)879 d->doWsaAsyncSelect(sockets.at(i));880 881 // start all normal timers882 for (int i = 0; i < d->timerVec.count(); ++i)883 d->registerTimer(d->timerVec.at(i));884 }885 886 #endif887 1092 888 1093 QEventDispatcherPM::QEventDispatcherPM(QObject *parent) … … 1022 1227 d->createAuxWnd(); 1023 1228 1024 QS ockSelectThread::addSelect(notifier, d->auxWnd.hwnd());1229 QSelectThread::addSelect(notifier, d->auxWnd.hwnd()); 1025 1230 } 1026 1231 … … 1041 1246 #endif 1042 1247 1043 QS ockSelectThread::removeSelect(notifier);1248 QSelectThread::removeSelect(notifier); 1044 1249 } 1045 1250 1046 1251 void QEventDispatcherPM::registerTimer(int timerId, int interval, QObject *object) 1047 1252 { 1048 // @todo later 1049 #if 0 1253 #ifndef QT_NO_DEBUG 1050 1254 if (timerId < 1 || interval < 0 || !object) { 1051 1255 qWarning("QEventDispatcherPM::registerTimer: invalid arguments"); … … 1055 1259 return; 1056 1260 } 1261 #endif 1057 1262 1058 1263 Q_D(QEventDispatcherPM); 1059 1060 register WinTimerInfo *t = new WinTimerInfo; 1061 t->dispatcher = this; 1062 t->timerId = timerId; 1063 t->interval = interval; 1064 t->obj = object; 1065 t->inTimerEvent = false; 1066 t->fastTimerId = 0; 1067 1068 if (d->internalHwnd) 1069 d->registerTimer(t); 1070 1071 d->timerVec.append(t); // store in timer vector 1072 d->timerDict.insert(t->timerId, t); // store timers in dict 1073 #endif 1264 d->createAuxWnd(); 1265 1266 QSelectThread::addTimer(timerId, interval, object, d->auxWnd.hwnd()); 1074 1267 } 1075 1268 1076 1269 bool QEventDispatcherPM::unregisterTimer(int timerId) 1077 1270 { 1078 // @todo later 1079 #if 0 1271 #ifndef QT_NO_DEBUG 1080 1272 if (timerId < 1) { 1081 1273 qWarning("QEventDispatcherPM::unregisterTimer: invalid argument"); 1082 1274 return false; 1083 } 1084 QThread *currentThread = QThread::currentThread(); 1085 if (thread() != currentThread) { 1275 } else if (thread() != QThread::currentThread()) { 1086 1276 qWarning("QObject::killTimer: timers cannot be stopped from another thread"); 1087 1277 return false; 1088 1278 } 1089 1090 Q_D(QEventDispatcherPM);1091 if (d->timerVec.isEmpty() || timerId <= 0)1092 return false;1093 1094 WinTimerInfo *t = d->timerDict.value(timerId);1095 if (!t)1096 return false;1097 1098 d->timerDict.remove(t->timerId);1099 d->timerVec.removeAll(t);1100 d->unregisterTimer(t);1101 return true;1102 #else1103 return false;1104 1279 #endif 1280 1281 return QSelectThread::removeTimer(timerId); 1105 1282 } 1106 1283 1107 1284 bool QEventDispatcherPM::unregisterTimers(QObject *object) 1108 1285 { 1109 // @todo later 1110 #if 0 1286 #ifndef QT_NO_DEBUG 1111 1287 if (!object) { 1112 1288 qWarning("QEventDispatcherPM::unregisterTimers: invalid argument"); 1113 1289 return false; 1114 } 1115 QThread *currentThread = QThread::currentThread(); 1116 if (object->thread() != thread() || thread() != currentThread) { 1290 } else if (object->thread() != thread() || thread() != QThread::currentThread()) { 1117 1291 qWarning("QObject::killTimers: timers cannot be stopped from another thread"); 1118 1292 return false; 1119 1293 } 1120 1121 Q_D(QEventDispatcherPM);1122 if (d->timerVec.isEmpty())1123 return false;1124 register WinTimerInfo *t;1125 for (int i=0; i<d->timerVec.size(); i++) {1126 t = d->timerVec.at(i);1127 if (t && t->obj == object) { // object found1128 d->timerDict.remove(t->timerId);1129 d->timerVec.removeAt(i);1130 d->unregisterTimer(t);1131 --i;1132 }1133 }1134 return true;1135 #else1136 return false;1137 1294 #endif 1295 1296 return QSelectThread::removeTimers(object); 1138 1297 } 1139 1298 … … 1141 1300 QEventDispatcherPM::registeredTimers(QObject *object) const 1142 1301 { 1143 // @todo later 1144 #if 0 1302 #ifndef QT_NO_DEBUG 1145 1303 if (!object) { 1146 1304 qWarning("QEventDispatcherPM:registeredTimers: invalid argument"); 1147 1305 return QList<TimerInfo>(); 1148 1306 } 1149 1150 Q_D(const QEventDispatcherPM);1151 QList<TimerInfo> list;1152 for (int i = 0; i < d->timerVec.size(); ++i) {1153 const WinTimerInfo *t = d->timerVec.at(i);1154 if (t && t->obj == object)1155 list << TimerInfo(t->timerId, t->interval);1156 }1157 return list;1158 #else1159 return QList<TimerInfo>();1160 1307 #endif 1308 1309 return QSelectThread::knownTimers(object); 1161 1310 } 1162 1311 … … 1185 1334 void QEventDispatcherPM::startingUp() 1186 1335 { 1187 QS ockSelectThread::attachThread();1336 QSelectThread::attachThread(); 1188 1337 } 1189 1338 1190 1339 void QEventDispatcherPM::closingDown() 1191 1340 { 1192 QSockSelectThread::detachThread(); 1193 1194 // @todo remove later 1195 #if 0 1196 Q_D(QEventDispatcherPM); 1197 1198 // clean up any timers 1199 while (!d->timerDict.isEmpty()) 1200 unregisterTimer((*(d->timerDict.begin()))->timerId); 1201 #endif 1202 } 1203 1204 // @todo remove later 1205 #if 0 1206 bool QEventDispatcherPM::event(QEvent *e) 1207 { 1208 Q_D(QEventDispatcherPM); 1209 if (e->type() == QEvent::ZeroTimerEvent) { 1210 QZeroTimerEvent *zte = static_cast<QZeroTimerEvent*>(e); 1211 WinTimerInfo *t = d->timerDict.value(zte->timerId()); 1212 if (t) { 1213 t->inTimerEvent = true; 1214 1215 QTimerEvent te(zte->timerId()); 1216 QCoreApplication::sendEvent(t->obj, &te); 1217 1218 t = d->timerDict.value(zte->timerId()); 1219 if (t) { 1220 if (t->interval == 0 && t->inTimerEvent) { 1221 // post the next zero timer event as long as the timer was not restarted 1222 QCoreApplication::postEvent(this, new QZeroTimerEvent(zte->timerId())); 1223 } 1224 1225 t->inTimerEvent = false; 1226 } 1227 } 1228 return true; 1229 } else if (e->type() == QEvent::Timer) { 1230 QTimerEvent *te = static_cast<QTimerEvent*>(e); 1231 d->sendTimerEvent(te->timerId()); 1232 } 1233 return QAbstractEventDispatcher::event(e); 1234 } 1235 #endif 1341 QSelectThread::detachThread(); 1342 } 1236 1343 1237 1344 QT_END_NAMESPACE -
trunk/src/corelib/kernel/qeventdispatcher_pm_p.h
r67 r84 91 91 void startingUp(); 92 92 void closingDown(); 93 94 // @todo remove later95 // bool event(QEvent *e);96 93 }; 97 94
Note:
See TracChangeset
for help on using the changeset viewer.