Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Qt includes
Toshihiro Shimizu 890ddd
#include <qcoreapplication></qcoreapplication>
Toshihiro Shimizu 890ddd
#include <qthread></qthread>
shun-iwasawa 443318
#include <qelapsedtimer></qelapsedtimer>
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
Shinya Kitaoka 120a6e
// System-specific includes
Campbell Barton d869b5
#if defined(_WIN32)
Toshihiro Shimizu 890ddd
#include <windows.h></windows.h>
Campbell Barton d869b5
#elif defined(MACOSX)
Toshihiro Shimizu 890ddd
#include <sys sysctl.h=""></sys>
Toshihiro Shimizu 890ddd
#include <unistd.h></unistd.h>
Rozhuk Ivan ac51ab
#elif defined(LINUX) || defined(FREEBSD)
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
Shinya Kitaoka 120a6e
  the case, presumably because the data is written to a buffer which can be read
Shinya Kitaoka 120a6e
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
Shinya Kitaoka 120a6e
  Whereas tipc respects the former parameter, there must be a way to circumvent
Shinya Kitaoka 120a6e
the
Shinya Kitaoka 120a6e
  latter in order to make the allocation of multiple shared segments of the
Shinya Kitaoka 120a6e
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
shun-iwasawa 443318
// #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
Shinya Kitaoka 120a6e
namespace {
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;
shun-iwasawa 443318
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************
Toshihiro Shimizu 890ddd
//    tipc Stream Implementation
Toshihiro Shimizu 890ddd
//********************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int tipc::Stream::readSize() {
Shinya Kitaoka 120a6e
  if (m_socket->bytesAvailable() < sizeof(TINT32)) return -1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TINT32 msgSize = -1;
Shinya Kitaoka 120a6e
  m_socket->peek((char *)&msgSize, sizeof(TINT32));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return msgSize;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool tipc::Stream::messageReady() {
Shinya Kitaoka 120a6e
  TINT32 msgSize;
Shinya Kitaoka 120a6e
  return (msgSize = readSize()) >= 0 && m_socket->bytesAvailable() >= msgSize;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool tipc::Stream::readData(char *data, qint64 dataSize, int msecs) {
Shinya Kitaoka 120a6e
  tipc_debug(qDebug("tipc::Stream::readData entry"));
Shinya Kitaoka 120a6e
  qint64 r, dataRead = 0;
Shinya Kitaoka 120a6e
  char *currData = data;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  while (dataRead < dataSize) {
Shinya Kitaoka 120a6e
    if ((m_socket->bytesAvailable() == 0) &&
Shinya Kitaoka 120a6e
        !m_socket->waitForReadyRead(msecs)) {
Shinya Kitaoka 120a6e
      tipc_debug(
Shinya Kitaoka 120a6e
          qDebug("tipc::Stream::readData exit (unexpected loss of data)"));
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Read the supplied data
Shinya Kitaoka 120a6e
    currData += r = m_socket->read(currData, dataSize - dataRead);
Shinya Kitaoka 120a6e
    dataRead += r;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  tipc_debug(qDebug("tipc::Stream::readData exit"));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  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,
Shinya Kitaoka 120a6e
                              QEventLoop::ProcessEventsFlag flag) {
Shinya Kitaoka 120a6e
  tipc_debug(qDebug("tipc::Stream::readDataNB entry"));
Shinya Kitaoka 120a6e
  qint64 r, dataRead = 0;
Shinya Kitaoka 120a6e
  char *currData = data;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QEventLoop loop;
Shinya Kitaoka 120a6e
  QObject::connect(m_socket, SIGNAL(readyRead()), &loop, SLOT(quit()));
Shinya Kitaoka 120a6e
  QObject::connect(m_socket, SIGNAL(error(QLocalSocket::LocalSocketError)),
Shinya Kitaoka 120a6e
                   &loop, SLOT(quit()));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (msecs >= 0) QTimer::singleShot(msecs, &loop, SLOT(quit()));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  while (dataRead < dataSize) {
Shinya Kitaoka 120a6e
    if (m_socket->bytesAvailable() == 0) {
Shinya Kitaoka 120a6e
      loop.exec(flag);
Shinya Kitaoka 120a6e
      if (m_socket->bytesAvailable() == 0) {
Shinya Kitaoka 120a6e
        tipc_debug(
Shinya Kitaoka 120a6e
            qDebug("tipc::Stream::readDataNB exit (unexpected loss of data)"));
Shinya Kitaoka 120a6e
        return false;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Read the supplied data
Shinya Kitaoka 120a6e
    currData += r = m_socket->read(currData, dataSize - dataRead);
Shinya Kitaoka 120a6e
    dataRead += r;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  tipc_debug(qDebug("tipc::Stream::readDataNB exit"));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  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
*/
Shinya Kitaoka 120a6e
bool tipc::Stream::readMessage(Message &msg, int msecs) {
Shinya Kitaoka 120a6e
  TINT32 msgSize = 0;
Shinya Kitaoka 120a6e
  if (!readData((char *)&msgSize, sizeof(TINT32), msecs)) return false;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  msg.ba().resize(msgSize);
Shinya Kitaoka 120a6e
  if (!readData(msg.ba().data(), msgSize, msecs)) return false;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  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,
Shinya Kitaoka 120a6e
                                 QEventLoop::ProcessEventsFlag flag) {
Shinya Kitaoka 120a6e
  TINT32 msgSize = 0;
Shinya Kitaoka 120a6e
  if (!readDataNB((char *)&msgSize, sizeof(TINT32), msecs, flag)) return false;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  msg.ba().resize(msgSize);
Shinya Kitaoka 120a6e
  if (!readDataNB(msg.ba().data(), msgSize, msecs, flag)) return false;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  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
*/
Shinya Kitaoka 120a6e
bool tipc::Stream::flush(int msecs) {
Shinya Kitaoka 120a6e
  tipc_debug(qDebug("tipc:flush entry"));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  while (m_socket->bytesToWrite() > 0) {
Shinya Kitaoka 120a6e
    tipc_debug(qDebug() << "bytes to write:" << m_socket->bytesToWrite());
Shinya Kitaoka 120a6e
    bool ok = m_socket->flush();
Shinya Kitaoka 120a6e
    tipc_debug(qDebug() << "flush success:" << ok
Shinya Kitaoka 120a6e
                        << "bytes to write:" << m_socket->bytesToWrite());
Shinya Kitaoka 120a6e
    if (m_socket->bytesToWrite() > 0 && !m_socket->waitForBytesWritten(msecs))
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  tipc_debug(qDebug() << "tipc:flush exit - bytes to write:"
Shinya Kitaoka 120a6e
                      << m_socket->bytesToWrite());
Shinya Kitaoka 120a6e
  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.
Shinya Kitaoka 120a6e
tipc::Stream &operator>>(tipc::Stream &stream, tipc::Message &msg) {
Shinya Kitaoka 120a6e
  QLocalSocket *socket = stream.socket();
Shinya Kitaoka 120a6e
  msg.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TINT32 msgSize;
Shinya Kitaoka 120a6e
  socket->read((char *)&msgSize, sizeof(TINT32));
Shinya Kitaoka 120a6e
  msg.ba().resize(msgSize);
Shinya Kitaoka 120a6e
  socket->read(msg.ba().data(), msgSize);
Shinya Kitaoka 120a6e
  return stream;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
tipc::Stream &operator<<(tipc::Stream &stream, tipc::Message &msg) {
Shinya Kitaoka 120a6e
  QLocalSocket *socket = stream.socket();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TINT32 size = msg.ba().size();
Shinya Kitaoka 120a6e
  socket->write((char *)&size, sizeof(TINT32));
Shinya Kitaoka 120a6e
  socket->write(msg.ba().data(), size);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  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
*/
Shinya Kitaoka 120a6e
QString tipc::applicationSpecificServerName(QString srvName) {
Shinya Kitaoka 120a6e
  return srvName + QString::number(QCoreApplication::applicationPid());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
shun-iwasawa 443318
bool tipc::startBackgroundProcess(QString cmdlineProgram,
shun-iwasawa 443318
                                  QStringList cmdlineArguments) {
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Shinya Kitaoka 120a6e
  QProcess *proc = new QProcess;
shun-iwasawa 443318
shun-iwasawa 443318
  proc->start(cmdlineProgram, cmdlineArguments);
Shinya Kitaoka 120a6e
  if (proc->state() == QProcess::NotRunning) {
Shinya Kitaoka 120a6e
    delete proc;
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QObject::connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)), proc,
Shinya Kitaoka 120a6e
                   SLOT(deleteLater()));
Shinya Kitaoka 120a6e
  QObject::connect(proc, SIGNAL(error(QProcess::ProcessError)), proc,
Shinya Kitaoka 120a6e
                   SLOT(deleteLater()));
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
#else
shun-iwasawa 443318
  return QProcess::startDetached(cmdlineProgram, cmdlineArguments);
Shinya Kitaoka 120a6e
  ;
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
*/
shun-iwasawa 443318
bool tipc::startSlaveServer(QString srvName, QString cmdlineProgram,
shun-iwasawa 443318
                            QStringList cmdlineArguments) {
shun-iwasawa 443318
  if (!tipc::startBackgroundProcess(cmdlineProgram, cmdlineArguments))
shun-iwasawa 443318
    return false;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  QString mainSrvName(srvName + "_main");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Establish a dummy socket connection to provide a mean for the process
Shinya Kitaoka 120a6e
  // to tell whether the calling process exited unexpectedly.
Shinya Kitaoka 120a6e
  QLocalSocket *dummySock = new QLocalSocket;
Shinya Kitaoka 120a6e
  dummySock->connectToServer(mainSrvName);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Wait up to msecs until the socket is connecting. Wait a small amount of
Shinya Kitaoka 120a6e
  // time
Shinya Kitaoka 120a6e
  // until the server is up and listening to connection (there is no other way
Shinya Kitaoka 120a6e
  // to tell).
Shinya Kitaoka 120a6e
  while (dummySock->state() == QLocalSocket::UnconnectedState) {
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Shinya Kitaoka 120a6e
    Sleep(10);
Toshihiro Shimizu 890ddd
#else
Shinya Kitaoka 120a6e
    usleep(10 << 10);  // 10.24 msecs
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    dummySock->connectToServer(mainSrvName);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  dummySock->waitForConnected(-1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  tipc::Stream stream(dummySock);
Shinya Kitaoka 120a6e
  tipc::Message msg;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Supply the 'quit if this socket connection fails' command
Shinya Kitaoka 120a6e
  // This command ensure termination of the child process in case of some errors
Shinya Kitaoka 120a6e
  // or ending of the program
Shinya Kitaoka 120a6e
  stream << (msg << QString("$quit_on_error"));
Shinya Kitaoka 120a6e
  if (tipc::readMessage(stream, msg, 3000) == QString()) {
Shinya Kitaoka 120a6e
    std::cout << "tipc::startSlaveServer - tipc::readMessage TIMEOUT"
Shinya Kitaoka 120a6e
              << std::endl;
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // The server should die if dummyDock is destroyed. This should happen when
Shinya Kitaoka 120a6e
  // the *MAIN* thread
Shinya Kitaoka 120a6e
  // in *this process* exits. So, if this is not the main thread, we must move
Shinya Kitaoka 120a6e
  // the socket there.
shun-iwasawa 51c8ee
  if (QCoreApplication::instance() &&
shun-iwasawa 51c8ee
      QThread::currentThread() != QCoreApplication::instance()->thread())
Shinya Kitaoka 120a6e
    dummySock->moveToThread(QCoreApplication::instance()->thread());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // If a connection error takes place, release the dummy socket.
Shinya Kitaoka 120a6e
  // Please, observe that this QObject::connect is invoked *AFTER* the
Shinya Kitaoka 120a6e
  // connection trials above...
Shinya Kitaoka 120a6e
  QObject::connect(dummySock, SIGNAL(error(QLocalSocket::LocalSocketError)),
Shinya Kitaoka 120a6e
                   dummySock, SLOT(deleteLater()));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  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
*/
Shinya Kitaoka 120a6e
bool tipc::startSlaveConnection(QLocalSocket *socket, QString srvName,
shun-iwasawa 443318
                                int msecs, QString cmdlineProgram,
shun-iwasawa 443318
                                QStringList cmdlineArguments,
Shinya Kitaoka 120a6e
                                QString threadName) {
shun-iwasawa 443318
  QElapsedTimer time;
Shinya Kitaoka 120a6e
  time.start();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (msecs == -1) msecs = (std::numeric_limits<int>::max)();</int>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QString fullSrvName(srvName + threadName);
Shinya Kitaoka 120a6e
  socket->connectToServer(fullSrvName);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // If the socket is not connecting, the server lookup table returned that the
Shinya Kitaoka 120a6e
  // no server with
Shinya Kitaoka 120a6e
  // the passed name exists. This means that a server must be created.
shun-iwasawa 443318
  if (socket->state() == QLocalSocket::UnconnectedState &&
shun-iwasawa 443318
      !cmdlineProgram.isEmpty()) {
Shinya Kitaoka 120a6e
    // Completely serialize the server start
Shinya Kitaoka 120a6e
    static QMutex mutex;
Shinya Kitaoka 120a6e
    QMutexLocker locker(&mutex);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Retry connection - this is required due to the mutex
Shinya Kitaoka 120a6e
    socket->connectToServer(fullSrvName);
Shinya Kitaoka 120a6e
    if (socket->state() != QLocalSocket::UnconnectedState) goto connecting;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Invoke the supplied command line to start the server
shun-iwasawa 443318
    if (!tipc::startSlaveServer(srvName, cmdlineProgram, cmdlineArguments))
shun-iwasawa 443318
      return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Reconnect to the server
Shinya Kitaoka 120a6e
    socket->connectToServer(fullSrvName);
Shinya Kitaoka 120a6e
    if (socket->state() == QLocalSocket::UnconnectedState) return false;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
connecting:
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Now, the server is connecting or already connected. Wait until the socket
Shinya Kitaoka 120a6e
  // is connected.
Shinya Kitaoka 120a6e
  socket->waitForConnected(msecs - time.elapsed());
Shinya Kitaoka 120a6e
  if (socket->state() != QLocalSocket::ConnectedState) return false;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  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
*/
Shinya Kitaoka 120a6e
QString tipc::readMessage(Stream &stream, Message &msg, int msecs) {
Shinya Kitaoka 120a6e
  msg.clear();
Shinya Kitaoka 120a6e
  stream.flush();
Shinya Kitaoka 120a6e
  if (!stream.readMessage(msg, msecs)) return QString();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QString res;
Shinya Kitaoka 120a6e
  msg >> res;
Shinya Kitaoka 120a6e
  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,
Shinya Kitaoka 120a6e
                            QEventLoop::ProcessEventsFlag flag) {
Shinya Kitaoka 120a6e
  msg.clear();
Shinya Kitaoka 120a6e
  if (!stream.readMessageNB(msg, msecs, flag)) return QString();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QString res;
Shinya Kitaoka 120a6e
  msg >> res;
Shinya Kitaoka 120a6e
  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
*/
Shinya Kitaoka 120a6e
QString tipc::uniqueId() {
Shinya Kitaoka 120a6e
  static QAtomicInt count;
Shinya Kitaoka 120a6e
  count.ref();
Shinya Kitaoka 120a6e
  return QString::number(QCoreApplication::applicationPid()) + "_" +
Shinya Kitaoka 120a6e
         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
Shinya Kitaoka 120a6e
int tipc::shm_maxSegmentSize() {
Shinya Kitaoka 120a6e
  if (shm_max < 0) {
Toshihiro Shimizu 890ddd
#ifdef MACOSX
Shinya Kitaoka 120a6e
    // Retrieve it by invoking sysctl
Shinya Kitaoka 120a6e
    size_t valSize = sizeof(TINT64);
Shinya Kitaoka 120a6e
    TINT64 val;
Shinya Kitaoka 120a6e
    sysctlbyname("kern.sysv.shmmax", &val, &valSize, NULL, 0);
Shinya Kitaoka 120a6e
    shm_max = std::min(val, (TINT64)(std::numeric_limits<int>::max)());</int>
Toshihiro Shimizu 890ddd
#else
Shinya Kitaoka 120a6e
    // Windows case: no such limit
Shinya Kitaoka 120a6e
    // Observe that QSharedMemory accepts only an int size - so the num_lim is
Shinya Kitaoka 120a6e
    // against int.
Shinya Kitaoka 120a6e
    shm_max = (std::numeric_limits<int>::max)();</int>
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  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
Shinya Kitaoka 120a6e
int tipc::shm_maxSegmentCount() {
Shinya Kitaoka 120a6e
  if (shm_seg < 0) {
Toshihiro Shimizu 890ddd
#ifdef MACOSX
Shinya Kitaoka 120a6e
    size_t valSize = sizeof(TINT64);
Shinya Kitaoka 120a6e
    TINT64 val;
Shinya Kitaoka 120a6e
    sysctlbyname("kern.sysv.shmseg", &val, &valSize, NULL, 0);
Shinya Kitaoka 120a6e
    shm_seg = std::min(val, (TINT64)(std::numeric_limits<int>::max)());</int>
Toshihiro Shimizu 890ddd
#else
Shinya Kitaoka 120a6e
    // Windows case: no such limit - again, using limit against max due to Qt
Shinya Kitaoka 120a6e
    shm_seg = (std::numeric_limits<int>::max)();</int>
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return shm_seg;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int tipc::shm_maxSharedPages() {
Shinya Kitaoka 120a6e
  if (shm_all < 0) {
Toshihiro Shimizu 890ddd
#ifdef MACOSX
Shinya Kitaoka 120a6e
    size_t valSize = sizeof(TINT64);
Shinya Kitaoka 120a6e
    TINT64 val;
Shinya Kitaoka 120a6e
    sysctlbyname("kern.sysv.shmall", &val, &valSize, NULL, 0);
Shinya Kitaoka 120a6e
    shm_all = std::min(val, (TINT64)(std::numeric_limits<int>::max)());</int>
Toshihiro Shimizu 890ddd
#else
Shinya Kitaoka 120a6e
    shm_all = (std::numeric_limits<int>::max)();</int>
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return shm_all;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int tipc::shm_maxSharedCount() {
Shinya Kitaoka 120a6e
  if (shm_mni < 0) {
Toshihiro Shimizu 890ddd
#ifdef MACOSX
Shinya Kitaoka 120a6e
    size_t valSize = sizeof(TINT64);
Shinya Kitaoka 120a6e
    TINT64 val;
Shinya Kitaoka 120a6e
    sysctlbyname("kern.sysv.shmmni", &val, &valSize, NULL, 0);
Shinya Kitaoka 120a6e
    shm_mni = std::min(val, (TINT64)(std::numeric_limits<int>::max)());</int>
Toshihiro Shimizu 890ddd
#else
Shinya Kitaoka 120a6e
    shm_mni = (std::numeric_limits<int>::max)();</int>
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  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
*/
Shinya Kitaoka 120a6e
void tipc::shm_set(int shmmax, int shmseg, int shmall, int shmmni) {
Shinya Kitaoka 120a6e
  tipc_debug(qDebug("shmmax: %i, shmseg: %i, shmall: %i, shmmni: %i", shmmax,
Shinya Kitaoka 120a6e
                    shmseg, shmall, shmmni));
Toshihiro Shimizu 890ddd
#ifdef MACOSX
Shinya Kitaoka 120a6e
  TINT64 val;
Shinya Kitaoka 120a6e
  int err;
Shinya Kitaoka 120a6e
  if (shmmax > 0) {
Shinya Kitaoka 120a6e
    val = shmmax;
Shinya Kitaoka 120a6e
    err = sysctlbyname("kern.sysv.shmmax", NULL, NULL, &val, sizeof(TINT64));
Shinya Kitaoka 120a6e
    if (!err) shm_max = shmmax;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (shmseg > 0) {
Shinya Kitaoka 120a6e
    val = shmseg;
Shinya Kitaoka 120a6e
    err = sysctlbyname("kern.sysv.shmseg", NULL, NULL, &val, sizeof(TINT64));
Shinya Kitaoka 120a6e
    if (!err) shm_seg = shmseg;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (shmall > 0) {
Shinya Kitaoka 120a6e
    val = shmall;
Shinya Kitaoka 120a6e
    err = sysctlbyname("kern.sysv.shmall", NULL, NULL, &val, sizeof(TINT64));
Shinya Kitaoka 120a6e
    if (!err) shm_all = shmall;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (shmmni > 0) {
Shinya Kitaoka 120a6e
    val = shmmni;
Shinya Kitaoka 120a6e
    err = sysctlbyname("kern.sysv.shmmni", NULL, NULL, &val, sizeof(TINT64));
Shinya Kitaoka 120a6e
    if (!err) shm_mni = shmmni;
Shinya Kitaoka 120a6e
  }
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
    */
    Shinya Kitaoka 120a6e
    int tipc::create(QSharedMemory &shmem, int size, bool strictSize) {
    Shinya Kitaoka 120a6e
      bool ok, retried = false;
    Toshihiro Shimizu 890ddd
    Shinya Kitaoka 120a6e
      if (!strictSize) size = std::min(size, (int)shm_maxSegmentSize());
    Toshihiro Shimizu 890ddd
    Shinya Kitaoka 120a6e
      tipc_debug(qDebug() << "shMem create: size =" << size);
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    retry:
    Toshihiro Shimizu 890ddd
    Shinya Kitaoka 120a6e
      ok = shmem.create(size);
    Shinya Kitaoka 120a6e
      if (!ok) {
    Shinya Kitaoka 120a6e
        tipc_debug(qDebug() << "Error: Shared Segment could not be created: #"
    Shinya Kitaoka 120a6e
                            << shmem.errorString());
    Shinya Kitaoka 120a6e
    Shinya Kitaoka 120a6e
        // Unix-specific error recovery follows. See Qt's docs about it.
    Shinya Kitaoka 120a6e
    Shinya Kitaoka 120a6e
        // Try to recover error #AlreadyExists - supposedly, the server crashed in a
    Shinya Kitaoka 120a6e
        // previous instance.
    Shinya Kitaoka 120a6e
        // As shared memory segments that happen to go this way are owned by the
    Shinya Kitaoka 120a6e
        // server process with 1
    Shinya Kitaoka 120a6e
        // reference count, detaching it now may solve the issue.
    Shinya Kitaoka 120a6e
        if (shmem.error() == QSharedMemory::AlreadyExists && !retried) {
    Shinya Kitaoka 120a6e
          retried = true;  // We're trying this only once... for now it works.
    Shinya Kitaoka 120a6e
          shmem.attach();
    Shinya Kitaoka 120a6e
          shmem.detach();
    Shinya Kitaoka 120a6e
          goto retry;
    Shinya Kitaoka 120a6e
        }
    Shinya Kitaoka 120a6e
    Shinya Kitaoka 120a6e
        return -1;
    Shinya Kitaoka 120a6e
      }
    Shinya Kitaoka 120a6e
    Shinya Kitaoka 120a6e
      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
    */
    Shinya Kitaoka 120a6e
    bool tipc::writeShMemBuffer(Stream &stream, Message &msg, int bufSize,
    Shinya Kitaoka 120a6e
                                ShMemWriter *dataWriter) {
    Shinya Kitaoka 120a6e
      tipc_debug(QTime time; time.start());
    Shinya Kitaoka 120a6e
      tipc_debug(qDebug("tipc::writeShMemBuffer entry"));
    Shinya Kitaoka 120a6e
    Shinya Kitaoka 120a6e
      static QSemaphore sem(tipc::shm_maxSegmentCount());
    Shinya Kitaoka 120a6e
      sem.acquire(1);
    Shinya Kitaoka 120a6e
    Shinya Kitaoka 120a6e
      {
    Shinya Kitaoka 120a6e
        // Create a shared memory segment, possibly of passed size
    Shinya Kitaoka 120a6e
        QSharedMemory shmem(tipc::uniqueId());
    Shinya Kitaoka 120a6e
        bool ok = (tipc::create(shmem, bufSize) > 0);
    Shinya Kitaoka 120a6e
        if (!ok) goto err;
    Shinya Kitaoka 120a6e
    Shinya Kitaoka 120a6e
        // Communicate the shared memory id and bufSize to the reader
    Shinya Kitaoka 120a6e
        msg << QString("shm") << shmem.key() << bufSize;
    Shinya Kitaoka 120a6e
    Shinya Kitaoka 120a6e
        // Fill in data until all the buffer has been sent
    Shinya Kitaoka 120a6e
        int chunkData, remainingData = bufSize;
    Shinya Kitaoka 120a6e
        while (remainingData > 0) {
    Shinya Kitaoka 120a6e
          // Write to the shared memory segment
    Shinya Kitaoka 120a6e
          tipc_debug(QTime xchTime; xchTime.start());
    Shinya Kitaoka 120a6e
          shmem.lock();
    Shinya Kitaoka 120a6e
          remainingData -= chunkData = dataWriter->write(
    Shinya Kitaoka 120a6e
              (char *)shmem.data(), std::min(shmem.size(), remainingData));
    Shinya Kitaoka 120a6e
          shmem.unlock();
    Shinya Kitaoka 120a6e
          tipc_debug(qDebug() << "exchange time:" << xchTime.elapsed());
    Shinya Kitaoka 120a6e
    Shinya Kitaoka 120a6e
          stream << (msg << QString("chk") << chunkData);
    Shinya Kitaoka 120a6e
    Shinya Kitaoka 120a6e
          if (tipc::readMessage(stream, msg) != "ok") goto err;
    Shinya Kitaoka 120a6e
    Shinya Kitaoka 120a6e
          msg.clear();
    Shinya Kitaoka 120a6e
        }
    Shinya Kitaoka 120a6e
      }
    Shinya Kitaoka 120a6e
    Shinya Kitaoka 120a6e
      sem.release(1);
    Shinya Kitaoka 120a6e
      tipc_debug(qDebug("tipc::writeShMemBuffer exit"));
    Shinya Kitaoka 120a6e
      tipc_debug(qDebug() << "tipc::writeShMemBuffer time:" << time.elapsed());
    Shinya Kitaoka 120a6e
      return true;
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    err:
    Toshihiro Shimizu 890ddd
    Shinya Kitaoka 120a6e
      tipc_debug(qDebug("tipc::writeShMemBuffer exit (error)"));
    Toshihiro Shimizu 890ddd
    Shinya Kitaoka 120a6e
      msg.clear();
    Shinya Kitaoka 120a6e
      sem.release(1);
    Shinya Kitaoka 120a6e
      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
    */
    Shinya Kitaoka 120a6e
    bool tipc::readShMemBuffer(Stream &stream, Message &msg,
    Shinya Kitaoka 120a6e
                               ShMemReader *dataReader) {
    Shinya Kitaoka 120a6e
      tipc_debug(QTime time; time.start(););
    Shinya Kitaoka 120a6e
      tipc_debug(qDebug("tipc::readShMemBuffer entry"));
    Shinya Kitaoka 120a6e
    Shinya Kitaoka 120a6e
      // Read the id from stream
    Shinya Kitaoka 120a6e
      QString res(tipc::readMessage(stream, msg));
    Shinya Kitaoka 120a6e
      if (res != "shm") {
    Shinya Kitaoka 120a6e
        tipc_debug(qDebug("tipc::readShMemBuffer exit (res != \"shm\")"));
    Shinya Kitaoka 120a6e
        return false;
    Shinya Kitaoka 120a6e
      }
    Shinya Kitaoka 120a6e
    Shinya Kitaoka 120a6e
      // Read message and reply
    Shinya Kitaoka 120a6e
      QString id, chkStr;
    Shinya Kitaoka 120a6e
      int bufSize;
    Shinya Kitaoka 120a6e
      msg >> id >> bufSize >> chkStr;
    Shinya Kitaoka 120a6e
    Shinya Kitaoka 120a6e
      // Data is ready to be read - attach to the shared memory segment.
    Shinya Kitaoka 120a6e
      QSharedMemory shmem(id);
    Shinya Kitaoka 120a6e
      shmem.attach();
    Shinya Kitaoka 120a6e
      if (!shmem.isAttached()) {
    Shinya Kitaoka 120a6e
        tipc_debug(qDebug("tipc::readShMemBuffer exit (shmem not attached)"));
    Shinya Kitaoka 120a6e
        return false;
    Shinya Kitaoka 120a6e
      }
    Shinya Kitaoka 120a6e
    Shinya Kitaoka 120a6e
      // Start reading from it
    Shinya Kitaoka 120a6e
      int chunkData, remainingData = bufSize;
    Shinya Kitaoka 120a6e
      while (true) {
    Shinya Kitaoka 120a6e
        msg >> chunkData;
    Shinya Kitaoka 120a6e
    Shinya Kitaoka 120a6e
        tipc_debug(QTime xchTime; xchTime.start());
    Shinya Kitaoka 120a6e
        shmem.lock();
    Shinya Kitaoka 120a6e
        remainingData -= dataReader->read((const char *)shmem.data(), chunkData);
    Shinya Kitaoka 120a6e
        shmem.unlock();
    Shinya Kitaoka 120a6e
        tipc_debug(qDebug() << "exchange time:" << xchTime.elapsed());
    Shinya Kitaoka 120a6e
    Shinya Kitaoka 120a6e
        // Data was read. Inform the writer
    Shinya Kitaoka 120a6e
        stream << (msg << clr << QString("ok"));
    Shinya Kitaoka 120a6e
        stream.flush();
    Shinya Kitaoka 120a6e
    Shinya Kitaoka 120a6e
        if (remainingData <= 0) break;
    Shinya Kitaoka 120a6e
    Shinya Kitaoka 120a6e
        // Wait for more chunks
    Shinya Kitaoka 120a6e
        if (tipc::readMessage(stream, msg) != "chk") {
    Shinya Kitaoka 120a6e
          tipc_debug(
    Shinya Kitaoka 120a6e
              qDebug("tipc::readShMemBuffer exit (unexpected chunk absence)"));
    Shinya Kitaoka 120a6e
          return false;
    Shinya Kitaoka 120a6e
        }
    Shinya Kitaoka 120a6e
      }
    Shinya Kitaoka 120a6e
    Shinya Kitaoka 120a6e
      shmem.detach();
    Shinya Kitaoka 120a6e
      tipc_debug(qDebug("tipc::readShMemBuffer exit"));
    Shinya Kitaoka 120a6e
      tipc_debug(qDebug() << "tipc::readShMemBuffer time:" << time.elapsed());
    Shinya Kitaoka 120a6e
      return true;
    Toshihiro Shimizu 890ddd
    }