-
-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix "out of buffers" crash #3783
Changes from 5 commits
b6421d4
6b557d2
c11d12f
9c91079
73728d7
aebbe22
70ac7db
d1aa39b
93e4bd7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,7 +42,7 @@ struct MemoryPool | |
{ | ||
void * m_pool; | ||
char * m_free; | ||
int m_chunks; | ||
size_t m_chunks; | ||
QMutex m_mutex; | ||
|
||
MemoryPool() : | ||
|
@@ -51,10 +51,10 @@ struct MemoryPool | |
m_chunks( 0 ) | ||
{} | ||
|
||
MemoryPool( int chunks ) : | ||
MemoryPool( size_t chunks ) : | ||
m_chunks( chunks ) | ||
{ | ||
m_free = (char*) MemoryHelper::alignedMalloc( chunks ); | ||
m_free = reinterpret_cast<char*>(MemoryHelper::alignedMalloc( chunks )); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same inconsistency here, |
||
memset( m_free, 1, chunks ); | ||
} | ||
|
||
|
@@ -103,6 +103,25 @@ class EXPORT MemoryManager | |
static QMutex s_pointerMutex; | ||
}; | ||
|
||
template<typename T> | ||
struct MmAllocator | ||
{ | ||
typedef T value_type; | ||
template< class U > struct rebind { typedef MmAllocator<U> other; }; | ||
|
||
T* allocate(std::size_t n) | ||
{ | ||
return reinterpret_cast<T*>( MemoryManager::alloc( sizeof(T) * n ) ); | ||
} | ||
|
||
void deallocate(T* p, std::size_t) | ||
{ | ||
MemoryManager::free( p ); | ||
} | ||
|
||
typedef std::vector<T, MmAllocator<T> > vector; | ||
}; | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These parts aren't used. Are there some reasons you leave them in our codebase? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I plan on using them at a later point in time. Using an Allocator class is the standard C++ way of having custom allocators, and should be preferred over using the macros
This has already been discussed by @Umcaruje and me in the comments here. C++03 doesn't allow There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Well it's a vector, so why not call it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right, but you used both There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, no that's not intentional. |
||
|
||
#define MM_OPERATORS \ | ||
public: \ | ||
|
@@ -124,7 +143,7 @@ static void operator delete[] ( void * ptr ) \ | |
} | ||
|
||
// for use in cases where overriding new/delete isn't a possibility | ||
#define MM_ALLOC( type, count ) (type*) MemoryManager::alloc( sizeof( type ) * count ) | ||
#define MM_ALLOC( type, count ) reinterpret_cast<type*>(MemoryManager::alloc( sizeof( type ) * count )) | ||
// and just for symmetry... | ||
#define MM_FREE( ptr ) MemoryManager::free( ptr ) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
/* | ||
* BufferManager.cpp - A buffer caching/memory management system | ||
* | ||
* Copyright (c) 2017 Lukas W <lukaswhl/at/gmail.com> | ||
* Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi> | ||
* Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net> | ||
* | ||
|
@@ -25,56 +26,28 @@ | |
|
||
#include "BufferManager.h" | ||
|
||
#include "Engine.h" | ||
#include "Mixer.h" | ||
#include "MemoryManager.h" | ||
|
||
sampleFrame ** BufferManager::s_available; | ||
AtomicInt BufferManager::s_availableIndex = 0; | ||
sampleFrame ** BufferManager::s_released; | ||
AtomicInt BufferManager::s_releasedIndex = 0; | ||
//QReadWriteLock BufferManager::s_mutex; | ||
int BufferManager::s_size; | ||
|
||
static fpp_t framesPerPeriod; | ||
|
||
void BufferManager::init( fpp_t framesPerPeriod ) | ||
{ | ||
s_available = MM_ALLOC( sampleFrame*, BM_INITIAL_BUFFERS ); | ||
s_released = MM_ALLOC( sampleFrame*, BM_INITIAL_BUFFERS ); | ||
|
||
int c = framesPerPeriod * BM_INITIAL_BUFFERS; | ||
sampleFrame * b = MM_ALLOC( sampleFrame, c ); | ||
|
||
for( int i = 0; i < BM_INITIAL_BUFFERS; ++i ) | ||
{ | ||
s_available[ i ] = b; | ||
b += framesPerPeriod; | ||
} | ||
s_availableIndex = BM_INITIAL_BUFFERS - 1; | ||
s_size = BM_INITIAL_BUFFERS; | ||
::framesPerPeriod = framesPerPeriod; | ||
} | ||
|
||
|
||
sampleFrame * BufferManager::acquire() | ||
{ | ||
if( s_availableIndex < 0 ) | ||
{ | ||
qFatal( "BufferManager: out of buffers" ); | ||
} | ||
|
||
int i = s_availableIndex.fetchAndAddOrdered( -1 ); | ||
sampleFrame * b = s_available[ i ]; | ||
|
||
//qDebug( "acquired buffer: %p - index %d", b, i ); | ||
return b; | ||
return MM_ALLOC(sampleFrame, ::framesPerPeriod); | ||
} | ||
|
||
|
||
void BufferManager::clear( sampleFrame * ab, const f_cnt_t frames, | ||
const f_cnt_t offset ) | ||
void BufferManager::clear(sampleFrame *ab, const f_cnt_t frames, const f_cnt_t offset) | ||
{ | ||
memset( ab + offset, 0, sizeof( *ab ) * frames ); | ||
} | ||
|
||
|
||
#ifndef LMMS_DISABLE_SURROUND | ||
void BufferManager::clear( surroundSampleFrame * ab, const f_cnt_t frames, | ||
const f_cnt_t offset ) | ||
|
@@ -86,43 +59,6 @@ void BufferManager::clear( surroundSampleFrame * ab, const f_cnt_t frames, | |
|
||
void BufferManager::release( sampleFrame * buf ) | ||
{ | ||
if (buf == nullptr) return; | ||
int i = s_releasedIndex.fetchAndAddOrdered( 1 ); | ||
s_released[ i ] = buf; | ||
//qDebug( "released buffer: %p - index %d", buf, i ); | ||
MM_FREE(buf); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a nitpick, but space missing here too. Thanks for fixing the other lines. |
||
} | ||
|
||
|
||
void BufferManager::refresh() // non-threadsafe, hence it's called periodically from mixer at a time when no other threads can interfere | ||
{ | ||
if( s_releasedIndex == 0 ) return; | ||
//qDebug( "refresh: %d buffers", int( s_releasedIndex ) ); | ||
|
||
int j = s_availableIndex; | ||
for( int i = 0; i < s_releasedIndex; ++i ) | ||
{ | ||
++j; | ||
s_available[ j ] = s_released[ i ]; | ||
} | ||
s_availableIndex = j; | ||
s_releasedIndex = 0; | ||
} | ||
|
||
|
||
/* // non-extensible for now | ||
void BufferManager::extend( int c ) | ||
{ | ||
s_size += c; | ||
sampleFrame ** tmp = MM_ALLOC( sampleFrame*, s_size ); | ||
MM_FREE( s_available ); | ||
s_available = tmp; | ||
|
||
int cc = c * Engine::mixer()->framesPerPeriod(); | ||
sampleFrame * b = MM_ALLOC( sampleFrame, cc ); | ||
|
||
for( int i = 0; i < c; ++i ) | ||
{ | ||
s_available[ s_availableIndex.fetchAndAddOrdered( 1 ) + 1 ] = b; | ||
b += Engine::mixer()->framesPerPeriod(); | ||
} | ||
}*/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,18 +22,23 @@ | |
* | ||
*/ | ||
|
||
#include "PlayHandle.h" | ||
#include "BufferManager.h" | ||
#include "Engine.h" | ||
#include "Mixer.h" | ||
#include "PlayHandle.h" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why this line have been moved from above? It should stay above There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No reason, probably an unintentional change. |
||
|
||
#include <QtCore/QThread> | ||
#include <QDebug> | ||
|
||
#include <iterator> | ||
|
||
PlayHandle::PlayHandle( const Type type, f_cnt_t offset ) : | ||
m_type( type ), | ||
m_offset( offset ), | ||
m_affinity( QThread::currentThread() ), | ||
m_playHandleBuffer( NULL ), | ||
m_usesBuffer( true ) | ||
PlayHandle::PlayHandle(const Type type, f_cnt_t offset) : | ||
m_type(type), | ||
m_offset(offset), | ||
m_affinity(QThread::currentThread()), | ||
m_playHandleBuffer(BufferManager::acquire()), | ||
m_bufferReleased(true), | ||
m_usesBuffer(true) | ||
{ | ||
} | ||
|
||
|
@@ -48,8 +53,8 @@ void PlayHandle::doProcessing() | |
{ | ||
if( m_usesBuffer ) | ||
{ | ||
if( ! m_playHandleBuffer ) m_playHandleBuffer = BufferManager::acquire(); | ||
play( m_playHandleBuffer ); | ||
m_bufferReleased = false; | ||
play( buffer() ); | ||
} | ||
else | ||
{ | ||
|
@@ -60,6 +65,10 @@ void PlayHandle::doProcessing() | |
|
||
void PlayHandle::releaseBuffer() | ||
{ | ||
BufferManager::release( m_playHandleBuffer ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @lukas-w Why did you move this to destructor? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @PhysSong Because I moved buffer allocation to the constructor. The buffer's lifetime matches the |
||
m_playHandleBuffer = NULL; | ||
m_bufferReleased = true; | ||
} | ||
|
||
sampleFrame* PlayHandle::buffer() | ||
{ | ||
return m_bufferReleased ? nullptr : reinterpret_cast<sampleFrame*>(m_playHandleBuffer); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
inconsistent spaces inside the bracket here