Page 1 of 1

AddPendingEvent to a child window hangs wxGTK hard

Posted: Mon May 22, 2006 10:03 pm
by rmd6502
I'm trying to do some automated testing of a wx application, using wxGTK version 2.6.2 on Linux FC3. The tester starts the main loop, then executes in another thread. It uses AddPendingEvent to post button presses, etc. to the application.

As long as I post events to the main window everythings seems to work fine. However, as soon as I post an event to a child wxEvtHandler (that is, a child of a top level window), the next AddPendingEvent call to a top level window hangs X hard. I have to ssh in and kill -9 the process to unlock my desktop.

In this excerpt, the hang occurs at the line after the "Find the Verify New Dialog" comment. It hangs about 85% of the time.

thanks!
Rob D

Code: Select all

        // Close all the other windows
        wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK);
        while (wxTopLevelWindows.GetCount() > 1) {
            wxWindow *dialogPtr = wxTopLevelWindows.Item(1).GetData();
            if (dialogPtr == 0)
                continue;
            wxWindow *buttonPtr = dialogPtr->FindWindow(wxID_OK);
            if (buttonPtr == 0)
                continue;

            wxPostEvent(buttonPtr, event);

            sleep(1);
        }

        // Invoke file->new so things are clear for the next test.
        event.SetEventType(wxEVT_COMMAND_MENU_SELECTED);
        event.SetId(ID_MENUNEW);
        wxPostEvent(_guiPtr->_shell, event);

        // Find the Verify New dialog.
        wxWindow *verifyDialog = 0;
        while (verifyDialog == 0) {
            sleep(1);
            verifyDialog =
                wxWindow::FindWindowById(SYMBOL__MESSAGEDIALOG_IDNAME);
            if (verifyDialog == 0)
                break;
            wxWindow *buttonPtr = verifyDialog->FindWindow(wxID_YES);
            if (buttonPtr == 0)
                continue;
            
            event.SetId(wxID_YES);
            event.SetEventType(wxEVT_COMMAND_BUTTON_CLICKED);
            wxPostEvent(buttonPtr, event);
        }

Posted: Tue May 23, 2006 10:05 am
by chris
Hi,

I recommend running the app in gdb and posting a backtrace showing where exactly the hanging occurs.

Chris

Posted: Tue May 23, 2006 5:17 pm
by rmd6502
I put a breakpoint at wxMutexInternal::Lock and ::Unlock. It looks like this invocation of Lock never returns:
Breakpoint 5, 0x08190d32 in wxMutexInternal::Lock ()
#0 0x08190d32 in wxMutexInternal::Lock ()
#1 0x081939d5 in wxEvtHandler::ProcessPendingEvents ()
#2 0x0815808c in wxAppConsole::ProcessPendingEvents ()
#3 0x0819ef21 in wxapp_pending_callback ()
#4 0x4763db5a in g_child_watch_add () from /usr/lib/libglib-2.0.so.0
#5 0x4763a7bb in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0
#6 0x4763c242 in g_main_context_acquire () from /usr/lib/libglib-2.0.so.0
#7 0x4763c4ef in g_main_loop_run () from /usr/lib/libglib-2.0.so.0
#8 0x4eeb9f97 in gtk_main () from /usr/lib/libgtk-x11-2.0.so.0
#9 0x082922eb in wxEventLoop::Run ()
[Switching to Thread -1208154432 (LWP 4295)]
I think the address corresponds to line 1155 in event.cpp, which is in wxEvtHandler::ProcessPendingEvents, at the second invocation of wxENTER_CRIT_SECT(Lock()), immediately after ProcessEvent(*event). I looked back through the trace to see if I could figure out who had the lock before, but didn't see any other invocations of lock that weren't subsequently unlocked.

Posted: Tue May 23, 2006 5:21 pm
by rmd6502
Oops, spoke too soon, here's the other lock that doesn't return:
Breakpoint 5, 0x08190d32 in wxMutexInternal::Lock ()
#0 0x08190d32 in wxMutexInternal::Lock ()
#1 0x08190da5 in wxMutexGuiEnter ()
#2 0x0819e807 in wxapp_poll_func ()
#3 0x4763c1d3 in g_main_context_acquire () from /usr/lib/libglib-2.0.so.0
#4 0x4763c4ef in g_main_loop_run () from /usr/lib/libglib-2.0.so.0
#5 0x4eeb9f97 in gtk_main () from /usr/lib/libgtk-x11-2.0.so.0
#6 0x082922eb in wxEventLoop::Run ()
#7 0x081fc465 in wxAppBase::MainLoop ()
#8 0x0817b9d6 in wxEntry ()
#9 0x080e57ea in *****::run (
this=0x8580fd0, argc=0, argv=0xbfef0fe4) at src/ui/wx/_Gui.cpp:162

Posted: Wed May 24, 2006 10:26 am
by chris
Can't you suspend the process in gdb when it hangs?
I know your desktop is blocked, but couldn't you run the app in a ssh session w/ X11 forward? That way you should still be able to ctrl-z the session in gdb.

Posted: Wed May 24, 2006 5:35 pm
by rmd6502
I ran gdb in an ssh session, with $DISPLAY still set to my original desktop - my desktop didn't hang this time - don't know if that datapoint helps.'

I've appended the stack traces when the gui hangs.

thanks again,
Rob D
Test Thread
#0 0xffffe410 in __kernel_vsyscall ()
#1 0x00a881a6 in __nanosleep_nocancel () from /lib/tls/libc.so.6
#2 0x00a87fac in sleep () from /lib/tls/libc.so.6
#3 0x0811399f in UiTest::testDisconnect (this=0x85829a0) at req/uitest.cpp:165
#4 0x081130d3 in CppUnit::TestCaller<UiTest>::runTest (this=0x8582950)
at TestCaller.h:166


GUI Thread
#0 0xffffe410 in __kernel_vsyscall ()
#1 0x00c4a13e in __lll_mutex_lock_wait () from /lib/tls/libpthread.so.0
#2 0x00c46d9b in _L_mutex_lock_32 () from /lib/tls/libpthread.so.0
#3 0xb7f40058 in ?? ()
#4 0x08caba08 in ?? ()
#5 0x08c8cd50 in ?? ()
#6 0x08769138 in ?? ()
#7 0xb7f40058 in ?? ()
#8 0x08192fa6 in wxMutexInternal::Lock ()
#9 0x08192fa6 in wxMutexInternal::Lock ()
#10 0x08195c41 in wxEvtHandler::ProcessPendingEvents ()
#11 0x0815a2f8 in wxAppConsole::ProcessPendingEvents ()
#12 0x081a118d in wxapp_pending_callback ()
#13 0x4763db5a in g_child_watch_add () from /usr/lib/libglib-2.0.so.0
#14 0x4763a7bb in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0
#15 0x4763c242 in g_main_context_acquire () from /usr/lib/libglib-2.0.so.0
#16 0x4763c4ef in g_main_loop_run () from /usr/lib/libglib-2.0.so.0
#17 0x4eeb9f97 in gtk_main () from /usr/lib/libgtk-x11-2.0.so.0
#18 0x08294557 in wxEventLoop::Run ()
#19 0x081fe6d1 in wxAppBase::MainLoop ()
#20 0x0817dc42 in wxEntry ()

Posted: Wed May 24, 2006 6:51 pm
by rmd6502
I've found a workaround - instead of using AddPendingEvent, I use

Code: Select all

wxMutexGuiEnter();
childWindow->ProcessEvent(event);
wxMutexGuiLeave();
in the tester thread, and everything runs properly. I'm makring this thread as solved, but if anyone has any comments about dangers of doing this, or a solution to the AddPendingEvent hang, as I assume I'm still doing something wrong, please reply.

Thanks!
Rob D