Chrome_IOThread blocks application main 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.

Chrome_IOThread blocks application main thread

Postby scanty » Wed Jan 09, 2019 12:02 pm

I am trying to CEF in my application(on mac) from 3.1523 to 3.3497 and facing main thread blocking issues.
Basically, I am doing some time intensive operation ( ranging from a few seconds to a minute) in GetResourceHandler call which blocks the main thread for the whole duration.

I tried profiling the issue using System Trace tool in instruments and found that the main thread is blocked with the following stack trace:

0 libsystem_kernel.dylib mach_msg_trap
1 libsystem_kernel.dylib mach_msg
2 Chromium Embedded Framework base::WaitableEvent::TimedWaitUntil(base::TimeTicks const&) ../../base/synchronization/waitable_event_mac.cc:142
3 Chromium Embedded Framework base::WaitableEvent::Wait() ../../base/synchronization/waitable_event_mac.cc:105
4 Chromium Embedded Framework gpu::GpuChannelHost::Send(IPC::Message*) ../../gpu/ipc/client/gpu_channel_host.cc:83
5 Chromium Embedded Framework gpu::CommandBufferProxyImpl::Initialize(unsigned long long, gpu::CommandBufferProxyImpl*, gpu::SchedulingPriority, gpu::ContextCreationAttribs const&, GURL const&) ../../gpu/ipc/client/command_buffer_proxy_impl.cc:126
6 Chromium Embedded Framework ui::ContextProviderCommandBuffer::BindToCurrentThread() ../../services/ui/public/cpp/gpu/context_provider_command_buffer.cc:134
7 Chromium Embedded Framework content::GpuProcessTransportFactory::EstablishedGpuChannel(base::WeakPtr<ui::Compositor>, bool, scoped_refptr<gpu::GpuChannelHost>) ../../content/browser/compositor/gpu_process_transport_factory.cc:405
8 Chromium Embedded Framework void base::internal::FunctorTraits<void (content::GpuProcessTransportFactory::*)(base::WeakPtr<ui::Compositor>, bool, scoped_refptr<gpu::GpuChannelHost>), void>::Invoke<void (content::GpuProcessTransportFactory::*)(base::WeakPtr<ui::Compositor>, bool, scoped_refptr<gpu::GpuChannelHost>), base::WeakPtr<content::GpuProcessTransportFactory>, base::WeakPtr<ui::Compositor>, bool, scoped_refptr<gpu::GpuChannelHost> >(void (content::GpuProcessTransportFactory::*)(base::WeakPtr<ui::Compositor>, bool, scoped_refptr<gpu::GpuChannelHost>), base::WeakPtr<content::GpuProcessTransportFactory>&&, base::WeakPtr<ui::Compositor>&&, bool&&, scoped_refptr<gpu::GpuChannelHost>&&) ../../base/bind_internal.h:507
9 Chromium Embedded Framework void base::internal::InvokeHelper<true, void>::MakeItSo<void (content::GpuProcessTransportFactory::*)(base::WeakPtr<ui::Compositor>, bool, scoped_refptr<gpu::GpuChannelHost>), base::WeakPtr<content::GpuProcessTransportFactory>, base::WeakPtr<ui::Compositor>, bool, scoped_refptr<gpu::GpuChannelHost> >(void (content::GpuProcessTransportFactory::*&&)(base::WeakPtr<ui::Compositor>, bool, scoped_refptr<gpu::GpuChannelHost>), base::WeakPtr<content::GpuProcessTransportFactory>&&, base::WeakPtr<ui::Compositor>&&, bool&&, scoped_refptr<gpu::GpuChannelHost>&&) ../../base/bind_internal.h:627
10 Chromium Embedded Framework void base::internal::Invoker<base::internal::BindState<void (content::GpuProcessTransportFactory::*)(base::WeakPtr<ui::Compositor>, bool, scoped_refptr<gpu::GpuChannelHost>), base::WeakPtr<content::GpuProcessTransportFactory>, base::WeakPtr<ui::Compositor>, bool>, void (scoped_refptr<gpu::GpuChannelHost>)>::RunImpl<void (content::GpuProcessTransportFactory::*)(base::WeakPtr<ui::Compositor>, bool, scoped_refptr<gpu::GpuChannelHost>), std::__1::tuple<base::WeakPtr<content::GpuProcessTransportFactory>, base::WeakPtr<ui::Compositor>, bool>, 0ul, 1ul, 2ul>(void (content::GpuProcessTransportFactory::*&&)(base::WeakPtr<ui::Compositor>, bool, scoped_refptr<gpu::GpuChannelHost>), std::__1::tuple<base::WeakPtr<content::GpuProcessTransportFactory>, base::WeakPtr<ui::Compositor>, bool>&&, std::__1::integer_sequence<unsigned long, 0ul, 1ul, 2ul>, scoped_refptr<gpu::GpuChannelHost>&&) ../../base/bind_internal.h:680
11 Chromium Embedded Framework base::internal::Invoker<base::internal::BindState<void (content::GpuProcessTransportFactory::*)(base::WeakPtr<ui::Compositor>, bool, scoped_refptr<gpu::GpuChannelHost>), base::WeakPtr<content::GpuProcessTransportFactory>, base::WeakPtr<ui::Compositor>, bool>, void (scoped_refptr<gpu::GpuChannelHost>)>::RunOnce(base::internal::BindStateBase*, scoped_refptr<gpu::GpuChannelHost>&&) ../../base/bind_internal.h:649
12 Chromium Embedded Framework base::OnceCallback<void (scoped_refptr<gpu::GpuChannelHost>)>::Run(scoped_refptr<gpu::GpuChannelHost>) && ../../content/browser/gpu/browser_gpu_channel_host_factory.cc:99
13 Chromium Embedded Framework content::BrowserGpuChannelHostFactory::EstablishGpuChannel(base::OnceCallback<void (scoped_refptr<gpu::GpuChannelHost>)>) ../../content/browser/gpu/browser_gpu_channel_host_factory.cc:308
14 Chromium Embedded Framework content::GpuProcessTransportFactory::CreateLayerTreeFrameSink(base::WeakPtr<ui::Compositor>) ../../content/browser/compositor/gpu_process_transport_factory.cc:322
15 Chromium Embedded Framework ui::Compositor::RequestNewLayerTreeFrameSink() ../../ui/compositor/compositor.cc:595
16 Chromium Embedded Framework base::OnceCallback<void ()>::Run() && ../../ui/accelerated_widget_mac/window_resize_helper_mac.cc:99
17 Chromium Embedded Framework ui::(anonymous namespace)::WrappedTask::Run() ../../ui/accelerated_widget_mac/window_resize_helper_mac.cc:146
18 Chromium Embedded Framework ui::WindowResizeHelperMac::WaitForSingleTaskToRun(base::TimeDelta const&) ../../ui/accelerated_widget_mac/window_resize_helper_mac.cc:227
19 Chromium Embedded Framework ui::CATransactionCoordinator::PostCommitHandler() ../../ui/accelerated_widget_mac/ca_transaction_observer.mm:108
20 QuartzCore CA::Transaction::run_commit_handlers(CATransactionPhase)
21 QuartzCore CA::Context::commit_transaction(CA::Transaction*)
22 QuartzCore CA::Transaction::commit()
23 AppKit __65+[CATransaction(NSCATransaction) NS_setFlushesWithDisplayRefresh]_block_invoke
24 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
25 CoreFoundation __CFRunLoopDoObservers
26 CoreFoundation __CFRunLoopRun
27 CoreFoundation CFRunLoopRunSpecific
28 HIToolbox RunCurrentEventLoopInMode
29 HIToolbox ReceiveNextEventCommon
30 HIToolbox _BlockUntilNextEventMatchingListInModeWithFilter
31 AppKit _DPSNextEvent
32 AppKit -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:]
33 AppKit -[NSApplication run]
34 AppKit NSApplicationMain


Am I missing anything while upgrading to new CEF which is causing this behaviour? Are there any debug logs which can help me to identify the issue?
I am new to CEF world, any help will be greatly appreciated.
scanty
Newbie
 
Posts: 4
Joined: Wed Jan 09, 2019 9:45 am

Re: Chrome_IOThread blocks application main thread

Postby magreenblatt » Wed Jan 09, 2019 1:22 pm

Do not perform blocking work on the CEF UI or IO threads, use a new thread or TID_FILE instead. See https://bitbucket.org/chromiumembedded/ ... er-threads
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: Chrome_IOThread blocks application main thread

Postby scanty » Thu Jan 10, 2019 9:00 am

To provide some more context, IO thread is not doing any blocking operation in GetResourceHandler but just reading a local html file. However, the content of the html file is provided by Main thread via a common queue. As the Main Thread is already blocked during GetResourceHandler call, IO thread never gets the html file and eventually timeouts. While the html file is not served, the main is stalled for the duration of the GetResourceHandler call.
The same mechanism worked fine in CEF 3.1523 but failing in 3.3497.
scanty
Newbie
 
Posts: 4
Joined: Wed Jan 09, 2019 9:45 am

Re: Chrome_IOThread blocks application main thread

Postby magreenblatt » Thu Jan 10, 2019 9:45 am

scanty wrote:To provide some more context, IO thread is not doing any blocking operation in GetResourceHandler but just reading a local html file. However, the content of the html file is provided by Main thread via a common queue. As the Main Thread is already blocked during GetResourceHandler call, IO thread never gets the html file and eventually timeouts. While the html file is not served, the main is stalled for the duration of the GetResourceHandler call.
The same mechanism worked fine in CEF 3.1523 but failing in 3.3497.

Get the content from CefResourceHandler::ProcessRequest and use the CefCallback to continue after the content is available.
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: Chrome_IOThread blocks application main thread

Postby scanty » Mon Jan 14, 2019 10:46 am

Hi magreenblatt,

Debugging the application further, I found out that the second request does not face any such issues and completes successfully. I have not explored the ProcessRequest route yet as I want to minimise the changes for request handling, but the completion of second request sounds like some initialisation issue that could be blocking the first request.
Any pointers would be appreciated.
Thanks
scanty
Newbie
 
Posts: 4
Joined: Wed Jan 09, 2019 9:45 am

Re: Chrome_IOThread blocks application main thread

Postby scanty » Wed Jan 23, 2019 8:26 am

Hi magreenblatt,

I added a custom resource handler to handle these requests as follows:

Code: Select all
bool CustomResourceHandler::ProcessRequest(CefRefPtr<CefRequest> request,
                                     CefRefPtr<CefCallback> callback) {
    callback->Continue();
    return true;
}

void CustomResourceHandler::GetResponseHeaders(CefRefPtr<CefResponse> response,
                                         int64& response_length,
                                         CefString& redirectUrl) {
    response_length = -1;
    response->SetMimeType("text/html");
    response->SetStatus(200);
    response->SetStatusText("OK");
   
}

bool CustomResourceHandler::ReadResponse(void* data_out,
                                   int bytes_to_read,
                                   int& bytes_read,
                                   CefRefPtr<CefCallback> callback)  {
 
    if (_completed) {
        bytes_read = 0;
        return false;
    } else {
        if( !_contentDqueued) {
            // sets _bytesProcessed, _bytesTotal, _response, _contentDqueued
            DqueueContent();
        }

         if ( _contentDqueued ) {
            //process _response here
            int bytesToProcess = MIN(bytes_to_read, _bytesTotal - _bytesProcessed);
            void *loc =  ((char*)_response  + _bytesProcessed);
            memcpy(data_out, loc, bytesToProcess);
            _bytesProcessed += bytesToProcess;
            bytes_read = bytesToProcess;
        } else {
            bytes_read = 0;
        }
        if (_bytesProcessed == _bytesTotal ) {
            _completed = true;
        }
        return true;
    }
}


I am trying to form the response in ReadResponse function. Here Dqueue() call gets the content from the queue which is populated by the main thread.
However, Dqueue() fails sometimes as the main thread does get the chance always before Dequeue call and ReadResponse returns with bytes_read=0 and true. In that case, main thread queues the response later but the control does not come back to ReadResponse.

I was going through the documentation of https://magpcss.org/ceforum/apidocs3/projects/(default)/CefResourceHandler.html but could not understand from where to call the Cefcallback so that ReadResponse could be called again?
Not sure, if the implementation of methods in CustomResourceHandler correct or I am missing something.
Thanks
scanty
Newbie
 
Posts: 4
Joined: Wed Jan 09, 2019 9:45 am


Return to Support Forum

Who is online

Users browsing this forum: Google [Bot] and 76 guests