mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-25 14:40:26 -05:00
The GUI thread deadlocked on a non-recursive QMutex during OSDU well import. The download-completion slots and DataLoadController::onTaskFinished held a mutex while triggering progress updates, which call QApplication::processEvents(). That re-enters the event loop and dispatches another queued parquet-download-complete event for a different well, whose handler then blocks trying to lock the same mutex. Release the mutex before emitting taskDone in the OSDU well path and well log data loaders, and before calling incrementProgress() in onTaskFinished. The map access that the mutex protects stays inside the locked scope; the captured ProgressInfo outlives the call (kept alive by blockUntilDone) and incrementProgress() is thread-safe via self-marshaling to the GUI thread. Fixes #14230.
134 lines
5.0 KiB
C++
134 lines
5.0 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2024- Equinor ASA
|
|
//
|
|
// ResInsight is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
|
// for more details.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "RimOsduWellPathDataLoader.h"
|
|
|
|
#include "Cloud/RiaOsduConnector.h"
|
|
#include "RiaApplication.h"
|
|
#include "RiaLogging.h"
|
|
#include "RiaQStringFormatter.h"
|
|
|
|
#include "RimOsduWellPath.h"
|
|
|
|
#include "RifOsduWellPathReader.h"
|
|
|
|
#include "Well/RigWellPath.h"
|
|
|
|
#include "cafProgressInfo.h"
|
|
|
|
#include <QApplication>
|
|
#include <QObject>
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimOsduWellPathDataLoader::RimOsduWellPathDataLoader()
|
|
: caf::DataLoader()
|
|
{
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimOsduWellPathDataLoader::loadData( caf::PdmObject& pdmObject, const QString& dataType, int taskId, caf::ProgressInfo& progressInfo )
|
|
{
|
|
RiaApplication* app = RiaApplication::instance();
|
|
RiaOsduConnector* osduConnector = app->makeOsduConnector();
|
|
if ( !osduConnector )
|
|
{
|
|
RiaLogging::error( "Failed to create OSDU connector" );
|
|
return;
|
|
}
|
|
|
|
// TODO: this is weird?
|
|
m_dataType = dataType;
|
|
|
|
auto oWPath = dynamic_cast<RimOsduWellPath*>( &pdmObject );
|
|
if ( oWPath )
|
|
{
|
|
connect( osduConnector,
|
|
SIGNAL( parquetDownloadFinished( const QByteArray&, const QString&, const QString& ) ),
|
|
this,
|
|
SLOT( parquetDownloadComplete( const QByteArray&, const QString&, const QString& ) ),
|
|
Qt::ConnectionType( Qt::QueuedConnection | Qt::UniqueConnection ) );
|
|
|
|
QString trajectoryId = oWPath->wellboreTrajectoryId();
|
|
m_wellPaths[trajectoryId] = oWPath;
|
|
m_taskIds[trajectoryId] = taskId;
|
|
osduConnector->requestWellboreTrajectoryParquetDataById( trajectoryId );
|
|
}
|
|
QApplication::processEvents();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimOsduWellPathDataLoader::isRunnable() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimOsduWellPathDataLoader::cancel()
|
|
{
|
|
RiaApplication* app = RiaApplication::instance();
|
|
RiaOsduConnector* osduConnector = app->makeOsduConnector();
|
|
|
|
for ( auto& [trajectoryId, taskId] : m_taskIds )
|
|
{
|
|
osduConnector->cancelRequestForId( trajectoryId );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimOsduWellPathDataLoader::parquetDownloadComplete( const QByteArray& contents, const QString& url, const QString& id )
|
|
{
|
|
int taskId = -1;
|
|
{
|
|
QMutexLocker lock( &m_mutex );
|
|
|
|
if ( m_wellPaths.find( id ) == m_wellPaths.end() || m_taskIds.find( id ) == m_taskIds.end() ) return;
|
|
|
|
RiaLogging::info( std::format( "Parquet download complete. Id: {} Size: {}", id, contents.size() ) );
|
|
taskId = m_taskIds[id];
|
|
|
|
if ( !contents.isEmpty() )
|
|
{
|
|
auto oWPath = m_wellPaths[id];
|
|
auto [wellPathGeometry, errorMessage] = RifOsduWellPathReader::readWellPathData( contents, oWPath->datumElevationFromOsdu() );
|
|
if ( wellPathGeometry.notNull() )
|
|
{
|
|
oWPath->setWellPathGeometry( wellPathGeometry.p() );
|
|
}
|
|
else
|
|
{
|
|
RiaLogging::warning( errorMessage.toStdString() );
|
|
}
|
|
}
|
|
}
|
|
|
|
// The lock is released above before emitting taskDone. The signal is delivered synchronously and triggers
|
|
// progress updates that call QApplication::processEvents(), which can re-enter this slot for another
|
|
// well. Holding the non-recursive m_mutex across send() would then deadlock the GUI thread (#14230).
|
|
taskDone.send( m_dataType, taskId );
|
|
}
|