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
Shinya Kitaoka 9f5a1b
#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
{
Shinya Kitaoka 9f5a1b
#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) {
Shinya Kitaoka 9f5a1b
#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
    }