magreenblatt wrote: CBrowserHandler::OnAfterCreated browser 1
Application is shutting down. Close all open browsers
CBrowserHandler::DoClose browser 1
CBrowserHandler::OnBeforeClose browser 1
CBrowserManager::OnBeforeClose: All browsers closed
Calling CefShutdown
Does this output indicate that OnBeforeClose was called for the main browser and the popup browser?
This output is in the case of only 1 main browser.
I will explain more clearly because I probably confused you with mentioning the popup browsers.
In my app, I have a class that keeps track of all opened browsers; called CBrowserManager.
When I want to exit the app, I first call CBrowserManager::CloseAllBorwsers from the main application thread. CloseAllBorwsers will loop over all existing browsers and call browser->GetHost()->CloseBrowser( true ).
I then wait for a windows Event object to be set that signals that all the browsers have called OnBeforeClose(). To wait for that event, I use the MsgWaitForMultipleObjectsEx function (in combination with TranslateMessage and DispatchMessage).
The windows event object is set (using SetEvent) when OnBeforeClose has been called for the last browser.
When that event is set, CBrowserManager::CloseAllBorwsers returns and then CefShutdown is called.
Simplified code:
- Code: Select all
void CCefApp::OnPreShutdown()
{
CBrowserManager::Instance().CloseAllBrowsers(); // this will wait for all the browsers' OnBeforeClose to be called
CefShutdown();
}
void CBrowserManager::CloseAllBrowsers()
{
_browsersClosedEvent.reset();
for ( auto const &browser : _browsers )
browser->GetHost()->CloseBrowser( true );
// wait for the event to be triggered before returning
_browsersClosedEvent.wait();
}
void CBrowserManager::OnBeforeClose( CefRefPtr< CefBrowser > browser )
{
_browsers.erase( browser->GetIdentifier() );
if ( _browsers.empty() == true )
{
_browsersClosedEvent.trigger();
//::Sleep( 100 ); // adding this sleep will guarantee that the AssertNotShutdown is triggered
}
}
The problem I have is that sometimes I still get the AssertNotShutdown assert. This is because when I set the event to signal that all browsers have closed, CefShutdown might be called even BEFORE the last OnBeforeClose had the time to return. If that happens, then some Cef objects will go out of scope AFTER I have called CefShutdown --> AssertNotShutdown is triggered.
See this callstack:
- Code: Select all
libcef.dll!logging::LogMessage::~LogMessage() Line 909 C++
libcef.dll!logging::LogMessage::~LogMessage() Line 593 C++
libcef.dll!logging::CheckError::~CheckError() Line 109 C++
libcef.dll!shutdown_checker::AssertNotShutdown() Line 32 C++
[Inline Frame] libcef.dll!CefBrowserCppToC::~CefBrowserCppToC() Line 423 C++
libcef.dll!CefBrowserCppToC::~CefBrowserCppToC() Line 422 C++
libcef.dll!CefCppToCRefCounted<CefBrowserCppToC,CefBrowser,_cef_browser_t>::Release() Line 86 C++
libcef.dll!CefCppToCRefCounted<CefBrowserCppToC,CefBrowser,_cef_browser_t>::struct_release(_cef_base_ref_counted_t * base) Line 167 C++
LmsHq_DataModelVC_D2DFDispCef_v1.dll!CefCToCppRefCounted<CefBrowserCToCpp,CefBrowser,_cef_browser_t>::UnderlyingRelease() Line 78 C++
LmsHq_DataModelVC_D2DFDispCef_v1.dll!CefCToCppRefCounted<CefBrowserCToCpp,CefBrowser,_cef_browser_t>::Release() Line 154 C++
LmsHq_DataModelVC_D2DFDispCef_v1.dll!scoped_refptr<CefBrowser>::Release(CefBrowser * ptr) Line 356 C++
LmsHq_DataModelVC_D2DFDispCef_v1.dll!scoped_refptr<CefBrowser>::~scoped_refptr<CefBrowser>() Line 258 C++
************************ I call CefShutdown somewhere here from another thread ************************
LmsHq_DataModelVC_D2DFDispCef_v1.dll!LmsHq::DataModelVC::D2DFDispCef::CBrowserManager::OnBeforeClose(scoped_refptr<CefBrowser> ac_xBrowser) Line 36 C++
LmsHq_DataModelVC_D2DFDispCef_v1.dll!`anonymous namespace'::life_span_handler_on_before_close(_cef_life_span_handler_t * self, _cef_browser_t * browser) Line 207 C++
libcef.dll!CefLifeSpanHandlerCToCpp::OnBeforeClose(scoped_refptr<CefBrowser> browser) Line 162 C++
What happens to produce the above callstack:
- I have 1 open browser
- I request to close it from the main thread
- OnBeforeClose is called on thread A
- The event to signal that all browsers are closed is set from thread A
- I added a ::Sleep after I set the event
- Thread A goes to sleep
- CefShutdown is called from the main thread
- Thread A wakes up and OnBeforeClose returns
- When OnBeforeClose returns, the browser argument goes out of scope and its destructor is called
- The assert is triggered in the destructor of CefBrowserCppToC because CefShutdown has already been called
I added the Sleep because it's the simplest way to reproduce the problem. But I had AssertNotShutdown trigger without the Sleep many times before.
And my question is: Am I doing something fundamentally wrong (using the callbacks in the wrong way or something) to know when I can call CefShutdown?
If yes then what is the proper way to do it?
I hope this is more clear now.
Thanks