/* ---- This file is part of SECONDO. Copyright (C) 2015, Faculty of Mathematics and Computer Science, Database Systems for New Applications. SECONDO is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. SECONDO is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with SECONDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ---- September 2015 - Nico Kaufmann: IPCLoopBuffer is inspired by an article on codeproject.com by Richard Lin www.codeproject.com/Articles/10618/Loop-buffer-an-efficient-way-of-using-shared-memor (havn't looked at the source so i'm not sure how similar it actually is) */ #include "ipc.h" #include "boost/date_time.hpp" using namespace std; IPCInit::IPCInit() : magicId(0), confirmIdx(0), nextIdx(0) {} IPCLoopBuffer::IPCLoopBuffer() : magicId(0), bufferSize(IPC_QUEUE_BUFFER_SIZE), ownerId(0), readIndex(0), writeIndex(0), totalWritten(0), totalRead(0) {} bool IPCLoopBuffer::avail() { return totalWritten != totalRead; } bool IPCLoopBuffer::read(char* data, unsigned int n) { int offset = 0; while (true) { int available = totalWritten - totalRead; if (available == 0) { continue; } if (available > static_cast(n)) { available = n; } if (readIndex + available >= bufferSize) { available = bufferSize - readIndex; assert(available > 0); } memcpy(data + offset, buffer + readIndex, available); totalRead += available; readIndex += available; if (readIndex == bufferSize) { readIndex = 0; } n -= available; if (n == 0) { return true; } offset += available; } } bool IPCLoopBuffer::write(const char* data, unsigned int n) { int offset = 0; while (true) { int space = bufferSize - (totalWritten - totalRead); assert(space >= 0); if (space == 0) { continue; } if (space > static_cast(n)) { space = n; } if (writeIndex + space >= bufferSize) { space = bufferSize - writeIndex; assert(space > 0); } memcpy(buffer + writeIndex, data + offset, space); totalWritten += space; writeIndex += space; if (writeIndex == bufferSize) { writeIndex = 0; } n -= space; if (n == 0) { return true; } offset += space; } } bool IPCConnection::avail() { return readBuffer->totalWritten != readBuffer->totalRead; } bool IPCConnection::read(char* data, unsigned int n) { if (writeBuffer->ownerId == ownerId) { if (n > 0) { return readBuffer->read(data, n); } return true; } else { cout << "IPC-Error: Ownership corrupted..." << endl; return false; } } bool IPCConnection::write(const char* data, unsigned int n) { if (writeBuffer->ownerId == ownerId) { if (n > 0) { return writeBuffer->write(data, n); } return true; } else { cout << "IPC-Error: Ownership corrupted..." << endl; return false; } } bool IPCConnection::read(IPCMessage* msgType) { return read((char*)msgType, sizeof(IPCMessage)); } bool IPCConnection::write(IPCMessage msgType) { return write((char*)&msgType, sizeof(IPCMessage)); } bool IPCConnection::write(IPCMessage* msgType) { return write((char*)msgType, sizeof(IPCMessage)); } bool IPCConnection::read(int* data) { return read((char*)data, sizeof(int)); } bool IPCConnection::write(const int* data) { return write((char*)data, sizeof(int)); } bool IPCConnection::read(unsigned int* data) { return read((char*)data, sizeof(unsigned int)); } bool IPCConnection::write(const unsigned int* data) { return write((char*)data, sizeof(unsigned int)); } bool IPCConnection::read(double* data) { return read((char*)data, sizeof(double)); } bool IPCConnection::write(const double* data) { return write((char*)data, sizeof(double)); } bool IPCConnection::read(string* data) { int len = 0; if (read(&len)) { if (len > 0 && len < IPC_MAX_STRING_SIZE) { char* temp = new char[len]; if (read(temp, len)) { data->assign(temp, len); delete[] temp; return true; } delete[] temp; } else { data->clear(); return (len == 0); } } return false; } bool IPCConnection::write(const string* data) { int len = data->length(); if (write(&len)) { return write(data->c_str(), len); } else { return false; } } bool IPCConnection::read(IPCArray* data) { if (read(&data->size)) { if (data->size < IPC_MAX_ARRAY_SIZE) { delete[] data->array; bool result = true; data->array = new double[data->size]; for (unsigned int i = 0; i < data->size; ++i) { result &= read((char*)&data->array[i], sizeof(double)); } return result; } } return false; } bool IPCConnection::write(const IPCArray* data) { if (write(&data->size)) { bool result = true; for (unsigned int i = 0; i < data->size; ++i) { result &= write((char*)&data->array[i], sizeof(double)); } return result; } return false; } bool IPCConnection::read(set* data) { unsigned int nrResults; if (read(&nrResults)) { bool result = true; int tempElem; for (unsigned int i = 0; i < nrResults; ++i) { result &= read(&tempElem); if (result) { data->insert(tempElem); } } return result; } return false; } bool IPCConnection::write(const set* data) { unsigned int nrResults = data->size(); if (write(&nrResults)) { bool result = true; if (nrResults > 0) { for (auto it = data->begin(); it != data->end(); ++it) { auto tempResult = *it; result &= write(&tempResult); } } return result; } return false; } bool IPCConnection::read(bool* data) { return read((char*)data, sizeof(bool)); } bool IPCConnection::write(const bool* data) { return write((char*)data, sizeof(bool)); } IPCConnection::~IPCConnection() { close(); } bool IPCConnection::health() { return connected; }