Skip to content

abort() has been called #3

Open

Description

@flamsk

When i run the StandaloneOscilloscopeSpectralAnalyzer i get an "abort() has been called" error...
Sometimes is occurs immediately, and sometimes it takes a while.

It could also be nice if you have made visual studio project for the application.

Activity

  1. JanosGit commented on Jun 19, 2019

    @JanosGit
    Owner

    Could you give some more information about the system that triggers the error? Have you run it under a debugger? A stack trace would be great to track the source of the error down.

    Regarding Visual Studio, I didn't try it on Windows so far, but as JUCE is cross platform I would expect it to just work. You can simply add a Visual Studio exporter in the Projucer yourself. I will add one if I found some time to test it on Windows...

  2. flamsk commented on Jun 19, 2019

    @flamsk
    Author

    I have been running it under debug.

    Stack trace
    !std::_Mtx_unlockX(_Mtx_internal_imp_t * _Mtx) Line 87
    !std::_Mutex_base::unlock() Line 60
    !ntlab::DataCollector::finishedReading() Line 127
    !ntlab::LocalDataSinkAndSource::finishedReading(ntlab::VisualizationTarget & target) Line 83
    !ntlab::OscilloscopeComponent::endFrame() Line 209
    !ntlab::Plot2D::renderOpenGL() Line 503

    It seams to be happening when writeBufferLock.unlock it called.
    void finishedReading()
    {
    if (readBlock.getSize() != expectedBlockSize)
    readBlock.setSize(expectedBlockSize, true);
    if (readerShouldSwapBlocks)
    {
    writeBlock.swapWith(readBlock);
    writeBufferLock.unlock(); <------
    readerShouldSwapBlocks = false;
    dataBlockReady(sinkIdx);
    }

    readBufferLock.unlock();
    };

    which call unlock on the mutex
    void unlock()
    { // unlock the mutex
    _Mtx_unlockX(_Mymtx());
    }

    which call _Mtx_unlockX on xthread
    inline int _Mtx_unlockX(_Mtx_t _Mtx)
    { // throw exception on failure
    return (_Check_C_return(_Mtx_unlock(_Mtx)));
    }

    ant the _Check_C_return is throwing the _CRTIMP2_PURE void __cdecl _Throw_C_error(int _Code); exception...

  3. flamsk commented on Jun 19, 2019

    @flamsk
    Author

    I just tried to add a lot of logging around the locks and when it fails i see the following in output:

    readBufferLock locked
    readBufferLock unlock
    readBufferLock unlocked
    writeBufferLock try_lock=true
    readBufferLock try_lock=true
    writeBufferLock unlock
    writeBufferLock unlocked
    readBufferLock unlock
    readBufferLock unlocked
    writeBufferLock try_lock=true
    readBufferLock try_lock=true
    writeBufferLock unlock
    writeBufferLock unlocked
    readBufferLock unlock
    readBufferLock unlocked
    writeBufferLock try_lock=true
    readBufferLock try_lock=true
    writeBufferLock unlock
    writeBufferLock unlocked
    readBufferLock unlock
    readBufferLock unlocked
    writeBufferLock try_lock=true
    readBufferLock try_lock=true
    writeBufferLock unlock
    writeBufferLock unlocked
    readBufferLock unlock
    readBufferLock unlocked
    readBufferLock lock
    writeBufferLock try_lock=true
    readBufferLock locked
    readBufferLock try_lock=false
    writeBufferLock unlock
    Debug Error!

    Program: ...jects\OpenGl\Builds\VisualStudio2017\x64\Debug\App\OpenGl.exe

    abort() has been called

    (Press Retry to debug the application)
    writeBufferLock try_lock=false
    writeBufferLock try_lock=false
    writeBufferLock try_lock=false
    writeBufferLock try_lock=false
    writeBufferLock try_lock=false
    writeBufferLock try_lock=false

    Note: my test application is called opengl but contains your example.

    The modified DataCollector.h

    /*
    MIT License

    Copyright (c) 2018 Janos Buttgereit

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE.
    */

    #pragma once

    #include <JuceHeader.h>
    #include < mutex >

    namespace ntlab
    {
    class RealtimeDataSink;

    /**
     * A base class for all objects collecting some data from the realtime stream, preprocesses this data and then
     * transmits the processed result to a RealtimeDataSink instance that manages the transport of the collected
     * data to the visualization target. To keep it as abstract and extendable as possible, juce::MemoryBlocks are
     * used to exchange the preprocessed data, allowing to exchange any kind of data.
     * @see RealtimeDataSink, VisualizationTarget
     */
    class DataCollector
    {
    
    public:
    
        /** The identifier string must be the same on the visualization side to map both instances */
        DataCollector (const juce::String& idenfifier) : id (idenfifier) {};
    
        virtual ~DataCollector () {};
    
        /** This can be used to send settings from the target to the DataCollector */
        virtual void applySettingFromTarget (const juce::String& setting, const juce::var& value) {};
    
        /** Returns immediately and causes the memory blocks managed by this class to resize before the next usage */
        void resizeMemoryBlock (size_t newSizeInBytes)
        {
            expectedBlockSize = newSizeInBytes;
        };
    
        /** Called to begin writing to a memory block. It won't be swapped until finishedWriting was called */
        juce::MemoryBlock* startWriting()
        {
    
    				if (writeBufferLock.try_lock())
    				{
    					DBG("writeBufferLock try_lock=true");
    					return &writeBlock;
    				}
    				else
    				{
    					DBG("writeBufferLock try_lock=false");
    				}
    
          return nullptr;
        };
    
        /**
         * Always call this after having finished writing to release the block for swapping and invoking the next
         * dataBlockReady call.
         */
        void finishedWriting()
        {
            if (readBufferLock.try_lock())
            {
    							DBG("readBufferLock try_lock=true");
    
                writeBlock.swapWith (readBlock);
    							DBG("writeBufferLock unlock");
    							writeBufferLock.unlock();
    							DBG("writeBufferLock unlocked");
    
    							DBG("readBufferLock unlock");
    							readBufferLock.unlock();
    							DBG("readBufferLock unlocked");
    
                dataBlockReady (sinkIdx);
            }
            else {
    						DBG("readBufferLock try_lock=false");
                readerShouldSwapBlocks = true;
            }
        };
    
        /**
         * This is called to indicate that the sink can now read a new data block. It doesn't have to use it
         * but can also just poll startReading on a regular basis. The Lambda should be assigned by
         * RealtimeDataSink when adding it to the sink. As this will be called from the realtime thread, it should
         * return as fast as possible
         */
        std::function<void(int)> dataBlockReady = [](int) {};
    
        /**
         * Called by the sink to start reading from the block. The caller might swap the block supplied with
         * another block
         * */
        juce::MemoryBlock& startReading()
        {
    				try
    				{
    					DBG("readBufferLock lock");
    					readBufferLock.lock();
    					DBG("readBufferLock locked");
    				}
    				catch (int e)
    				{
    					int i = 0;
    					i++;
    				}
            return readBlock;
        };
    
        /** Called by the sink to indicate that it has finished reading */
        void finishedReading()
        {
    				if (readBlock.getSize() != expectedBlockSize)
    					readBlock.setSize(expectedBlockSize, true);
    				if (readerShouldSwapBlocks)
    				{
    					writeBlock.swapWith(readBlock);						
    					DBG("writeBufferLock unlock");
    					writeBufferLock.unlock();
    					DBG("writeBufferLock unlocked");
    					readerShouldSwapBlocks = false;
    					dataBlockReady(sinkIdx);
    				}
    
    				DBG("readBufferLock unlock");
    				readBufferLock.unlock();
    				DBG("readBufferLock unlocked");
        };
    
        /** For internal use only, don't change */
        int sinkIdx = -1;
    
        /** For internal use only, don't change */
        RealtimeDataSink *sink = nullptr;
    
        const juce::String id;
    
    private:
    
        juce::MemoryBlock readBlock;
        juce::MemoryBlock writeBlock;
    
        bool readerShouldSwapBlocks = false;
    
        std::mutex readBufferLock, writeBufferLock;
    
        size_t expectedBlockSize = 0;
    };
    

    }

  4. flamsk commented on Jun 19, 2019

    @flamsk
    Author

    would it be better to use the lock functionallity within Juce??
    https://docs.juce.com/master/group__juce__core-threads.html

  5. adamski commented on Sep 20, 2019

    @adamski
    Contributor

    @flamsk How did you get the module to compile under Windows? I am compiling with VS2019 on Windows 10 via Parallels, and get lots of errors e.g. GL_ARRAY_BUFFER undefined

  6. SimonHGit commented on Sep 24, 2021

    @SimonHGit

    @adamski Maybe its outdated, but if someone will go into errors like GL_ARRAY_BUFFER undefined it worked for me by adding

    using namespace juce;
    //todo: update to a newer version of juce to define this in juce_gles2.h
    #define GL_ALIASED_LINE_WIDTH_RANGE 0x846E

    But to come to the reported issue:
    Since I configured my App to use ASIO devices it runns into this debug error too:
    grafik

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions