Calling DoMessageLoopWork on demand

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.

Calling DoMessageLoopWork on demand

Postby pchuong » Wed Jan 02, 2013 3:02 pm

Hi,

Is there any way to determine whether the browser has more work to do? So that I don't need to call DoMessageLoopWork too often and prevent starving the rest of the application where the browser has been integrated into?

thanks,
Patrick
pchuong
Mentor
 
Posts: 73
Joined: Tue Nov 06, 2012 1:41 pm

Re: Calling DoMessageLoopWork on demand

Postby ryanmolden » Wed Jan 02, 2013 10:46 pm

I haven't looked exhaustively through the layers of indirection, but are you seeing DoMessageLoopWork 'starving' your app?

From what I can tell it does a single 'loop' (i.e. processes one message) and returns. It seems a bit odd since, at least on Windows, message queues are per thread not per window, so DoMessageLoopWork is going to be 'pulling' from the same queue as your primary message loop is, in which case it isn't clear why calling it is even needed, unless somewhere along the path it is doing 'extra' work beyond a simple Translate/Dispatch.

Either way you could probably dig through the sources, look what kind of messages it is looking for, and try a PeekMessage PM_NOREMOVE for messages in that range from your primary loop. It isn't a perfect solution since PeekMessage has side effects (i.e. sent messages are dispatched), and it is brittle since you have to specify the message range. Personally I wouldn't bother, if you want to try and 'throttle' CEF you could implement a simple counter in your primary message loop that wrapped on some value (say 5) and only call DoMessageLoopWork when the counter hit the last value before wrapping, so if your value was 5 you would end up with a 5:1 'split' between your primary app and CEF. That said, any Translate/Dispatch from your primary loop where the msg targets the any HWND owned by CEF and you will end up invoking into CEF code anyways, so even trying to throttle seems questionable at best.

EDIT: Most of this is talking about Windows specifically, but, apart from some 'function name/concept translation' I suspect it holds for any other event-driven app model, specifically most GUI apps on most platforms.

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

Re: Calling DoMessageLoopWork on demand

Postby pchuong » Thu Jan 03, 2013 11:10 am

Hi Ryan,

Thanks for the reply. To answer your question, yes I do see starvation in my app. It is not the call into DoMessageLoopWork that causes the problem, it is how often that I call it.

I am writing an eclipse plugin, so I don't have access to the message loop. I have setup a timer to call DoMessageLoopWork, which is similar to your suggestion of a ratio. And this is working well. However, I do want to slow down the timer if there is no additional messages that the browser needs to handle. This is what I am looking for, to be able to throttle the timer; pull as fast as it need or slow it down if there is no message to handle.

Thanks,
Patrick
pchuong
Mentor
 
Posts: 73
Joined: Tue Nov 06, 2012 1:41 pm

Re: Calling DoMessageLoopWork on demand

Postby magreenblatt » Thu Jan 03, 2013 2:34 pm

Integrating with external run loops is a hard problem to solve for a browser hosting active content (animation, flash, etc.). CEF's implementation of CefDoMessageLoopWork should ideally provide information about when it should next be called based on an analysis of pending tasks, timers, etc. However, Chromium does not (and perhaps cannot due to the complexity) expose this information. This is the reason why we introduced CefRunMessageLoop -- it provides the optimal performance.

So, you have a few options if you must integrate with an external run loop:

1. On Windows use CefSettings.multi_threaded_message_loop to work around the problem.

2. Call CefDoMessageLoopWork as often as possible. This will always have edge cases with reduced performance.

3. Create an out-of-process implementation (perhaps using off-screen rendering) to completely decouple the run loops.
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: Calling DoMessageLoopWork on demand

Postby magreenblatt » Thu Jan 03, 2013 2:39 pm

CefDoMessageLoopWork returns when Chromium feels that the message loop is idle. This is not an exact science and the definition of "idle" is platform dependent. Check out the various platform MessageLoop implementations for details.
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: Calling DoMessageLoopWork on demand

Postby ryanmolden » Thu Jan 03, 2013 9:56 pm

CefDoMessageLoopWork returns when Chromium feels that the message loop is idle.


So it runs a (nested) message pump until it clears all pending messages in the thread's message queue?
ryanmolden
Techie
 
Posts: 12
Joined: Mon Dec 17, 2012 2:56 pm

Re: Calling DoMessageLoopWork on demand

Postby magreenblatt » Fri Jan 04, 2013 4:17 am

ryanmolden wrote:
CefDoMessageLoopWork returns when Chromium feels that the message loop is idle.


So it runs a (nested) message pump until it clears all pending messages in the thread's message queue?

Effectively yes (OS messages, timers, tasks, etc). The message pump runs until DoIdleWork() is called, at which time CEF calls |pump_->Quit()|. You can see the code here (it works the same for both CEF1 and CEF3):

libcef/browser/browser_message_loop.cc: http://code.google.com/p/chromiumembedd ... loop.cc#26

base/message_pump_win.cc: http://code.google.com/searchframe#OAMl ... e=cs&l=214
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: Calling DoMessageLoopWork on demand

Postby ryanmolden » Sat Jan 05, 2013 1:56 pm

Effectively yes (OS messages, timers, tasks, etc). The message pump runs until DoIdleWork() is called, at which time CEF calls |pump_->Quit()|. You can see the code here (it works the same for both CEF1 and CEF3):


It wasn't clear from that code, I see CefBrowserMessageLoop::RunMessageLoop, which calls CefBrowserMessageLoop::DoLoopIteration which calls Run. I don't see an impl of Run in either link. I assume it is some base class method that will eventually thunk back down to one of the functions in MessagePumpWin (MessagePumpForUI::DoRunLoop)? I would enlist in the Chromium sources but depot_tools are broken on Windows and no one on the Chromium project seems to care (http://code.google.com/p/chromium/issue ... ?id=151645).

I get the 'doing non-message queue related work', but it is kind of scary that it is running a nested message pump underneath my primary message pump. Why does it pump at all? Does it presume the real message loop is 'doing it wrong'?

Assuming the reason I have a message pump at all is because I am doing more complex work than simple Translate->Dispatch, this model means that my message loop will NOT see all posted messages, and in fact, upon calling DoMessageLoopWork will see NONE of the messages that are currently in the queue. This would definitely break things like keybindings if the host app were using a 'PreTranslate' pattern to handle those.

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

Re: Calling DoMessageLoopWork on demand

Postby magreenblatt » Sat Jan 05, 2013 2:43 pm

Only Chromium's message pump exists in the Chromium/Chrome browser. CEF's implementation of CefDoMessageLoopWork is a hack to allow integration with applications that can't use Chromium's message pump exclusively. If you would like to attempt a better implementation I can suggest some additional reading material and a number of edge cases to consider. In order to be accepted by CEF it would need to involve minimal or no changes to the Chromium code base. As you can probably guess the MessageLoop/MessagePump code is highly optimized for the Chromium browser and changes to this code for non-Chromium use cases will not be accepted upstream.

In regards to the depot_tools problem, try using a shorter path for your Chromium checkout. I use c:\code\chromium on Windows and run gclient from cmd.exe. It works fine for me. I also check out depot_tools using svn (must be version 1.6) instead of using the zip -- not sure if that matters.
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: Calling DoMessageLoopWork on demand

Postby ryanmolden » Sat Jan 05, 2013 6:04 pm

In regards to the depot_tools problem, try using a shorter path for your Chromium checkout. I use c:\code\chromium on Windows and run gclient from cmd.exe. It works fine for me. I also check out depot_tools using svn (must be version 1.6) instead of using the zip -- not sure if that matters.


The path suggestion in the bug doesn't help, I have depot_tools unpacked to c:\depot_tools, if that path is too long something is wrong. It hasn't even gotten to the phase where it tries the checkout, but if it had my path would be c:\chromium, so again no path length issues. The other comments talk about someone narrowing it down to a git command failing and someone else mentions some changes around the very area that is now failing that were made shortly before it started failing.

If it 'works for you' the question is have you set up depot_tools recently or are you using an install/enlistment from long ago? I suspect the latter, I am trying a brand new setup on a machine using the exact sequence of steps the Chromium web page gives for enlisting, and it is failing. Do they have instructions for the 'check out depot_tools from svn'? Because I only saw ones for bootstrapping it from the archive,which doesn't work.

As far as changing the message loop, unless Chromium had a way for embedders to call something akin to DoNonMessageQueueRelatedWork that DIDN'T involve them calling PeekMessage with PM_REMOVE then I don't think you (CEF) can integrate in a way that doesn't put embedders with non-trivial message loops at risk.
ryanmolden
Techie
 
Posts: 12
Joined: Mon Dec 17, 2012 2:56 pm

Next

Return to Support Forum

Who is online

Users browsing this forum: No registered users and 208 guests

cron