From fb6641a81a90a8bbfc82f90fb3e2626a6049c0b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Fri, 26 Aug 2022 02:49:04 -0300 Subject: [PATCH] MemoryManager now handles realloc. TerminalDisplay: Cursor fixes. TerminalEmulator: Memory leaks fixes. --- include/eepp/core/memorymanager.hpp | 21 ++++ src/eepp/core/memorymanager.cpp | 40 +++++++ .../eterm/terminal/terminalemulator.hpp | 14 ++- .../src/eterm/terminal/terminaldisplay.cpp | 15 ++- .../src/eterm/terminal/terminalemulator.cpp | 108 ++++++++++++------ src/tools/ecode/terminalmanager.cpp | 1 + src/tools/eterm/eterm.cpp | 1 + 7 files changed, 159 insertions(+), 41 deletions(-) diff --git a/include/eepp/core/memorymanager.hpp b/include/eepp/core/memorymanager.hpp index d4067c4d4..7906b4670 100644 --- a/include/eepp/core/memorymanager.hpp +++ b/include/eepp/core/memorymanager.hpp @@ -29,6 +29,8 @@ class EE_API MemoryManager { public: static void* addPointer( const AllocatedPointer& aAllocatedPointer ); + static void* reallocPointer( void* data, const AllocatedPointer& aAllocatedPointer ); + static void* addPointerInPlace( void* place, const AllocatedPointer& aAllocatedPointer ); static bool removePointer( void* data, const char* file, const size_t& line ); @@ -61,6 +63,17 @@ class EE_API MemoryManager { return malloc( size ); } + inline static void* reallocate( void* ptr, size_t size ) { +#if defined( __GNUC__ ) && __GNUC__ >= 12 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuse-after-free" + return realloc( ptr, size ); +#pragma GCC diagnostic pop +#else + return realloc( ptr, size ); +#endif + } + static size_t getPeakMemoryUsage(); static size_t getTotalMemoryUsage(); @@ -90,6 +103,11 @@ class EE_API MemoryManager { EE::MemoryManager::addPointer( EE::AllocatedPointer( EE::MemoryManager::allocate( amount ), \ __FILE__, __LINE__, amount ) ) +#define eeRealloc( ptr, amount ) \ + EE::MemoryManager::reallocPointer( \ + ptr, EE::AllocatedPointer( EE::MemoryManager::reallocate( ptr, amount ), __FILE__, \ + __LINE__, amount ) ) + #define eeDelete( data ) \ { \ if ( EE::MemoryManager::removePointer( EE::MemoryManager::deletePtr( data ), __FILE__, \ @@ -122,11 +140,14 @@ class EE_API MemoryManager { #define eeMalloc( amount ) malloc( amount ) +#define eeRealloc( ptr, amount ) realloc( ptr, amount ) + #define eeDelete( data ) delete data #define eeDeleteArray( data ) delete[] data #define eeFree( data ) free( data ) + #endif } // namespace EE diff --git a/src/eepp/core/memorymanager.cpp b/src/eepp/core/memorymanager.cpp index b35a34b19..1dd0a656a 100644 --- a/src/eepp/core/memorymanager.cpp +++ b/src/eepp/core/memorymanager.cpp @@ -61,6 +61,46 @@ void* MemoryManager::addPointer( const AllocatedPointer& aAllocatedPointer ) { return aAllocatedPointer.mData; } +void* MemoryManager::reallocPointer( void* data, const AllocatedPointer& aAllocatedPointer ) { + Lock l( sAlloMutex ); + + AllocatedPointerMapIt it = sMapPointers.find( data ); + + if ( it->second.mTrack ) + eePRINTL( "Realloc pointer %p at '%s' %d", data, aAllocatedPointer.mFile.c_str(), + aAllocatedPointer.mLine ); + + if ( it == sMapPointers.end() ) + return addPointer( aAllocatedPointer ); + + if ( aAllocatedPointer.mTrack ) + eePRINTL( "Reallocating pointer %p at '%s' %d", aAllocatedPointer.mData, + aAllocatedPointer.mFile.c_str(), aAllocatedPointer.mLine ); + + if ( it->first != aAllocatedPointer.mData ) { + removePointer( data, aAllocatedPointer.mFile.c_str(), aAllocatedPointer.mLine ); + addPointer( aAllocatedPointer ); + } else { + sTotalMemoryUsage -= it->second.mMemory; + it->second.mMemory = aAllocatedPointer.mMemory; + it->second.mFile = aAllocatedPointer.mFile; + it->second.mLine = aAllocatedPointer.mLine; + it->second.mTrack = aAllocatedPointer.mTrack; + + sTotalMemoryUsage += aAllocatedPointer.mMemory; + + if ( sPeakMemoryUsage < sTotalMemoryUsage ) { + sPeakMemoryUsage = sTotalMemoryUsage; + } + + if ( aAllocatedPointer.mMemory > sBiggestAllocation.mMemory ) { + sBiggestAllocation = aAllocatedPointer; + } + } + + return aAllocatedPointer.mData; +} + bool MemoryManager::removePointer( void* data, const char* file, const size_t& line ) { Lock l( sAlloMutex ); diff --git a/src/modules/eterm/include/eterm/terminal/terminalemulator.hpp b/src/modules/eterm/include/eterm/terminal/terminalemulator.hpp index 3a74ad1ca..111babfa7 100644 --- a/src/modules/eterm/include/eterm/terminal/terminalemulator.hpp +++ b/src/modules/eterm/include/eterm/terminal/terminalemulator.hpp @@ -63,8 +63,9 @@ struct Term { int col{ 0 }; /* nb col */ Line* line{ nullptr }; /* screen */ Line* alt{ nullptr }; /* alternate screen */ - std::vector hist; /* history buffer */ - int histsize{ 0 }; /* history size */ + Line* hist{ nullptr }; /* history buffer */ + int histcursize{ 0 }; /* history current size */ + int histsize{ 0 }; /* history max size */ int histi{ 0 }; /* history index */ int scr{ 0 }; /* scroll back */ int* dirty{ nullptr }; /* dirtyness of lines */ @@ -80,6 +81,8 @@ struct Term { int icharset{ 0 }; /* selected charset for sequence */ int* tabs{ nullptr }; Rune lastc{ 0 }; /* last printed char outside of sequence, 0 if control */ + + ~Term(); }; /* CSI Escape sequence structs */ @@ -214,6 +217,10 @@ class TerminalEmulator final { int scrollPos(); + bool getAllowMemoryTrimnming() const; + + void setAllowMemoryTrimnming( bool allowMemoryTrimnming ); + private: DpyPtr mDpy; PtyPtr mPty; @@ -221,6 +228,7 @@ class TerminalEmulator final { bool mColorsLoaded; bool mDirty{ true }; + bool mAllowMemoryTrimnming{ false }; int mExitCode; enum { STARTING = 0, RUNNING, TERMINATED } mStatus; @@ -328,6 +336,8 @@ class TerminalEmulator final { void xsetsel( char* ); void xximspot( int, int ); + void trimMemory(); + TerminalEmulator( PtyPtr&& pty, ProcPtr&& process, const std::shared_ptr& display, const size_t& historySize = 1000 ); diff --git a/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp b/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp index ca11ce5a4..9ccc71ff0 100644 --- a/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp +++ b/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp @@ -1096,6 +1096,9 @@ void TerminalDisplay::drawGrid( const Vector2f& pos ) { } y += lineHeight; + + if ( j == (Uint32)mCursor.y ) + invalidateCursor(); } if ( mVBBackground ) { @@ -1228,6 +1231,9 @@ void TerminalDisplay::drawGrid( const Vector2f& pos ) { } y += lineHeight; + + if ( j == (Uint32)mCursor.y ) + invalidateCursor(); } if ( mVBForeground ) { @@ -1287,7 +1293,7 @@ void TerminalDisplay::drawGrid( const Vector2f& pos ) { case SteadyUnderline: mPrimitives.drawRectangle( Rectf( { pos.x + mCursor.x * spaceCharAdvanceX, - pos.y + ( mCursor.y + 1 ) * lineHeight - cursorThickness }, + pos.y + mCursor.y * lineHeight + lineHeight - cursorThickness }, { spaceCharAdvanceX, cursorThickness } ) ); break; case BlinkingBlock: @@ -1318,6 +1324,13 @@ void TerminalDisplay::drawGrid( const Vector2f& pos ) { } } + if ( mFrameBuffer && pos.y + lineHeight * mRows < mSize.getHeight() ) { + mPrimitives.setColor( defaultBg ); + mPrimitives.drawRectangle( + { { pos.x, pos.y + lineHeight * mRows }, + { mSize.getWidth(), mSize.getHeight() - pos.y + lineHeight * mRows } } ); + } + if ( mFrameBuffer ) mFrameBuffer->unbind(); } diff --git a/src/modules/eterm/src/eterm/terminal/terminalemulator.cpp b/src/modules/eterm/src/eterm/terminal/terminalemulator.cpp index c5afef8a7..0a1cad5c0 100644 --- a/src/modules/eterm/src/eterm/terminal/terminalemulator.cpp +++ b/src/modules/eterm/src/eterm/terminal/terminalemulator.cpp @@ -39,9 +39,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -50,6 +52,13 @@ #include #include +#if EE_PLATFORM == EE_PLATFORM_LINUX +// For malloc_trim, which is a GNU extension +extern "C" { +#include +} +#endif + namespace eterm { namespace Terminal { /* identification sequence returned in DA and DECID */ @@ -219,21 +228,9 @@ ushort TerminalEmulator::boxdrawindex( const TerminalGlyph* g ) { return boxdata[g->u & 0xFF]; } -static void* xmalloc( size_t len ) { - void* p; - - p = malloc( len ); - assert( p != NULL ); - - return p; -} - -static void* xrealloc( void* p, size_t len ) { - p = realloc( p, len ); - assert( p != NULL ); - - return p; -} +#define xfree( p ) eeFree( p ) +#define xmalloc( p ) eeMalloc( p ) +#define xrealloc( p, len ) eeRealloc( p, len ) static size_t utf8decode( const char*, Rune*, size_t ); static Rune utf8decodebyte( char, size_t* ); @@ -587,7 +584,7 @@ std::string TerminalEmulator::getSelection() const { char* sel = getsel(); if ( sel ) { std::string selection( sel ); - free( sel ); + xfree( sel ); return selection; } return ""; @@ -704,17 +701,35 @@ int TerminalEmulator::rowCount() const { return mTerm.row; } +void TerminalEmulator::trimMemory() { +#if EE_PLATFORM == EE_PLATFORM_LINUX + if ( mAllowMemoryTrimnming ) { + malloc_trim( 0 ); + } +#endif +} + void TerminalEmulator::clearHistory() { - for ( size_t i = 0; i < mTerm.hist.size(); ++i ) - free( mTerm.hist[i] ); - mTerm.hist.clear(); + for ( int i = 0; i < mTerm.histcursize; ++i ) + eeSAFE_FREE( mTerm.hist[i] ); + eeSAFE_FREE( mTerm.hist ); + mTerm.histcursize = 0; mTerm.histi = 0; + trimMemory(); } int TerminalEmulator::scrollPos() { return mTerm.scr; } +bool TerminalEmulator::getAllowMemoryTrimnming() const { + return mAllowMemoryTrimnming; +} + +void TerminalEmulator::setAllowMemoryTrimnming( bool allowMemoryTrimnming ) { + mAllowMemoryTrimnming = allowMemoryTrimnming; +} + bool TerminalEmulator::isScrolling() const { return mTerm.scr != 0; } @@ -862,13 +877,14 @@ void TerminalEmulator::tswapscreen( void ) { } void TerminalEmulator::resizeHistory() { - size_t oriSize = mTerm.hist.size(); - if ( mTerm.histi >= (int)mTerm.hist.size() ) { + size_t oriSize = mTerm.histcursize; + if ( mTerm.histi >= (int)mTerm.histcursize ) { int newSize = eemin( mTerm.histi + mTerm.row, mTerm.histsize ); - mTerm.hist.resize( newSize, nullptr ); - for ( size_t i = oriSize; i < mTerm.hist.size(); i++ ) { - mTerm.hist[i] = - (TerminalGlyph*)xrealloc( mTerm.hist[i], mTerm.col * sizeof( TerminalGlyph ) ); + mTerm.hist = (Line*)xrealloc( mTerm.hist, newSize * sizeof( Line ) ); + mTerm.histcursize = newSize; + + for ( int i = oriSize; i < mTerm.histcursize; i++ ) { + mTerm.hist[i] = (TerminalGlyph*)xmalloc( mTerm.col * sizeof( TerminalGlyph ) ); for ( int j = 0; j < mTerm.col; j++ ) { mTerm.hist[i][j] = mTerm.c.attr; mTerm.hist[i][j].u = ' '; @@ -1790,7 +1806,7 @@ void TerminalEmulator::tdumpsel( void ) { if ( ( ptr = getsel() ) ) { tprinter( ptr, strlen( ptr ) ); - free( ptr ); + xfree( ptr ); } } @@ -2284,8 +2300,8 @@ void TerminalEmulator::tresize( int col, int row ) { * memmove because we're freeing the earlier lines */ for ( i = 0; i <= mTerm.c.y - row; i++ ) { - free( mTerm.line[i] ); - free( mTerm.alt[i] ); + xfree( mTerm.line[i] ); + xfree( mTerm.alt[i] ); } /* ensure that both src and dst are not NULL */ if ( i > 0 ) { @@ -2293,8 +2309,8 @@ void TerminalEmulator::tresize( int col, int row ) { memmove( mTerm.alt, mTerm.alt + i, row * sizeof( Line ) ); } for ( i += row; i < mTerm.row; i++ ) { - free( mTerm.line[i] ); - free( mTerm.alt[i] ); + xfree( mTerm.line[i] ); + xfree( mTerm.alt[i] ); } /* resize to new height */ @@ -2303,14 +2319,6 @@ void TerminalEmulator::tresize( int col, int row ) { mTerm.dirty = (int*)xrealloc( mTerm.dirty, row * sizeof( *mTerm.dirty ) ); mTerm.tabs = (int*)xrealloc( mTerm.tabs, col * sizeof( *mTerm.tabs ) ); - for ( size_t i = 0; i < mTerm.hist.size(); i++ ) { - mTerm.hist[i] = (TerminalGlyph*)xrealloc( mTerm.hist[i], col * sizeof( TerminalGlyph ) ); - for ( j = mincol; j < col; j++ ) { - mTerm.hist[i][j] = mTerm.c.attr; - mTerm.hist[i][j].u = ' '; - } - } - /* resize each row to new width, zero-pad if needed */ for ( i = 0; i < minrow; i++ ) { mTerm.line[i] = (Line)xrealloc( mTerm.line[i], col * sizeof( TerminalGlyph ) ); @@ -2322,6 +2330,16 @@ void TerminalEmulator::tresize( int col, int row ) { mTerm.line[i] = (Line)xmalloc( col * sizeof( TerminalGlyph ) ); mTerm.alt[i] = (Line)xmalloc( col * sizeof( TerminalGlyph ) ); } + + /* add new columns to history */ + for ( int i = 0; i < mTerm.histcursize; i++ ) { + mTerm.hist[i] = (TerminalGlyph*)xrealloc( mTerm.hist[i], col * sizeof( TerminalGlyph ) ); + for ( j = mincol; j < col; j++ ) { + mTerm.hist[i][j] = mTerm.c.attr; + mTerm.hist[i][j].u = ' '; + } + } + if ( col > mTerm.col ) { bp = mTerm.tabs + mTerm.col; @@ -2331,6 +2349,7 @@ void TerminalEmulator::tresize( int col, int row ) { for ( bp += tabspaces; bp < mTerm.tabs + col; bp += tabspaces ) *bp = 1; } + /* update terminal size */ mTerm.col = col; mTerm.row = row; @@ -2582,6 +2601,14 @@ TerminalEmulator::TerminalEmulator( PtyPtr&& pty, ProcPtr&& process, } TerminalEmulator::~TerminalEmulator() { + for ( int i = 0; i < mTerm.row; i++ ) { + eeSAFE_FREE( mTerm.line[i] ); + eeSAFE_FREE( mTerm.alt[i] ); + } + eeSAFE_FREE( mTerm.dirty ); + eeSAFE_FREE( mTerm.tabs ); + eeSAFE_FREE( mStrescseq.buf ); + clearHistory(); { @@ -2686,4 +2713,9 @@ bool TerminalEmulator::update() { return read != 0; } +Term::~Term() { + eeSAFE_FREE( line ); + eeSAFE_FREE( alt ); +} + }} // namespace eterm::Terminal diff --git a/src/tools/ecode/terminalmanager.cpp b/src/tools/ecode/terminalmanager.cpp index aa32de38a..e4b6dbecd 100644 --- a/src/tools/ecode/terminalmanager.cpp +++ b/src/tools/ecode/terminalmanager.cpp @@ -172,6 +172,7 @@ UITerminal* TerminalManager::createNewTerminal( const std::string& title, UITabW ? workingDir : ( !mApp->getCurrentProject().empty() ? mApp->getCurrentProject() : "" ), 10000, nullptr, mUseFrameBuffer ); + term->getTerm()->getTerminal()->setAllowMemoryTrimnming( true ); auto ret = mApp->getSplitter()->createWidgetInTabWidget( tabWidget, term, title.empty() ? mApp->i18n( "shell", "Shell" ).toUtf8() : title, true ); mApp->getSplitter()->removeUnusedTab( tabWidget ); diff --git a/src/tools/eterm/eterm.cpp b/src/tools/eterm/eterm.cpp index f0b3e0cd5..6f437f094 100644 --- a/src/tools/eterm/eterm.cpp +++ b/src/tools/eterm/eterm.cpp @@ -217,6 +217,7 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) { file.isRegularFile() && file.isExecutable() ? file.getFilepath() : shell.Get(), {}, file.getDirectoryPath(), historySize.Get(), nullptr, fb.Get(), !( file.isRegularFile() && file.isExecutable() ) ); + terminal->getTerminal()->setAllowMemoryTrimnming( true ); terminal->pushEventCallback( [&]( const TerminalDisplay::Event& event ) { if ( event.type == TerminalDisplay::EventType::TITLE ) { windowStringData = event.eventData;