[mythtv-commits] Ticket #9223: Sluggish menu when watching a recording

MythTV noreply at mythtv.org
Tue Feb 8 22:35:33 UTC 2011


#9223: Sluggish menu when watching a recording
-------------------------------------+--------------------------------
 Reporter:  glemsom@…                |          Owner:  markk
     Type:  defect                   |         Status:  infoneeded_new
 Priority:  minor                    |      Milestone:  0.24.1
Component:  MythTV - Video Playback  |        Version:  0.24-fixes
 Severity:  medium                   |     Resolution:
 Keywords:  sluggish menu            |  Ticket locked:  0
-------------------------------------+--------------------------------

Comment (by dgatwood@…):

 Pure backtraces are probably not what you want.  Samples are generally
 much more helpful at tracking down these sorts of problems.  To take a
 sample, run Terminal and type

 sample PID 10 10

 to sample process ID "PID" for 10 seconds, sampling every 10 milliseconds.
 (Type "man sample" for more info.)

 Also, MythTVForMacOSX tracker ID 3165719 is also tracking these SPODs over
 on sf.net.  I'm seeing this on both of my MythTV boxes (one current Mini,
 one ancient MacBook).  The Mini is particularly bad because in addition to
 complete loss of control, the video is just a white screen.

 I've rolled back to the November 12th build of 0.24, which does *not*
 exhibit this hanging problem (haven't tried on the Mini yet).  So
 basically, this regressed some time between mid-November and mid-January.
 Hope that helps narrow things down a little.

 If a sample of the last public build would be helpful, you can find one
 at:

 http://www.gatwood.net/junk/MythFrontend_35911.MWzwF1.sample.txt

 BTW, the keypress is a red herring.  You folks may well know all the
 things I'm about to say, so if you do, know that this isn't intended to be
 talking down to you guys or anything.  :-)

 Mac OS X shows the spinning wheel of death (a.k.a. spinning pizza of
 death, a.k.a. SPOD) when an application's event queue fills up and the
 window server can no longer deliver new events.  It continues to try every
 few seconds until the app responds, at which point the cursor no longer
 SPODs when hovering over the application.

 Basically, the key event just happens to be the first event that gets the
 queue too full in certain cases.  If you command-tab out of the app and
 wait about thirty seconds, you'll see Mythfrontend go into a SPOD state
 all by itself.  This spod state can only be caused by one thing: the app
 isn't servicing events.  I can only think of three possible reasons why
 this can occur:

 1.  The run loop was stopped for some reason.  It kind of looks like this
 may have occurred here....  I'm not seeing CFRunLoopRun in any of the
 samples while the app is playing, and that's not a good sign.  :-)
 2.  The event sources were removed from the run loop for some reason.
 3.  You are doing work in your main thread that blocks, thus preventing
 the main thread from returning to CFRunLoopRun or CFRunLoopRunSpecific or
 whatever the QT equivalent is.

 Even when it is working correctly, I've seen Mythfrontend's main thread do
 things it shouldn't be doing (blocking database queries, for example) from
 the main thread.  When this happens, it is no longer returning program
 control up the stack to the QT run loop code, which means that no thread
 is actually handling events that get delivered to the application from the
 rest of the OS.  Hence, keyboard events never arrive, window server "are
 you there" messages never get answered, and so on.  In effect, the
 application is cut off from the OS and all user control.

 You should never call any sleep variant function (sleep, usleep,
 nanosleep, etc.) in your main (UI) thread, nor should you ever do anything
 that could cause indefinite blocking (e.g. waiting on a lock that could be
 held by another thread for a long period of time).  This means, among
 other things, that you should not be making synchronous database calls
 from anywhere in your GUI thread (the current code is *notorious* for
 this), nor any synchronous network calls, nor synchronous disk reads or
 writes, nor anything else that can potentially block for seconds at a
 time....

 You should instead be doing these things asynchronously on a separate
 thread, with the helper thread posting an event to the run loop when the
 work is done, causing the run loop to wake up and call a continuation
 function or whatever).  Similarly, when you need to wait a while in the
 main thread, you should set a timer to wake up the run loop and call a
 continuation function after a particular period of time, schedule the
 timer on the run loop, then start it and return so that the main run loop
 can run.  It looks like the player portion is instead tearing down the run
 loop entirely and then running draw operations in a loop with timers and
 never draining the event queue.  That's bad.  :-)

 BTW, this is not a Mac-specific design pattern.  You should be doing
 things the way I'm describing on every platform, not just Mac OS X.
 Blocking the main thread is also verboten on Android, iOS, and Windows.
 And Xlib and GLib work the same way (though I suppose you could hack
 around it in X11 by calling XNextEvent() from various places in your
 code—blech).  This is why whenever the network goes away, Mythfrontend
 basically hangs for half a minute or more while requests time out.

 The crash report shown below (caused by doing a command-tab out of MythTV
 during the initial grey screen) shows roughly what your main thread
 backtrace should look like.


 {{{
 Thread 0 Crashed:  Dispatch queue: com.apple.main-thread
 0   org.osx-bundler.MythFrontend        0x0001c5f6 QString::~QString() + 6
 1   org.osx-bundler.MythFrontend        0x000c9778
 ComboBoxSetting::~ComboBoxSetting() + 104
 2   org.osx-bundler.MythFrontend        0x000c9b13
 GlobalComboBox::~GlobalComboBox() + 83
 3   QtCore                              0x8cbdc508 QObject::event(QEvent*)
 + 1080
 4   QtGui                               0x8cdc3f7c
 QApplicationPrivate::notify_helper(QObject*, QEvent*) + 188
 5   QtGui                               0x8cdc84ed
 QApplication::notify(QObject*, QEvent*) + 1341
 6   QtCore                              0x8caf516c
 QCoreApplication::notifyInternal(QObject*, QEvent*) + 108
 7   QtCore                              0x8cbd09a6
 QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) +
 694
 8   QtGui                               0x8cd7e03e
 QEventDispatcherMacPrivate::postedEventsSourcePerformCallback(void*) + 78
 9   com.apple.CoreFoundation            0x0069d4cb __CFRunLoopDoSources0 +
 1563
 10  com.apple.CoreFoundation            0x0069af8f __CFRunLoopRun + 1071
 11  com.apple.CoreFoundation            0x0069a464 CFRunLoopRunSpecific +
 452
 12  com.apple.CoreFoundation            0x0069a291 CFRunLoopRunInMode + 97
 13  com.apple.HIToolbox                 0x04ebb004
 RunCurrentEventLoopInMode + 392
 14  com.apple.HIToolbox                 0x04ebacf7 ReceiveNextEventCommon
 + 158
 15  com.apple.HIToolbox                 0x05043255 ReceiveNextEvent + 83
 16  QtGui                               0x8cd7da7f
 QEventDispatcherMac::processEvents(QFlags<QEventLoop::ProcessEventsFlag>)
 + 303
 17  QtCore                              0x8cbcf321
 QEventLoop::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 65
 18  QtCore                              0x8cbcf65a
 QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) + 170
 19  QtCore                              0x8cbd0c86
 QCoreApplication::exec() + 182
 20  org.osx-bundler.MythFrontend        0x0001a92e main + 27038
 21  org.osx-bundler.MythFrontend        0x0000c459 _start + 208
 22  org.osx-bundler.MythFrontend        0x0000c388 start + 40
 }}}


 Note that you see Mythfrontend's start, then _start, then main, then a
 bunch of things up to CFRunLoopRun, *then* code specific to the app.  When
 the player is running, I'm instead seeing this:


 {{{
      32 main
         32 BusyWaitVideoSync::WaitForFrame(int)
           32 usleep
             32 nanosleep
               32 mach_wait_until
 }}}


 among other things.  That's almost certainly the problem right there.
 Note that CFRunLoopRun is not running during all of this.  No
 CFRunLoopRun, no run loop.  No run loop, no event handling.  No event
 handling, no keyboard control.  And I'm getting a SPOD even without any
 keypresses.


 Hope that helps.

-- 
Ticket URL: <http://code.mythtv.org/trac/ticket/9223#comment:28>
MythTV <http://code.mythtv.org/trac>
MythTV Media Center


More information about the mythtv-commits mailing list