mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06:45 +08:00
complete ipc send & recv; prepare ipc::channel; add ipc ut (basic test); add ut suit name;
This commit is contained in:
parent
c8e81e2794
commit
85bb05bb52
@ -1,6 +1,7 @@
|
|||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
|
|
||||||
QT += core testlib
|
QT += core testlib
|
||||||
|
QT -= gui
|
||||||
CONFIG += console c++14
|
CONFIG += console c++14
|
||||||
CONFIG -= app_bundle
|
CONFIG -= app_bundle
|
||||||
|
|
||||||
@ -17,6 +18,7 @@ HEADERS += \
|
|||||||
SOURCES += \
|
SOURCES += \
|
||||||
../test/main.cpp \
|
../test/main.cpp \
|
||||||
../test/test_shm.cpp \
|
../test/test_shm.cpp \
|
||||||
../test/test_circ.cpp
|
../test/test_circ.cpp \
|
||||||
|
../test/test_ipc.cpp
|
||||||
|
|
||||||
LIBS += -L$${DESTDIR} -lipc
|
LIBS += -L$${DESTDIR} -lipc
|
||||||
|
|||||||
@ -65,7 +65,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ui_t index_of(uc_t c) {
|
static ui_t index_of(uc_t c) {
|
||||||
return static_cast<ui_t>(c & std::numeric_limits<ui_t>::max());
|
return static_cast<ui_t>(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_t index_of(elem_t* el) {
|
ui_t index_of(elem_t* el) {
|
||||||
@ -96,7 +96,7 @@ public:
|
|||||||
while (lc_.exchange(1, std::memory_order_acquire)) {
|
while (lc_.exchange(1, std::memory_order_acquire)) {
|
||||||
std::this_thread::yield();
|
std::this_thread::yield();
|
||||||
}
|
}
|
||||||
elem_t* el = elem(wt_.load(std::memory_order_relaxed));
|
elem_t* el = elem(index_of(wt_.load(std::memory_order_relaxed)));
|
||||||
// check all consumers have finished reading
|
// check all consumers have finished reading
|
||||||
while(1) {
|
while(1) {
|
||||||
std::uint32_t expected = 0;
|
std::uint32_t expected = 0;
|
||||||
|
|||||||
@ -13,7 +13,24 @@ using shm::handle_t;
|
|||||||
IPC_EXPORT handle_t connect (std::string const & name);
|
IPC_EXPORT handle_t connect (std::string const & name);
|
||||||
IPC_EXPORT void disconnect(handle_t h);
|
IPC_EXPORT void disconnect(handle_t h);
|
||||||
|
|
||||||
IPC_EXPORT bool send(handle_t h, byte_t* data, int size);
|
IPC_EXPORT bool send(handle_t h, void* data, int size);
|
||||||
IPC_EXPORT std::vector<byte_t> recv(handle_t h);
|
IPC_EXPORT std::vector<byte_t> recv(handle_t h);
|
||||||
|
|
||||||
|
class channel_;
|
||||||
|
class IPC_EXPORT channel {
|
||||||
|
public:
|
||||||
|
channel(void);
|
||||||
|
channel(std::string const & name);
|
||||||
|
channel(channel&& rhs);
|
||||||
|
|
||||||
|
~channel(void);
|
||||||
|
|
||||||
|
void swap(channel& rhs);
|
||||||
|
channel& operator=(channel rhs);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class channel_;
|
||||||
|
channel_* p_;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace ipc
|
} // namespace ipc
|
||||||
|
|||||||
80
src/ipc.cpp
80
src/ipc.cpp
@ -3,6 +3,7 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "ipc.h"
|
#include "ipc.h"
|
||||||
#include "circ_queue.h"
|
#include "circ_queue.h"
|
||||||
@ -14,8 +15,9 @@ using namespace ipc;
|
|||||||
using data_t = byte_t[data_length];
|
using data_t = byte_t[data_length];
|
||||||
|
|
||||||
struct msg_t {
|
struct msg_t {
|
||||||
int remain_;
|
int remain_;
|
||||||
data_t data_;
|
unsigned id_;
|
||||||
|
data_t data_;
|
||||||
};
|
};
|
||||||
|
|
||||||
using queue_t = circ::queue<msg_t>;
|
using queue_t = circ::queue<msg_t>;
|
||||||
@ -67,7 +69,7 @@ void disconnect(handle_t h) {
|
|||||||
h2q__.erase(it);
|
h2q__.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool send(handle_t h, byte_t* data, int size) {
|
bool send(handle_t h, void* data, int size) {
|
||||||
if (data == nullptr) {
|
if (data == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -78,51 +80,91 @@ bool send(handle_t h, byte_t* data, int size) {
|
|||||||
if (queue == nullptr) {
|
if (queue == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
queue_t drop_box { queue->elems() };
|
static unsigned msg_id = 0;
|
||||||
|
++msg_id; // calc a new message id
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
for (int i = 0; i < (size / static_cast<int>(data_length)); ++i, offset += data_length) {
|
for (int i = 0; i < (size / static_cast<int>(data_length)); ++i, offset += data_length) {
|
||||||
msg_t msg {
|
msg_t msg {
|
||||||
size - offset - static_cast<int>(data_length),
|
size - offset - static_cast<int>(data_length),
|
||||||
{ 0 }
|
msg_id, { 0 }
|
||||||
};
|
};
|
||||||
std::memcpy(msg.data_, data + offset, data_length);
|
std::memcpy(msg.data_, static_cast<byte_t*>(data) + offset, data_length);
|
||||||
drop_box.push(msg);
|
queue->push(msg);
|
||||||
}
|
}
|
||||||
int remain = size - offset;
|
int remain = size - offset;
|
||||||
if (remain > 0) {
|
if (remain > 0) {
|
||||||
msg_t msg { remain - static_cast<int>(data_length), { 0 } };
|
msg_t msg {
|
||||||
std::memcpy(msg.data_, data + offset, static_cast<std::size_t>(remain));
|
remain - static_cast<int>(data_length),
|
||||||
drop_box.push(msg);
|
msg_id, { 0 }
|
||||||
|
};
|
||||||
|
std::memcpy(msg.data_, static_cast<byte_t*>(data) + offset,
|
||||||
|
static_cast<std::size_t>(remain));
|
||||||
|
queue->push(msg);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<byte_t> recv(handle_t h) {
|
std::vector<byte_t> recv(handle_t h) {
|
||||||
std::vector<byte_t> all;
|
|
||||||
auto queue = queue_of(h);
|
auto queue = queue_of(h);
|
||||||
if (queue == nullptr) {
|
if (queue == nullptr) {
|
||||||
return all;
|
return {};
|
||||||
}
|
}
|
||||||
if (!queue->connected()) {
|
if (!queue->connected()) {
|
||||||
queue->connect();
|
queue->connect();
|
||||||
}
|
}
|
||||||
|
static thread_local std::unordered_map<int, std::vector<byte_t>> all;
|
||||||
do {
|
do {
|
||||||
auto msg = queue->pop();
|
auto msg = queue->pop();
|
||||||
auto last_size = all.size();
|
// here comes a new message
|
||||||
|
auto& cache = all[msg.id_]; // find the cache using message id
|
||||||
|
auto last_size = cache.size();
|
||||||
if (msg.remain_ > 0) {
|
if (msg.remain_ > 0) {
|
||||||
all.resize(last_size + data_length);
|
cache.resize(last_size + data_length);
|
||||||
std::memcpy(all.data() + last_size, msg.data_, data_length);
|
std::memcpy(cache.data() + last_size, msg.data_, data_length);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// remain_ is minus & abs(remain_) < data_length
|
// remain_ is minus & abs(remain_) < data_length
|
||||||
std::size_t remain = static_cast<std::size_t>(
|
std::size_t remain = static_cast<std::size_t>(
|
||||||
static_cast<int>(data_length) + msg.remain_);
|
static_cast<int>(data_length) + msg.remain_);
|
||||||
all.resize(last_size + remain);
|
cache.resize(last_size + remain);
|
||||||
std::memcpy(all.data() + last_size, msg.data_, remain);
|
std::memcpy(cache.data() + last_size, msg.data_, remain);
|
||||||
break;
|
// finish this message, erase it from cache
|
||||||
|
auto ret { std::move(cache) };
|
||||||
|
all.erase(msg.id_);
|
||||||
|
return std::move(ret);
|
||||||
}
|
}
|
||||||
} while(1);
|
} while(1);
|
||||||
return all;
|
}
|
||||||
|
|
||||||
|
class channel_ {
|
||||||
|
public:
|
||||||
|
};
|
||||||
|
|
||||||
|
channel::channel(void)
|
||||||
|
: p_(new channel_) {
|
||||||
|
}
|
||||||
|
|
||||||
|
channel::channel(std::string const & /*name*/)
|
||||||
|
: channel() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
channel::channel(channel&& rhs)
|
||||||
|
: channel() {
|
||||||
|
swap(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
channel::~channel(void) {
|
||||||
|
delete p_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void channel::swap(channel& rhs) {
|
||||||
|
std::swap(p_, rhs.p_);
|
||||||
|
}
|
||||||
|
|
||||||
|
channel& channel::operator=(channel rhs) {
|
||||||
|
swap(rhs);
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ipc
|
} // namespace ipc
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
#include <QString>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
|
||||||
@ -18,6 +20,14 @@ TestSuite::TestSuite(void) {
|
|||||||
_.suites_ << this;
|
_.suites_ << this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* TestSuite::name(void) const {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSuite::initTestCase(void) {
|
||||||
|
qDebug() << QString("#### Start: %1 ####").arg(name());
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
QCoreApplication app(argc, argv);
|
QCoreApplication app(argc, argv);
|
||||||
Q_UNUSED(app)
|
Q_UNUSED(app)
|
||||||
|
|||||||
@ -8,4 +8,10 @@ class TestSuite : public QObject
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit TestSuite(void);
|
explicit TestSuite(void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual const char* name(void) const;
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
virtual void initTestCase(void);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -9,14 +9,18 @@
|
|||||||
|
|
||||||
#include "circ_elem_array.h"
|
#include "circ_elem_array.h"
|
||||||
#include "circ_queue.h"
|
#include "circ_queue.h"
|
||||||
#include "test.h"
|
|
||||||
#include "stopwatch.hpp"
|
#include "stopwatch.hpp"
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
class Unit : public TestSuite {
|
class Unit : public TestSuite {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
const char* name(void) const {
|
||||||
|
return "test_circ";
|
||||||
|
}
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void initTestCase(void);
|
void initTestCase(void);
|
||||||
void cleanupTestCase(void);
|
void cleanupTestCase(void);
|
||||||
@ -36,6 +40,7 @@ using cq_t = ipc::circ::elem_array<12>;
|
|||||||
cq_t* cq__;
|
cq_t* cq__;
|
||||||
|
|
||||||
void Unit::initTestCase(void) {
|
void Unit::initTestCase(void) {
|
||||||
|
TestSuite::initTestCase();
|
||||||
cq__ = new cq_t;
|
cq__ = new cq_t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
29
test/test_ipc.cpp
Normal file
29
test/test_ipc.cpp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#include "ipc.h"
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class Unit : public TestSuite {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
const char* name(void) const {
|
||||||
|
return "test_ipc";
|
||||||
|
}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void test_send_recv(void);
|
||||||
|
} unit__;
|
||||||
|
|
||||||
|
#include "test_ipc.moc"
|
||||||
|
|
||||||
|
void Unit::test_send_recv(void) {
|
||||||
|
auto h = ipc::connect("my-ipc");
|
||||||
|
QVERIFY(h != nullptr);
|
||||||
|
char data[] = "hello ipc!";
|
||||||
|
QVERIFY(ipc::send(h, data, sizeof(data)));
|
||||||
|
auto got = ipc::recv(h);
|
||||||
|
QCOMPARE((char*)got.data(), data);
|
||||||
|
ipc::disconnect(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // internal-linkage
|
||||||
@ -12,6 +12,10 @@ namespace {
|
|||||||
class Unit : public TestSuite {
|
class Unit : public TestSuite {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
const char* name(void) const {
|
||||||
|
return "test_shm";
|
||||||
|
}
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void test_acquire(void);
|
void test_acquire(void);
|
||||||
void test_release(void);
|
void test_release(void);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user