view src/runguard.cpp @ 228:37d5f4329449

Implement single running instance check to prevent problems with the SQLite database.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 20 Mar 2018 13:45:21 +0200
parents
children
line wrap: on
line source

//
// Taken and modified from https://stackoverflow.com/questions/5006547/qt-best-practice-for-a-single-instance-app-protection
//
#include "runguard.h"
#include <QCryptographicHash>


namespace
{

QString generateKeyHash(const QString &key, const QString &salt)
{
    QByteArray data;

    data.append(key.toUtf8());
    data.append(salt.toUtf8());
    data = QCryptographicHash::hash(data, QCryptographicHash::Sha1).toHex();

    return data;
}

}


RunGuard::RunGuard(const QString &key)
    : key(key)
    , memLockKey(generateKeyHash(key, "_memLockKey"))
    , sharedmemKey(generateKeyHash(key, "_sharedmemKey"))
    , sharedMem(sharedmemKey)
    , memLock(memLockKey, 1)
{
    memLock.acquire();

    QSharedMemory fix(sharedmemKey); // Fix for *nix: http://habrahabr.ru/post/173281/
    fix.attach();

    memLock.release();
}


RunGuard::~RunGuard()
{
    release();
}


bool RunGuard::isAnotherRunning()
{
    if (sharedMem.isAttached())
        return false;

    memLock.acquire();

    const bool isRunning = sharedMem.attach();
    if (isRunning)
        sharedMem.detach();

    memLock.release();

    return isRunning;
}


bool RunGuard::tryToRun()
{
    if (isAnotherRunning())
        return false;

    memLock.acquire();
    const bool result = sharedMem.create(sizeof(quint64));
    memLock.release();

    if (!result)
        release();

    return result;
}


void RunGuard::release()
{
    memLock.acquire();

    if (sharedMem.isAttached())
        sharedMem.detach();

    memLock.release();
}