CefURLRequest in IO thread blocked by UI 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.

CefURLRequest in IO thread blocked by UI thread

Postby Mayhew » Wed Aug 26, 2015 6:32 pm

When our CEF app initializes it uses CefURLRequest to retrieve data from a remote server. We create the CefURLRequest in a helper method that is called from the IO thread via a CefPostTask() call as follows:

Code: Select all
void MyClass::GetDataHelper() {
  <in the Browser/UI thread>
  CefRefPtr<WebRequestDelegate> delegate = new WebRequestDelegate();
  CefPostTask(TID_IO, NewCefRunnableMethod(this, &MyClass::StartUrlRead, url, delegate);
  <block on a condition variable and wait for the request to finish>
}

The StartUrlRead method looks as follows:
Code: Select all
void MyClass::StartUrlRead(const char* url, CefRefPtr<WebRequestDelegate> delegate) {
  CefRefPtr<CefRequest> request = CefRequest::Create();
  request->SetMethod("GET");
  request->SetURL(url);
  CreateUrlRequest(request, delegate);
}

After the CefPostTask call our UI thread blocks via a condition variable that is signaled by the request delegate when the request finishes. This has worked perfectly up through the 2171 branch. This week we attempted to update to the 2454 branch on Mac and it no loner works. With 2454, the request delegates methods like OnDownloadData() are not called while the UI thread is blocked. As soon as the UI thread becomes unblocked, the request delegate methods start getting called. It's as if the IO thread is not able to run while the UI thread is blocked. Has the implementation of the threading or the url request changed in any way that would cause this?

I am about to try this on Win to see if it exhibits the same behavior and will report back.

John
Mayhew
Expert
 
Posts: 303
Joined: Mon Apr 18, 2011 8:02 pm

Re: CefURLRequest in IO thread blocked by UI thread

Postby magreenblatt » Wed Aug 26, 2015 9:49 pm

It's quite possible that the threading behavior has changed. Do not block the UI thread on the IO thread or visa-versa. If you need to wait for the request to complete then just delay window/browser creation until that time.
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: CefURLRequest in IO thread blocked by UI thread

Postby Mayhew » Fri Aug 28, 2015 3:45 pm

Ok, this happens on Windows as well. What is strange to me is that the CefPostTask does execute the StartUrlRead method on the IO thread and the CreateUrlRequest is made. The request is fully created but no HTTP IO happens during my wait. So the IO thread doesn't appear blocked but the URLRequest is.

And yes, I wait for this to complete prior to calling CreateBrowser so the browser window is not created at the time the code I provided is run.

Any thoughts as to why the request would not proceed?
Mayhew
Expert
 
Posts: 303
Joined: Mon Apr 18, 2011 8:02 pm

Re: CefURLRequest in IO thread blocked by UI thread

Postby magreenblatt » Fri Aug 28, 2015 3:58 pm

Mayhew wrote:Any thoughts as to why the request would not proceed?

It's waiting for something to occur on the UI thread -- as to what, I don't know.
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: CefURLRequest in IO thread blocked by UI thread

Postby Mayhew » Fri Aug 28, 2015 4:16 pm

It sort of looks like that request doesn't proceed until I call CefRunMessageLoop(). Our app is pretty old and CefClient and our code have diverged quite a bit with the last several release branches. We are still doing the older CefRunMessageLoop(); call from our main() method. The CefClient does a lot more via classes like MainMessageLoopStd, etc. Is it possible that is the problem?
Mayhew
Expert
 
Posts: 303
Joined: Mon Apr 18, 2011 8:02 pm

Re: CefURLRequest in IO thread blocked by UI thread

Postby Mayhew » Fri Aug 28, 2015 4:35 pm

Hmm, CefBrowserURLRequest::Start() calls

Code: Select all
    BrowserThread::PostTaskAndReply(
      BrowserThread::UI,
      FROM_HERE,
      base::Bind(&CefBrowserURLRequest::Context::GetRequestContextOnUIThread,
                 this),
      base::Bind(&CefBrowserURLRequest::Context::ContinueOnOriginatingThread,
                 this, url, request_type));


It is posting that task to the UI thread. Is that the same thread as my main method? If so it would explain why if I'm blocking in my main call that task doesn't execute until I unblock.
Mayhew
Expert
 
Posts: 303
Joined: Mon Apr 18, 2011 8:02 pm

Re: CefURLRequest in IO thread blocked by UI thread

Postby Mayhew » Fri Aug 28, 2015 5:53 pm

That appears to be the problem.

Commit ca0e381on 2015-03-02 in the 2357 branch made the change.

If I force BrowserThread::PostTaskAndReply to post to the IO thread my code works (but you do get tons of debug breaks from the CURRENTLY_ON(BrowserThread::UI) and CEF_REQUIRE_UIT(); calls).

It looks like the original implementation supported handling the request directly in the thread it was created in. It seems a bit strange to block the UI/Browser thread for any CefURlRequest and it would be great if it was an option to choose the thread.

Short of reworking that change I can't see how anyone could use CefURLRequest to get data that is required prior to starting the browser and calling CefRunMessageLoop.
Mayhew
Expert
 
Posts: 303
Joined: Mon Apr 18, 2011 8:02 pm

Re: CefURLRequest in IO thread blocked by UI thread

Postby magreenblatt » Fri Aug 28, 2015 7:25 pm

Why do you need to execute the request before calling CefRunMessageLoop? Why are you blocking the UI thread by waiting on the IO thread?
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: CefURLRequest in IO thread blocked by UI thread

Postby Mayhew » Mon Aug 31, 2015 5:26 pm

magreenblatt wrote:Why do you need to execute the request before calling CefRunMessageLoop?

We issue this HTTP request in our main methods prior to calling CreateBrowser(). This data retrieved from this HTTP request is required for us to establish our initial URL. I think the CefRunMessageLoop being an issue here is incorrect. The problem is that the initial code in CefBrowserURLRequest::Start() is posting tasks on the UI thread and we are waiting via a ConditionVariable for the request to process or time out. That wait causes the deadlock.

magreenblatt wrote:Why are you blocking the UI thread by waiting on the IO thread?

As stated above we need to wait until we have the data from that HTTP request before we initialize the browser.
Mayhew
Expert
 
Posts: 303
Joined: Mon Apr 18, 2011 8:02 pm

Re: CefURLRequest in IO thread blocked by UI thread

Postby Mayhew » Mon Aug 31, 2015 7:30 pm

FWIW, I don't think assuming you can put a CEFURLRequest on another thread and wait for it in the originating thread is an unreasonable design by any stretch. Most native UI implementations require synchronous operations of some kind. The fact that CEFURLRequest now requires access to a thread outside the one it was started in is limiting. I can't claim to fully understand the browser context change that precipitated this new behavior but I would hope that if I passed in my own context, the UI task could be avoided. This would at least support our workflow if we provided our own context. If you pass null or the global UI/browser context then you are subject to the rule that the UI thread cannot block waiting for the response.


Code: Select all
if (!request_context_.get()) {
    BrowserThread::PostTaskAndReply(
      BrowserThread::UI,
      FROM_HERE,
      base::Bind(&CefBrowserURLRequest::Context::GetRequestContextOnUIThread,
                 this),
      base::Bind(&CefBrowserURLRequest::Context::ContinueOnOriginatingThread,
                 this, url, request_type));
} else {
   url_request_getter_ = request_context_->GetRequestContext();
   ContinueOnOriginatingThread, this, url, request_type);
}


If you feel that is a reasonable approach I'd be glad to put a patch together.
Mayhew
Expert
 
Posts: 303
Joined: Mon Apr 18, 2011 8:02 pm

Next

Return to Support Forum

Who is online

Users browsing this forum: Majestic-12 [Bot] and 117 guests