/*
    SPDX-FileCopyrightText: 2022 David Faure <faure@kde.org>
    SPDX-FileCopyrightText: 2022 Harald Sitter <sitter@kde.org>
    SPDX-License-Identifier: LGPL-2.0-or-later
*/

#include "kiocoredebug.h"
#include "slavebase.h"
#include "workerbase.h"
#include "workerbase_p.h"
#include "workerfactory.h"
#include "workerthread_p.h"

#include <QPluginLoader>

namespace KIO
{

#ifdef BUILD_TESTING
bool WorkerThread::s_testExitGateEnabled = false;
QSemaphore WorkerThread::s_testExitGate;

void WorkerThread::setTestExitGateEnabled(bool enabled)
{
    s_testExitGateEnabled = enabled;
}

void WorkerThread::releaseTestExitGate()
{
    s_testExitGate.release();
}
#endif

WorkerThread::WorkerThread(QObject *parent, WorkerFactory *factory, const QByteArray &appSocket, QPluginLoader *pluginLoader)
    : QThread(parent)
    , m_factory(factory)
    , m_appSocket(appSocket)
    , m_pluginLoader(pluginLoader)
{
}

WorkerThread::~WorkerThread()
{
    wait();
    if (m_pluginLoader) {
        m_pluginLoader->unload();
        delete m_pluginLoader;
    }
}

void WorkerThread::abort()
{
    QMutexLocker locker(&m_workerMutex);
    if (m_worker) { // not deleted yet
        m_worker->exit();
    }
}

void WorkerThread::run()
{
    qCDebug(KIO_CORE) << QThread::currentThreadId() << "Creating threaded worker";

    auto worker = m_factory->createWorker({}, m_appSocket);
    SlaveBase *base = &(worker->d->bridge);

    base->setRunInThread(true);
    setWorker(base);

    base->dispatchLoop();

    setWorker(nullptr); // before the actual deletion

#ifdef BUILD_TESTING
    if (s_testExitGateEnabled) {
        // Block here until the main thread releases us through its event loop, so a
        // synchronous join in Worker::deref() deadlocks deterministically (see header).
        s_testExitGate.acquire();
    }
#endif
}

void WorkerThread::setWorker(SlaveBase *worker)
{
    QMutexLocker locker(&m_workerMutex);
    m_worker = worker;
}

} // namespace KIO

#include "moc_workerthread_p.cpp"
