Author Topic: Crash with batch build on linux  (Read 5163 times)

Online BlueHazzard

  • Developer
  • Lives here!
  • *****
  • Posts: 2566
Re: Crash with batch build on linux
« Reply #15 on: July 26, 2019, 03:54:57 pm »
Thank you for your feedback....

The patch in ticket 738 is for sure a simple and fast solution....
I have looked into the log window management, and it looks somehow like a big pile that needs some rework...

Quote
Destroy the window after closing the workspace, not before
This is somehow the solution i would like look into... Maybe i find some time...

Offline oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 12123
    • Travis build status
Re: Crash with batch build on linux
« Reply #16 on: July 26, 2019, 11:08:59 pm »
Is this the full stack you will see in a debugger? I doubt it is? How to reproduce this?

Quote
The window is destroyed in the CodeBlocksApp::OnInit method and this needs to change.
Obviously this is the only correct fix. I doubt wx is really happy when we destroy windows from OnInit.
Do not push the fix from the patch in #738, it just hides the problem as I've already stated!!!
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

Online BlueHazzard

  • Developer
  • Lives here!
  • *****
  • Posts: 2566
Re: Crash with batch build on linux
« Reply #17 on: July 29, 2019, 11:56:06 pm »
i am playing around with this, and this is my first try:
Code: [Select]
diff --git a/src/src/app.cpp b/src/src/app.cpp
index 22a46dfb1..abb415c60 100644
--- a/src/src/app.cpp
+++ b/src/src/app.cpp
@@ -974,6 +974,7 @@ int CodeBlocksApp::BatchJob()
     wxString bb_title = m_pBatchBuildDialog->GetTitle();
     m_pBatchBuildDialog->SetTitle(bb_title + _T(" - ") + title);
     m_pBatchBuildDialog->Show();
+    m_pBatchBuildDialog->Bind(wxEVT_CLOSE_WINDOW, [=](wxCloseEvent& evt) { m_Frame->Close();});
 
     if (m_ReBuild)
     {
@@ -1000,7 +1001,7 @@ int CodeBlocksApp::BatchJob()
     // The batch build log might have been deleted in
     // CodeBlocksApp::OnBatchBuildDone().
     // If it has not, it's still compiling.
-    if (m_pBatchBuildDialog)
+    /*if (m_pBatchBuildDialog)
     {
         // If operation is "--clean", there is no need to display the dialog
         // as the operation is synchronous and it already has finished by the
@@ -1015,7 +1016,7 @@ int CodeBlocksApp::BatchJob()
             m_pBatchBuildDialog->Destroy();
             m_pBatchBuildDialog = nullptr;
         }
-    }
+    }*/
 
     if (tbIcon)
     {
I know Bind is not possible with wx28 but it is a first try... There are still other problems, but i wanted to know if this approach is ok. I am not familiar with this kind of wxWidgets stuff...

Online BlueHazzard

  • Developer
  • Lives here!
  • *****
  • Posts: 2566
Re: Crash with batch build on linux
« Reply #18 on: July 30, 2019, 08:06:08 am »
I also added a timer that moves the BatchBuild() out of the OnInit function. Somehow this is missing in this diff...

Offline oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 12123
    • Travis build status
Re: Crash with batch build on linux
« Reply #19 on: July 30, 2019, 11:57:19 am »
Can you post the full patch?
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

Online BlueHazzard

  • Developer
  • Lives here!
  • *****
  • Posts: 2566
Re: Crash with batch build on linux
« Reply #20 on: July 31, 2019, 11:39:15 pm »
Code: [Select]
diff --git a/src/src/app.cpp b/src/src/app.cpp
index 22a46dfb1..8b90cae68 100644
--- a/src/src/app.cpp
+++ b/src/src/app.cpp
@@ -749,8 +749,15 @@ bool CodeBlocksApp::OnInit()
             s_Loading = false;
             LoadDelayedFiles(frame);
 
-            BatchJob();
-            frame->Close();
+            m_startBatchBuild.Bind(wxEVT_TIMER, [this](wxTimerEvent& evt)
+                {
+                    this->BatchJob();
+                });
+
+            m_startBatchBuild.Start(2000, true);
+
+
+            //frame->Close();
             return true;
         }
 
@@ -974,6 +981,10 @@ int CodeBlocksApp::BatchJob()
     wxString bb_title = m_pBatchBuildDialog->GetTitle();
     m_pBatchBuildDialog->SetTitle(bb_title + _T(" - ") + title);
     m_pBatchBuildDialog->Show();
+    m_pBatchBuildDialog->Bind(wxEVT_CLOSE_WINDOW, [=](wxCloseEvent& evt)
+                                                    {
+                                                        m_Frame->Close();
+                                                    });
 
     if (m_ReBuild)
     {
@@ -1000,7 +1011,7 @@ int CodeBlocksApp::BatchJob()
     // The batch build log might have been deleted in
diff --git a/src/src/app.cpp b/src/src/app.cpp
index 22a46dfb1..8b90cae68 100644
--- a/src/src/app.cpp
+++ b/src/src/app.cpp
@@ -749,8 +749,15 @@ bool CodeBlocksApp::OnInit()
             s_Loading = false;
             LoadDelayedFiles(frame);
 
-            BatchJob();
-            frame->Close();
+            m_startBatchBuild.Bind(wxEVT_TIMER, [this](wxTimerEvent& evt)
+                {
+                    this->BatchJob();
+                });
+
+            m_startBatchBuild.Start(2000, true);
+
+
+            //frame->Close();
             return true;
         }
 
@@ -974,6 +981,10 @@ int CodeBlocksApp::BatchJob()
     wxString bb_title = m_pBatchBuildDialog->GetTitle();
     m_pBatchBuildDialog->SetTitle(bb_title + _T(" - ") + title);
     m_pBatchBuildDialog->Show();
+    m_pBatchBuildDialog->Bind(wxEVT_CLOSE_WINDOW, [=](wxCloseEvent& evt)
+                                                    {
+                                                        m_Frame->Close();
+                                                    });
 
     if (m_ReBuild)
     {
@@ -1000,7 +1011,7 @@ int CodeBlocksApp::BatchJob()
     // The batch build log might have been deleted in
diff --git a/src/src/app.cpp b/src/src/app.cpp
index 22a46dfb1..8b90cae68 100644
--- a/src/src/app.cpp
+++ b/src/src/app.cpp
@@ -749,8 +749,15 @@ bool CodeBlocksApp::OnInit()
             s_Loading = false;
             LoadDelayedFiles(frame);
 
-            BatchJob();
-            frame->Close();
+            m_startBatchBuild.Bind(wxEVT_TIMER, [this](wxTimerEvent& evt)
+                {
+                    this->BatchJob();
+                });
+
+            m_startBatchBuild.Start(2000, true);
+
+
+            //frame->Close();
             return true;
         }
 
@@ -974,6 +981,10 @@ int CodeBlocksApp::BatchJob()
     wxString bb_title = m_pBatchBuildDialog->GetTitle();
     m_pBatchBuildDialog->SetTitle(bb_title + _T(" - ") + title);
     m_pBatchBuildDialog->Show();
+    m_pBatchBuildDialog->Bind(wxEVT_CLOSE_WINDOW, [=](wxCloseEvent& evt)
+                                                    {
+                                                        m_Frame->Close();
+                                                    });
 
     if (m_ReBuild)
     {
@@ -1000,7 +1011,7 @@ int CodeBlocksApp::BatchJob()
     // The batch build log might have been deleted in
     // CodeBlocksApp::OnBatchBuildDone().
     // If it has not, it's still compiling.
-    if (m_pBatchBuildDialog)
+    /*if (m_pBatchBuildDialog)
     {
         // If operation is "--clean", there is no need to display the dialog
         // as the operation is synchronous and it already has finished by the
@@ -1015,7 +1026,7 @@ int CodeBlocksApp::BatchJob()
             m_pBatchBuildDialog->Destroy();
             m_pBatchBuildDialog = nullptr;
         }
-    }
+    }*/
 
     if (tbIcon)
     {
@@ -1053,13 +1064,16 @@ void CodeBlocksApp::OnBatchBuildDone(CodeBlocksEvent& event)
 
     if (m_pBatchBuildDialog && m_BatchWindowAutoClose)
     {
-        if (m_pBatchBuildDialog->IsModal())
+        /*if (m_pBatchBuildDialog->IsModal())
             m_pBatchBuildDialog->EndModal(wxID_OK);
         else
         {
-            m_pBatchBuildDialog->Destroy();
-            m_pBatchBuildDialog = nullptr;
-        }
+
+
+        }*/
+        m_pBatchBuildDialog->Close();
+        //m_pBatchBuildDialog->Destroy();
+        //m_pBatchBuildDialog = nullptr;
     }
 }
 
diff --git a/src/src/app.h b/src/src/app.h
index 97c69e74e..953916fba 100644
--- a/src/src/app.h
+++ b/src/src/app.h
@@ -142,6 +142,8 @@ class CodeBlocksApp : public wxApp
         void SetupPersonality(const wxString& personality);
         void SetupImageSizes(wxToolBarAddOnXmlHandler *toolbarAddonHandler);
 
+        wxTimer m_startBatchBuild;
+
 
         wxString m_Prefix; // directory specified in --prefix switch
         wxString m_UserDataDir; // directory specified in --user-data-dir switch

still quick patch. I am still testing.... time is limited... and testing is difficult and slow...

[edit:] first problem found: can not cancel building withtout crash
« Last Edit: July 31, 2019, 11:41:54 pm by BlueHazzard »

Online BlueHazzard

  • Developer
  • Lives here!
  • *****
  • Posts: 2566
Re: Crash with batch build on linux
« Reply #21 on: August 05, 2019, 11:43:33 pm »
This is really a shit situation...

I am close to throw the log manager out from the compiler

1) Is there some way to know when the build is completely finished? Not just project or file, but workspace? (If not, why do we do not have an event for this?)
2) Is there a way to wait until the event queue is completely empty?
3) Is there a way to put an event at the end of the event loop?

Offline sodev

  • Regular
  • ***
  • Posts: 333
Re: Crash with batch build on linux
« Reply #22 on: August 06, 2019, 12:18:51 am »
1) Is there some way to know when the build is completely finished? Not just project or file, but workspace? (If not, why do we do not have an event for this?)
Not my business 8)

Quote
2) Is there a way to wait until the event queue is completely empty?
Sort of, wxWidgets will create an Idle-Event whenever the main event loop runs empty, however that doesn't mean that there won't be any new events beeing queued. Only way to know that wxWidgets is about to end is when the OnExit() method of the App object is called. This however requires that wxWidgets will be stopped which usually does not happen if there is a wxFrame open.

Quote
3) Is there a way to put an event at the end of the event loop?
You can use QueueEvent() or CallAfter() but this will queue the event at the end of the wxEvtHandler you called these methods on, there may be other event handlers active that will be called later, hence these events are only locally at the end, not globally. Plus i am not sure which of these do work in wx 2.8.

Online BlueHazzard

  • Developer
  • Lives here!
  • *****
  • Posts: 2566
Re: Crash with batch build on linux
« Reply #23 on: August 06, 2019, 10:46:43 am »
Thank you for the help. So wxWidgets does not supports me in this..

Offline oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 12123
    • Travis build status
Re: Crash with batch build on linux
« Reply #24 on: August 06, 2019, 07:03:58 pm »
Why do you want to do 2 and 3 in the first place?

As far as I know events aren't reordered, so you can put an event in the queue and when it is executed you would know that it is the last one or at least you've reached something like a barrier.
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

Online BlueHazzard

  • Developer
  • Lives here!
  • *****
  • Posts: 2566
Re: Crash with batch build on linux
« Reply #25 on: August 07, 2019, 12:22:05 am »
Ok, adding two timers fixes all crashes, but this does not feel right.

Ideas?

Code: [Select]
diff --git a/src/src/app.cpp b/src/src/app.cpp
index 22a46dfb1..5263e1d2c 100644
--- a/src/src/app.cpp
+++ b/src/src/app.cpp
@@ -749,8 +749,15 @@ bool CodeBlocksApp::OnInit()
             s_Loading = false;
             LoadDelayedFiles(frame);
 
-            BatchJob();
-            frame->Close();
+            m_startBatchBuild.Bind(wxEVT_TIMER, [this](wxTimerEvent& evt)
+                {
+                    this->BatchJob();
+                });
+
+            m_startBatchBuild.Start(2000, true);
+
+
+            //frame->Close();
             return true;
         }
 
@@ -974,6 +981,21 @@ int CodeBlocksApp::BatchJob()
     wxString bb_title = m_pBatchBuildDialog->GetTitle();
     m_pBatchBuildDialog->SetTitle(bb_title + _T(" - ") + title);
     m_pBatchBuildDialog->Show();
+    m_pBatchBuildDialog->Bind(wxEVT_CLOSE_WINDOW, [=](wxCloseEvent& evt)
+                                                    {
+                                                        //m_sceduleForClose = true;
+                                                        cbCompilerPlugin *compiler = Manager::Get()->GetPluginManager()->GetFirstCompiler();
+                                                        if(compiler != nullptr && compiler->IsRunning())
+                                                        {
+                                                            evt.Veto();
+                                                            compiler->KillProcess();
+                                                        }
+                                                        else
+                                                        {
+                                                            m_Frame->Close();
+                                                        }
+
+                                                    });
 
     if (m_ReBuild)
     {
@@ -1000,7 +1022,7 @@ int CodeBlocksApp::BatchJob()
     // The batch build log might have been deleted in
     // CodeBlocksApp::OnBatchBuildDone().
     // If it has not, it's still compiling.
-    if (m_pBatchBuildDialog)
+    /*if (m_pBatchBuildDialog)
     {
         // If operation is "--clean", there is no need to display the dialog
         // as the operation is synchronous and it already has finished by the
@@ -1015,7 +1037,7 @@ int CodeBlocksApp::BatchJob()
             m_pBatchBuildDialog->Destroy();
             m_pBatchBuildDialog = nullptr;
         }
-    }
+    }*/
 
     if (tbIcon)
     {
@@ -1053,13 +1075,23 @@ void CodeBlocksApp::OnBatchBuildDone(CodeBlocksEvent& event)
 
     if (m_pBatchBuildDialog && m_BatchWindowAutoClose)
     {
-        if (m_pBatchBuildDialog->IsModal())
+        /*if (m_pBatchBuildDialog->IsModal())
             m_pBatchBuildDialog->EndModal(wxID_OK);
         else
         {
-            m_pBatchBuildDialog->Destroy();
-            m_pBatchBuildDialog = nullptr;
-        }
+
+
+        }*/
+        //m_Frame->Close();
+        m_closeCodeblocks.Bind(wxEVT_TIMER, [=](wxTimerEvent& evt)
+            {
+                m_pBatchBuildDialog->Close();
+            });
+        m_closeCodeblocks.Start(3000, true);
+
+        //m_pBatchBuildDialog->Close();
+        //m_pBatchBuildDialog->Destroy();
+        //m_pBatchBuildDialog = nullptr;
     }
 }
 
diff --git a/src/src/app.h b/src/src/app.h
index 97c69e74e..4aafa9f7e 100644
--- a/src/src/app.h
+++ b/src/src/app.h
@@ -142,6 +142,9 @@ class CodeBlocksApp : public wxApp
         void SetupPersonality(const wxString& personality);
         void SetupImageSizes(wxToolBarAddOnXmlHandler *toolbarAddonHandler);
 
+        wxTimer m_startBatchBuild;
+        wxTimer m_closeCodeblocks;
+
 
         wxString m_Prefix; // directory specified in --prefix switch
         wxString m_UserDataDir; // directory specified in --user-data-dir switch

Offline sodev

  • Regular
  • ***
  • Posts: 333
Re: Crash with batch build on linux
« Reply #26 on: August 07, 2019, 01:37:29 am »
I'm sure it is not right :).

I examined the code only a little but i spot one big problem there: you are doing operations that create / use events in OnInit(). There is no event loop running in OnInit(). You get around it partly by processing events manually but still this looks like trouble, especially because the event handlers will get executed before OnInit() did finish. Offloading the work with timers actually postones the execution of the code because these will get executed later by the event loop.

A minimal invasive attempt to check if executing the batch job after OnInit() is enough would be to wrap
Code: [Select]
        if (m_Batch)
        {
            Manager::SetAppStartedUp(true);

            // the compiler plugin might be waiting for this
            CodeBlocksEvent event(cbEVT_APP_STARTUP_DONE);
            Manager::Get()->ProcessEvent(event);

            Manager::Get()->RegisterEventSink(cbEVT_COMPILER_FINISHED, new cbEventFunctor<CodeBlocksApp, CodeBlocksEvent>(this, &CodeBlocksApp::OnBatchBuildDone));
            s_Loading = false;
            LoadDelayedFiles(frame);

            BatchJob();
            frame->Close();
            return true;
        }

into

Code: [Select]
        if (m_Batch)
        {
            CallAfter([this, frame]() {
                Manager::SetAppStartedUp(true);

                // the compiler plugin might be waiting for this
                CodeBlocksEvent event(cbEVT_APP_STARTUP_DONE);
                Manager::Get()->ProcessEvent(event);

                Manager::Get()->RegisterEventSink(cbEVT_COMPILER_FINISHED, new cbEventFunctor<CodeBlocksApp, CodeBlocksEvent>(this, &CodeBlocksApp::OnBatchBuildDone));
                s_Loading = false;
                LoadDelayedFiles(frame);

                BatchJob();
                frame->Close();
            });
            return true;
        }

However i still see the problem that you have not set a top window and this might exit wxWidgets too early. And no, i didn't even compile this, all your compiler error are belong to you :D.

Online BlueHazzard

  • Developer
  • Lives here!
  • *****
  • Posts: 2566
Re: Crash with batch build on linux
« Reply #27 on: August 07, 2019, 11:45:58 am »
Quote
I examined the code only a little but i spot one big problem there: you are doing operations that create / use events in OnInit(). There is no event loop running in OnInit(). You get around it partly by processing events manually but still this looks like trouble, especially because the event handlers will get executed before OnInit() did finish. Offloading the work with timers actually postones the execution of the code because these will get executed later by the event loop.
So what would be the wxWidgets way to do this?
As far as i understand: in the OnInit the Window for the application is initialized and after the OnInit the event handler of the main window takes over. If i go this approach the Batch Job should be started in the Batch build window. But we do not want this: we want to separate logic from UI as far as possible, the BatchWindow should only display log messages and give the user a possibility to stop the process but not handle the build process. This should happen in the "main" thread also without any GUI componentes running, only the wxWidgets basics (like an event loop) . With the Timer i was thinking to move the start of the Batch build to outside of OnInit to the event loop of the main thread. According to your post (as far as i understand) this does not work, because in OnInit there is no event loop and with creating the timer  i create an artificially (???) event handler only for this in the OnInit function?. Isn't there an event loop of the "main thread" outside of the GUI?
Since we remove wx28 support CallAfter is a nice alternative (and i really like it over the timer), but isn't this technically the same as the timer events? It queues the execution to the end of an event loop.

Thank you for adding your wxWidgets knowledge here! This goes way beyond my wxWidgets knowledge.

Offline oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 12123
    • Travis build status
Re: Crash with batch build on linux
« Reply #28 on: August 07, 2019, 11:33:31 pm »
@BlueHazzard: Please read more about events and how to handle them correctly in wx. Most of the problems in C::B related to events are because people (including me) had no good understanding what is going on. Read about idle events. I think this is all that is needed. And please don't run everything from lambda's.

And no timers aren't creating fake events they are real events which happen after oninit ends. Same as the idle event.
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

Offline sodev

  • Regular
  • ***
  • Posts: 333
Re: Crash with batch build on linux
« Reply #29 on: August 08, 2019, 10:08:05 pm »
@BlueHazzard: Your understanding is not quite correct, but the effects of CallAfter() and the timers are technically the same, they move the processing time of the code fragments out of OnInit() into OnRun(). I am a bad teacher but i try to give a short overview of what is happening.

After OnInit() did finish the thread that does execute OnRun() becomes the main thread. This main thread just drives the main event loop which is processing the events. This is done roughly speaking by passing each event through the event handler chain until it is processed. In wxWidgets pretty much every GUI element is an event handler and these form a vertical chain. Most simple case is a button inside a frame:

wxButton -> wxFrame -> wxTheApp

So if the button gets clicked the event loop first calls the event handler of the button, if that doesn't process the event it is passed to the frame and if that also doesn't process it, it is passed to the global app object (this is very simplified, check the wxWidgets docs for details).

In your OnInit() method the CallAfter() and the timers actually queue the event in the App object and nothing more happens there. Only when OnRun() starts executing they will be actually executed. On the other hand in OnInit() your Manager object manually processes the startup event. This itself might be an issue but what is even more problematic is that im pretty sure that your own event handling system uses wxWidgets events and processes them horizontally.

This means in contrast to wxWidgets where event processing ends when the event got consumed you pass the event to all other registered sinks as well. This usually is not a problem unless one of the sinks opens a modal dialog (or anything else that causes the creation of another event loop). Because control flow has to stop for the modal dialog, another event loop gets created which is again driven by the main thread. This ensures that event processing does not stop. In horizontal processing this has however the side effect that after that modal dialog got closed, the originating event that opened it gets passed along to the next event sinks. So this "old" event gets further processed after all the events that it might have created.

I hope this wall of text doesn't confuse you even more but maybe gives you some ideas what can cause the present problems.


@oBFusCATed: I don't think idle events are the way to go, they happen all the time and are not suited for one time tasks. These lambdas are nice to write code in one place and let it execute in another place, like work units for a work queue. But i also like auto so im afraid we won't agree here as well  ::) ;D