Disclosure Statement: This site contains affiliate links, which means that I may receive a commission if you make a purchase using these links. As an eBay Partner, I earn from qualifying purchases.
If you find these projects useful please consider becoming a sponsor with Patreon, GitHub or Liberapay.

Freezing on exit app / 100% CPU

Post Reply
thefunkyjoint
Posts: 513
Joined: Thu Aug 10, 2017 12:40 pm

Freezing on exit app / 100% CPU

Post by thefunkyjoint »

Hi,

Since i'm migrated from DCEF3 to CEF4, everything worked fine except the fact when i close my app, it freezes using 100% CPU.

After debugging, i could find out that the line that cause the freezing is this one on the code below, on uCEFApplication unit :

Code: Select all

if FMustShutDown then cef_shutdown;

Code: Select all

procedure TCefApplication.ShutDown;
begin
  try
    if (FLibHandle <> 0) then
      begin
        if FMustShutDown then cef_shutdown;

        FreeLibrary(FLibHandle);
        FLibHandle := 0;
      end;
  except
    on e : exception do
      if CustomExceptionHandler('TCefApplication.ShutDown', e) then raise;
  end;
end;
Any hints on how to debug / fix this ?

Thanks
User avatar
salvadordf
Posts: 4564
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Freezing on exit app / 100% CPU

Post by salvadordf »

Hi,

Try to open the same web page or html contents with the MDIBrowser or the ToolBoxBrowser demos.

If you can't replicate the freezing problem with the demos then there's something missing in the browser destruction code of your app.

Are you running several copies of your app using the same cache directory?
thefunkyjoint
Posts: 513
Joined: Thu Aug 10, 2017 12:40 pm

Re: Freezing on exit app / 100% CPU

Post by thefunkyjoint »

I'll try to replicate the issue with the demo, problem is they won't open on Delphi 2007, i need to create a new project and copy / paste the units.

I don't run multiple instances of my app, but i create multiple instances of TChromium , each one with its instance of TCEFWindowParent.

Thanks
User avatar
salvadordf
Posts: 4564
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Freezing on exit app / 100% CPU

Post by salvadordf »

Remember that you can also download the Starter edition of Delphi 10.2 for free and install it in a virtual machine.

https://www.embarcadero.com/products/de ... l-download
thefunkyjoint
Posts: 513
Joined: Thu Aug 10, 2017 12:40 pm

Re: Freezing on exit app / 100% CPU

Post by thefunkyjoint »

I'm trying to debug to find out exactly where in code the problem happens, but at some point Delphi goes to the CPU window and i can't debug anymore. Is there a way to keep only on the .pas units ?
You do not have the required permissions to view the files attached to this post.
User avatar
salvadordf
Posts: 4564
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Freezing on exit app / 100% CPU

Post by salvadordf »

thefunkyjoint wrote: Tue Nov 28, 2017 5:46 pm I'm trying to debug to find out exactly where in code the problem happens, but at some point Delphi goes to the CPU window and i can't debug anymore. Is there a way to keep only on the .pas units ?
Debugging an error inside the CEF3 libraries can be VERY complicated, specially if there are some problems with unreleased interfaces.

I would recommend you to test your website in the demos I mentioned before using Delphi 10.2 Starter.

If you see the same problem then it could be a CEF4Delphi problem or even a CEF3 or Chromium problem.

However, if you don't see the same problem, then you have to check if you are creating and destroying all the browsers following the sequence described in the demos.

The problem would be much easier to identify and fix if you could copy part of your code here or if you could replicate the problem in a new application that you could share.
User avatar
salvadordf
Posts: 4564
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Freezing on exit app / 100% CPU

Post by salvadordf »

Please, read this thread :
https://www.briskbard.com/forum/viewtopic.php?f=8&t=160

The destruction sequence is explained with more detail in that thread.
thefunkyjoint
Posts: 513
Joined: Thu Aug 10, 2017 12:40 pm

Re: Freezing on exit app / 100% CPU

Post by thefunkyjoint »

I don't know why, but in my case even following the destruction steps, i still get a crash (or a freezing on 100% CPU) on exit my app.

As far as i understand, when i call CloseBrowser(true) , it will send a WM_CLOSE message to the app , right ?

So in my case i have 4 TChromium, it will send 4 WM_CLOSE messages, so FormCloseQuery will be called 4 times, am i right ? Maybe is this the problem ?
User avatar
salvadordf
Posts: 4564
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Freezing on exit app / 100% CPU

Post by salvadordf »

thefunkyjoint wrote: Wed Nov 29, 2017 12:02 pm I don't know why, but in my case even following the destruction steps, i still get a crash (or a freezing on 100% CPU) on exit my app.

As far as i understand, when i call CloseBrowser(true) , it will send a WM_CLOSE message to the app , right ?

So in my case i have 4 TChromium, it will send 4 WM_CLOSE messages, so FormCloseQuery will be called 4 times, am i right ? Maybe is this the problem ?
Let's say your application has only one TForm called MainForm with 4 TChromium called Chromium1, Chromium2, Chromium3 and Chromium4.

Each TChromium uses one TCEFWindowParent, so you will have 4 TCEFWindowParent called WindowParent1, WindowParent2, WindowParent3 and WindowParent4.
  • Chromium1 uses WindowParent1.
  • Chromium2 uses WindowParent2.
  • Chromium3 uses WindowParent3.
  • Chromium4 uses WindowParent4.
You will need to use these events :
  • MainForm.FormCloseQuery
  • Chromium1.OnClose
  • Chromium2.OnClose
  • Chromium3.OnClose
  • Chromium4.OnClose
  • Chromium1.OnBeforeClose
  • Chromium2.OnBeforeClose
  • Chromium3.OnBeforeClose
  • Chromium4.OnBeforeClose
  • Chromium1.OnAfterCreated
  • Chromium2.OnAfterCreated
  • Chromium3.OnAfterCreated
  • Chromium4.OnAfterCreated
Some of those events are called from a thread where you can't destroy VCL components so you will also need to declare some messages :

Code: Select all

const
  CEFBROWSER_DESTROYPARENT1          = WM_APP + $100;
  CEFBROWSER_DESTROYPARENT2          = WM_APP + $101;
  CEFBROWSER_DESTROYPARENT3          = WM_APP + $102;
  CEFBROWSER_DESTROYPARENT4          = WM_APP + $103;
You will also have to use several procedures to handle all those messages :
  • The procedure DestroyParent1Msg will handle CEFBROWSER_DESTROYPARENT1
  • The procedure DestroyParent2Msg will handle CEFBROWSER_DESTROYPARENT2
  • The procedure DestroyParent3Msg will handle CEFBROWSER_DESTROYPARENT3
  • The procedure DestroyParent4Msg will handle CEFBROWSER_DESTROYPARENT4
You will also need to know which browsers are initialized so you will declare 4 boolean variables called : Browser1Initialized, Browser2Initialized, Browser3Initialized and Browser4Initialized.

You will set each of them to True in the TChromium.OnAfterCreated event like this :
  • Chromium1.OnAfterCreated sets Browser1Initialized to True
  • Chromium2.OnAfterCreated sets Browser2Initialized to True
  • Chromium3.OnAfterCreated sets Browser3Initialized to True
  • Chromium4.OnAfterCreated sets Browser4Initialized to True
You will also need 4 more boolean variables to know which browser is in the process of destruction. Let's call them Browser1Closing, Browser2Closing, Browser3Closing and Browser4Closing. Set all of them to False when your app is created.

The destruction sequence is this :
  • A user decides to close your app and clicks on the X of your MainForm which will trigger the MainForm.FormCloseQuery event. In this event you will check Browser1Initialized, Browser2Initialized, Browser3Initialized and Browser4Initialized. If all of them are False then you can set CanClose to True.
    However, if any of them are True you will set CanClose to False and you will have to call the CloseBrowser function for each initialized browser like this :

    Code: Select all

    if Browser1Initialized and not(Browser1Closing) then
    begin
      Browser1Closing := True;
      Chromium1.CloseBrowser(True);
    end;
      
    if Browser2Initialized and not(Browser2Closing) then 
    begin
      Browser2Closing := True;
      Chromium2.CloseBrowser(True);
    end;
    
    if Browser3Initialized and not(Browser3Closing) then 
    begin
      Browser3Closing := True;
      Chromium3.CloseBrowser(True);
    end;
    
    if Browser4Initialized and not(Browser4Closing) then 
    begin
      Browser4Closing := True;
      Chromium4.CloseBrowser(True);
    end;
    
  • Each TChrromium.CloseBrowser will trigger a TChrromium.OnClose but you can't destroy VCL components in this event so you will need to send a message to your MainForm like this :
    • Chromium1.OnClose will do a PostMessage(MainForm.Handle, CEFBROWSER_DESTROYPARENT1, 0, 0);
    • Chromium2.OnClose will do a PostMessage(MainForm.Handle, CEFBROWSER_DESTROYPARENT2, 0, 0);
    • Chromium3.OnClose will do a PostMessage(MainForm.Handle, CEFBROWSER_DESTROYPARENT3, 0, 0);
    • Chromium4.OnClose will do a PostMessage(MainForm.Handle, CEFBROWSER_DESTROYPARENT4, 0, 0);
  • You have 4 procedures to handle those messages called : DestroyParent1Msg, DestroyParent2Msg, DestroyParent3Msg and DestroyParent4Msg. Each of those procedures will destroy one TCEFWindowParent like this
    • DestroyParent1Msg will call WindowParent1.Free
    • DestroyParent2Msg will call WindowParent2.Free
    • DestroyParent3Msg will call WindowParent3.Free
    • DestroyParent4Msg will call WindowParent4.Free
  • Each destroyed TCEFWindowParent will trigger a TChromium.OnBeforeClose event and you will set Browser1Initialized, Browser2Initialized, Browser3Initialized and Browser4Initialized to False in each of them like this :
    • Chromium1.OnBeforeClose will set Browser1Initialized to False and send WM_CLOSE to the MainForm.
    • Chromium2.OnBeforeClose will set Browser2Initialized to False and send WM_CLOSE to the MainForm.
    • Chromium3.OnBeforeClose will set Browser3Initialized to False and send WM_CLOSE to the MainForm.
    • Chromium4.OnBeforeClose will set Browser4Initialized to False and send WM_CLOSE to the MainForm.
  • After the last TChromium.OnBeforeClose event, all Browser*Initialized variables are False and the MainForm.FormCloseQuery will set CanClose to True to close your app safely.
Edit : You should modify all boolean variables inside a CRITICAL SECTION.
thefunkyjoint
Posts: 513
Joined: Thu Aug 10, 2017 12:40 pm

Re: Freezing on exit app / 100% CPU

Post by thefunkyjoint »

Thank you for the detailed explanation. Will do it and post the results here later.
Post Reply