Using CEF from non-main application thread?

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.

Using CEF from non-main application thread?

Postby VadZ » Mon Nov 27, 2023 9:05 pm

Hello,

I'm trying to integrate a CEF wrapper into OTP, Erlang-based platform/environment (https://www.erlang.org/). Unfortunately with Erlang I don't have any possibility to run any code in the main thread, it always runs in one of many threads created by the Erlang VM (BEAM). I naively thought it shouldn't be a problem as long as I do everything UI-related in this thread, but after spending a lot of time on this I just can't manage to make this work.

I managed to make event dispatching work with manual calls to g_main_context_iteration() with the separate GMainContext created by Chrome in this case for some reason (see https://github.com/chromium/chromium/bl ... #L390-L397 where it explicitly checks for being run on the main thread), but now the problem is that my OnScheduleMessagePumpWork() is not getting called and so nothing happens -- the browser window just remains blank.

Would anybody have any idea about what could be preventing it from being called? I should also mention that in a simple example creating the browser from another thread things work perfectly fine, so perhaps it is not even that which triggers the problem but something else that OTP does, but I have really no idea what could it be.

Thanks in advance for any help!
VZ
VadZ
Techie
 
Posts: 16
Joined: Wed Oct 18, 2023 7:02 pm

Re: Using CEF from non-main application thread?

Postby KatrinaS » Mon Nov 27, 2023 11:49 pm

I don't think OnScheduleMessagePumpWork() actually does do anything ever,, but then maybe I just don't know its dark secrets and it's actually brilliant :D

I don't know this programming lingo you are using, seems dunno,, I suspect CEF and its displayable component are working fine but just need a quick (what ever your languages equivalent of is) repaint once it's displayed :)
KatrinaS
Mentor
 
Posts: 83
Joined: Tue Jul 04, 2023 6:30 pm

Re: Using CEF from non-main application thread?

Postby VadZ » Tue Nov 28, 2023 9:09 am

I don't think OnScheduleMessagePumpWork() actually does do anything ever


In my case the overridden OnScheduleMessagePumpWork() (in a class inheriting from CefBrowserProcessHandler) is used to call CefDoMessageLoopWork(), so if OnScheduleMessagePumpWork() is not called, neither is CefDoMessageLoopWork().

I probably can just call CefDoMessageLoopWork() from a timer, but it seems wrong/inefficient to do it and I'd really prefer Chrome to let me know when there is some work to do, but for some reason it doesn't. I've been trying to understand under which conditions OnScheduleMessagePumpWork() is being called, but it's not really clear to me and it would be great if somebody could tell me what might prevent it from being called.

P.S. I do know that OnScheduleMessagePumpWork() is called from libcef MessagePumpExternal::ScheduleWork(), so I guess the real question is rather why the latter function itself not being called.
VadZ
Techie
 
Posts: 16
Joined: Wed Oct 18, 2023 7:02 pm

Re: Using CEF from non-main application thread?

Postby KatrinaS » Tue Nov 28, 2023 10:18 am

In my lingo I can only trace it back to Context::GetInstance()->DoMessageLoopWork();, but there is a comment that says :

Code: Select all
/**
 * Perform a single message loop iteration. Used on all platforms except
 * Windows with windowed rendering.
 */


So that might explain why I've personally never experienced it actually doing anything :D So if you are on the 'doze and your component is Windowed then it's never called :)
KatrinaS
Mentor
 
Posts: 83
Joined: Tue Jul 04, 2023 6:30 pm

Re: Using CEF from non-main application thread?

Postby magreenblatt » Tue Nov 28, 2023 11:28 am

What Linux distro? What UI framework does Erlang use on that distro? Is that UI framework thread-safe and compatible with other libraries that talk to the X server directly?
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: Using CEF from non-main application thread?

Postby VadZ » Tue Nov 28, 2023 1:50 pm

magreenblatt wrote:What Linux distro?


Sorry, I didn't mention this because I didn't think this was relevant, but it is under Debian Bookworm, using CEF 116.0.15+g0b8c265+chromium-116.0.5845.111. The problem can be also seen at least under Ubuntu 22.04.

magreenblatt wrote:What UI framework does Erlang use on that distro?


Erlang/OTP uses wxWidgets which, in turn, uses GTK. wxWidgets now has (not yet merged, see https://github.com/wxWidgets/wxWidgets/pull/706) support for embedding CEF and this works fine when using it from the main thread and, with the additional workaround of manually dispatching GTK events using the thread-specific GMainContext created by Chrome when it's used in another thread in a simple example (see https://gist.github.com/vadz/917ce401d2 ... 991da12c7c for how I call g_main_context_iteration() for it).

magreenblatt wrote:Is that UI framework thread-safe and compatible with other libraries that talk to the X server directly?


It's not thread-safe in the sense that neither wxWidgets nor GTK can be used from multiple threads, but they both can be used just fine from a single thread, whether it's the main one or not (I still have no idea why does this matter for Chrome, main thread is really not special in any way) and OTP only uses wxWidgets from one Erlang process, i.e. from a single thread.

Debugging the difference between the simple working example linked above and OTP, I can see that OnScheduleMessagePumpWork() at https://github.com/vadz/wxWidgets/blob/ ... m.cpp#L318 is getting called in the working case but not when it's used from OTP, but I couldn't find out why does this happen.

Thanks in advance for any help!
VadZ
Techie
 
Posts: 16
Joined: Wed Oct 18, 2023 7:02 pm

Re: Using CEF from non-main application thread?

Postby magreenblatt » Tue Nov 28, 2023 2:27 pm

I still have no idea why does this matter for Chrome, main thread is really not special in any way

Chromium requires the main thread on Linux because it wants to do certain things (like fork()ing, configuring sandbox attributes, etc) before any other threads are created, and it expects to tear down certain singletons on main thread termination. The details change over time, but I would expect problems if you don't call CefInitialize() and CefShutdown() on the main thread.

It's not thread-safe in the sense that neither wxWidgets nor GTK can be used from multiple threads, but they both can be used just fine from a single thread

Is GTK being initialized on the same thread that you plan to run CEF on? You can read about some of the multi-threading complexity in this issue.

I've been trying to understand under which conditions OnScheduleMessagePumpWork() is being called

You can run `cefclient --external-message-pump` to exercise this functionality. The related code is here.
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: Using CEF from non-main application thread?

Postby VadZ » Tue Nov 28, 2023 3:01 pm

magreenblatt wrote:Chromium requires the main thread on Linux because it wants to do certain things (like fork()ing, configuring sandbox attributes, etc) before any other threads are created


I don't use sandboxing -- at least for now -- and I hoped that forking would be done from the helper process (I forgot to mention, but I do use one, as Erlang can't be repurposed for this). In any case, I realize that using it from the main thread would make things simpler, but there is just no way to do it with Erlang.

magreenblatt wrote:Is GTK being initialized on the same thread that you plan to run CEF on?


Yes, absolutely. All GUI-related code (outside of Chromium, at any rate) only runs on a single thread, I'm very much aware that things wouldn't work otherwise. It's just not the main one.

FWIW, I think the assumption that the "main thread" is the same thing as "the UI thread" is problematic. IMHO Chromium and CEF should really consider the thread calling CefInitialize() the main one -- whether it's the real main thread or not.

magreenblatt wrote:You can run `cefclient --external-message-pump` to exercise this functionality. The related code is here.


Thanks for the pointer! I've already looked at this code but I'll try to modify it to use a separate thread to see if I can reproduce the issue there. The trouble is that I expect that it should work because my simple example using wxWebViewChromium from a secondary thread works flawlessly (and I do use external pump, of course, in order to be able to use GTK message loop). There must be something else that OTP does which prevents this from working there but I still have no idea what (and OTP is a massive pile of code, smaller than Chromium, maybe, but still huge).
VadZ
Techie
 
Posts: 16
Joined: Wed Oct 18, 2023 7:02 pm

Re: Using CEF from non-main application thread?

Postby magreenblatt » Tue Nov 28, 2023 3:18 pm

IMHO Chromium and CEF should really consider the thread calling CefInitialize() the main one -- whether it's the real main thread or not.

I agree. Unfortunately this is a non-goal for Chromium developers and CEF is limited to Chromium supported behaviors.
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: Using CEF from non-main application thread?

Postby VadZ » Tue Nov 28, 2023 7:43 pm

I can make things more or less work by calling CefDoMessageLoopWork() myself from the "idle" handler (this is similar in wx and GTK even though they're implemented differently) in addition to calling it from the overridden CefBrowserProcessHandler::OnScheduleMessagePumpWork().

But unfortunately the UI is not smooth, notably scrolling using scrollbars is noticeably jerky. Do you think replacing CefDoMessageLoopWork() with the equivalent of what MainMessageLoopMultithreadedGtk::RunTasks() does would help with this?
VadZ
Techie
 
Posts: 16
Joined: Wed Oct 18, 2023 7:02 pm

Next

Return to Support Forum

Who is online

Users browsing this forum: No registered users and 114 guests