#include <QSharedMemory>
#include <QSystemSemaphore>
+#include <QMutexLocker>
#include <QStringList>
+///////////////////////////////////////////////////////////////////////////////
+// Constants
+///////////////////////////////////////////////////////////////////////////////
+
static const size_t MAX_STR_LEN = 1024;
static const size_t MAX_ARG_CNT = 3;
static const size_t MAX_ENTRIES = 16;
static const char *s_key_sema_rd = "{D331CBB5-8BCD-4127-9105-E22281130C77}";
static const wchar_t *EMPTY_STRING = L"";
+static unsigned long TIMEOUT_MS = 12000;
typedef struct
{
#define IS_FIRST_INSTANCE(X) ((X) > 0)
///////////////////////////////////////////////////////////////////////////////
+// IPC Base Class
+///////////////////////////////////////////////////////////////////////////////
+
+class IPCCore : public QObject
+{
+ friend class IPC;
+ friend class IPCReceiveThread;
+ friend class IPCSendThread;
+
+public:
+ bool initialize(bool &firstInstance);
+
+ inline bool isInitialized(void)
+ {
+ return (m_initialized >= 0);
+ }
+
+protected:
+ IPCCore(void);
+ ~IPCCore(void);
+
+ bool popCommand(int &command, QStringList &args);
+ bool pushCommand(const int &command, const QStringList *args);
+
+ volatile int m_initialized;
+
+ QSharedMemory *m_sharedMemory;
+ QSystemSemaphore *m_semaphoreRd;
+ QSystemSemaphore *m_semaphoreWr;
+};
+
+///////////////////////////////////////////////////////////////////////////////
// Send Thread
///////////////////////////////////////////////////////////////////////////////
-IPCSendThread::IPCSendThread(IPC *ipc, const int &command, const QStringList &args)
+IPCSendThread::IPCSendThread(IPCCore *ipc, const int &command, const QStringList &args)
:
m_ipc(ipc), m_command(command), m_args(new QStringList(args))
{
X264_DELETE(m_args);
}
-
void IPCSendThread::run(void)
{
try
// Receive Thread
///////////////////////////////////////////////////////////////////////////////
-IPCReceiveThread::IPCReceiveThread(IPC *ipc)
+IPCReceiveThread::IPCReceiveThread(IPCCore *ipc)
:
m_ipc(ipc)
{
{
QStringList args;
int command;
- if(m_ipc->popCommand(command, args, &m_stopped))
+ if(m_ipc->popCommand(command, args))
{
- if((command >= 0) && (command < IPC::IPC_OPCODE_MAX))
- {
- emit receivedCommand(command, args);
- }
- else
+ if(!m_stopped)
{
- qWarning("IPC: Received the unknown opcode %d", command);
+ if((command >= 0) && (command < IPC_OPCODE_MAX))
+ {
+ emit receivedCommand(command, args);
+ }
+ else
+ {
+ qWarning("IPC: Received the unknown opcode %d", command);
+ }
}
}
+ else
+ {
+ m_stopped = true;
+ qWarning("IPC: Receive operation has failed -> stopping thread!");
+ }
}
}
///////////////////////////////////////////////////////////////////////////////
-// IPC Class
+// IPC Core Class
///////////////////////////////////////////////////////////////////////////////
-IPC::IPC(void)
+IPCCore::IPCCore(void)
{
m_initialized = -1;
m_sharedMemory = NULL;
m_semaphoreWr = NULL;
m_semaphoreRd = NULL;
- m_recvThread = NULL;
}
-IPC::~IPC(void)
+IPCCore::~IPCCore(void)
{
- if(m_recvThread && m_recvThread->isRunning())
- {
- qWarning("Receive thread still running -> terminating!");
- m_recvThread->terminate();
- m_recvThread->wait();
- }
-
- X264_DELETE(m_recvThread);
X264_DELETE(m_sharedMemory);
X264_DELETE(m_semaphoreWr);
X264_DELETE(m_semaphoreRd);
}
-bool IPC::initialize(bool &firstInstance)
+bool IPCCore::initialize(bool &firstInstance)
{
firstInstance = false;
return false;
}
-bool IPC::pushCommand(const int &command, const QStringList *args)
+bool IPCCore::pushCommand(const int &command, const QStringList *args)
{
if(m_initialized < 0)
{
- qWarning("Error: IPC not initialized yet!");
- return false;
+ throw std::runtime_error("IPC not initialized!");
}
if(!m_semaphoreWr->acquire())
memory->data[memory->posWr].command = command;
for(int i = 0; i < MAX_ARG_CNT; i++)
{
- const wchar_t *current = (i < args->count()) ? ((const wchar_t*)((*args)[i].utf16())) : EMPTY_STRING;
+ const wchar_t *current = (args && (i < args->count())) ? ((const wchar_t*)((*args)[i].utf16())) : EMPTY_STRING;
wcsncpy_s(memory->data[memory->posWr].args[i], MAX_STR_LEN, current, _TRUNCATE);
}
memory->posWr = (memory->posWr + 1) % MAX_ENTRIES;
return success;
}
-bool IPC::popCommand(int &command, QStringList &args, volatile bool *abortFlag)
+bool IPCCore::popCommand(int &command, QStringList &args)
{
command = -1;
args.clear();
if(m_initialized < 0)
{
- qWarning("Error: IPC not initialized yet!");
- return false;
+ throw std::runtime_error("IPC not initialized!");
}
if(!m_semaphoreRd->acquire())
}
else
{
- if(!abortFlag)
- {
- qWarning("IPC: Shared memory is empty -> cannot pop string!");
- }
+ qWarning("IPC: Shared memory is empty -> cannot pop string!");
success = false;
}
}
return success;
}
-bool IPC::sendAsync(const int &command, const QStringList &args, const int timeout)
+///////////////////////////////////////////////////////////////////////////////
+// IPC Handler Class
+///////////////////////////////////////////////////////////////////////////////
+
+IPC::IPC(void)
+:
+ m_mutex(QMutex::Recursive)
{
- if(m_initialized < 0)
+ m_ipcCore = new IPCCore();
+ m_recvThread = NULL;
+}
+
+IPC::~IPC(void)
+{
+ if(m_recvThread && m_recvThread->isRunning())
+ {
+ qWarning("Receive thread still running -> terminating!");
+ m_recvThread->terminate();
+ m_recvThread->wait();
+ }
+ X264_DELETE(m_recvThread);
+ X264_DELETE(m_ipcCore);
+}
+
+bool IPC::initialize(bool &firstInstance)
+{
+ QMutexLocker lock(&m_mutex);
+ return m_ipcCore->initialize(firstInstance);
+}
+
+bool IPC::sendAsync(const int &command, const QStringList &args)
+{
+ QMutexLocker lock(&m_mutex);
+
+ if(!m_ipcCore->isInitialized())
{
qWarning("Error: IPC not initialized yet!");
return false;
}
- IPCSendThread sendThread(this, command, args);
+ IPCSendThread sendThread(m_ipcCore, command, args);
sendThread.start();
- if(!sendThread.wait(timeout))
+ if(!sendThread.wait(TIMEOUT_MS))
{
qWarning("IPC send operation encountered timeout!");
sendThread.terminate();
bool IPC::startListening(void)
{
- if(m_initialized < 0)
+ QMutexLocker lock(&m_mutex);
+
+ if(!m_ipcCore->isInitialized())
{
qWarning("Error: IPC not initialized yet!");
return false;
if(!m_recvThread)
{
- m_recvThread = new IPCReceiveThread(this);
+ m_recvThread = new IPCReceiveThread(m_ipcCore);
connect(m_recvThread, SIGNAL(receivedCommand(int,QStringList)), this, SIGNAL(receivedCommand(int,QStringList)), Qt::QueuedConnection);
}
bool IPC::stopListening(void)
{
- if(m_initialized < 0)
+ QMutexLocker lock(&m_mutex);
+
+ if(!m_ipcCore->isInitialized())
{
qWarning("Error: IPC not initialized yet!");
return false;
if(m_recvThread && m_recvThread->isRunning())
{
m_recvThread->stop();
- m_semaphoreRd->release();
+ sendAsync(IPC_OPCODE_MAX, QStringList()); //push dummy command to unblock thread!
- if(!m_recvThread->wait(5000))
+ if(!m_recvThread->wait(TIMEOUT_MS))
{
qWarning("Receive thread seems deadlocked -> terminating!");
m_recvThread->terminate();
return true;
}
+
+bool IPC::isInitialized(void)
+{
+ QMutexLocker lock(&m_mutex);
+ return m_ipcCore->isInitialized();
+}
+
+bool IPC::isListening(void)
+{
+ QMutexLocker lock(&m_mutex);
+ return (isInitialized() && m_recvThread && m_recvThread->isRunning());
+}
#pragma once
#include <QThread>
+#include <QMutex>
class QSharedMemory;
class QStringList;
class QSystemSemaphore;
-class IPCSendThread;
+
+class IPCCore;
class IPCReceiveThread;
+class IPCSendThread;
+
+//IPC Commands
+static const int IPC_OPCODE_PING = 0;
+static const int IPC_OPCODE_ADD_FILE = 1;
+static const int IPC_OPCODE_ADD_JOB = 2;
+static const int IPC_OPCODE_MAX = 3;
+
+///////////////////////////////////////////////////////////////////////////////
+// IPC Handler Class
+///////////////////////////////////////////////////////////////////////////////
class IPC : public QObject
{
Q_OBJECT
- friend class IPCReceiveThread;
- friend class IPCSendThread;
public:
IPC(void);
~IPC(void);
- static const int IPC_OPCODE_PING = 0;
- static const int IPC_OPCODE_ADD_FILE = 1;
- static const int IPC_OPCODE_ADD_JOB = 2;
- static const int IPC_OPCODE_MAX = 3;
-
bool initialize(bool &firstInstance);
- bool sendAsync(const int &command, const QStringList &args, const int timeout = 5000);
-
- inline bool isInitialized(void) { return (m_initialized >= 0); }
- inline bool isListening(void);
+ bool sendAsync(const int &command, const QStringList &args);
+ bool isInitialized(void);
+ bool isListening(void);
public slots:
bool startListening(void);
void receivedCommand(const int &command, const QStringList &args);
protected:
- bool popCommand(int &command, QStringList &args, volatile bool *abortFlag);
- bool pushCommand(const int &command, const QStringList *args);
-
- int m_initialized;
-
- QSharedMemory *m_sharedMemory;
- QSystemSemaphore *m_semaphoreRd;
- QSystemSemaphore *m_semaphoreWr;
+ IPCCore *m_ipcCore;
IPCReceiveThread *m_recvThread;
+ QMutex m_mutex;
};
///////////////////////////////////////////////////////////////////////////////
friend class IPC;
protected:
- IPCSendThread(IPC *ipc, const int &command, const QStringList &args);
+ IPCSendThread(IPCCore *ipc, const int &command, const QStringList &args);
IPCSendThread::~IPCSendThread(void);
inline bool result(void) { return m_result; }
-
virtual void run(void);
private:
volatile bool m_result;
- IPC *const m_ipc;
+ IPCCore *const m_ipc;
const int m_command;
const QStringList *m_args;
};
friend class IPC;
protected:
- IPCReceiveThread(IPC *ipc);
- inline void stop(void) { m_stopped = true; }
+ IPCReceiveThread(IPCCore *ipc);
+ inline void stop(void) { m_stopped = true; }
virtual void run(void);
signals:
private:
void receiveLoop(void);
volatile bool m_stopped;
- IPC *const m_ipc;
+ IPCCore *const m_ipc;
};
-
-///////////////////////////////////////////////////////////////////////////////
-// Inline Functions
-///////////////////////////////////////////////////////////////////////////////
-
-inline bool IPC::isListening(void)
-{
- return (m_recvThread && m_recvThread->isRunning());
-}
connect(ui->actionWebJEEB, SIGNAL(triggered()), this, SLOT(showWebLink()));
connect(ui->actionWebAvisynth32, SIGNAL(triggered()), this, SLOT(showWebLink()));
connect(ui->actionWebAvisynth64, SIGNAL(triggered()), this, SLOT(showWebLink()));
+ connect(ui->actionWebAvisynthPlus, SIGNAL(triggered()), this, SLOT(showWebLink()));
connect(ui->actionWebVapourSynth, SIGNAL(triggered()), this, SLOT(showWebLink()));
connect(ui->actionWebVapourSynthDocs, SIGNAL(triggered()), this, SLOT(showWebLink()));
connect(ui->actionWebWiki, SIGNAL(triggered()), this, SLOT(showWebLink()));
if(QObject::sender() == ui->actionWebJEEB) QDesktopServices::openUrl(QUrl("http://x264.fushizen.eu/"));
if(QObject::sender() == ui->actionWebAvisynth32) QDesktopServices::openUrl(QUrl("http://sourceforge.net/projects/avisynth2/files/AviSynth%202.5/"));
if(QObject::sender() == ui->actionWebAvisynth64) QDesktopServices::openUrl(QUrl("http://code.google.com/p/avisynth64/downloads/list"));
+ if(QObject::sender() == ui->actionWebAvisynthPlus) QDesktopServices::openUrl(QUrl("http://www.avs-plus.net/"));
if(QObject::sender() == ui->actionWebVapourSynth) QDesktopServices::openUrl(QUrl("http://www.vapoursynth.com/"));
if(QObject::sender() == ui->actionWebVapourSynthDocs) QDesktopServices::openUrl(QUrl("http://www.vapoursynth.com/doc/"));
if(QObject::sender() == ui->actionWebWiki) QDesktopServices::openUrl(QUrl("http://mewiki.project357.com/wiki/X264_Settings"));
switch(command)
{
- case IPC::IPC_OPCODE_PING:
+ case IPC_OPCODE_PING:
qDebug("Received a PING request from another instance!");
x264_blink_window(this, 5, 125);
break;
- case IPC::IPC_OPCODE_ADD_FILE:
+ case IPC_OPCODE_ADD_FILE:
if(!args.isEmpty())
{
if(QFileInfo(args[0]).exists() && QFileInfo(args[0]).isFile())
}
}
break;
- case IPC::IPC_OPCODE_ADD_JOB:
+ case IPC_OPCODE_ADD_JOB:
if(args.size() >= 3)
{
if(QFileInfo(args[0]).exists() && QFileInfo(args[0]).isFile())
{
if((m_status != STATUS_IDLE) && (m_status != STATUS_EXITTING))
{
+ e->ignore();
qWarning("Cannot close window at this time!");
return;
}
bCommandAccepted = true;
if(!args.isEmpty())
{
- handleCommand(IPC::IPC_OPCODE_ADD_FILE, QStringList() << args.takeFirst());
+ handleCommand(IPC_OPCODE_ADD_FILE, QStringList() << args.takeFirst());
}
else
{
if(args.size() >= 3)
{
const QStringList list = args.mid(0, 3);
- handleCommand(IPC::IPC_OPCODE_ADD_JOB, list);
+ handleCommand(IPC_OPCODE_ADD_JOB, list);
args.erase(args.begin(), args.begin() + 3);
}
else