Menu

#1393 C::B freezes after creating a class or a file using File -> New

Next_Nightly
fixed
pecan
Bug_Report
2023-10-10
2023-05-10
No

User @cbuser1 reported in the forum a freeze after adding a class using the menu. I have observed this lately when adding any new file.

cbuser1 bisected the nightlies (thank you) and reported that [r12579] works while [r12596] fails.

I do not see which commit inside that range may cause this problem, bisection will be needed but I can not currently do it.

Related

Commit: [r12579]
Commit: [r12596]

Discussion

  • Miguel Gimenez

    Miguel Gimenez - 2023-05-12

    Update: cbuser1 has found the problem also in [r12579], he will test older nightlies.

     

    Related

    Commit: [r12579]

  • Miguel Gimenez

    Miguel Gimenez - 2023-06-06

    It is a problem with Code Completion, adding the files to the active project blocks it.
    The issue also affects File -> New -> File

    IMHO this issue is a show stopper.

     

    Last edit: Miguel Gimenez 2023-06-06
  • Miguel Gimenez

    Miguel Gimenez - 2023-06-06
    • summary: C::B freezes after creating a class using the menu --> C::B freezes after creating a class or a file using File -> New
     
  • pecan

    pecan - 2023-09-28

    Environment: windows 11
    I download the nightly containing rev 12579 reported as freezing.
    I was unable to reproduce the freeze using the steps provided by OP.

    I compared the source for CodeCompletion revs 12596 and 12579.
    There are no source changes between those revisions.

    This may be only a Windows 7 problem.
    I'll continue to test.

     
  • Miguel Gimenez

    Miguel Gimenez - 2023-09-29

    I am using Windows 10 and get the freeze. When I refer to CodeCompletion I am talking about the "Classic" one, I have not tested with Clangd-client.

     
  • pecan

    pecan - 2023-09-29

    Thanks Miguel,
    I'll keep trying to get the freeze and track it down.
    Do you have an assured way (code) to get the freeze that you can share.
    cbuser1 gets the freeze with: https://forums.codeblocks.org/index.php?topic=25383.msg172937#msg172937. Reply #3.
    But I've been unsuccessful using this. Does it work for you?
    [code]
    To reproduce, Create a new C++ console project. Save it, and exit code::blocks. Launch code::blocks again and open the project. Opening an existing project seems to matter for some reason. It wouldn't freeze if I have created the class right away.

    Click File->New->Class... and create a Dummy class.
    Click on Create then click on Yes for the Add to project dialog box.
    Click Ok on the Multiple selection dialog box.

    Code::Blocks then becomes unresponsive for me.
    [/code]

    Have you definately determined that old CodeCompletion is the cause.
    Ie., that you disabled old CC and the probem went away.

     

    Last edit: pecan 2023-09-29
  • Miguel Gimenez

    Miguel Gimenez - 2023-09-29

    My steps are (on W7 and W10 with the "Legacy" code completion and current head):
    * Open an existing project (I use a wxWidgets one I am working on)
    * Click File -> New -> Empty file
    * Add it to the project when asked. I save it as Test.cpp
    * Right click on the new file tab and select "Swap header/source"
    * This will create the include file Test.h and add it to the project
    * Write something in the include file, say #include <stdlib.h> followed by Enter
    * Click the Save button

    The mouse pointer changes to a rotating circle and C::B stops responding. This happens on every time.

     

    Last edit: Miguel Gimenez 2023-09-29
    • ollydbg

      ollydbg - 2023-09-30

      I try to reproduce this hang issue by following the steps on a Win7 with the classical CodeCompletion enabled, I'm using the latest svn version code, but I don't get the hang issue.

       

      Last edit: ollydbg 2023-10-07
  • ollydbg

    ollydbg - 2023-09-30
    • labels: --> CodeCompletion
     
  • pecan

    pecan - 2023-10-02

    Would those of you able to get the hang please disable the Symbols Bowser and see if you still get the hang.

    Settings>Editor>CodeCompletion>SymbolsBrowser>[]Disable Symbols Browser check box.

    After 12 hours tracing the code in the debugger, it's led me to the hang when updating the GUI Symbols tree. But I want to know if this is correct or I'm barking up the wrong tree.

    Thanks

     
  • Miguel Gimenez

    Miguel Gimenez - 2023-10-03

    Disabling the Symbol Browser C::B does not hang anymore.

     
  • pecan

    pecan - 2023-10-06

    I've found the source of the freeze.
    Let's see if I can explain it to all and especially to myself.

    The freeze is happening at ClassBrowserBuilderThread::Init(..) attempting to lock mutex m_ClassBrowserBuilderThreadMutex called from ThreadedBuildTree() on the main gui thread.
    It fails sometimes because ExpandItem() or SelectGuiItem() has it locked on its own thread which also locks m_TokenTreeMutex all over the place.

    This is usually ok, especially if only one file has been parsed, so that ThreadedBuildTree (which builds the Symbols window tree) gets in and out without being interrupted while holding the mutexes.

    But when two short files are being parsed, it's possible that the end of the second parse causes ClassBrowserBuildThread to be entered a second time as a race condition..
    The second entry will block the main thread trying to lock ClassBrowserBuilderThreadMutex which is already locked from the first entry to ExpandItem() or SelectGuiItem() .

    I don't know why this happens yet. IE., I don't know why the interrupt is allowed to happen, but I can actually experience it with the debugger. While stepping through ClassBrowserBuildThread, an interrupt occurs and I'm right back in OnParseEnd() attempting to call UpdateClassBrowser the second time.

    The only guess I can make is that the semaphore wait at ClassBrowserBuilderThread::Entry() is allowing the second parse OnParseEnd() interrupt to happend before the first OnParseEnd() is through. But that would mean the mutexes would have to be locked across that wait condition. Doesn't yet make sense to me.

    Suggestions welcome.

    void* ClassBrowserBuilderThread::Entry()
    {
        while (!m_TerminationRequested && !Manager::IsAppShuttingDown())
        {
            // waits here, until the ClassBrowser unlocks
            // we put a semaphore wait function in the while loop, so the first time if
            // the semaphore is 1, we can call BuildTree() in the loop, in the meanwhile
            // the semaphore becomes 0. We will be blocked by semaphore's wait function
            // in the next while loop. The semaphore post function will be called in the
            // GUI thread once a new BuildTree() call is needed.
            m_ClassBrowserSemaphore.Wait();
    
            if (m_TerminationRequested || Manager::IsAppShuttingDown() )
                break;
    
            m_Busy = true;
    
            // The thread can do many jobs:
            switch (m_nextJob)
              {
              case JobBuildTree:  // build internal trees and transfer to GUI ones
                  BuildTree();
                  break;
              case JobSelectTree: // fill the bottom tree with data relative to the selected item
                  SelectGUIItem(); <== Locks occur in here
                  FillGUITree(false);
                  break;
              case JobExpandItem: // add child items on the fly
                  ExpandGUIItem(); <== Locks occur in here also
                  break;
              default:
                  ;
              }
    
            m_Busy = false;
        }
    
        m_NativeParser = nullptr;
        m_CCTreeTop = nullptr;
        m_CCTreeBottom = nullptr;
    
        return nullptr;
    }
    
     

    Last edit: pecan 2023-10-06
  • ollydbg

    ollydbg - 2023-10-07

    First, thanks for the explanation.

    main gui thread                                                    
    
        ThreadedBuildTree()                                            
    
            ClassBrowserBuilderThread::Init(..)                        
    
                Lock m_ClassBrowserBuilderThreadMutex                  
    
    
    
    Worker thread loop                                                 
    
        ExpandGUIItem()                                                
    
            ClassBrowserBuilderThread::ExpandGUIItem()                 
    
                ClassBrowserBuilderThread::ExpandItem(CCTreeItem* item)
    
                    Lock m_ClassBrowserBuilderThreadMutex              
    
                    Lock s_TokenTreeMutex                              
    

    It looks like the Lockers work correctly.

    I also do not understand the logic of the m_ClassBrowserSemaphore.Wait() in the void* ClassBrowserBuilderThread::Entry(). function call.

    Second, from my point of view, why do we need a m_ClassBrowserSemaphore here? Do we just need a worker thread pool?
    I mean a job queue which need to be run from the worker thread. Once we have a job, just add the job to the pool.

    The Semphore here looks like try to block the loop in the ClassBrowserBuilderThread::Entry() if nothing to be done, but do we really need a loop?

     

    Last edit: ollydbg 2023-10-07
  • pecan

    pecan - 2023-10-08

    The freeze is caused by the following"
    m_ClassBrowserBuilderThread::Init blocks the main thread because ClassBrowserBuilderThread::entry() is already busy from the SwitchParser() call.
    The mutex has been owned by two calls in entry() (a race condition loop) and a second call to UpdateClassBrower after SwitchParser() pauses the thread.

    But the m_ClassBrowserBuilderThread has been paused by the immediate second call to UpdateClassBrowser() which now cannot proceed to release the mutex blocking the main GUI thread. Deadly embrace. !!

    // ----------------------------------------------------------------------------
    void NativeParser::OnParserEnd(wxCommandEvent& event) ///Line 2447
    // ----------------------------------------------------------------------------
    {
        SwitchParser(info.first, info.second); // Calls SetParser() which also calls UpdateClassBrowserView() Line 2472
        UpdateClassBrowser(); Line 2492 <===== the culpret; immediate second call to UpdateBrowserView !!. ///Line 2492
    }
    
    // ----------------------------------------------------------------------------
    void ClassBrowser::UpdateClassBrowserView(bool checkHeaderSwap) ///Line 218
    // ----------------------------------------------------------------------------
    {
        ThreadedBuildTree(activeProject); // (Re-) create tree UI Line 260
    
    }
    
    // ----------------------------------------------------------------------------
    void ClassBrowser::ThreadedBuildTree(cbProject* activeProject)
    // ----------------------------------------------------------------------------
    {
            m_ClassBrowserBuilderThread->Pause(); ///Line 914
    
        // initialise it, this function is called from the GUI main thread.
        m_ClassBrowserBuilderThread->Init(m_NativeParser,       ///Line 977
                                          m_ActiveFilename,
                                          activeProject,
                                          m_Parser->ClassBrowserOptions(),
                                          m_Parser->GetTokenTree(),
                                          idThreadEvent);
    
        Init blocks the main thread because ClassBrowserBuilderThread::entry() is already busy
            from the SwitchParser() call. The mutex has been owned by two calls in this function (a race condition).
    
        But the m_ClassBrowserBuilderThread has been paused and cannot proceed to release the mutex. Deadly embrace. !!
    }
    

    The solution I've found is to check if the Entry() fuction of m_ClassBrowserBuilderThread is busy and NOT pause the thread and NOT call ClassBrowserBuilderThread::Init();

    It works to eliminate the freeze, but I haven't yet explored all the ramification or side efects to the Symbols windows tree.

    Solution:

    // ----------------------------------------------------------------------------
    void ClassBrowser::ThreadedBuildTree(cbProject* activeProject)
    // ----------------------------------------------------------------------------
    {
        if (Manager::IsAppShuttingDown() || !m_Parser)
            return;
    
        if (m_ClassBrowserBuilderThread and m_ClassBrowserBuilderThread->IsBusy()) //(ph 2023/10/08)
            return; // Do not block the main thread when the builder thread is busy.
    
        TRACE("ClassBrowser: ThreadedBuildTree started.");
    

    I believe it's important to eliminate this freeze now and explore the side efects on the Symbols display later.

    Suggestions welcome.

     

    Last edit: pecan 2023-10-08
  • pecan

    pecan - 2023-10-10
    • status: open --> fixed
    • assigned_to: pecan
    • Milestone: Next_Release --> Next_Nightly
     
  • pecan

    pecan - 2023-10-10

    Fix commited 2023/10/10 rev 13369 through 13371

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.