Using the CEF C API without CefClient

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 the CEF C API without CefClient

Postby mojosaurus » Mon Dec 24, 2012 6:33 am

Hello!
I've been working on building a basic, no-frills, CEF client using the C API, from Ruby.
I've run into a problem where the gpu-process fails to initialise.
The code is up at https://github.com/asengupta/cef-ruby

The embed.c file is responsible for loading the libcef-test.rb script and passing in all command line arguments to it.
Most of the work is done in the run() method of libcef-test.rb.

However, when I build and run, the output is something like this:

Code: Select all
avishek@Bane:~/Code/chromium-tar/home/src_tarball/tarball/chromium/src/cef/binary_distrib/cef_binary_3.1339.959_linux/Debug$ ./embed.out

Invoked with...["./embed.out"]
About to execute...
Exit Code = -1

[1224/165420:ERROR:zygote_host_impl_linux.cc(146)] Running without the SUID sandbox! See https://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment for more information on developing with the sandbox on.
[1224/165420:WARNING:proxy_service.cc(885)] PAC support disabled because there is no system implementation
Invoked with...["/home/avishek/Code/chromium-tar/home/src_tarball/tarball/chromium/src/cef/binary_distrib/cef_binary_3.1339.959_linux/Debug/embed.out", "--type=zygote", "--no-sandbox", "--lang=en-US", "--locales-dir-path=/home/avishek/Code/chromium-tar/home/src_tarball/tarball/chromium/src/cef/binary_distrib/cef_binary_3.1339.959_linux/Debug/locales", "--log-file=./chromium.log", "--resources-dir-path=/home/avishek/Code/chromium-tar/home/src_tarball/tarball/chromium/src/cef/binary_distrib/cef_binary_3.1339.959_linux/Debug"]
About to execute...

Invoked with...["/proc/self/exe", "--type=gpu-process", "--channel=17415.0.213110064", "--no-sandbox", "--lang=en-US", "--locales-dir-path=/home/avishek/Code/chromium-tar/home/src_tarball/tarball/chromium/src/cef/binary_distrib/cef_binary_3.1339.959_linux/Debug/locales", "--log-file=./chromium.log", "--resources-dir-path=/home/avishek/Code/chromium-tar/home/src_tarball/tarball/chromium/src/cef/binary_distrib/cef_binary_3.1339.959_linux/Debug", "--supports-dual-gpus=false", "--gpu-vendor-id=0x10de", "--gpu-device-id=0x1056", "--gpu-driver-vendor=NVIDIA", "--gpu-driver-version=304.43", "--lang=en-US", "--locales-dir-path=/home/avishek/Code/chromium-tar/home/src_tarball/tarball/chromium/src/cef/binary_distrib/cef_binary_3.1339.959_linux/Debug/locales", "--log-file=./chromium.log", "--resources-dir-path=/home/avishek/Code/chromium-tar/home/src_tarball/tarball/chromium/src/cef/binary_distrib/cef_binary_3.1339.959_linux/Debug"]
About to execute...
[b][1224/165420:ERROR:sandbox_init_linux.cc(32)] InitializeSandbox() called with multiple threads in process gpu-process
[/b]


It seems that neither the zygote process, nor the gpu-process actually end up returning an exit code. Also, the error about "InitializeSandbox() called with multiple threads in process gpu-process" kind of stumps me.
I know that the CefApp methods (the C versions) need to be implemented, currently, they just print out stuff. Is there some absolutely essential functionality that needs to be implemented in the CefApp methods, in order to get this to work?
I'm still looking at the CefClient code, but nothing specific so far.

Any help would be appreciated.
Thanks!
mojosaurus
Newbie
 
Posts: 5
Joined: Mon Dec 24, 2012 6:20 am

Re: Using the CEF C API without CefClient

Postby fddima » Wed Dec 26, 2012 3:54 pm

Looks like
[1224/165420:ERROR:sandbox_init_linux.cc(32)] InitializeSandbox() called with multiple threads in process gpu-process
is actual problem.

I'm use CEF C API with Xilium.CefGlue (R778.1) without any problems at linux, ubuntu 12.04, multi-process mode.
Last edited by fddima on Wed Dec 26, 2012 3:57 pm, edited 1 time in total.
fddima
Master
 
Posts: 788
Joined: Tue Dec 07, 2010 6:10 am

Re: Using the CEF C API without CefClient

Postby mojosaurus » Wed Dec 26, 2012 3:56 pm

Some more updates, fixed most of the issues in the post above.

For testing purposes, I'm running my code using the --single-process switch.
The problem I've run into, is that the renderer thread never finishes initialisation, which means the function constructing it never returns, and the process hangs.
I've debugged the process through gdb, and have pasted the backtrace below.
The example C++ client that is provided with CEF moves past this point just fine (using the --single-process).
I'll keep looking into this some more, but I'd be grateful if anyone has ideas about why the renderer thread would never finish initialising.

I'm running this code on Ubuntu 12.04.

Code: Select all
#0  pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162
#1  0x00007fffeed2d3cf in base::ConditionVariable::Wait (this=0x7fffffff9b98) at base/synchronization/condition_variable_posix.cc:37
#2  0x00007fffeed2e530 in base::WaitableEvent::TimedWait (this=0x7fffffffa258, max_time=...) at base/synchronization/waitable_event_posix.cc:211
#3  0x00007fffeed2e1cf in base::WaitableEvent::Wait (this=0x7fffffffa258) at base/synchronization/waitable_event_posix.cc:156
#4  0x00007fffeed4b28b in base::Thread::StartWithOptions (this=0x7fffe3876640, options=...) at base/threading/thread.cc:99
#5  0x00007fffee80ed01 in content::RenderProcessHostImpl::Init (this=0x7fffe383d680)
    at content/browser/renderer_host/render_process_host_impl.cc:452
#6  0x00007fffee8228cc in content::RenderViewHostImpl::CreateRenderView (this=0x7fffe3802e00, frame_name=..., opener_route_id=-2, max_page_id=-1)
    at content/browser/renderer_host/render_view_host_impl.cc:233
#7  0x00007fffee8e67eb in content::WebContentsImpl::CreateRenderViewForRenderManager (this=0x7fffe3803a00, render_view_host=0x7fffe3802e00,
    opener_route_id=-2) at content/browser/web_contents/web_contents_impl.cc:3286
#8  0x00007fffee8d3ec8 in content::RenderViewHostManager::InitRenderView (this=0x7fffe3803c70, render_view_host=0x7fffe3802e00, opener_route_id=-2)
    at content/browser/web_contents/render_view_host_manager.cc:666
#9  0x00007fffee8d22f9 in content::RenderViewHostManager::Navigate (this=0x7fffe3803c70, entry=...)
    at content/browser/web_contents/render_view_host_manager.cc:119
#10 0x00007fffee8dfcb7 in content::WebContentsImpl::NavigateToEntry (this=0x7fffe3803a00, entry=...,
    reload_type=content::NavigationController::NO_RELOAD) at content/browser/web_contents/web_contents_impl.cc:1588
#11 0x00007fffee8dfb9c in content::WebContentsImpl::NavigateToPendingEntry (this=0x7fffe3803a00,
    reload_type=content::NavigationController::NO_RELOAD) at content/browser/web_contents/web_contents_impl.cc:1570
#12 0x00007fffee8ccf26 in content::NavigationControllerImpl::NavigateToPendingEntry (this=0x7fffe3803aa8,
    reload_type=content::NavigationController::NO_RELOAD) at content/browser/web_contents/navigation_controller_impl.cc:1484
#13 0x00007fffee8c848a in content::NavigationControllerImpl::LoadEntry (this=0x7fffe3803aa8, entry=0x7fffe386cc00)
    at content/browser/web_contents/navigation_controller_impl.cc:397
#14 0x00007fffee8c976f in content::NavigationControllerImpl::LoadURLWithParams (this=0x7fffe3803aa8, params=...)
    at content/browser/web_contents/navigation_controller_impl.cc:685
#15 0x00007fffee8c920c in content::NavigationControllerImpl::LoadURL (this=0x7fffe3803aa8, url=..., referrer=...,
    transition=content::PAGE_TRANSITION_TYPED, extra_headers=...) at content/browser/web_contents/navigation_controller_impl.cc:605
#16 0x00007fffef919a17 in CefBrowserHostImpl::LoadURL (this=0x7fffe3840800, frame_id=-1, url=...) at cef/libcef/browser/browser_host_impl.cc:1046
#17 0x00007fffef9154cd in CefBrowserHost::CreateBrowserSync (windowInfo=..., client=..., url=..., settings=...)

Thanks in advance!
mojosaurus
Newbie
 
Posts: 5
Joined: Mon Dec 24, 2012 6:20 am

Re: Using the CEF C API without CefClient

Postby mojosaurus » Wed Dec 26, 2012 3:59 pm

Some more updates in my investigation:

Hello!
I ran an "info threads" command, and this is what it came up with:

Code: Select all
  Id   Target Id         Frame
  21   Thread 0x7fffb3fff700 (LWP 29797) "VC manager" pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162
  20   Thread 0x7fffc1069700 (LWP 29796) "Chrome_ChildIOT" syscall () at ../sysdeps/unix/sysv/linux/x86_64/syscall.S:39
[color=#40BF00]  19   Thread 0x7fffc186a700 (LWP 29795) "Chrome_InProcRe" pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162
[/color]  18   Thread 0x7fffc27fc700 (LWP 29794) "BrowserBlocking" pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162
  17   Thread 0x7fffc2ffd700 (LWP 29792) "MediaStreamDevi" pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162
  16   Thread 0x7fffc37fe700 (LWP 29791) "Chrome_IOThread" pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162
  15   Thread 0x7fffc3fff700 (LWP 29790) "Chrome_CacheThr" syscall () at ../sysdeps/unix/sysv/linux/x86_64/syscall.S:39
  14   Thread 0x7fffd0b66700 (LWP 29789) "Chrome_ProcessL" pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162
  13   Thread 0x7fffd1367700 (LWP 29788) "Chrome_FileUser" pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162
  12   Thread 0x7fffd1b68700 (LWP 29787) "Chrome_FileThre" syscall () at ../sysdeps/unix/sysv/linux/x86_64/syscall.S:39
  11   Thread 0x7fffd2369700 (LWP 29786) "Chrome_DBThread" pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162
  10   Thread 0x7fffd2b6a700 (LWP 29785) "AudioThread" pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162
  9    Thread 0x7fffe0038700 (LWP 29784) "WorkerPool/2978" pthread_cond_timedwait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:215
  8    Thread 0x7fffe2f7b700 (LWP 29783) "WorkerPool/2978" pthread_cond_timedwait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:215
  7    Thread 0x7fffd336b700 (LWP 29782) "inotify_reader" 0x00007ffff76cb023 in select () at ../sysdeps/unix/syscall-template.S:82
  6    Thread 0x7fffd3b6c700 (LWP 29780) "NetworkChangeNo" syscall () at ../sysdeps/unix/sysv/linux/x86_64/syscall.S:39
  5    Thread 0x7fffe1ad5700 (LWP 29777) "gdbus" 0x00007ffff76c6303 in __GI___poll (fds=<optimized out>, nfds=<optimized out>,
    timeout=<optimized out>) at ../sysdeps/unix/sysv/linux/poll.c:87
  4    Thread 0x7fffe22d6700 (LWP 29776) "dconf worker" 0x00007ffff76c6303 in __GI___poll (fds=<optimized out>, nfds=<optimized out>,
    timeout=<optimized out>) at ../sysdeps/unix/sysv/linux/poll.c:87
  3    Thread 0x7fffe36e5700 (LWP 29774) "embed.out" pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162
  2    Thread 0x7ffff7ff7700 (LWP 29770) "embed.out" 0x00007ffff76cb023 in select () at ../sysdeps/unix/syscall-template.S:82
* 1    Thread 0x7ffff7fd1700 (LWP 29769) "embed.out" pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162

I've highlighted the specific thread of interest, Thread 19. Switching to that thread and checking the backtrace, gives me this:

Code: Select all
#0  pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162
#1  0x00007fffeed2d3cf in base::ConditionVariable::Wait (this=0x7fffc18692a8) at base/synchronization/condition_variable_posix.cc:37
#2  0x00007fffeed2e9eb in base::WaitableEvent::WaitMany (raw_waitables=0x7fffc1869320, count=2) at base/synchronization/waitable_event_posix.cc:273
#3  0x00007fffeed9a85e in IPC::SyncChannel::WaitForReply (context=0x7fffe38171c0, pump_messages_event=0x0) at ipc/ipc_sync_channel.cc:495
#4  0x00007fffeed9a7a5 in IPC::SyncChannel::SendWithTimeout (this=0x7fffe381e100, message=0x7fffe384bb60, timeout_ms=-1)
    at ipc/ipc_sync_channel.cc:479
#5  0x00007fffeed9a384 in IPC::SyncChannel::Send (this=0x7fffe381e100, message=0x7fffe384bb60) at ipc/ipc_sync_channel.cc:430
#6  0x00007fffee93fbee in content::ChildThread::Send (this=0x7fffe3823808, msg=0x7fffe384bb60) at content/common/child_thread.cc:169
#7  0x00007fffeebd28c8 in content::RenderThreadImpl::Send (this=0x7fffe3823800, msg=0x7fffe384bb60) at content/renderer/render_thread_impl.cc:441
#8  0x00007fffef9a49fd in CefContentRendererClient::RenderThreadStarted (this=0x7fffe3818e70) at cef/libcef/renderer/content_renderer_client.cc:188
#9  0x00007fffeebd2053 in content::RenderThreadImpl::Init (this=0x7fffe3823800) at content/renderer/render_thread_impl.cc:318
#10 0x00007fffeebd1c8c in content::RenderThreadImpl::RenderThreadImpl (this=0x7fffe3823800, channel_name=...)
    at content/renderer/render_thread_impl.cc:258
#11 0x00007fffee8135ac in content::RendererMainThread::Init (this=0x7fffe3859be0) at content/browser/renderer_host/render_process_host_impl.cc:151
#12 0x00007fffeed4b6f2 in base::Thread::ThreadMain (this=0x7fffe3859be0) at base/threading/thread.cc:188
#13 0x00007fffeed40a93 in base::(anonymous namespace)::ThreadFunc (params=0x7fffe3850540) at base/threading/platform_thread_posix.cc:65
#14 0x00007ffff73c8e9a in start_thread (arg=0x7fffc186a700) at pthread_create.c:308
#15 0x00007ffff76d1cbd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:112
#16 0x0000000000000000 in ?? ()

it seems that the Renderer thread itself is waiting for something itself. Specifically, I dug into the code of frame 8 (highlighted in the backtrace above). The blocking line is:

Code: Select all
  thread->Send(new CefProcessHostMsg_GetNewRenderThreadInfo(&params));

Internally, it is doing an IPC call, ultimately ending up src/ipc/ipc_sync_channel.cc:471

Code: Select all
    context->ipc_task_runner()->PostDelayedTask(
        FROM_HERE,
        base::Bind(&SyncContext::OnSendTimeout, context.get(), message_id),
        base::TimeDelta::FromMilliseconds(timeout_ms));

After this, it waits for the response, which never arrives. I took a peek at the message object that is being created. It looks like this:
Code: Select all
{<Pickle> = {_vptr.Pickle = 0x7ffff52ba390, static kPayloadUnit = 64, header_ = 0x7fffb8000cb0, header_size_ = 20, capacity_ = 64,
    variable_buffer_offset_ = 0}, file_descriptor_set_ = {ptr_ = 0x0}, received_time_ = 0, output_params_ = {static npos = <optimized out>,
    _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7fffe7d254d8 ""}},
  log_data_ = 0x0, dont_log_ = false}

Here is the message from the client which *does* work:

Code: Select all
{<Pickle> = {_vptr.Pickle = 0x7ffff7ad7390, static kPayloadUnit = 64, header_ = 0x7fffdad16370, header_size_ = 20, capacity_ = 64,
    variable_buffer_offset_ = 0}, file_descriptor_set_ = {ptr_ = 0x0}, received_time_ = 0, output_params_ = {static npos = <optimized out>,
    _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7fffee8974d8 ""}},
  log_data_ = 0x0, dont_log_ = false}

There's no difference between the two messages, so I'm forced to conclude that the problem is not in the message, but rather in the routing:
Based on the IPC configuration on the working CEF client, which I reproduce below, the above IPC call should hit the OnGetNewRenderThreadInfo() method, which it does. But not when run from my code.

Code: Select all
bool CefBrowserMessageFilter::OnMessageReceived(const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(CefBrowserMessageFilter, message)
    IPC_MESSAGE_HANDLER(CefProcessHostMsg_GetNewRenderThreadInfo,
                        OnGetNewRenderThreadInfo)
    IPC_MESSAGE_HANDLER(CefProcessHostMsg_GetNewBrowserInfo,
                        OnGetNewBrowserInfo)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

What should I check to verify that the IPC call is being routed correctly?

Thanks in advance!
mojosaurus
Newbie
 
Posts: 5
Joined: Mon Dec 24, 2012 6:20 am

Re: Using the CEF C API without CefClient

Postby magreenblatt » Thu Dec 27, 2012 6:33 am

Are you running the message loop for the main process thread via either CefRunMessageLoop or CefDoMessageLoopWork?
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: Using the CEF C API without CefClient

Postby mojosaurus » Thu Dec 27, 2012 10:32 am

Hello!
Yes, I've tried both methods. However, the hang actually happens in the call to cef_browser_host_create_browser_sync(), which occurs before cef_run_message_loop(). Thus, it never reaches the point where the message loop should kick off.
mojosaurus
Newbie
 
Posts: 5
Joined: Mon Dec 24, 2012 6:20 am

Re: Using the CEF C API without CefClient

Postby fddima » Thu Dec 27, 2012 10:36 am

mojosaurus wrote:Hello!
Yes, I've tried both methods. However, the hang actually happens in the call to cef_browser_host_create_browser_sync(), which occurs before cef_run_message_loop(). Thus, it never reaches the point where the message loop should kick off.

I think that it is impossible to create browser without message loop started.
fddima
Master
 
Posts: 788
Joined: Tue Dec 07, 2010 6:10 am

Re: Using the CEF C API without CefClient

Postby magreenblatt » Thu Dec 27, 2012 11:57 am

The message loop must be started immediately after calling CefInitialize and continue until CefShutdown.
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: Using the CEF C API without CefClient

Postby mojosaurus » Thu Dec 27, 2012 1:16 pm

Hello!
I used the CefClient code to guide me, and the code in cefclient_gtk.cpp's main() goes like this:

Code: Select all
  CefInitialize(main_args, settings, app.get());

  // Register the scheme handler.
  scheme_test::InitTest();

  // ....some GTK initialisation I've omitted

  // Create the browser view.
  CefWindowInfo window_info;
  CefBrowserSettings browserSettings;

  // Populate the settings based on command line arguments.
  AppGetBrowserSettings(browserSettings);

  window_info.SetAsChild(vbox);

  CefBrowserHost::CreateBrowserSync(
      window_info, g_handler.get(),
      g_handler->GetStartupURL(), browserSettings);

  gtk_container_add(GTK_CONTAINER(window), vbox);
  gtk_widget_show_all(GTK_WIDGET(window));

  // Install an signal handler so we clean up after ourselves.
  signal(SIGINT, TerminationSignalHandler);
  signal(SIGTERM, TerminationSignalHandler);

  CefRunMessageLoop();

  CefShutdown();


Regardless, running the message loop before creating the browser does not make any difference. It seems like a message is being sent from the Renderer thread to the BrowserHost thread, but this message is not received for some reason.
I'll keep looking into this.
mojosaurus
Newbie
 
Posts: 5
Joined: Mon Dec 24, 2012 6:20 am

Re: Using the CEF C API without CefClient

Postby fddima » Thu Dec 27, 2012 6:12 pm

mojosaurus wrote:Hello!
I used the CefClient code to guide me, and the code in cefclient_gtk.cpp's main() goes like this:
Regardless, running the message loop before creating the browser does not make any difference. It seems like a message is being sent from the Renderer thread to the BrowserHost thread, but this message is not received for some reason.
I'll keep looking into this.

Hm. Interesting.
But, man, i'm never get this issue with xilium.cefglue. So, if you can't get it with ruby - get it working with plain first (plain c first). Looks as you fight with environment, which, probably you doesn't know. And looks like unrelated to CEF.
fddima
Master
 
Posts: 788
Joined: Tue Dec 07, 2010 6:10 am


Return to Support Forum

Who is online

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