Changeset 80009 in webkit


Ignore:
Timestamp:
Mar 1, 2011 10:13:54 AM (13 years ago)
Author:
Adam Roben
Message:

Save a crash log when the web process crashes

On Windows, WebKitTestRunner now detects when the web process is crashing and waits to exit
until it has finished crashing, which guarantees that the crash log will have had time to be
saved, too. On Mac, we always wait until ReportCrash has exited before capturing the crash
log, so all we have to do is choose the right crash log out of the CrashReporter directory.

Fixes <http://webkit.org/b/44121> <rdar://problem/8320759> When the web process crashes and
a crash log is being saved, WebKitTestRunner thinks the web process has become unresponsive

Reviewed by Sam Weinig.

  • Scripts/old-run-webkit-tests:

(testCrashedOrTimedOut): Don't kill WebKitTestRunner when the web process crashes. It will
kill itself. On Windows, this will cause us to wait until the crash log has been saved. On
Mac, it should have no effect. Capture saved crash logs for web process crashes, too.
(captureSavedCrashLog): Added $webProcessCrashed argument. On Mac, look for
WebProces_*.crash files when the web process crashes.

  • WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:

(WTR::InjectedBundle::initialize): Added an initializationUserData argument. Updated for
initializePlatformDefaults -> platformInitialize rename. Pass the initializationUserData
along to platformInitialize.

  • WebKitTestRunner/InjectedBundle/InjectedBundle.h: See above.
  • WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp:

(WKBundleInitialize): Pass along the initializationUserData to the InjectedBundle.

  • WebKitTestRunner/InjectedBundle/mac/InjectedBundleMac.mm:

(WTR::InjectedBundle::platformInitialize):

  • WebKitTestRunner/InjectedBundle/qt/InjectedBundleQt.cpp:

(WTR::InjectedBundle::platformInitialize):
Updated function signature.

  • WebKitTestRunner/InjectedBundle/win/InjectedBundleWin.cpp:

(WTR::exceptionFilter): Added. Tells the UI process we're crashing by signaling the
webProcessCrashingEvent, then lets the crash continue as normal.

(WTR::InjectedBundle::platformInitialize): Hook up exceptionFilter. Retrieve the name of the
event we should use to tell the UI process we're crashing from the initializationUserData,
and get a handle to that event.

  • WebKitTestRunner/TestController.cpp:

(WTR::TestController::TestController): Initialize new members.
(WTR::TestController::processDidCrash): Removed unnecessary WKPageRef argument. Changed to
only print the "#CRASHED - WebProcess" message once, since this can be called more than once
when a crash log is being saved on Windows. Exit right away if specified. (This is the
default.)

  • WebKitTestRunner/TestController.h: Added new members.
  • WebKitTestRunner/win/TestControllerWin.cpp:

(WTR::TestController::platformInitialize): Set up the event the web process will use to tell
us it's crashing.
(WTR::TestController::platformRunUntil): Pass MWMO_INPUTAVAILABLE to
::MsgWaitForMultipleObjectsEx so we'll process messages that have already been seen by
::PeekMessage. (This is unrelated to the bug fix.) Notice when the webProcessCrashingEvent
has been signaled. When this happens, print the "#CRASHED - WebProcess" message right away
so the test harness will know the web process has crashed and not try to kill us, then wait
for the web process to finish crashing so a crash log will have time to be saved.
(WTR::toWK): Simple hepler function.
(WTR::TestController::platformInitializeContext): Pass along the name of the event the web
process should use to tell us it is crashing in the context's initialization user data.

Location:
trunk/Tools
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/Tools/ChangeLog

    r80008 r80009  
     12011-03-01  Adam Roben  <aroben@apple.com>
     2
     3        Save a crash log when the web process crashes
     4
     5        On Windows, WebKitTestRunner now detects when the web process is crashing and waits to exit
     6        until it has finished crashing, which guarantees that the crash log will have had time to be
     7        saved, too. On Mac, we always wait until ReportCrash has exited before capturing the crash
     8        log, so all we have to do is choose the right crash log out of the CrashReporter directory.
     9
     10        Fixes <http://webkit.org/b/44121> <rdar://problem/8320759> When the web process crashes and
     11        a crash log is being saved, WebKitTestRunner thinks the web process has become unresponsive
     12
     13        Reviewed by Sam Weinig.
     14
     15        * Scripts/old-run-webkit-tests:
     16        (testCrashedOrTimedOut): Don't kill WebKitTestRunner when the web process crashes. It will
     17        kill itself. On Windows, this will cause us to wait until the crash log has been saved. On
     18        Mac, it should have no effect. Capture saved crash logs for web process crashes, too.
     19        (captureSavedCrashLog): Added $webProcessCrashed argument. On Mac, look for
     20        WebProces_*.crash files when the web process crashes.
     21
     22        * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
     23        (WTR::InjectedBundle::initialize): Added an initializationUserData argument. Updated for
     24        initializePlatformDefaults -> platformInitialize rename. Pass the initializationUserData
     25        along to platformInitialize.
     26
     27        * WebKitTestRunner/InjectedBundle/InjectedBundle.h: See above.
     28
     29        * WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp:
     30        (WKBundleInitialize): Pass along the initializationUserData to the InjectedBundle.
     31
     32        * WebKitTestRunner/InjectedBundle/mac/InjectedBundleMac.mm:
     33        (WTR::InjectedBundle::platformInitialize):
     34        * WebKitTestRunner/InjectedBundle/qt/InjectedBundleQt.cpp:
     35        (WTR::InjectedBundle::platformInitialize):
     36        Updated function signature.
     37
     38        * WebKitTestRunner/InjectedBundle/win/InjectedBundleWin.cpp:
     39        (WTR::exceptionFilter): Added. Tells the UI process we're crashing by signaling the
     40        webProcessCrashingEvent, then lets the crash continue as normal.
     41
     42        (WTR::InjectedBundle::platformInitialize): Hook up exceptionFilter. Retrieve the name of the
     43        event we should use to tell the UI process we're crashing from the initializationUserData,
     44        and get a handle to that event.
     45
     46        * WebKitTestRunner/TestController.cpp:
     47        (WTR::TestController::TestController): Initialize new members.
     48        (WTR::TestController::processDidCrash): Removed unnecessary WKPageRef argument. Changed to
     49        only print the "#CRASHED - WebProcess" message once, since this can be called more than once
     50        when a crash log is being saved on Windows. Exit right away if specified. (This is the
     51        default.)
     52
     53        * WebKitTestRunner/TestController.h: Added new members.
     54
     55        * WebKitTestRunner/win/TestControllerWin.cpp:
     56        (WTR::TestController::platformInitialize): Set up the event the web process will use to tell
     57        us it's crashing.
     58        (WTR::TestController::platformRunUntil): Pass MWMO_INPUTAVAILABLE to
     59        ::MsgWaitForMultipleObjectsEx so we'll process messages that have already been seen by
     60        ::PeekMessage. (This is unrelated to the bug fix.) Notice when the webProcessCrashingEvent
     61        has been signaled. When this happens, print the "#CRASHED - WebProcess" message right away
     62        so the test harness will know the web process has crashed and not try to kill us, then wait
     63        for the web process to finish crashing so a crash log will have time to be saved.
     64        (WTR::toWK): Simple hepler function.
     65        (WTR::TestController::platformInitializeContext): Pass along the name of the event the web
     66        process should use to tell us it is crashing in the context's initialization user data.
     67
    1682011-03-01  Dimitri Glazkov  <dglazkov@chromium.org>
    269
  • trunk/Tools/Scripts/old-run-webkit-tests

    r79819 r80009  
    7878sub buildPlatformResultHierarchy();
    7979sub buildPlatformTestHierarchy(@);
    80 sub captureSavedCrashLog($);
     80sub captureSavedCrashLog($$);
    8181sub checkPythonVersion();
    8282sub closeCygpaths();
     
    17361736    recordActualResultsAndDiff($base, $actual);
    17371737
    1738     kill 9, $dumpToolPID unless $didCrash;
     1738    # There's no point in killing the dump tool when it's crashed. And it will kill itself when the
     1739    # web process crashes.
     1740    kill 9, $dumpToolPID unless $didCrash || $webProcessCrashed;
    17391741
    17401742    closeDumpTool();
    17411743
    1742     captureSavedCrashLog($base) if $didCrash;
     1744    captureSavedCrashLog($base, $webProcessCrashed) if $didCrash || $webProcessCrashed;
    17431745
    17441746    return unless isCygwin() && !$didCrash && $base =~ /^http/;
     
    17491751}
    17501752
    1751 sub captureSavedCrashLog($)
    1752 {
    1753     my ($base) = @_;
     1753sub captureSavedCrashLog($$)
     1754{
     1755    my ($base, $webProcessCrashed) = @_;
    17541756
    17551757    my $crashLog;
     
    17591761        $glob = File::Spec->catfile($testResultsDirectory, $windowsCrashLogFilePrefix . "*.txt");
    17601762    } elsif (isAppleMacWebKit()) {
    1761         $glob = File::Spec->catfile("~", "Library", "Logs", "CrashReporter", $dumpToolName . "_*.crash");
     1763        $glob = File::Spec->catfile("~", "Library", "Logs", "CrashReporter", ($webProcessCrashed ? "WebProcess" : $dumpToolName) . "_*.crash");
    17621764
    17631765        # Even though the dump tool has exited, CrashReporter might still be running. We need to
  • trunk/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp

    r79612 r80009  
    7373}
    7474
    75 void InjectedBundle::initialize(WKBundleRef bundle)
     75void InjectedBundle::initialize(WKBundleRef bundle, WKTypeRef initializationUserData)
    7676{
    7777    m_bundle = bundle;
     
    8787    WKBundleSetClient(m_bundle, &client);
    8888
    89     initializePlatformDefaults();
     89    platformInitialize(initializationUserData);
    9090
    9191    activateFonts();
  • trunk/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h

    r79612 r80009  
    4646
    4747    // Initialize the InjectedBundle.
    48     void initialize(WKBundleRef);
     48    void initialize(WKBundleRef, WKTypeRef initializationUserData);
    4949
    5050    WKBundleRef bundle() const { return m_bundle; }
     
    8383    void didReceiveMessage(WKStringRef messageName, WKTypeRef messageBody);
    8484
    85     void initializePlatformDefaults();
     85    void platformInitialize(WKTypeRef initializationUserData);
    8686    void resetLocalSettings();
    8787
  • trunk/Tools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp

    r71175 r80009  
    3434void WKBundleInitialize(WKBundleRef bundle, WKTypeRef initializationUserData)
    3535{
    36     WTR::InjectedBundle::shared().initialize(bundle);
     36    WTR::InjectedBundle::shared().initialize(bundle, initializationUserData);
    3737}
  • trunk/Tools/WebKitTestRunner/InjectedBundle/mac/InjectedBundleMac.mm

    r79612 r80009  
    2828namespace WTR {
    2929
    30 void InjectedBundle::initializePlatformDefaults()
     30void InjectedBundle::platformInitialize(WKTypeRef)
    3131{
    3232    NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
  • trunk/Tools/WebKitTestRunner/InjectedBundle/qt/InjectedBundleQt.cpp

    r79612 r80009  
    2828namespace WTR {
    2929
    30 void InjectedBundle::initializePlatformDefaults()
     30void InjectedBundle::platformInitialize(WKTypeRef)
    3131{
    3232}
  • trunk/Tools/WebKitTestRunner/InjectedBundle/win/InjectedBundleWin.cpp

    r79612 r80009  
    2828namespace WTR {
    2929
    30 void InjectedBundle::initializePlatformDefaults()
     30static HANDLE webProcessCrashingEvent;
     31
     32static LONG WINAPI exceptionFilter(EXCEPTION_POINTERS*)
    3133{
     34    // Let the UI process know right away that we crashed. It might take a long time for us to
     35    // finish crashing if a crash log is being saved.
     36    ::SetEvent(webProcessCrashingEvent);
     37
     38    return EXCEPTION_CONTINUE_SEARCH;
     39}
     40
     41void InjectedBundle::platformInitialize(WKTypeRef initializationUserData)
     42{
     43    ::SetUnhandledExceptionFilter(exceptionFilter);
     44
     45    ASSERT_ARG(initializationUserData, initializationUserData);
     46    ASSERT_ARG(initializationUserData, WKGetTypeID(initializationUserData) == WKStringGetTypeID());
     47
     48    WKStringRef string = static_cast<WKStringRef>(initializationUserData);
     49    Vector<char> buffer(WKStringGetMaximumUTF8CStringSize(string));
     50    WKStringGetUTF8CString(string, buffer.data(), buffer.size());
     51
     52    // The UI process should already have created this event. We're just getting another HANDLE to it.
     53    webProcessCrashingEvent = ::CreateEventA(0, FALSE, FALSE, buffer.data());
     54    ASSERT(webProcessCrashingEvent);
    3255}
    3356
  • trunk/Tools/WebKitTestRunner/TestController.cpp

    r79612 r80009  
    6464    , m_longTimeout(defaultLongTimeout)
    6565    , m_shortTimeout(defaultShortTimeout)
     66    , m_didPrintWebProcessCrashedMessage(false)
     67    , m_shouldExitWhenWebProcessCrashes(true)
    6668{
    6769    initialize(argc, argv);
     
    471473void TestController::processDidCrash(WKPageRef page, const void* clientInfo)
    472474{
    473     static_cast<TestController*>(const_cast<void*>(clientInfo))->processDidCrash(page);
     475    static_cast<TestController*>(const_cast<void*>(clientInfo))->processDidCrash();
    474476}
    475477
     
    490492}
    491493
    492 void TestController::processDidCrash(WKPageRef page)
    493 {
    494     fputs("#CRASHED - WebProcess\n", stderr);
    495     fflush(stderr);
     494void TestController::processDidCrash()
     495{
     496    // This function can be called multiple times when crash logs are being saved on Windows, so
     497    // ensure we only print the crashed message once.
     498    if (!m_didPrintWebProcessCrashedMessage) {
     499        fputs("#CRASHED - WebProcess\n", stderr);
     500        fflush(stderr);
     501        m_didPrintWebProcessCrashedMessage = true;
     502    }
     503
     504    if (m_shouldExitWhenWebProcessCrashes)
     505        exit(1);
    496506}
    497507
  • trunk/Tools/WebKitTestRunner/TestController.h

    r76559 r80009  
    8484
    8585    static void processDidCrash(WKPageRef, const void* clientInfo);
    86     void processDidCrash(WKPageRef);
     86    void processDidCrash();
    8787
    8888    static WKPageRef createOtherPage(WKPageRef oldPage, WKDictionaryRef, WKEventModifiers, WKEventMouseButton, const void*);
     
    118118    double m_longTimeout;
    119119    double m_shortTimeout;
     120
     121    bool m_didPrintWebProcessCrashedMessage;
     122    bool m_shouldExitWhenWebProcessCrashes;
    120123};
    121124
  • trunk/Tools/WebKitTestRunner/win/TestControllerWin.cpp

    r79695 r80009  
    3939namespace WTR {
    4040
     41static HANDLE webProcessCrashingEvent;
     42static const char webProcessCrashingEventName[] = "WebKitTestRunner.WebProcessCrashing";
     43
    4144#ifdef DEBUG_ALL
    4245const LPWSTR testPluginDirectoryName = L"TestNetscapePlugin_Debug";
     
    110113    // linked with older versions of qtmlclientlib.dll.
    111114    addQTDirToPATH();
     115
     116    webProcessCrashingEvent = ::CreateEventA(0, FALSE, FALSE, webProcessCrashingEventName);
    112117}
    113118
     
    138143            return;
    139144
    140         DWORD result = ::MsgWaitForMultipleObjectsEx(0, 0, end - now, QS_ALLINPUT, 0);
     145        DWORD result = ::MsgWaitForMultipleObjectsEx(1, &webProcessCrashingEvent, end - now, QS_ALLINPUT, MWMO_INPUTAVAILABLE);
    141146        if (result == WAIT_TIMEOUT)
    142147            return;
    143148
    144         ASSERT(result == WAIT_OBJECT_0);
     149        if (result == WAIT_OBJECT_0) {
     150            // The web process is crashing. A crash log might be being saved, which can take a long
     151            // time, and we don't want to time out while that happens.
     152
     153            // First, let the test harness know this happened so it won't think we've hung. But
     154            // make sure we don't exit just yet!
     155            m_shouldExitWhenWebProcessCrashes = false;
     156            processDidCrash();
     157            m_shouldExitWhenWebProcessCrashes = true;
     158
     159            // Then spin a run loop until it finishes crashing to give time for a crash log to be saved.
     160            MSG msg;
     161            while (BOOL bRet = ::GetMessageW(&msg, 0, 0, 0)) {
     162                if (bRet == -1)
     163                    break;
     164                ::TranslateMessage(&msg);
     165                ::DispatchMessageW(&msg);
     166            }
     167
     168            exit(1);
     169        }
     170
     171        ASSERT(result == WAIT_OBJECT_0 + 1);
    145172        // There are messages in the queue. Process them.
    146173        MSG msg;
     
    152179}
    153180
     181static WKRetainPtr<WKStringRef> toWK(const char* string)
     182{
     183    return WKRetainPtr<WKStringRef>(AdoptWK, WKStringCreateWithUTF8CString(string));
     184}
     185
    154186void TestController::platformInitializeContext()
    155187{
    156188    // FIXME: Make DRT pass with Windows native controls. <http://webkit.org/b/25592>
    157189    WKContextSetShouldPaintNativeControls(m_context.get(), false);
     190
     191    WKContextSetInitializationUserDataForInjectedBundle(m_context.get(), toWK(webProcessCrashingEventName).get());
    158192}
    159193
Note: See TracChangeset for help on using the changeset viewer.