Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-51888

WinRT: Timers can be blocked by other timers.

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • P2: Important
    • None
    • 5.6.0 RC
    • Core: Event loop
    • None
    • Windows 10.
    • WinRT
    • 7e72a5e11e92ed1df28ed34b13b711df6ca6fde2 in qtbase/5.6

    Description

      It is possible for timers to be blocked by other timers for an indefinite time due to the current implementation of the WaitForMultipleObjectsEx handling at qeventdispatcher_winrt.cpp:219.

      This is most likely to occur if a high frequency recurring timer is scheduled along with other timers, and the high frequency timer handle is first in the timerHandles list at qeventdispatcher_winrt.cpp:216.

      If more than one timer event handle is signalled when coming out of WaitForMultipleObjectsEx, only the first timer handle is processed - in this case the high frequency timer. Then the next time WaitForMultipleObjectsEx is called, it is possible that the high frequency timer handle is again only processed, ignoring the other potentially signalled timer event handlers.

      In our experience the QML render timer is usually the high frequency timer that causes this issue.

      A possible alternative WaitForMultipleObjectsEx implementation is as follows, where WaitForMultipleObjectsEx is called multiple times until WAIT_TIMEOUT is returned, which ensures that all signalled timer event handles are processed.

      This is what we are currently using and seems to work as expected.

      
      bool timerFired = false;
      DWORD waitResult = WaitForMultipleObjectsEx(timerHandles.count(), timerHandles.constData(), FALSE, waitTime, TRUE);
      while(waitResult >= WAIT_OBJECT_0 && waitResult < WAIT_OBJECT_0 + timerHandles.count()) {	
      	timerFired = true;
      
      	const HANDLE handle = timerHandles.value(waitResult - WAIT_OBJECT_0);
      	ResetEvent(handle);
      	const int timerId = d->timerHandleToId.value(handle);
      
      	if (timerId == INTERRUPT_HANDLE)
      		break;
      
      	WinRTTimerInfo &info = d->timerInfos[timerId];
      	Q_ASSERT(info.timerId != INVALID_TIMER_ID);
      
      	QCoreApplication::postEvent(this, new QTimerEvent(timerId));
      
      	// Update timer's targetTime
      	const quint64 targetTime = qt_msectime() + info.interval;
      	info.targetTime = targetTime;
      				
      	waitResult = WaitForMultipleObjectsEx(timerHandles.count(), timerHandles.constData(), FALSE, 0, TRUE);
      }
      
      if (timerFired) {
      	emit awake();
      	return true;
      }
      
      

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            owolff Oliver Wolff
            rupert_d Rupert Daniel
            Votes:
            1 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes