|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Qt includes
|
|
Toshihiro Shimizu |
890ddd |
#include <qcoreapplication></qcoreapplication>
|
|
Toshihiro Shimizu |
890ddd |
#include <qthread></qthread>
|
|
Toshihiro Shimizu |
890ddd |
#include <qtime></qtime>
|
|
Toshihiro Shimizu |
890ddd |
#include <qsharedmemory></qsharedmemory>
|
|
Toshihiro Shimizu |
890ddd |
#include <qprocess></qprocess>
|
|
Toshihiro Shimizu |
890ddd |
#include <qmutex></qmutex>
|
|
Toshihiro Shimizu |
890ddd |
#include <qsemaphore></qsemaphore>
|
|
Toshihiro Shimizu |
890ddd |
#include <qatomicint></qatomicint>
|
|
Toshihiro Shimizu |
890ddd |
#include <qeventloop></qeventloop>
|
|
Toshihiro Shimizu |
890ddd |
#include <qtimer></qtimer>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//System-specific includes
|
|
Toshihiro Shimizu |
890ddd |
#ifdef WIN32
|
|
Toshihiro Shimizu |
890ddd |
#include <windows.h></windows.h>
|
|
Toshihiro Shimizu |
890ddd |
#elif MACOSX
|
|
Toshihiro Shimizu |
890ddd |
#include <sys sysctl.h=""></sys>
|
|
Toshihiro Shimizu |
890ddd |
#include <unistd.h></unistd.h>
|
|
Campbell Barton |
107701 |
#elif LINUX
|
|
Campbell Barton |
107701 |
#include <sys time.h=""></sys>
|
|
Campbell Barton |
107701 |
#include <unistd.h></unistd.h>
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include "tipc.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
PLATFORM-SPECIFIC REMINDERS:
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
There are few remarks to be aware when maintaining this code.
|
|
Toshihiro Shimizu |
890ddd |
Please, be careful that:
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
- It seems that, on Windows, QLocalSocket::waitForBytesWritten does not return
|
|
Toshihiro Shimizu |
890ddd |
success unless the data is actually read on the other end. On Unix this is not
|
|
Toshihiro Shimizu |
890ddd |
the case, presumably because the data is written to a buffer which can be read by
|
|
Toshihiro Shimizu |
890ddd |
the other process at some later point.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
Thus, *BE SURE* that every data written is received on the other side.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
- On MACOSX, the default shared memory settings can be quite restrictive.
|
|
Toshihiro Shimizu |
890ddd |
On a standard machine, the maximum size of a shared segment is 4 MB, exactly
|
|
Toshihiro Shimizu |
890ddd |
the same as the TOTAL size of shared memory available.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
Whereas tipc respects the former parameter, there must be a way to circumvent the
|
|
Toshihiro Shimizu |
890ddd |
latter in order to make the allocation of multiple shared segments of the maximum
|
|
Toshihiro Shimizu |
890ddd |
size.
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//********************************************************
|
|
Toshihiro Shimizu |
890ddd |
// Diagnostics Stuff
|
|
Toshihiro Shimizu |
890ddd |
//********************************************************
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//#define TIPC_DEBUG
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#ifdef TIPC_DEBUG
|
|
Toshihiro Shimizu |
890ddd |
#define tipc_debug(expr) expr
|
|
Toshihiro Shimizu |
890ddd |
#else
|
|
Toshihiro Shimizu |
890ddd |
#define tipc_debug(expr)
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#ifdef TIPC_DEBUG
|
|
Toshihiro Shimizu |
890ddd |
#include <qtime></qtime>
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//********************************************************
|
|
Toshihiro Shimizu |
890ddd |
// Local namespace Stuff
|
|
Toshihiro Shimizu |
890ddd |
//********************************************************
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
namespace
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int shm_max = -1;
|
|
Toshihiro Shimizu |
890ddd |
int shm_all = -1;
|
|
Toshihiro Shimizu |
890ddd |
int shm_seg = -1;
|
|
Toshihiro Shimizu |
890ddd |
int shm_mni = -1;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//********************************************************
|
|
Toshihiro Shimizu |
890ddd |
// tipc Stream Implementation
|
|
Toshihiro Shimizu |
890ddd |
//********************************************************
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int tipc::Stream::readSize()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (m_socket->bytesAvailable() < sizeof(TINT32))
|
|
Toshihiro Shimizu |
890ddd |
return -1;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TINT32 msgSize = -1;
|
|
Toshihiro Shimizu |
890ddd |
m_socket->peek((char *)&msgSize, sizeof(TINT32));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return msgSize;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool tipc::Stream::messageReady()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TINT32 msgSize;
|
|
Toshihiro Shimizu |
890ddd |
return (msgSize = readSize()) >= 0 && m_socket->bytesAvailable() >= msgSize;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool tipc::Stream::readData(char *data, qint64 dataSize, int msecs)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug("tipc::Stream::readData entry"));
|
|
Toshihiro Shimizu |
890ddd |
qint64 r, dataRead = 0;
|
|
Toshihiro Shimizu |
890ddd |
char *currData = data;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
while (dataRead < dataSize) {
|
|
Toshihiro Shimizu |
890ddd |
if ((m_socket->bytesAvailable() == 0) && !m_socket->waitForReadyRead(msecs)) {
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug("tipc::Stream::readData exit (unexpected loss of data)"));
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Read the supplied data
|
|
Toshihiro Shimizu |
890ddd |
currData += r = m_socket->read(currData, dataSize - dataRead);
|
|
Toshihiro Shimizu |
890ddd |
dataRead += r;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug("tipc::Stream::readData exit"));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool tipc::Stream::readDataNB(char *data, qint64 dataSize, int msecs,
|
|
Toshihiro Shimizu |
890ddd |
QEventLoop::ProcessEventsFlag flag)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug("tipc::Stream::readDataNB entry"));
|
|
Toshihiro Shimizu |
890ddd |
qint64 r, dataRead = 0;
|
|
Toshihiro Shimizu |
890ddd |
char *currData = data;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QEventLoop loop;
|
|
Toshihiro Shimizu |
890ddd |
QObject::connect(m_socket, SIGNAL(readyRead()), &loop, SLOT(quit()));
|
|
Toshihiro Shimizu |
890ddd |
QObject::connect(m_socket, SIGNAL(error(QLocalSocket::LocalSocketError)), &loop, SLOT(quit()));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (msecs >= 0)
|
|
Toshihiro Shimizu |
890ddd |
QTimer::singleShot(msecs, &loop, SLOT(quit()));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
while (dataRead < dataSize) {
|
|
Toshihiro Shimizu |
890ddd |
if (m_socket->bytesAvailable() == 0) {
|
|
Toshihiro Shimizu |
890ddd |
loop.exec(flag);
|
|
Toshihiro Shimizu |
890ddd |
if (m_socket->bytesAvailable() == 0) {
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug("tipc::Stream::readDataNB exit (unexpected loss of data)"));
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Read the supplied data
|
|
Toshihiro Shimizu |
890ddd |
currData += r = m_socket->read(currData, dataSize - dataRead);
|
|
Toshihiro Shimizu |
890ddd |
dataRead += r;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug("tipc::Stream::readDataNB exit"));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*!
|
|
Toshihiro Shimizu |
890ddd |
Reads the message and returns its header.
|
|
Toshihiro Shimizu |
890ddd |
This function reads a complete message from the socket, waiting
|
|
Toshihiro Shimizu |
890ddd |
until it is completely available. The function accepts
|
|
Toshihiro Shimizu |
890ddd |
an inactivity timeout which can be supplied to drop the operation
|
|
Toshihiro Shimizu |
890ddd |
after msecs milliseconds no data has been received.
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
bool tipc::Stream::readMessage(Message &msg, int msecs)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TINT32 msgSize = 0;
|
|
Toshihiro Shimizu |
890ddd |
if (!readData((char *)&msgSize, sizeof(TINT32), msecs))
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
msg.ba().resize(msgSize);
|
|
Toshihiro Shimizu |
890ddd |
if (!readData(msg.ba().data(), msgSize, msecs))
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*!
|
|
Toshihiro Shimizu |
890ddd |
The non-blocking equivalent to readMessage(), this function
|
|
Toshihiro Shimizu |
890ddd |
performs event processing in a local event loop until all
|
|
Toshihiro Shimizu |
890ddd |
message data has been received.
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
bool tipc::Stream::readMessageNB(Message &msg, int msecs,
|
|
Toshihiro Shimizu |
890ddd |
QEventLoop::ProcessEventsFlag flag)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TINT32 msgSize = 0;
|
|
Toshihiro Shimizu |
890ddd |
if (!readDataNB((char *)&msgSize, sizeof(TINT32), msecs, flag))
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
msg.ba().resize(msgSize);
|
|
Toshihiro Shimizu |
890ddd |
if (!readDataNB(msg.ba().data(), msgSize, msecs, flag))
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*!
|
|
Toshihiro Shimizu |
890ddd |
Flushes all data written to the stream.
|
|
Toshihiro Shimizu |
890ddd |
This function waits until all data written on the stream
|
|
Toshihiro Shimizu |
890ddd |
has been successfully delivered in output.
|
|
Toshihiro Shimizu |
890ddd |
Returns true if the operation was successful, false if
|
|
Toshihiro Shimizu |
890ddd |
it timed out or an error occurred.
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
bool tipc::Stream::flush(int msecs)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug("tipc:flush entry"));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
while (m_socket->bytesToWrite() > 0) {
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug() << "bytes to write:" << m_socket->bytesToWrite());
|
|
Toshihiro Shimizu |
890ddd |
bool ok = m_socket->flush();
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug() << "flush success:" << ok << "bytes to write:" << m_socket->bytesToWrite());
|
|
Toshihiro Shimizu |
890ddd |
if (m_socket->bytesToWrite() > 0 && !m_socket->waitForBytesWritten(msecs))
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug() << "tipc:flush exit - bytes to write:" << m_socket->bytesToWrite());
|
|
Toshihiro Shimizu |
890ddd |
return (m_socket->bytesToWrite() == 0);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//********************************************************
|
|
Toshihiro Shimizu |
890ddd |
// tipc Stream Operators
|
|
Toshihiro Shimizu |
890ddd |
//********************************************************
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//! \warning This operation assumes that all the message is available for read.
|
|
Toshihiro Shimizu |
890ddd |
//! Use tipc::stream::readMessage if this cannot be ensured.
|
|
Toshihiro Shimizu |
890ddd |
tipc::Stream &operator>>(tipc::Stream &stream, tipc::Message &msg)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
QLocalSocket *socket = stream.socket();
|
|
Toshihiro Shimizu |
890ddd |
msg.clear();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TINT32 msgSize;
|
|
Toshihiro Shimizu |
890ddd |
socket->read((char *)&msgSize, sizeof(TINT32));
|
|
Toshihiro Shimizu |
890ddd |
msg.ba().resize(msgSize);
|
|
Toshihiro Shimizu |
890ddd |
socket->read(msg.ba().data(), msgSize);
|
|
Toshihiro Shimizu |
890ddd |
return stream;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
tipc::Stream &operator<<(tipc::Stream &stream, tipc::Message &msg)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
QLocalSocket *socket = stream.socket();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TINT32 size = msg.ba().size();
|
|
Toshihiro Shimizu |
890ddd |
socket->write((char *)&size, sizeof(TINT32));
|
|
Toshihiro Shimizu |
890ddd |
socket->write(msg.ba().data(), size);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return stream;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//********************************************************
|
|
Toshihiro Shimizu |
890ddd |
// tipc Utilities
|
|
Toshihiro Shimizu |
890ddd |
//********************************************************
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*!
|
|
Toshihiro Shimizu |
890ddd |
Appends the invoking process' pid to the passed srvName.
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
QString tipc::applicationSpecificServerName(QString srvName)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
return srvName + QString::number(QCoreApplication::applicationPid());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool tipc::startBackgroundProcess(QString cmdline)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
#ifdef WIN32
|
|
Toshihiro Shimizu |
890ddd |
QProcess *proc = new QProcess;
|
|
Toshihiro Shimizu |
890ddd |
proc->start(cmdline);
|
|
Toshihiro Shimizu |
890ddd |
if (proc->state() == QProcess::NotRunning) {
|
|
Toshihiro Shimizu |
890ddd |
delete proc;
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QObject::connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)), proc, SLOT(deleteLater()));
|
|
Toshihiro Shimizu |
890ddd |
QObject::connect(proc, SIGNAL(error(QProcess::ProcessError)), proc, SLOT(deleteLater()));
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
#else
|
|
Toshihiro Shimizu |
890ddd |
return QProcess::startDetached(cmdline);
|
|
Toshihiro Shimizu |
890ddd |
;
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*!
|
|
Toshihiro Shimizu |
890ddd |
Invokes the passed command line to run a slave server.
|
|
Toshihiro Shimizu |
890ddd |
A slave server is hereby intended as a 'child' server process which
|
|
Toshihiro Shimizu |
890ddd |
automatically destroys itself in case the calling application
|
|
Toshihiro Shimizu |
890ddd |
crashes.
|
|
Toshihiro Shimizu |
890ddd |
This process \b MUST support one server, running in the \b MAIN \b THREAD,
|
|
Toshihiro Shimizu |
890ddd |
whose name is <srvname>_main.</srvname>
|
|
Toshihiro Shimizu |
890ddd |
This function waits until the main server is up and ready to
|
|
Toshihiro Shimizu |
890ddd |
listen for incoming connections - no timeout accepted.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
\warning Please, observe that a correct slave server name should be
|
|
Toshihiro Shimizu |
890ddd |
ensured to be unique to the system.
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
bool tipc::startSlaveServer(QString srvName, QString cmdline)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (!tipc::startBackgroundProcess(cmdline))
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QString mainSrvName(srvName + "_main");
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Establish a dummy socket connection to provide a mean for the process
|
|
Toshihiro Shimizu |
890ddd |
//to tell whether the calling process exited unexpectedly.
|
|
Toshihiro Shimizu |
890ddd |
QLocalSocket *dummySock = new QLocalSocket;
|
|
Toshihiro Shimizu |
890ddd |
dummySock->connectToServer(mainSrvName);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Wait up to msecs until the socket is connecting. Wait a small amount of time
|
|
Toshihiro Shimizu |
890ddd |
//until the server is up and listening to connection (there is no other way to tell).
|
|
Toshihiro Shimizu |
890ddd |
while (dummySock->state() == QLocalSocket::UnconnectedState) {
|
|
Toshihiro Shimizu |
890ddd |
#ifdef WIN32
|
|
Toshihiro Shimizu |
890ddd |
Sleep(10);
|
|
Toshihiro Shimizu |
890ddd |
#else
|
|
Toshihiro Shimizu |
890ddd |
usleep(10 << 10); //10.24 msecs
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
dummySock->connectToServer(mainSrvName);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
dummySock->waitForConnected(-1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
tipc::Stream stream(dummySock);
|
|
Toshihiro Shimizu |
890ddd |
tipc::Message msg;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Supply the 'quit if this socket connection fails' command
|
|
Toshihiro Shimizu |
890ddd |
//This command ensure termination of the child process in case of some errors
|
|
Toshihiro Shimizu |
890ddd |
//or ending of the program
|
|
Toshihiro Shimizu |
890ddd |
stream << (msg << QString("$quit_on_error"));
|
|
Toshihiro Shimizu |
890ddd |
if (tipc::readMessage(stream, msg, 3000) == QString()) {
|
|
Toshihiro Shimizu |
890ddd |
std::cout << "tipc::startSlaveServer - tipc::readMessage TIMEOUT" << std::endl;
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//The server should die if dummyDock is destroyed. This should happen when the *MAIN* thread
|
|
Toshihiro Shimizu |
890ddd |
//in *this process* exits. So, if this is not the main thread, we must move the socket there.
|
|
Toshihiro Shimizu |
890ddd |
if (QThread::currentThread() != QCoreApplication::instance()->thread())
|
|
Toshihiro Shimizu |
890ddd |
dummySock->moveToThread(QCoreApplication::instance()->thread());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//If a connection error takes place, release the dummy socket.
|
|
Toshihiro Shimizu |
890ddd |
//Please, observe that this QObject::connect is invoked *AFTER* the connection trials above...
|
|
Toshihiro Shimizu |
890ddd |
QObject::connect(dummySock, SIGNAL(error(QLocalSocket::LocalSocketError)), dummySock, SLOT(deleteLater()));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*!
|
|
Toshihiro Shimizu |
890ddd |
Connects the passed socket to the server with name <srvname> + <threadname>.</threadname></srvname>
|
|
Toshihiro Shimizu |
890ddd |
Awaits for the connection up to msecs milliseconds before returning false.
|
|
Toshihiro Shimizu |
890ddd |
If no server was found, a new slave server is started by invoking
|
|
Toshihiro Shimizu |
890ddd |
the supplied command line and connection is re-attempted.
|
|
Toshihiro Shimizu |
890ddd |
Returns true on success, false otherwise.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
\warning Please, observe that a correct slave server name should be
|
|
Toshihiro Shimizu |
890ddd |
ensured to be unique to the parent process.
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
bool tipc::startSlaveConnection(QLocalSocket *socket, QString srvName, int msecs,
|
|
Toshihiro Shimizu |
890ddd |
QString cmdline, QString threadName)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
QTime time;
|
|
Toshihiro Shimizu |
890ddd |
time.start();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (msecs == -1)
|
|
Toshihiro Shimizu |
890ddd |
msecs = (std::numeric_limits<int>::max)();</int>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QString fullSrvName(srvName + threadName);
|
|
Toshihiro Shimizu |
890ddd |
socket->connectToServer(fullSrvName);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//If the socket is not connecting, the server lookup table returned that the no server with
|
|
Toshihiro Shimizu |
890ddd |
//the passed name exists. This means that a server must be created.
|
|
Toshihiro Shimizu |
890ddd |
if (socket->state() == QLocalSocket::UnconnectedState && !cmdline.isEmpty()) {
|
|
Toshihiro Shimizu |
890ddd |
//Completely serialize the server start
|
|
Toshihiro Shimizu |
890ddd |
static QMutex mutex;
|
|
Toshihiro Shimizu |
890ddd |
QMutexLocker locker(&mutex);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Retry connection - this is required due to the mutex
|
|
Toshihiro Shimizu |
890ddd |
socket->connectToServer(fullSrvName);
|
|
Toshihiro Shimizu |
890ddd |
if (socket->state() != QLocalSocket::UnconnectedState)
|
|
Toshihiro Shimizu |
890ddd |
goto connecting;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Invoke the supplied command line to start the server
|
|
Toshihiro Shimizu |
890ddd |
if (!tipc::startSlaveServer(srvName, cmdline))
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Reconnect to the server
|
|
Toshihiro Shimizu |
890ddd |
socket->connectToServer(fullSrvName);
|
|
Toshihiro Shimizu |
890ddd |
if (socket->state() == QLocalSocket::UnconnectedState)
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
connecting:
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Now, the server is connecting or already connected. Wait until the socket is connected.
|
|
Toshihiro Shimizu |
890ddd |
socket->waitForConnected(msecs - time.elapsed());
|
|
Toshihiro Shimizu |
890ddd |
if (socket->state() != QLocalSocket::ConnectedState)
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*!
|
|
Toshihiro Shimizu |
890ddd |
Waits and reads the next message from stream.
|
|
Toshihiro Shimizu |
890ddd |
This function is mainly a useful macro that encapsulates
|
|
Toshihiro Shimizu |
890ddd |
the following steps in one call:
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
\li Flush the write buffer (output messages)
|
|
Toshihiro Shimizu |
890ddd |
\li Wait until an input message is completely readable
|
|
Toshihiro Shimizu |
890ddd |
\li Read the message from stream
|
|
Toshihiro Shimizu |
890ddd |
\li Read the first string from the message and return it
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
This function returns an empty QString if the message could not be
|
|
Toshihiro Shimizu |
890ddd |
entirely retrieved from the stream.
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
QString tipc::readMessage(Stream &stream, Message &msg, int msecs)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
msg.clear();
|
|
Toshihiro Shimizu |
890ddd |
stream.flush();
|
|
Toshihiro Shimizu |
890ddd |
if (!stream.readMessage(msg, msecs))
|
|
Toshihiro Shimizu |
890ddd |
return QString();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QString res;
|
|
Toshihiro Shimizu |
890ddd |
msg >> res;
|
|
Toshihiro Shimizu |
890ddd |
return res;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*!
|
|
Toshihiro Shimizu |
890ddd |
The non-blocking equivalent to tipc::readMessage.
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
QString tipc::readMessageNB(Stream &stream, Message &msg, int msecs,
|
|
Toshihiro Shimizu |
890ddd |
QEventLoop::ProcessEventsFlag flag)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
msg.clear();
|
|
Toshihiro Shimizu |
890ddd |
if (!stream.readMessageNB(msg, msecs, flag))
|
|
Toshihiro Shimizu |
890ddd |
return QString();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QString res;
|
|
Toshihiro Shimizu |
890ddd |
msg >> res;
|
|
Toshihiro Shimizu |
890ddd |
return res;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*!
|
|
Toshihiro Shimizu |
890ddd |
Returns an inter-process unique id string; the returned
|
|
Toshihiro Shimizu |
890ddd |
id should be used to create QSharedMemory objects.
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
QString tipc::uniqueId()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
static QAtomicInt count;
|
|
Toshihiro Shimizu |
890ddd |
count.ref();
|
|
Toshihiro Shimizu |
890ddd |
return QString::number(QCoreApplication::applicationPid()) + "_" + QString::number((int)count);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//! Returns the maximum size of a shared memory segment allowed by the system
|
|
Toshihiro Shimizu |
890ddd |
int tipc::shm_maxSegmentSize()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (shm_max < 0) {
|
|
Toshihiro Shimizu |
890ddd |
#ifdef MACOSX
|
|
Toshihiro Shimizu |
890ddd |
//Retrieve it by invoking sysctl
|
|
Toshihiro Shimizu |
890ddd |
size_t valSize = sizeof(TINT64);
|
|
Toshihiro Shimizu |
890ddd |
TINT64 val;
|
|
Toshihiro Shimizu |
890ddd |
sysctlbyname("kern.sysv.shmmax", &val, &valSize, NULL, 0);
|
|
Toshihiro Shimizu |
890ddd |
shm_max = tmin(val, (TINT64)(std::numeric_limits<int>::max)());</int>
|
|
Toshihiro Shimizu |
890ddd |
#else
|
|
Toshihiro Shimizu |
890ddd |
//Windows case: no such limit
|
|
Toshihiro Shimizu |
890ddd |
//Observe that QSharedMemory accepts only an int size - so the num_lim is against int.
|
|
Toshihiro Shimizu |
890ddd |
shm_max = (std::numeric_limits<int>::max)();</int>
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return shm_max;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//! Returns the maximum number of shared segments allowed by the system
|
|
Toshihiro Shimizu |
890ddd |
int tipc::shm_maxSegmentCount()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (shm_seg < 0) {
|
|
Toshihiro Shimizu |
890ddd |
#ifdef MACOSX
|
|
Toshihiro Shimizu |
890ddd |
size_t valSize = sizeof(TINT64);
|
|
Toshihiro Shimizu |
890ddd |
TINT64 val;
|
|
Toshihiro Shimizu |
890ddd |
sysctlbyname("kern.sysv.shmseg", &val, &valSize, NULL, 0);
|
|
Toshihiro Shimizu |
890ddd |
shm_seg = tmin(val, (TINT64)(std::numeric_limits<int>::max)());</int>
|
|
Toshihiro Shimizu |
890ddd |
#else
|
|
Toshihiro Shimizu |
890ddd |
//Windows case: no such limit - again, using limit against max due to Qt
|
|
Toshihiro Shimizu |
890ddd |
shm_seg = (std::numeric_limits<int>::max)();</int>
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return shm_seg;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int tipc::shm_maxSharedPages()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (shm_all < 0) {
|
|
Toshihiro Shimizu |
890ddd |
#ifdef MACOSX
|
|
Toshihiro Shimizu |
890ddd |
size_t valSize = sizeof(TINT64);
|
|
Toshihiro Shimizu |
890ddd |
TINT64 val;
|
|
Toshihiro Shimizu |
890ddd |
sysctlbyname("kern.sysv.shmall", &val, &valSize, NULL, 0);
|
|
Toshihiro Shimizu |
890ddd |
shm_all = tmin(val, (TINT64)(std::numeric_limits<int>::max)());</int>
|
|
Toshihiro Shimizu |
890ddd |
#else
|
|
Toshihiro Shimizu |
890ddd |
shm_all = (std::numeric_limits<int>::max)();</int>
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return shm_all;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int tipc::shm_maxSharedCount()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (shm_mni < 0) {
|
|
Toshihiro Shimizu |
890ddd |
#ifdef MACOSX
|
|
Toshihiro Shimizu |
890ddd |
size_t valSize = sizeof(TINT64);
|
|
Toshihiro Shimizu |
890ddd |
TINT64 val;
|
|
Toshihiro Shimizu |
890ddd |
sysctlbyname("kern.sysv.shmmni", &val, &valSize, NULL, 0);
|
|
Toshihiro Shimizu |
890ddd |
shm_mni = tmin(val, (TINT64)(std::numeric_limits<int>::max)());</int>
|
|
Toshihiro Shimizu |
890ddd |
#else
|
|
Toshihiro Shimizu |
890ddd |
shm_mni = (std::numeric_limits<int>::max)();</int>
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return shm_mni;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*!
|
|
Toshihiro Shimizu |
890ddd |
Attempts to set the shared memory parameters to the system.
|
|
Toshihiro Shimizu |
890ddd |
This is only working on MAC's SystemV shm, it's a no-op on Win.
|
|
Toshihiro Shimizu |
890ddd |
This function will fail anyway if the process is not owned by an
|
|
Toshihiro Shimizu |
890ddd |
admin.
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
void tipc::shm_set(int shmmax, int shmseg, int shmall, int shmmni)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug("shmmax: %i, shmseg: %i, shmall: %i, shmmni: %i", shmmax, shmseg, shmall, shmmni));
|
|
Toshihiro Shimizu |
890ddd |
#ifdef MACOSX
|
|
Toshihiro Shimizu |
890ddd |
TINT64 val;
|
|
Toshihiro Shimizu |
890ddd |
int err;
|
|
Toshihiro Shimizu |
890ddd |
if (shmmax > 0) {
|
|
Toshihiro Shimizu |
890ddd |
val = shmmax;
|
|
Toshihiro Shimizu |
890ddd |
err = sysctlbyname("kern.sysv.shmmax", NULL, NULL, &val, sizeof(TINT64));
|
|
Toshihiro Shimizu |
890ddd |
if (!err)
|
|
Toshihiro Shimizu |
890ddd |
shm_max = shmmax;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (shmseg > 0) {
|
|
Toshihiro Shimizu |
890ddd |
val = shmseg;
|
|
Toshihiro Shimizu |
890ddd |
err = sysctlbyname("kern.sysv.shmseg", NULL, NULL, &val, sizeof(TINT64));
|
|
Toshihiro Shimizu |
890ddd |
if (!err)
|
|
Toshihiro Shimizu |
890ddd |
shm_seg = shmseg;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (shmall > 0) {
|
|
Toshihiro Shimizu |
890ddd |
val = shmall;
|
|
Toshihiro Shimizu |
890ddd |
err = sysctlbyname("kern.sysv.shmall", NULL, NULL, &val, sizeof(TINT64));
|
|
Toshihiro Shimizu |
890ddd |
if (!err)
|
|
Toshihiro Shimizu |
890ddd |
shm_all = shmall;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (shmmni > 0) {
|
|
Toshihiro Shimizu |
890ddd |
val = shmmni;
|
|
Toshihiro Shimizu |
890ddd |
err = sysctlbyname("kern.sysv.shmmni", NULL, NULL, &val, sizeof(TINT64));
|
|
Toshihiro Shimizu |
890ddd |
if (!err)
|
|
Toshihiro Shimizu |
890ddd |
shm_mni = shmmni;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*!
|
|
Toshihiro Shimizu |
890ddd |
Creates a shared memory segment for passed QSharedMemory.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
This function attempts creation of a shared memory segment
|
|
Toshihiro Shimizu |
890ddd |
in the form of Qt's QSharedMemory, with the following \b UNIX-specific
|
|
Toshihiro Shimizu |
890ddd |
distinctions:
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
If the segment size is beyond that supported by the system,
|
|
Toshihiro Shimizu |
890ddd |
the function can be set to either fail or return a segment with
|
|
Toshihiro Shimizu |
890ddd |
the maximum supported size. <\LI>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
Unlike QSharedMemory::create, this function attempts to
|
|
Toshihiro Shimizu |
890ddd |
reclaim an already existing memory id before creating a new one. <\LI>
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
int tipc::create(QSharedMemory &shmem, int size, bool strictSize)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
bool ok, retried = false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!strictSize)
|
|
Toshihiro Shimizu |
890ddd |
size = tmin(size, (int)shm_maxSegmentSize());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug() << "shMem create: size =" << size);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
retry:
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
ok = shmem.create(size);
|
|
Toshihiro Shimizu |
890ddd |
if (!ok) {
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug() << "Error: Shared Segment could not be created: #" << shmem.errorString());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Unix-specific error recovery follows. See Qt's docs about it.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Try to recover error #AlreadyExists - supposedly, the server crashed in a previous instance.
|
|
Toshihiro Shimizu |
890ddd |
//As shared memory segments that happen to go this way are owned by the server process with 1
|
|
Toshihiro Shimizu |
890ddd |
//reference count, detaching it now may solve the issue.
|
|
Toshihiro Shimizu |
890ddd |
if (shmem.error() == QSharedMemory::AlreadyExists && !retried) {
|
|
Toshihiro Shimizu |
890ddd |
retried = true; // We're trying this only once... for now it works.
|
|
Toshihiro Shimizu |
890ddd |
shmem.attach();
|
|
Toshihiro Shimizu |
890ddd |
shmem.detach();
|
|
Toshihiro Shimizu |
890ddd |
goto retry;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return -1;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return size;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*!
|
|
Toshihiro Shimizu |
890ddd |
Writes data through a shared memory segment medium.
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
bool tipc::writeShMemBuffer(Stream &stream, Message &msg, int bufSize, ShMemWriter *dataWriter)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(QTime time; time.start());
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug("tipc::writeShMemBuffer entry"));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
static QSemaphore sem(tipc::shm_maxSegmentCount());
|
|
Toshihiro Shimizu |
890ddd |
sem.acquire(1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
//Create a shared memory segment, possibly of passed size
|
|
Toshihiro Shimizu |
890ddd |
QSharedMemory shmem(tipc::uniqueId());
|
|
Toshihiro Shimizu |
890ddd |
bool ok = (tipc::create(shmem, bufSize) > 0);
|
|
Toshihiro Shimizu |
890ddd |
if (!ok)
|
|
Toshihiro Shimizu |
890ddd |
goto err;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Communicate the shared memory id and bufSize to the reader
|
|
Toshihiro Shimizu |
890ddd |
msg << QString("shm") << shmem.key() << bufSize;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Fill in data until all the buffer has been sent
|
|
Toshihiro Shimizu |
890ddd |
int chunkData, remainingData = bufSize;
|
|
Toshihiro Shimizu |
890ddd |
while (remainingData > 0) {
|
|
Toshihiro Shimizu |
890ddd |
//Write to the shared memory segment
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(QTime xchTime; xchTime.start());
|
|
Toshihiro Shimizu |
890ddd |
shmem.lock();
|
|
Toshihiro Shimizu |
890ddd |
remainingData -= chunkData = dataWriter->write((char *)shmem.data(), tmin(shmem.size(), remainingData));
|
|
Toshihiro Shimizu |
890ddd |
shmem.unlock();
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug() << "exchange time:" << xchTime.elapsed());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
stream << (msg << QString("chk") << chunkData);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (tipc::readMessage(stream, msg) != "ok")
|
|
Toshihiro Shimizu |
890ddd |
goto err;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
msg.clear();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
sem.release(1);
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug("tipc::writeShMemBuffer exit"));
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug() << "tipc::writeShMemBuffer time:" << time.elapsed());
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
err:
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug("tipc::writeShMemBuffer exit (error)"));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
msg.clear();
|
|
Toshihiro Shimizu |
890ddd |
sem.release(1);
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*!
|
|
Toshihiro Shimizu |
890ddd |
Reads data through a shared memory segment medium.
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
bool tipc::readShMemBuffer(Stream &stream, Message &msg, ShMemReader *dataReader)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(QTime time; time.start(););
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug("tipc::readShMemBuffer entry"));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Read the id from stream
|
|
Toshihiro Shimizu |
890ddd |
QString res(tipc::readMessage(stream, msg));
|
|
Toshihiro Shimizu |
890ddd |
if (res != "shm") {
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug("tipc::readShMemBuffer exit (res != \"shm\")"));
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Read message and reply
|
|
Toshihiro Shimizu |
890ddd |
QString id, chkStr;
|
|
Toshihiro Shimizu |
890ddd |
int bufSize;
|
|
Toshihiro Shimizu |
890ddd |
msg >> id >> bufSize >> chkStr;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Data is ready to be read - attach to the shared memory segment.
|
|
Toshihiro Shimizu |
890ddd |
QSharedMemory shmem(id);
|
|
Toshihiro Shimizu |
890ddd |
shmem.attach();
|
|
Toshihiro Shimizu |
890ddd |
if (!shmem.isAttached()) {
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug("tipc::readShMemBuffer exit (shmem not attached)"));
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Start reading from it
|
|
Toshihiro Shimizu |
890ddd |
int chunkData, remainingData = bufSize;
|
|
Toshihiro Shimizu |
890ddd |
while (true) {
|
|
Toshihiro Shimizu |
890ddd |
msg >> chunkData;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(QTime xchTime; xchTime.start());
|
|
Toshihiro Shimizu |
890ddd |
shmem.lock();
|
|
Toshihiro Shimizu |
890ddd |
remainingData -= dataReader->read((const char *)shmem.data(), chunkData);
|
|
Toshihiro Shimizu |
890ddd |
shmem.unlock();
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug() << "exchange time:" << xchTime.elapsed());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Data was read. Inform the writer
|
|
Toshihiro Shimizu |
890ddd |
stream << (msg << clr << QString("ok"));
|
|
Toshihiro Shimizu |
890ddd |
stream.flush();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (remainingData <= 0)
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Wait for more chunks
|
|
Toshihiro Shimizu |
890ddd |
if (tipc::readMessage(stream, msg) != "chk") {
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug("tipc::readShMemBuffer exit (unexpected chunk absence)"));
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
shmem.detach();
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug("tipc::readShMemBuffer exit"));
|
|
Toshihiro Shimizu |
890ddd |
tipc_debug(qDebug() << "tipc::readShMemBuffer time:" << time.elapsed());
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|