1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

refactor(ipc): cleanup and improve debug messages

This commit is contained in:
sudden6 2018-12-18 23:37:59 +01:00
parent 49507d76d8
commit 5afa78cd4d
No known key found for this signature in database
GPG Key ID: 279509B499E032B9

View File

@ -82,14 +82,15 @@ IPC::IPC(uint32_t profileId)
IPC::~IPC() IPC::~IPC()
{ {
if (globalMemory.lock()) { if (!globalMemory.lock()) {
if (isCurrentOwnerNoLock()) {
global()->globalId = 0;
}
globalMemory.unlock();
} else {
qWarning() << "Failed to lock in ~IPC"; qWarning() << "Failed to lock in ~IPC";
return;
} }
if (isCurrentOwnerNoLock()) {
global()->globalId = 0;
}
globalMemory.unlock();
} }
/** /**
@ -97,42 +98,46 @@ IPC::~IPC()
* @param name Name to set in IPC event. * @param name Name to set in IPC event.
* @param data Data to set in IPC event (default QByteArray()). * @param data Data to set in IPC event (default QByteArray()).
* @param dest Settings::getCurrentProfileId() or 0 (main instance, default). * @param dest Settings::getCurrentProfileId() or 0 (main instance, default).
* @return Time the event finished. * @return Time the event finished or 0 on error.
*/ */
time_t IPC::postEvent(const QString& name, const QByteArray& data, uint32_t dest) time_t IPC::postEvent(const QString& name, const QByteArray& data, uint32_t dest)
{ {
QByteArray binName = name.toUtf8(); QByteArray binName = name.toUtf8();
if (binName.length() > (int32_t)sizeof(IPCEvent::name)) if (binName.length() > (int32_t)sizeof(IPCEvent::name)) {
return 0; return 0;
}
if (data.length() > (int32_t)sizeof(IPCEvent::data)) if (data.length() > (int32_t)sizeof(IPCEvent::data)) {
return 0; return 0;
}
if (globalMemory.lock()) { if (!globalMemory.lock()) {
IPCEvent* evt = nullptr;
IPCMemory* mem = global();
time_t result = 0;
for (uint32_t i = 0; !evt && i < EVENT_QUEUE_SIZE; ++i) {
if (mem->events[i].posted == 0)
evt = &mem->events[i];
}
if (evt) {
memset(evt, 0, sizeof(IPCEvent));
memcpy(evt->name, binName.constData(), binName.length());
memcpy(evt->data, data.constData(), data.length());
mem->lastEvent = evt->posted = result = qMax(mem->lastEvent + 1, time(nullptr));
evt->dest = dest;
evt->sender = getpid();
qDebug() << "postEvent " << name << "to" << dest;
}
globalMemory.unlock();
return result;
} else
qDebug() << "Failed to lock in postEvent()"; qDebug() << "Failed to lock in postEvent()";
return 0;
}
return 0; IPCEvent* evt = nullptr;
IPCMemory* mem = global();
time_t result = 0;
for (uint32_t i = 0; !evt && i < EVENT_QUEUE_SIZE; ++i) {
if (mem->events[i].posted == 0) {
evt = &mem->events[i];
}
}
if (evt) {
memset(evt, 0, sizeof(IPCEvent));
memcpy(evt->name, binName.constData(), binName.length());
memcpy(evt->data, data.constData(), data.length());
mem->lastEvent = evt->posted = result = qMax(mem->lastEvent + 1, time(nullptr));
evt->dest = dest;
evt->sender = getpid();
qDebug() << "postEvent " << name << "to" << dest;
}
globalMemory.unlock();
return result;
} }
bool IPC::isCurrentOwner() bool IPC::isCurrentOwner()
@ -159,18 +164,21 @@ void IPC::registerEventHandler(const QString& name, IPCEventHandler handler)
bool IPC::isEventAccepted(time_t time) bool IPC::isEventAccepted(time_t time)
{ {
bool result = false; bool result = false;
if (globalMemory.lock()) { if (!globalMemory.lock()) {
if (difftime(global()->lastProcessed, time) > 0) { return result;
IPCMemory* mem = global(); }
for (uint32_t i = 0; i < EVENT_QUEUE_SIZE; ++i) {
if (mem->events[i].posted == time && mem->events[i].processed) { if (difftime(global()->lastProcessed, time) > 0) {
result = mem->events[i].accepted; IPCMemory* mem = global();
break; for (uint32_t i = 0; i < EVENT_QUEUE_SIZE; ++i) {
} if (mem->events[i].posted == time && mem->events[i].processed) {
result = mem->events[i].accepted;
break;
} }
} }
globalMemory.unlock();
} }
globalMemory.unlock();
return result; return result;
} }
@ -181,8 +189,9 @@ bool IPC::waitUntilAccepted(time_t postTime, int32_t timeout /*=-1*/)
forever forever
{ {
result = isEventAccepted(postTime); result = isEventAccepted(postTime);
if (result || (timeout > 0 && difftime(time(nullptr), start) >= timeout)) if (result || (timeout > 0 && difftime(time(nullptr), start) >= timeout)) {
break; break;
}
qApp->processEvents(); qApp->processEvents();
QThread::msleep(0); QThread::msleep(0);
@ -214,12 +223,14 @@ IPC::IPCEvent* IPC::fetchEvent()
// and events that were processed and EVENT_GC_TIMEOUT passed after // and events that were processed and EVENT_GC_TIMEOUT passed after
// so sending instance has time to react to those events. // so sending instance has time to react to those events.
if ((evt->processed && difftime(time(nullptr), evt->processed) > EVENT_GC_TIMEOUT) if ((evt->processed && difftime(time(nullptr), evt->processed) > EVENT_GC_TIMEOUT)
|| (!evt->processed && difftime(time(nullptr), evt->posted) > EVENT_GC_TIMEOUT)) || (!evt->processed && difftime(time(nullptr), evt->posted) > EVENT_GC_TIMEOUT)) {
memset(evt, 0, sizeof(IPCEvent)); memset(evt, 0, sizeof(IPCEvent));
}
if (evt->posted && !evt->processed && evt->sender != getpid() if (evt->posted && !evt->processed && evt->sender != getpid()
&& (evt->dest == profileId || (evt->dest == 0 && isCurrentOwnerNoLock()))) && (evt->dest == profileId || (evt->dest == 0 && isCurrentOwnerNoLock()))) {
return evt; return evt;
}
} }
return nullptr; return nullptr;
@ -228,58 +239,67 @@ IPC::IPCEvent* IPC::fetchEvent()
bool IPC::runEventHandler(IPCEventHandler handler, const QByteArray& arg) bool IPC::runEventHandler(IPCEventHandler handler, const QByteArray& arg)
{ {
bool result = false; bool result = false;
if (QThread::currentThread() == qApp->thread()) if (QThread::currentThread() == qApp->thread()) {
result = handler(arg); result = handler(arg);
else } else {
QMetaObject::invokeMethod(this, "runEventHandler", Qt::BlockingQueuedConnection, QMetaObject::invokeMethod(this, "runEventHandler", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, result), Q_ARG(IPCEventHandler, handler), Q_RETURN_ARG(bool, result), Q_ARG(IPCEventHandler, handler),
Q_ARG(const QByteArray&, arg)); Q_ARG(const QByteArray&, arg));
}
return result; return result;
} }
void IPC::processEvents() void IPC::processEvents()
{ {
if (globalMemory.lock()) { if (!globalMemory.lock()) {
IPCMemory* mem = global(); timer.start();
return;
}
if (mem->globalId == globalId) { IPCMemory* mem = global();
// We're the owner, let's process those events
if (mem->globalId == globalId) {
// We're the owner, let's process those events
mem->lastProcessed = time(nullptr);
} else {
// Only the owner processes events. But if the previous owner's dead, we can take
// ownership now
if (difftime(time(nullptr), mem->lastProcessed) >= OWNERSHIP_TIMEOUT_S) {
qDebug() << "Previous owner timed out, taking ownership" << mem->globalId << "->"
<< globalId;
// Ignore events that were not meant for this instance
memset(mem, 0, sizeof(IPCMemory));
mem->globalId = globalId;
mem->lastProcessed = time(nullptr); mem->lastProcessed = time(nullptr);
} else {
// Only the owner processes events. But if the previous owner's dead, we can take
// ownership now
if (difftime(time(nullptr), mem->lastProcessed) >= OWNERSHIP_TIMEOUT_S) {
qDebug() << "Previous owner timed out, taking ownership" << mem->globalId << "->"
<< globalId;
// Ignore events that were not meant for this instance
memset(mem, 0, sizeof(IPCMemory));
mem->globalId = globalId;
mem->lastProcessed = time(nullptr);
}
// Non-main instance is limited to events destined for specific profile it runs
} }
// Non-main instance is limited to events destined for specific profile it runs
}
while (IPCEvent* evt = fetchEvent()) { while (IPCEvent* evt = fetchEvent()) {
QString name = QString::fromUtf8(evt->name); QString name = QString::fromUtf8(evt->name);
auto it = eventHandlers.find(name); auto it = eventHandlers.find(name);
if (it != eventHandlers.end()) { if (it != eventHandlers.end()) {
qDebug() << "Processing event: " << name << ":" << evt->posted << "=" << evt->accepted; evt->accepted = runEventHandler(it.value(), evt->data);
evt->accepted = runEventHandler(it.value(), evt->data); qDebug() << "Processed event:" << name << "posted:" << evt->posted
if (evt->dest == 0) { << "accepted:" << evt->accepted;
// Global events should be processed only by instance that accepted event. if (evt->dest == 0) {
// Otherwise global // Global events should be processed only by instance that accepted event.
// event would be consumed by very first instance that gets to check it. // Otherwise global
if (evt->accepted) // event would be consumed by very first instance that gets to check it.
evt->processed = time(nullptr); if (evt->accepted) {
} else {
evt->processed = time(nullptr); evt->processed = time(nullptr);
} }
} else {
evt->processed = time(nullptr);
} }
} else {
qDebug() << "Received event:" << name << "without handler";
qDebug() << "Available handlers:" << eventHandlers.keys();
} }
globalMemory.unlock();
} }
globalMemory.unlock();
timer.start(); timer.start();
} }