Problems Getting Started using CEF

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.

Re: Problems Getting Started using CEF

Postby johnh » Fri Aug 03, 2018 12:36 pm

The clientManager class is declared in WinMain, it's a singleton however so should be accessible from any thread.
That being said the issue only happens in a debug build, release mode is working perfectly.

The app startup looks like this:

Code: Select all

int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) {
   
   // Enable High-DPI support on Windows 7 or newer.
   CefEnableHighDPISupport();
   
   void* sandbox_info = NULL;

   // Provide CEF with command-line arguments.
   CefMainArgs main_args(hInstance);

   // Create a temporary CommandLine object.
   CefRefPtr<CefCommandLine> command_line = shared::CreateCommandLine(main_args);

   // Create a CefApp of the correct process type.
   CefRefPtr<CefApp> app;
   switch (shared::GetProcessType(command_line)) {
   case shared::PROCESS_TYPE_BROWSER:
      app = shared::CreateBrowserProcessApp();
      break;
   case shared::PROCESS_TYPE_RENDERER:
      app = shared::CreateRendererProcessApp();
      break;
   case shared::PROCESS_TYPE_OTHER:
      app = shared::CreateOtherProcessApp();
      break;
   }

   // CEF applications have multiple sub-processes (render, plugin, GPU, etc)
   // that share the same executable. This function checks the command-line and,
   // if this is a sub-process, executes the appropriate logic.
   int exit_code = CefExecuteProcess(main_args, app, sandbox_info);
   if (exit_code >= 0) {
      // The sub-process has completed so return here.
      return exit_code;
   }
   
   // Create the singleton manager instance.
   shared::ClientManager manager;

   // Specify CEF global settings here.
   CefSettings settings;
   settings.no_sandbox = true;
   settings.command_line_args_disabled = true;
   settings.multi_threaded_message_loop = true;

   // Initialize CEF.
   CefInitialize(main_args, settings, app, sandbox_info);
   
   CWindow appWindow( hInstance, nCmdShow );
   appWindow.Display();
   
   appWindow.MessageLoop();
   
   // Shut down CEF.
   CefShutdown();

   return 0;
}

johnh
Techie
 
Posts: 44
Joined: Wed Aug 01, 2018 12:14 pm

Re: Problems Getting Started using CEF

Postby johnh » Fri Aug 03, 2018 12:39 pm

Checking in VS debug / threads window shows that the WinMain starts on the main thread as expected, and the failing line with DCHECK in OnAfterCreated is running in CrBrowserMain thread.

Digging in further gets to this:

cef_thread_checker_impl.cc
Code: Select all

bool ThreadCheckerImpl::CalledOnValidThread() const {
  EnsureThreadIdAssigned();
  AutoLock auto_lock(lock_);
  return valid_thread_id_ == PlatformThread::CurrentRef();
}



CrBrowserMain thread's id = 22236,
Main Thread id = 41168

valid_thread_id_ = 41168
PlatformThread::CurrentRef() = 22236

So according to this, it's expecting the main thread, as opposed to the UI thread.. so that seems wrong ? valid_thread_id should surely by 22236.
johnh
Techie
 
Posts: 44
Joined: Wed Aug 01, 2018 12:14 pm

Re: Problems Getting Started using CEF

Postby magreenblatt » Fri Aug 03, 2018 12:49 pm

If you're going to use ClientManager from multiple threads then you need to either synchronize access to the member variables (using include/base/cef_lock.h, for example) or only access the variables on the expected thread (using CefPostTask and WeakPtrFactory, for example).
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: Problems Getting Started using CEF

Postby johnh » Sat Aug 04, 2018 4:14 am

Ok, but I'm not doing anything with the client manager yet, the only calls to it are coming internally from CEF so surely it would call itself on the appropriate thread already. If I create it where I do in WinMain it is being instantiated on the main browser thread, as all sub-processes terminate at the CefExecuteProcess(..)

It's odd that it works in release mode ?

It seems like the following is the issue: the main application starts on thread x ... the sub processes are spawned, the CEF message loop starts up on thread x2.
When the message loop sends out the events for OnAfterCreated, those methods are being called on the message loops thread, and not the main thread, but I don't have any control over CEFs internal message loop ?
All of this occurs before I have a chance to do anything, post any messages etc.

Trace:

Code: Select all
    libcef.dll!base::debug::BreakDebugger() Line 21   C++
    libcef.dll!logging::LogMessage::~LogMessage() Line 855   C++
    libcef.dll!cef_log(const char * file, int line, int severity, const char * message) Line 336   C++
    PlayTableHub.exe!cef::logging::LogMessage::~LogMessage() Line 187   C++
    PlayTableHub.exe!shared::ClientManager::OnAfterCreated(scoped_refptr<CefBrowser> browser) Line 37   C++                     <<<< CHECK FAILS HERE
>   PlayTableHub.exe!shared::OnAfterCreated(scoped_refptr<CefBrowser> browser) Line 41   C++
    PlayTableHub.exe!resource_manager::Client::OnAfterCreated(scoped_refptr<CefBrowser> browser) Line 94   C++
    PlayTableHub.exe!`anonymous namespace'::life_span_handler_on_after_created(_cef_life_span_handler_t * self, _cef_browser_t * browser) Line 138   C++
    libcef.dll!CefLifeSpanHandlerCToCpp::OnAfterCreated(scoped_refptr<CefBrowser> browser) Line 100   C++
    libcef.dll!CefBrowserHostImpl::CreateInternal(const CefStructBase<CefBrowserSettingsTraits> & settings, scoped_refptr<CefClient> client, content::WebContents * web_contents, bool own_web_contents, scoped_refptr<CefBrowserInfo> browser_info, scoped_refptr<CefBrowserHostImpl> opener, bool is_devtools_popup, scoped_refptr<CefRequestContext> request_context, std::unique_ptr<CefBrowserPlatformDelegate,std::default_delete<CefBrowserPlatformDelegate> > platform_delegate, scoped_refptr<CefExtension> extension) Line 433   C++
    libcef.dll!CefBrowserHostImpl::Create(CefBrowserHostImpl::CreateParams & create_params) Line 359   C++
    libcef.dll!CefBrowserHost::CreateBrowserSync(const CefWindowInfo & windowInfo, scoped_refptr<CefClient> client, const CefStringBase<CefStringTraitsUTF16> & url, const CefStructBase<CefBrowserSettingsTraits> & settings, scoped_refptr<CefRequestContext> request_context) Line 276   C++
    libcef.dll!`anonymous namespace'::CreateBrowserWithHelper(`anonymous namespace'::CreateBrowserHelper * helper) Line 142   C++
    libcef.dll!base::debug::TaskAnnotator::RunTask(const char * queue_function, base::PendingTask * pending_task) Line 101   C++
    libcef.dll!base::internal::IncomingTaskQueue::RunTask(base::PendingTask * pending_task) Line 124   C++
    libcef.dll!base::MessageLoop::RunTask(base::PendingTask * pending_task) Line 320   C++
    libcef.dll!base::MessageLoop::DeferOrRunPendingTask(base::PendingTask pending_task) Line 329   C++
    libcef.dll!base::MessageLoop::DoWork() Line 373   C++
    libcef.dll!base::MessagePumpForUI::DoRunLoop() Line 179   C++
    libcef.dll!base::MessagePumpWin::Run(base::MessagePump::Delegate * delegate) Line 59   C++
    libcef.dll!base::MessageLoop::Run(bool application_tasks_allowed) Line 273   C++
    libcef.dll!base::RunLoop::Run() Line 105   C++
    libcef.dll!base::Thread::Run(base::RunLoop * run_loop) Line 255   C++
    libcef.dll!base::Thread::ThreadMain() Line 340   C++
    libcef.dll!base::`anonymous namespace'::ThreadFunc(void * params) Line 94   C++
    kernel32.dll!BaseThreadInitThunk()   Unknown
    ntdll.dll!RtlUserThreadStart()   Unknown
johnh
Techie
 
Posts: 44
Joined: Wed Aug 01, 2018 12:14 pm

Re: Problems Getting Started using CEF

Postby magreenblatt » Sat Aug 04, 2018 11:07 am

It doesn't "work" in Release build. ThreadChecker only checks in Debug build and is a no-op in Release build.

You are creating the ThreadChecker on the main thread so it expects to be called on the main thread -- that is what CalledOnValidThread is checking.

With multi-threaded message loop mode CEF callbacks will occur on the UI thread, which is not the main thread.

See the above comments about how you should fix your ClientManager implementation.
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: Problems Getting Started using CEF

Postby johnh » Sat Aug 04, 2018 1:23 pm

It doesn't seem to matter where I instantiate the client manager, i've tried creating it in the main browser process / CefApp now with the same result... Clearly I'm missing something here.. the examples and documentation are obtuse at best too..
johnh
Techie
 
Posts: 44
Joined: Wed Aug 01, 2018 12:14 pm

Re: Problems Getting Started using CEF

Postby magreenblatt » Sat Aug 04, 2018 2:59 pm

magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: Problems Getting Started using CEF

Postby johnh » Sat Aug 04, 2018 3:23 pm

Hi, yep I have. I'm using that approach for the async js integration passing functions from renderer to browser via ipc and then results back again.

I still can't see how it relates to this issue, nothing calls the client manager, so there is no possible contention on it between threads, if I had more logic in it I would use locking or msg passing definitely, but for now it's just a shell.

When cef calls into it from thread X, then the method has to be executing on thread X.. so where i'm coming unstuck is I cannot fathom how it thinks it's on thread Y.
johnh
Techie
 
Posts: 44
Joined: Wed Aug 01, 2018 12:14 pm

Previous

Return to Support Forum

Who is online

Users browsing this forum: No registered users and 96 guests