Developer forums (C::B DEVELOPMENT STRICTLY!) > Development

Crash with batch build on linux

<< < (6/10) > >>

BlueHazzard:
Ok, adding two timers fixes all crashes, but this does not feel right.

Ideas?


--- Code: ---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
--- End code ---

sodev:
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: ---        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;
        }

--- End code ---

into


--- Code: ---        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;
        }

--- End code ---

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.

BlueHazzard:

--- 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.
--- End quote ---
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.

oBFusCATed:
@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.

sodev:
@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

Navigation

[0] Message Index

[#] Next page

[*] Previous page

Go to full version