I am using codeblocks under linux, I have tested under several distributions, but got the same result.Me too, but it is really hard to catch the bug, I even don't have ways to reproduce some hang bug. Sometimes, it works, sometimes, it hangs.
CodeBlocks always crash during working, due to codecompletion plugin.
I have had a look on its source code, I want to know why it must do GUI operation in non-main thread, but in worker thread, which cause crashing.In CC, the symbol browser trees (wxTreeCtrl) were built from a thread class named ClassBrowserBuilderThread. The reason I think is that the tree can have many labels(Tokens), and it take several seconds to build the tree, so the devs put those operations in a worker thread. This was done years before I becomes a C::B developer.
...But, its a common method to do UI operations in worker thread is via notifications, right?Basically, all the UI operations should be put in the main thread, note the bottle neck is building the big wxTreeCtrl, so notification method is not involved here.
Mightbe, the operations and data should be separated, for this condition.Yes, they should be separated, but if you want to construct a big wxTreeCtrl, what is a good method?
Hello ollydbg, I just define a simple event to notify ClassBrowser to call ClassBrowserBuilderThread's BuildTree function, because BuildTree was originally called in a while loop, also has semaphore to guarantee ths order of the operations. So, it works for me, under linux. Although this is not a good idea, it really works. And, this also has not make the GUI busy, almost fell nothing of it.Thanks, can you show some patches? So that I can tested on my local PC(winXP).
Probably the best way is to define a custom event where you can store 50 or 100 items. Then in the worker thread you just send these elements and in the main thread you add the items to the tree in small batches. I think this won't block the ui and user events might be process normally.Mightbe. But, it need more coding work, right? I just define a custom event and simply move the BuildTree into ClassBrowser window messages processing chain. I also think this operation does need to be processed in this window class, since, all operations of this function is work for ClassBrowser. All of this GUI operations in this function also would not take too much time. If move the responsibility to ClassBrowser, the function should be rewrite, and, some class definition should be redesined,too. I think.
I packed my modified files, I do not use patch file because Im afraid my base code was outdated. my base code was svn9925Hello ollydbg, I just define a simple event to notify ClassBrowser to call ClassBrowserBuilderThread's BuildTree function, because BuildTree was originally called in a while loop, also has semaphore to guarantee ths order of the operations. So, it works for me, under linux. Although this is not a good idea, it really works. And, this also has not make the GUI busy, almost fell nothing of it.Thanks, can you show some patches? So that I can tested on my local PC(winXP).
kipade: Have you do some work on this or this is just a suggestion?This just a try, of course I want the code looks perfect and works well.
196d6a6c37e1ff7f91bd76cbafd62d645c1f2e03
src/plugins/codecompletion/BuildTreeEvent.h | 37 ++++++++++++++++++++++
src/plugins/codecompletion/classbrowser.cpp | 11 +++++++
src/plugins/codecompletion/classbrowser.h | 3 ++
.../codecompletion/classbrowserbuilderthread.cpp | 11 +++++--
4 files changed, 60 insertions(+), 2 deletions(-)
diff --git a/src/plugins/codecompletion/BuildTreeEvent.h b/src/plugins/codecompletion/BuildTreeEvent.h
new file mode 100644
index 0000000..73cf2c5
--- /dev/null
+++ b/src/plugins/codecompletion/BuildTreeEvent.h
@@ -0,0 +1,37 @@
+#ifndef __BUILD_TREE_H__
+#define __BUILD_TREE_H__
+
+/*
+ * Simple BuildTree event for ClassBrowser
+ *
+ * Author: ZhiYu
+ */
+
+#include <wx/event.h>
+#include "classbrowserbuilderthread.h"
+
+class cbBuildTreeEvent;
+wxDECLARE_EVENT(cbBUILD_CLASSTREE_EVENT,cbBuildTreeEvent);
+class cbBuildTreeEvent : public wxCommandEvent
+{
+public:
+ cbBuildTreeEvent(ClassBrowserBuilderThread* builderThreadObject,wxEventType cmdType=cbBUILD_CLASSTREE_EVENT):wxCommandEvent(cmdType),clsBuilderThread(builderThreadObject){
+ }
+
+ ClassBrowserBuilderThread* GetBuilderThreadObject() const { return clsBuilderThread; }
+ cbBuildTreeEvent* Clone()
+ {
+ return new cbBuildTreeEvent(*this);
+ }
+private:
+ ClassBrowserBuilderThread* clsBuilderThread;
+};
+
+//following lines are only for you if you did not like use event table
+typedef void (wxEvtHandler::*cbBuildTreeFunction)(cbBuildTreeEvent&);
+
+#define cbBuildTreeEventHandler(func) wxEVENT_HANDLER_CAST(cbBuildTreeFunction,func)
+#define EVT_CBBUILD_CLASSTREE(id,func) \
+ wx__DECLARE_EVT1(cbBUILD_CLASSTREE_EVENT,id,cbBuildTreeEventHandler(func))
+
+#endif
diff --git a/src/plugins/codecompletion/classbrowser.cpp b/src/plugins/codecompletion/classbrowser.cpp
index cd96467..4914d86 100644
--- a/src/plugins/codecompletion/classbrowser.cpp
+++ b/src/plugins/codecompletion/classbrowser.cpp
@@ -44,6 +44,7 @@
#include "nativeparser.h"
#include "parser/ccdebuginfo.h"
+#include <stdio.h>
#define CC_CLASS_BROWSER_DEBUG_OUTPUT 0
@@ -76,6 +77,8 @@
#define TRACE2(format, args...)
#endif
+wxDEFINE_EVENT(cbBUILD_CLASSTREE_EVENT,cbBuildTreeEvent);
+
int idMenuJumpToDeclaration = wxNewId();
int idMenuJumpToImplementation = wxNewId();
int idMenuRefreshTree = wxNewId();
@@ -127,6 +130,7 @@ BEGIN_EVENT_TABLE(ClassBrowser, wxPanel)
EVT_MENU(idCBBottomTree, ClassBrowser::OnCBViewMode)
EVT_COMMAND(idThreadEvent, wxEVT_COMMAND_ENTER, ClassBrowser::OnThreadEvent)
+ EVT_CBBUILD_CLASSTREE(wxID_ANY,ClassBrowser::OnBuileTree)
END_EVENT_TABLE()
// class constructor
@@ -971,3 +975,10 @@ void ClassBrowser::OnThreadEvent(wxCommandEvent& event)
break;
}
}
+
+void ClassBrowser::OnBuileTree(cbBuildTreeEvent& event)
+{
+ ClassBrowserBuilderThread* thread = event.GetBuilderThreadObject();
+ if(thread)
+ thread->BuildTree();
+}
diff --git a/src/plugins/codecompletion/classbrowser.h b/src/plugins/codecompletion/classbrowser.h
index 9715c07..1a272c7 100644
--- a/src/plugins/codecompletion/classbrowser.h
+++ b/src/plugins/codecompletion/classbrowser.h
@@ -16,6 +16,7 @@
#include "classbrowserbuilderthread.h"
#include "parser/parser.h"
#include "parser/token.h"
+#include "BuildTreeEvent.h"
class NativeParser;
class wxComboBox;
@@ -90,6 +91,8 @@ private:
void OnDebugSmartSense(wxCommandEvent& event);
void OnSetSortType(wxCommandEvent& event);
+ void OnBuileTree(cbBuildTreeEvent& event);
+
void OnSearch(wxCommandEvent& event);
bool FoundMatch(const wxString& search, wxTreeCtrl* tree, const wxTreeItemId& item);
wxTreeItemId FindNext(const wxString& search, wxTreeCtrl* tree, const wxTreeItemId& start);
diff --git a/src/plugins/codecompletion/classbrowserbuilderthread.cpp b/src/plugins/codecompletion/classbrowserbuilderthread.cpp
index 24f05cb..6640ef0 100644
--- a/src/plugins/codecompletion/classbrowserbuilderthread.cpp
+++ b/src/plugins/codecompletion/classbrowserbuilderthread.cpp
@@ -63,6 +63,8 @@
#define TRACE2(format, args...)
#endif
+#include "BuildTreeEvent.h"
+
ClassBrowserBuilderThread::ClassBrowserBuilderThread(wxEvtHandler* evtHandler, wxSemaphore& sem) :
wxThread(wxTHREAD_JOINABLE),
m_Parent(evtHandler),
@@ -184,7 +186,7 @@ void ClassBrowserBuilderThread::Init(NativeParser* np,
}
// Thread function
-
+#include <stdio.h>
void* ClassBrowserBuilderThread::Entry()
{
while (!m_TerminationRequested && !Manager::IsAppShuttingDown() )
@@ -206,7 +208,10 @@ void* ClassBrowserBuilderThread::Entry()
::wxMutexGuiEnter();
}
- BuildTree();
+ //BuildTree();
+ cbBuildTreeEvent* evt = new cbBuildTreeEvent(this,cbBUILD_CLASSTREE_EVENT);
+ if(m_Parent)
+ m_Parent->QueueEvent(evt);
if (platform::gtk || platform::macosx)
{
@@ -447,6 +452,8 @@ void ClassBrowserBuilderThread::BuildTree()
// 6.) Hide&Freeze trees shown
if (m_BrowserOptions.treeMembers)
{
+ if(m_CCTreeCtrlBottom==NULL)
+ wxMessageBox(wxT("kcynice:classbrowserbuilderthread.cpp::BuildTree m_CCTreeCtrlBottom is null"));
m_CCTreeCtrlBottom->Hide();
m_CCTreeCtrlBottom->Freeze();
}
[ 20.0%] g++.exe -Wall -g -pipe -fmessage-length=0 -fexceptions -mthreads -Winvalid-pch -DHAVE_W32API_H -D__WXMSW__ -DWXUSINGDLL -DcbDEBUG -DCB_PRECOMP -DWX_PRECOMP -DwxUSE_UNICODE -DEXPORT_LIB=0 -DEXPORT_EVENTS=0 -DwxUSE_WX_RESOURCES=0 -DBUILDING_PLUGIN -IE:\code\wx-mingw-build-481-dw2\wxWidgets-2.8.12\include -IE:\code\wx-mingw-build-481-dw2\wxWidgets-2.8.12\lib\gcc_dll\mswu -I..\..\include -I..\..\sdk\wxscintilla\include -I..\..\include\mozilla_chardet -I..\..\include\mozilla_chardet\mfbt -I..\..\include\mozilla_chardet\nsprpub\pr\include -I..\..\include\mozilla_chardet\xpcom -I..\..\include\mozilla_chardet\xpcom\base -I..\..\include\mozilla_chardet\xpcom\glue -c classbrowser.cpp -o ..\..\.objs\plugins\codecompletion\classbrowser.o
In file included from classbrowser.h:19:0,
from classbrowser.cpp:43:
BuildTreeEvent.h:14:16: error: expected constructor, destructor, or type conversion before '(' token
BuildTreeEvent.h:18:87: error: 'cbBUILD_CLASSTREE_EVENT' was not declared in this scope
classbrowser.cpp:80:15: error: expected constructor, destructor, or type conversion before '(' token
classbrowser.cpp:133:5: error: 'cbBUILD_CLASSTREE_EVENT' was not declared in this scope
In file included from classbrowser.h:16:0,
from classbrowser.cpp:43:
classbrowserbuilderthread.h: In member function 'void ClassBrowser::OnBuileTree(cbBuildTreeEvent&)':
classbrowserbuilderthread.h:64:10: error: 'void ClassBrowserBuilderThread::BuildTree()' is protected
classbrowser.cpp:983:23: error: within this context
Process terminated with status 1 (0 minute(s), 13 second(s))
6 error(s), 0 warning(s) (0 minute(s), 13 second(s))
Thanks kipade, this is the patch against git-svn head, but I have build errors.I am sorry that, I forgot upload one file, but with only one line added, its in classbrowserbuilderthread.h, add ClassBrowser as a friend class of ClassBrowserBuilderThread. btw, you can do some slight modification to make it work. :)
src/plugins/codecompletion/BuildTreeEvent.h | 66 ++++++++++++++++++++++
src/plugins/codecompletion/classbrowser.cpp | 18 ++++++
src/plugins/codecompletion/classbrowser.h | 3 +
.../codecompletion/classbrowserbuilderthread.cpp | 14 ++++-
.../codecompletion/classbrowserbuilderthread.h | 1 +
5 files changed, 99 insertions(+), 3 deletions(-)
diff --git a/src/plugins/codecompletion/BuildTreeEvent.h b/src/plugins/codecompletion/BuildTreeEvent.h
new file mode 100644
index 0000000..73d0b1a
--- /dev/null
+++ b/src/plugins/codecompletion/BuildTreeEvent.h
@@ -0,0 +1,66 @@
+#ifndef __BUILD_TREE_H__
+#define __BUILD_TREE_H__
+
+/*
+ * Simple BuildTree event for ClassBrowser
+ *
+ * Author: ZhiYu
+ */
+
+#include <wx/event.h>
+#include "classbrowserbuilderthread.h"
+
+extern const wxEventType cbBUILD_CLASSTREE_EVENT;
+// the below does not work, see:
+// http://permalink.gmane.org/gmane.comp.lib.wxwindows.general/62431
+//DECLARE_EVENT_TYPE(cbBUILD_CLASSTREE_EVENT, wxID_ANY)
+
+class cbBuildTreeEvent : public wxCommandEvent
+{
+public:
+ cbBuildTreeEvent(ClassBrowserBuilderThread* builderThreadObject = NULL,
+ wxEventType cmdType = cbBUILD_CLASSTREE_EVENT)
+ :wxCommandEvent(cmdType),
+ clsBuilderThread(builderThreadObject)
+ {
+ }
+
+ cbBuildTreeEvent(const cbBuildTreeEvent& rhs)
+ : wxCommandEvent(rhs),
+ clsBuilderThread(rhs.clsBuilderThread)
+
+ {
+ }
+
+ ClassBrowserBuilderThread* GetBuilderThreadObject() const
+ {
+ return clsBuilderThread;
+ }
+ virtual wxEvent *Clone() const
+ {
+ return new cbBuildTreeEvent(*this);
+ }
+//private:
+ ClassBrowserBuilderThread* clsBuilderThread;
+ DECLARE_DYNAMIC_CLASS( cbBuildTreeEvent )
+};
+
+//following lines are only for you if you did not like use event table
+
+typedef void (wxEvtHandler::*cbBuildTreeFunction)(cbBuildTreeEvent&);
+
+
+#define cbBuildTreeEventHandler(func) \
+ (wxObjectEventFunction)(wxEventFunction) \
+ wxStaticCastEvent(cbBuildTreeFunction, &func)
+
+
+
+#define EVT_CBBUILD_CLASSTREE(id, fn) \
+ DECLARE_EVENT_TABLE_ENTRY(cbBUILD_CLASSTREE_EVENT, id, wxID_ANY, \
+ (wxObjectEventFunction) (wxEventFunction) (cbBuildTreeFunction) \
+ wxStaticCastEvent( cbBuildTreeFunction, & fn ), (wxObject *) NULL ),
+
+
+
+#endif
diff --git a/src/plugins/codecompletion/classbrowser.cpp b/src/plugins/codecompletion/classbrowser.cpp
index cd96467..498113d 100644
--- a/src/plugins/codecompletion/classbrowser.cpp
+++ b/src/plugins/codecompletion/classbrowser.cpp
@@ -44,6 +44,7 @@
#include "nativeparser.h"
#include "parser/ccdebuginfo.h"
+#include <stdio.h>
#define CC_CLASS_BROWSER_DEBUG_OUTPUT 0
@@ -76,6 +77,15 @@
#define TRACE2(format, args...)
#endif
+// below is used on wx3.x only
+//wxDEFINE_EVENT(cbBUILD_CLASSTREE_EVENT,cbBuildTreeEvent);
+
+IMPLEMENT_DYNAMIC_CLASS(cbBuildTreeEvent, wxCommandEvent)
+DEFINE_EVENT_TYPE(cbBUILD_CLASSTREE_EVENT)
+
+
+
+
int idMenuJumpToDeclaration = wxNewId();
int idMenuJumpToImplementation = wxNewId();
int idMenuRefreshTree = wxNewId();
@@ -127,6 +137,7 @@ BEGIN_EVENT_TABLE(ClassBrowser, wxPanel)
EVT_MENU(idCBBottomTree, ClassBrowser::OnCBViewMode)
EVT_COMMAND(idThreadEvent, wxEVT_COMMAND_ENTER, ClassBrowser::OnThreadEvent)
+ EVT_CBBUILD_CLASSTREE(wxID_ANY,ClassBrowser::OnBuileTree)
END_EVENT_TABLE()
// class constructor
@@ -971,3 +982,10 @@ void ClassBrowser::OnThreadEvent(wxCommandEvent& event)
break;
}
}
+
+void ClassBrowser::OnBuileTree(cbBuildTreeEvent& event)
+{
+ ClassBrowserBuilderThread* thread = event.GetBuilderThreadObject();
+ if(thread)
+ thread->BuildTree();
+}
diff --git a/src/plugins/codecompletion/classbrowser.h b/src/plugins/codecompletion/classbrowser.h
index 9715c07..1a272c7 100644
--- a/src/plugins/codecompletion/classbrowser.h
+++ b/src/plugins/codecompletion/classbrowser.h
@@ -16,6 +16,7 @@
#include "classbrowserbuilderthread.h"
#include "parser/parser.h"
#include "parser/token.h"
+#include "BuildTreeEvent.h"
class NativeParser;
class wxComboBox;
@@ -90,6 +91,8 @@ private:
void OnDebugSmartSense(wxCommandEvent& event);
void OnSetSortType(wxCommandEvent& event);
+ void OnBuileTree(cbBuildTreeEvent& event);
+
void OnSearch(wxCommandEvent& event);
bool FoundMatch(const wxString& search, wxTreeCtrl* tree, const wxTreeItemId& item);
wxTreeItemId FindNext(const wxString& search, wxTreeCtrl* tree, const wxTreeItemId& start);
diff --git a/src/plugins/codecompletion/classbrowserbuilderthread.cpp b/src/plugins/codecompletion/classbrowserbuilderthread.cpp
index 24f05cb..5b74337 100644
--- a/src/plugins/codecompletion/classbrowserbuilderthread.cpp
+++ b/src/plugins/codecompletion/classbrowserbuilderthread.cpp
@@ -26,11 +26,12 @@
#include <projectmanager.h>
#endif
+#include "BuildTreeEvent.h"
#include "classbrowserbuilderthread.h"
// sanity check for the build tree functions, this function should only be called in a worker thread
// also, there should be no termination requested, otherwise, it will return false
-#define CBBT_SANITY_CHECK ((!::wxIsMainThread() && m_TerminationRequested) || Manager::IsAppShuttingDown())
+#define CBBT_SANITY_CHECK (( m_TerminationRequested) || Manager::IsAppShuttingDown())
#define CC_BUILDERTHREAD_DEBUG_OUTPUT 0
@@ -63,6 +64,8 @@
#define TRACE2(format, args...)
#endif
+#include "BuildTreeEvent.h"
+
ClassBrowserBuilderThread::ClassBrowserBuilderThread(wxEvtHandler* evtHandler, wxSemaphore& sem) :
wxThread(wxTHREAD_JOINABLE),
m_Parent(evtHandler),
@@ -184,7 +187,7 @@ void ClassBrowserBuilderThread::Init(NativeParser* np,
}
// Thread function
-
+#include <stdio.h>
void* ClassBrowserBuilderThread::Entry()
{
while (!m_TerminationRequested && !Manager::IsAppShuttingDown() )
@@ -206,7 +209,10 @@ void* ClassBrowserBuilderThread::Entry()
::wxMutexGuiEnter();
}
- BuildTree();
+ //BuildTree();
+ cbBuildTreeEvent evt(this,cbBUILD_CLASSTREE_EVENT);
+ if(m_Parent)
+ m_Parent->AddPendingEvent(evt);
if (platform::gtk || platform::macosx)
{
@@ -447,6 +453,8 @@ void ClassBrowserBuilderThread::BuildTree()
// 6.) Hide&Freeze trees shown
if (m_BrowserOptions.treeMembers)
{
+ if(m_CCTreeCtrlBottom==NULL)
+ wxMessageBox(wxT("kcynice:classbrowserbuilderthread.cpp::BuildTree m_CCTreeCtrlBottom is null"));
m_CCTreeCtrlBottom->Hide();
m_CCTreeCtrlBottom->Freeze();
}
diff --git a/src/plugins/codecompletion/classbrowserbuilderthread.h b/src/plugins/codecompletion/classbrowserbuilderthread.h
index 9369a27..3acfcb8 100644
--- a/src/plugins/codecompletion/classbrowserbuilderthread.h
+++ b/src/plugins/codecompletion/classbrowserbuilderthread.h
@@ -20,6 +20,7 @@
*/
class ClassBrowserBuilderThread : public wxThread
{
+ friend class ClassBrowser;
public:
/** the builder threads' event sent to the GUI(class browser window)*/
enum EThreadEvent
ollydbg: The last patch does nothing interesting. Is it the only change that has to be made to C::B to fix the problem or other patches are required?Yes, the patch is not mature.
But if I understand you correctly you're moving all operations to the UI thread, because I don't see any data stored in the event's object.The function "void ClassBrowserBuilderThread::BuildTree()" is not called in "void* ClassBrowserBuilderThread::Entry()", but in "void ClassBrowser::OnBuileTree(cbBuildTreeEvent& event)".
OK, but how do you know how many elements you have to add to the tree in a single event handler? As far as I see it you still need locking.OK, I understand you idea, but we are not talking with the same lockers.
If I'm doing this I'd rather:
1. in the parser thread generate some data and store it in the symbolbrowser event object
2. post an event with the gathered data
3. continue with parsing
4. when I receive the event I'll add the data to the tree
This way it is explicitly stated how owns the data exclusively and there is no need for locking.
First of all the patch does not work but crashes cb at exit.Hi, Morten, thanks for the test. In-fact, If we need to build the Tree from GUI, we should totally remove the worker tree builder thread stuff.
Second if the data gets too large you can use a pointer.Yes, just as the same way as we access to Tokentree to query suggestion list information.
Third I don't think it's that easy.Yes, the method is called from outside but the task is still operated in the thread so it doesn't really change anything... Sorry.The tree build thread is large, also, I read some comments in the code like:
// 9.) Expand item --> Bottleneck: Takes ~4 secs on C::B workspace
....
// 11.) Select the item saved before --> Bottleneck: Takes ~4 secs on C::B workspace
If it still no official support, I might continue to complete it by my hand, because I need it work under linux. Any idea is welcome.Do you think it is definitely the codecompletion's browser tree which cause the crash issue?
I think Loaden has moved it in a thread, but anyway, ...No, the wxTreeCtrl builder thread has a long history, it exist before Loaden became a C::B developer.
Im sure. I will upload a crash trace when I have some free time to have a try.If it still no official support, I might continue to complete it by my hand, because I need it work under linux. Any idea is welcome.Do you think it is definitely the codecompletion's browser tree which cause the crash issue?
I haven't seen that on our forum about such issue, can you show us the crash backtrace?
Can you explain how this patch works and what it tries to achieve?The patch is quite simple, it just translate all the "tree building" code snippets from running in a worker thread to the main GUI thread. Those code snippets was running both from the main GUI thread and worker thread. By using this patch, a custom event is used, when we need to build the tree or operating on the tree, the event if fired, and the final operations all happens in the main GUI thread.
I've tried to look at it, but I'm not familiar with the code, so I cannot really say if it is a good idea.
Generally my understanding is that without a major redesign, the Class Browser would be a constant cause of problems. As far as I can see this is not a major redesign, but a try to workaround the problem...Yes, I agree, this patch is just a workaround.