diff --git a/src/server/qgsfcgiserverresponse.cpp b/src/server/qgsfcgiserverresponse.cpp index 3d501fde3335..818b03123805 100644 --- a/src/server/qgsfcgiserverresponse.cpp +++ b/src/server/qgsfcgiserverresponse.cpp @@ -27,6 +27,8 @@ #include "qgslogger.h" #include +#include +#include #if defined(Q_OS_UNIX) && !defined(Q_OS_ANDROID) #include @@ -56,6 +58,12 @@ typedef struct QgsFCGXStreamData } QgsFCGXStreamData; #endif +using namespace std::chrono_literals; + + +std::timed_mutex socketMonitoringMutex; + + // QgsSocketMonitoringThread constructor QgsSocketMonitoringThread::QgsSocketMonitoringThread( std::shared_ptr feedback ) : mFeedback( feedback ) @@ -100,18 +108,9 @@ QgsSocketMonitoringThread::~QgsSocketMonitoringThread() // Informs the thread to quit void QgsSocketMonitoringThread::setResponseFinished( bool responseFinished ) { - mIsResponseFinished = responseFinished; + mIsResponseFinished.store( responseFinished ); qDebug() << QDateTime::currentDateTime().toString( Qt::ISODateWithMs ).toStdString().c_str() - << "FCGIServer::setResponseFinished to:" << mIsResponseFinished; -} - -// Keep shared ptr reference to avoid too early deletion -void QgsSocketMonitoringThread::setShared( std::shared_ptr ptr ) -{ - mySelf = ptr; - qDebug() << QDateTime::currentDateTime().toString( Qt::ISODateWithMs ).toStdString().c_str() - << "FCGIServer::setShared count:" << mySelf.use_count(); - + << "FCGIServer::setResponseFinished to:" << mIsResponseFinished.load(); } void QgsSocketMonitoringThread::run( ) @@ -127,11 +126,12 @@ void QgsSocketMonitoringThread::run( ) } #if defined(Q_OS_UNIX) && !defined(Q_OS_ANDROID) + mIsResponseFinished.store( false ); char c; qDebug() << QDateTime::currentDateTime().toString( Qt::ISODateWithMs ).toStdString().c_str() << "FCGIServer::run" << threadId - << "run mIsResponseFinished:" << mIsResponseFinished; - while ( !mIsResponseFinished ) + << "run mIsResponseFinished:" << mIsResponseFinished.load(); + while ( false == mIsResponseFinished.load() ) { const ssize_t x = recv( mIpcFd, &c, 1, MSG_PEEK | MSG_DONTWAIT ); // see https://stackoverflow.com/a/12402596 if ( ( x != 0 ) ) // && errno == EAGAIN ) || ( x == 0 && errno == 0 ) ) @@ -145,10 +145,10 @@ void QgsSocketMonitoringThread::run( ) else { ssize_t x2 = 0; - for ( int i = 0; x2 == 0 && i < 10; i++ ) + for ( int i = 0; false == mIsResponseFinished.load() && x2 == 0 && i < 10; i++ ) { x2 = recv( mIpcFd, &c, 1, MSG_PEEK | MSG_DONTWAIT ); // see https://stackoverflow.com/a/12402596 - QThread::msleep( 50L ); + std::this_thread::sleep_for( 50ms ); } if ( x2 == 0 ) { @@ -167,10 +167,11 @@ void QgsSocketMonitoringThread::run( ) } } - QThread::msleep( 333L ); + if ( socketMonitoringMutex.try_lock_for( 333ms ) ) + socketMonitoringMutex.unlock(); } - if ( mIsResponseFinished ) + if ( mIsResponseFinished.load() ) { QgsDebugMsgLevel( QStringLiteral( "FCGIServer::run %1: socket monitoring quits normally." ).arg( threadId ), 1 ); } @@ -183,8 +184,7 @@ void QgsSocketMonitoringThread::run( ) // decrease the own count to allow deletion. qDebug() << QDateTime::currentDateTime().toString( Qt::ISODateWithMs ).toStdString().c_str() << "FCGIServer::run" << threadId - << "shared count:" << mySelf.use_count(); - mySelf = nullptr; + << "thread quit"; } @@ -196,6 +196,7 @@ QgsFcgiServerResponse::QgsFcgiServerResponse( QgsServerRequest::Method method ) : mMethod( method ) , mFeedback( new QgsFeedback ) { + socketMonitoringMutex.lock(); qDebug() << QDateTime::currentDateTime().toString( Qt::ISODateWithMs ).toStdString().c_str() << "==================================================================================================="; mBuffer.open( QIODevice::ReadWrite ); @@ -204,12 +205,11 @@ QgsFcgiServerResponse::QgsFcgiServerResponse( QgsServerRequest::Method method ) // This is not a unique_ptr because we want the response and the thread to not depend on eachother lifecycle. // The shared ptr is passed to the thread to increase the owner count and avoid QgsSocketMonitoringThread deletion // when the thread is still running in the background. - mSocketMonitoringThread = std::make_shared( mFeedback ); - mSocketMonitoringThread->setShared( mSocketMonitoringThread ); + mSocketMonitoringThread = std::make_unique( mFeedback ); // start and detach the monitoring thread - std::thread mThread = std::thread( &QgsSocketMonitoringThread::run, mSocketMonitoringThread ); - mThread.detach(); + mThread = std::thread( &QgsSocketMonitoringThread::run, mSocketMonitoringThread.get() ); + //mThread.detach(); } QgsFcgiServerResponse::~QgsFcgiServerResponse() @@ -217,9 +217,10 @@ QgsFcgiServerResponse::~QgsFcgiServerResponse() mFinished = true; // Inform the thread to quit when it ends its while loop mSocketMonitoringThread->setResponseFinished( mFinished ); + socketMonitoringMutex.unlock(); // will release any try_lock in socket monitoring thread qDebug() << QDateTime::currentDateTime().toString( Qt::ISODateWithMs ).toStdString().c_str() - << "QgsFcgiServerResponse::destructor" - << "count:" << mSocketMonitoringThread.use_count(); + << "QgsFcgiServerResponse::destructor"; + mThread.join(); } void QgsFcgiServerResponse::removeHeader( const QString &key ) diff --git a/src/server/qgsfcgiserverresponse.h b/src/server/qgsfcgiserverresponse.h index 96b038120186..64cd92e8c0c9 100644 --- a/src/server/qgsfcgiserverresponse.h +++ b/src/server/qgsfcgiserverresponse.h @@ -26,7 +26,7 @@ #include "qgsserverresponse.h" #include -#include +#include /** * \ingroup server @@ -48,13 +48,11 @@ class QgsSocketMonitoringThread void run( ); void setResponseFinished( bool responseFinished ); - void setShared( std::shared_ptr ptr ); private: - bool mIsResponseFinished = false; + std::atomic_bool mIsResponseFinished; std::shared_ptr mFeedback; int mIpcFd = -1; - std::shared_ptr mySelf; }; /** @@ -121,7 +119,8 @@ class SERVER_EXPORT QgsFcgiServerResponse: public QgsServerResponse QgsServerRequest::Method mMethod; int mStatusCode = 0; - std::shared_ptr mSocketMonitoringThread; + std::unique_ptr mSocketMonitoringThread; + std::thread mThread; std::shared_ptr mFeedback; };