CefShutdown hangs if UI thread has exited

Having problems with building or using CEF's C/C++ APIs? This forum is here to help. Please do not post bug reports or feature requests here.

CefShutdown hangs if UI thread has exited

Postby ryanmolden » Mon Dec 17, 2012 3:11 pm

I am playing around with making CEF into a co-creatable (COM) object on Windows as part of an experiment. I have some constraints in that it is intended to be used in an app whose code I can't change. I can get the app to CoCreate the CEF object, but I can't, for instance, have it call CefInitialize or CefShutdown.

My original idea here was that I would make the server dll call CefInitialize on the first request to create the COM object, and then call CefShutdown in DllMain on DLL_PROCESS_DETACH. The first part works fine, the second part, not so much.

The primary blocker is that I need to set multi_threaded_message_loop to true, since the client app can't be changed to call CefDoMessageLoopWork or CefRunMessageLoop. When you do that various shutdown/cleanup methods attempt to post messages to the UI thread. If this happens inside DLL_PROCESS_DETACH the UI thread is already long gone and the wait blocks forever since it has no timeout and the delegate that sets the event it is waiting on will never execute.

As a work around I thought perhaps I could simply call CefShutdown in the COM object destructor. This 'works' except for the fact that you could then never again create another browser object in the same process, since calling CefInitialize after having called CefShutdown fails with this error:

[1217/120605:FATAL:url_util.cc(386)] Check failed: !standard_schemes_locked. Trying to add a standard scheme after the list has been locked.
Backtrace:
cef_browser_host_create_browser [0x0F395B21+788825]
cef_browser_host_create_browser [0x0F38213F+708471]
DelayedLowerToken [0x10C9D828+2528088]
cef_time_from_doublet [0x108B38F7+20958423]
cef_time_from_doublet [0x103F14CD+15968429]
cef_browser_host_create_browser [0x0F429515+1393485]
cef_browser_host_create_browser [0x0F4287D2+1390090]
cef_browser_host_create_browser [0x0F2D987F+18103]
CefInitialize [0x5F7FB18D+189] (c:\cef\libcef_dll\wrapper\libcef_dll_wrapper.cc:141)
<snip>

Thoughts/ideas? It would be nice if CEF, before trying to post work to the UI thread during cleanup, checked if the UI thread had already exited and if so just did nothing, or tried its cleanup locally. Barring that being able to initialize/shutdown CEF multiple times in the same session would be nice.

Ryan
ryanmolden
Techie
 
Posts: 12
Joined: Mon Dec 17, 2012 2:56 pm

Re: CefShutdown hangs if UI thread has exited

Postby magreenblatt » Thu Dec 27, 2012 7:26 am

Re-initializing CEF3 is not supported due to the use of globals in Chromium and WebKit. You say that you can't change the existing application. Does this mean that you're emulating something like IWebBrowser2?
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: CefShutdown hangs if UI thread has exited

Postby ryanmolden » Thu Dec 27, 2012 6:23 pm

Re-initializing CEF3 is not supported due to the use of globals in Chromium and WebKit. You say that you can't change the existing application. Does this mean that you're emulating something like IWebBrowser2?


Ultimately yes, the app uses ATL to create the browser (which is currently embedded instance of IE), but ATL chooses the object to CoCreate based on the initial URL, and if that initial 'URL' is instead a GUID it will simply CoCreate that class. This is my intended injection point to get the embedded browser to be CEF based. Ultimately I will need to implement IWebBrowser2 and likely a few other shims so that the calling process is unawares what actual framework it is dealing with (all it does is load a web page and some JS, so it shouldn't really matter WHO does that, assuming it is someone that can handle HTML, JS and CSS). There are no real reasons WHY the host browser today is IE, other than it seems trivial to host IE embedded, not so much from Chromium and FireFox.

You can repro the hang at shutdown in CefClient simply by removing the call to CefShutdown, the global context object dtor does the same 'post a message and wait for it to be handled' that results in the hang.

It isn't clear why globals are a problem unless they aren't properly re-initialized. Does Chromium/WebKit not expose a way to set/reset the globals?

I realize not calling CefShutdown is not supported, so the hang in the global context object in Cef is probably 'by design', but it would be nice if I could find something that worked. Preferably cleanup code should not post messages to a thread that has terminated, and likely should not do infinite waits either. Not sure how much 'terrible' would happen if upon realizing the thread was gone they simply did no more cleanup, or if there was something like CefProcessTerminating or something that indicated that cleanup of any object that couldn't outlive the process (which very few objects can to my knowledge) is not necessary as the OS will forcibly reclaim all memory and most (all?) handles allocated to the process when it is terminated.

Ryan
ryanmolden
Techie
 
Posts: 12
Joined: Mon Dec 17, 2012 2:56 pm


Return to Support Forum

Who is online

Users browsing this forum: Google [Bot], MSN [Bot] and 188 guests