Added ConditionalLock.

Fixed a bug in ActionManager.
Fixed some bugs on UITableView and UITreeView.
Fixed a dead-lock un AutoCompleteModule.
This commit is contained in:
Martín Lucas Golini
2022-02-27 20:29:01 -03:00
parent a54da7d6da
commit 99110d6bef
10 changed files with 73 additions and 28 deletions

View File

@@ -24,6 +24,23 @@ class EE_API Lock : NonCopyable {
Mutex& mMutex; ///< Mutex to lock / unlock
};
class EE_API ConditionalLock : NonCopyable {
public:
/** @brief Construct the lock with a target mutex
* The mutex passed to Lock is automatically locked.
* @param condition Only if condition is true the mutex will be locked/unlocked.
* @param mutex Mutex to lock */
explicit ConditionalLock( bool condition, Mutex* mutex );
/** @brief Destructor
* The destructor of Lock automatically unlocks its mutex. */
~ConditionalLock();
private:
Mutex* mMutex{ nullptr }; ///< Mutex to lock / unlock
bool mCondition{ false };
};
}} // namespace EE::System
#endif

View File

@@ -136,11 +136,11 @@ class EE_API Model {
void endDeleteRows();
void endDeleteColumns();
Mutex& resourceLock();
Mutex& resourceMutex();
void acquireResourceLock() { mResourceLock.lock(); }
void acquireResourceMutex() { mResourceLock.lock(); }
void releaseResourceLock() { mResourceLock.unlock(); }
void releaseResourceMutex() { mResourceLock.unlock(); }
protected:
Model(){};

View File

@@ -101,7 +101,10 @@ void ActionManager::update( const Time& time ) {
Lock l( mMutex );
for ( auto it = mActions.begin(); it != mActions.end(); ++it ) {
// Actions can be added during action updates, we need to only iterate the current actions
auto actions = mActions;
for ( auto it = actions.begin(); it != actions.end(); ++it ) {
Action* action = *it;
action->update( time );

View File

@@ -11,4 +11,15 @@ Lock::~Lock() {
mMutex.unlock();
}
ConditionalLock::ConditionalLock( bool condition, Mutex* mutex ) :
mMutex( mutex ), mCondition( condition ) {
if ( mMutex && mCondition )
mMutex->lock();
}
ConditionalLock::~ConditionalLock() {
if ( mMutex && mCondition )
mMutex->unlock();
}
}} // namespace EE::System

View File

@@ -702,7 +702,7 @@ bool FileSystemModel::handleFileEvent( const FileEvent& event ) {
bool ret;
{
Lock l( resourceLock() );
Lock l( resourceMutex() );
ret = handleFileEventLocked( event );
}

View File

@@ -303,7 +303,7 @@ void Model::handleDelete( Operation const& operation ) {
}
}
Mutex& Model::resourceLock() {
Mutex& Model::resourceMutex() {
return mResourceLock;
}

View File

@@ -26,7 +26,7 @@ bool UITableView::isType( const Uint32& type ) const {
void UITableView::drawChilds() {
int realIndex = 0;
Lock l( const_cast<Model*>( getModel() )->resourceLock() );
ConditionalLock l( getModel() != nullptr, getModel() ? &getModel()->resourceMutex() : nullptr );
size_t start = mScrollOffset.y / getRowHeight();
size_t end =
eemin<size_t>( (size_t)eeceil( ( mScrollOffset.y + mSize.getHeight() ) / getRowHeight() ),
@@ -62,7 +62,8 @@ Node* UITableView::overFind( const Vector2f& point ) {
Node* pOver = NULL;
if ( mEnabled && mVisible ) {
Lock l( const_cast<Model*>( getModel() )->resourceLock() );
ConditionalLock l( getModel() != nullptr,
getModel() ? &getModel()->resourceMutex() : nullptr );
updateWorldPolygon();
if ( mWorldBounds.contains( point ) && mPoly.pointInside( point ) ) {
@@ -110,7 +111,7 @@ Node* UITableView::overFind( const Vector2f& point ) {
Float UITableView::getMaxColumnContentWidth( const size_t& colIndex, bool bestGuess ) {
Float lWidth = 0;
Lock l( const_cast<Model*>( getModel() )->resourceLock() );
ConditionalLock l( getModel() != nullptr, getModel() ? &getModel()->resourceMutex() : nullptr );
if ( getModel()->rowCount() == 0 )
return lWidth;
getUISceneNode()->setIsLoading( true );
@@ -175,7 +176,7 @@ Uint32 UITableView::onKeyDown( const KeyEvent& event ) {
return UIAbstractTableView::onKeyDown( event );
auto curIndex = getSelection().first();
int pageSize = eefloor( getVisibleArea().getHeight() / getRowHeight() ) - 1;
Lock l( const_cast<Model*>( getModel() )->resourceLock() );
ConditionalLock l( getModel() != nullptr, getModel() ? &getModel()->resourceMutex() : nullptr );
switch ( event.getKeyCode() ) {
case KEY_PAGEUP: {
if ( curIndex.row() - pageSize < 0 ) {
@@ -278,7 +279,8 @@ Uint32 UITableView::onKeyDown( const KeyEvent& event ) {
ModelIndex UITableView::findRowWithText( const std::string& text, const bool& caseSensitive,
const bool& exactMatch ) const {
const Model* model = getModel();
Lock l( const_cast<Model*>( getModel() )->resourceLock() );
ConditionalLock l( getModel() != nullptr,
getModel() ? &const_cast<Model*>( getModel() )->resourceMutex() : nullptr );
if ( !model || model->rowCount() == 0 )
return {};
size_t rc = model->rowCount();

View File

@@ -44,7 +44,7 @@ void UITreeView::traverseTree( TreeViewCallback callback ) const {
if ( !getModel() )
return;
auto& model = *getModel();
Lock l( const_cast<Model*>( getModel() )->resourceLock() );
Lock l( const_cast<Model*>( getModel() )->resourceMutex() );
int indentLevel = 0;
Float yOffset = getHeaderHeight();
int rowIndex = -1;
@@ -118,7 +118,8 @@ void UITreeView::bindNavigationClick( UIWidget* widget ) {
auto mouseEvent = static_cast<const MouseEvent*>( event );
auto idx = mouseEvent->getNode()->getParent()->asType<UITableRow>()->getCurIndex();
if ( mouseEvent->getFlags() & EE_BUTTON_LMASK ) {
Lock l( const_cast<Model*>( getModel() )->resourceLock() );
ConditionalLock l( getModel() != nullptr,
getModel() ? &getModel()->resourceMutex() : nullptr );
if ( getModel()->rowCount( idx ) ) {
auto& data = getIndexMetadata( idx );
data.open = !data.open;
@@ -157,7 +158,8 @@ UIWidget* UITreeView::setupCell( UITableCell* widget, UIWidget* rowWidget,
if ( icon ) {
Vector2f pos( icon->convertToNodeSpace( mouseEvent->getPosition().asFloat() ) );
if ( pos >= Vector2f::Zero && pos <= icon->getPixelsSize() ) {
Lock l( const_cast<Model*>( getModel() )->resourceLock() );
ConditionalLock l( getModel() != nullptr,
getModel() ? &getModel()->resourceMutex() : nullptr );
auto idx =
mouseEvent->getNode()->getParent()->asType<UITableRow>()->getCurIndex();
if ( getModel()->rowCount( idx ) ) {
@@ -646,7 +648,8 @@ void UITreeView::onSortColumn( const size_t& ) {
ModelIndex UITreeView::findRowWithText( const std::string& text, const bool& caseSensitive,
const bool& exactMatch ) const {
const Model* model = getModel();
Lock l( const_cast<Model*>( getModel() )->resourceLock() );
ConditionalLock l( getModel() != nullptr,
getModel() ? &const_cast<Model*>( getModel() )->resourceMutex() : nullptr );
if ( !model || model->rowCount() == 0 )
return {};
ModelIndex foundIndex = {};
@@ -692,7 +695,8 @@ ModelIndex UITreeView::selectRowWithPath( std::string path ) {
size_t rowCount = 0;
{
Lock l( const_cast<Model*>( getModel() )->resourceLock() );
ConditionalLock l( getModel() != nullptr,
getModel() ? &getModel()->resourceMutex() : nullptr );
rowCount = getModel()->rowCount( foundIndex );
}
if ( rowCount ) {

View File

@@ -445,10 +445,12 @@ static std::vector<std::string> fuzzyMatchSymbols( const AutoCompleteModule::Sym
void AutoCompleteModule::runUpdateSuggestions( const std::string& symbol,
const SymbolsList& symbols, UICodeEditor* editor ) {
Lock l( mLangSymbolsMutex );
Lock l2( mSuggestionsMutex );
mSuggestions = fuzzyMatchSymbols( symbols, symbol, mSuggestionsMaxVisible );
mSuggestionsEditor = editor;
{
Lock l( mLangSymbolsMutex );
Lock l2( mSuggestionsMutex );
mSuggestions = fuzzyMatchSymbols( symbols, symbol, mSuggestionsMaxVisible );
mSuggestionsEditor = editor;
}
editor->runOnMainThread( [editor] { editor->invalidateDraw(); } );
}

View File

@@ -1920,22 +1920,28 @@ void App::initProjectTreeView( const std::string& path ) {
return 1;
} );
if ( !path.empty() && FileSystem::fileExists( path ) ) {
if ( !path.empty() ) {
if ( FileSystem::isDirectory( path ) ) {
loadFolder( path );
} else {
std::string rpath( FileSystem::getRealPath( path ) );
std::string folderPath( FileSystem::fileRemoveFileName( rpath ) );
mFileSystemModel = FileSystemModel::New( FileSystem::fileRemoveFileName( rpath ),
FileSystemModel::Mode::FilesAndDirectories,
{ true, true, true } );
if ( FileSystem::isDirectory( folderPath ) ) {
mFileSystemModel = FileSystemModel::New(
folderPath, FileSystemModel::Mode::FilesAndDirectories, { true, true, true } );
mProjectTreeView->setModel( mFileSystemModel );
mProjectTreeView->setModel( mFileSystemModel );
if ( mFileSystemListener )
mFileSystemListener->setFileSystemModel( mFileSystemModel );
if ( mFileSystemListener )
mFileSystemListener->setFileSystemModel( mFileSystemModel );
loadFileFromPath( rpath, false );
if ( FileSystem::fileExists( rpath ) ) {
loadFileFromPath( rpath, false );
} else if ( FileSystem::fileCanWrite( folderPath ) ) {
loadFileFromPath( path, false );
}
}
}
} else {
loadFolder( "." );