File indexing completed on 2024-11-10 04:40:45

0001 /*
0002     SPDX-FileCopyrightText: 2016 Daniel Vrátil <dvratil@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "akonadicore_debug.h"
0008 #include "session_p.h"
0009 #include "sessionthread_p.h"
0010 
0011 #include <QCoreApplication>
0012 #include <QThread>
0013 
0014 Q_DECLARE_METATYPE(Akonadi::Connection::ConnectionType)
0015 Q_DECLARE_METATYPE(Akonadi::Connection *)
0016 Q_DECLARE_METATYPE(Akonadi::CommandBuffer *)
0017 
0018 using namespace Akonadi;
0019 
0020 SessionThread::SessionThread(QObject *parent)
0021     : QObject(parent)
0022 {
0023     qRegisterMetaType<Connection::ConnectionType>();
0024     qRegisterMetaType<Connection *>();
0025     qRegisterMetaType<CommandBuffer *>();
0026 
0027     auto thread = new QThread();
0028     thread->setObjectName(QLatin1StringView("SessionThread"));
0029     moveToThread(thread);
0030     thread->start();
0031 }
0032 
0033 SessionThread::~SessionThread()
0034 {
0035     QMetaObject::invokeMethod(this, &SessionThread::doThreadQuit, Qt::QueuedConnection);
0036     if (!thread()->wait(10 * 1000)) {
0037         thread()->terminate();
0038         // Make sure to wait until it's done, otherwise it can crash when the pthread callback is called
0039         thread()->wait();
0040     }
0041     delete thread();
0042 }
0043 
0044 void SessionThread::addConnection(Connection *connection)
0045 {
0046     connection->moveToThread(thread());
0047     const bool invoke = QMetaObject::invokeMethod(this, "doAddConnection", Qt::BlockingQueuedConnection, Q_ARG(Akonadi::Connection *, connection));
0048     Q_ASSERT(invoke);
0049     Q_UNUSED(invoke)
0050 }
0051 
0052 void SessionThread::doAddConnection(Connection *connection)
0053 {
0054     Q_ASSERT(thread() == QThread::currentThread());
0055     Q_ASSERT(!mConnections.contains(connection));
0056 
0057     connect(connection, &QObject::destroyed, this, [this](QObject *obj) {
0058         mConnections.removeOne(static_cast<Connection *>(obj));
0059     });
0060     mConnections.push_back(connection);
0061 }
0062 
0063 void SessionThread::destroyConnection(Connection *connection)
0064 {
0065     if (QCoreApplication::closingDown()) {
0066         return;
0067     }
0068 
0069     const bool invoke = QMetaObject::invokeMethod(this, "doDestroyConnection", Qt::BlockingQueuedConnection, Q_ARG(Akonadi::Connection *, connection));
0070     Q_ASSERT(invoke);
0071     Q_UNUSED(invoke)
0072 }
0073 
0074 void SessionThread::doDestroyConnection(Connection *connection)
0075 {
0076     Q_ASSERT(thread() == QThread::currentThread());
0077     Q_ASSERT(mConnections.contains(connection));
0078 
0079     connection->disconnect(this);
0080     connection->doCloseConnection();
0081     mConnections.removeAll(connection);
0082     delete connection;
0083 }
0084 
0085 void SessionThread::doThreadQuit()
0086 {
0087     Q_ASSERT(thread() == QThread::currentThread());
0088 
0089     for (Connection *conn : std::as_const(mConnections)) {
0090         conn->disconnect(this);
0091         conn->doCloseConnection(); // we can call directly because we are in the correct thread
0092         delete conn;
0093     }
0094 
0095     thread()->quit();
0096 }
0097 
0098 #include "moc_sessionthread_p.cpp"