Skip to content

Commit f2f1af8

Browse files
authored
Merge pull request #74 from mutouyun/develop
Develop
2 parents a572295 + f25668c commit f2f1af8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+2188
-485
lines changed

include/libipc/condition.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ class IPC_EXPORT condition {
2727
void close() noexcept;
2828

2929
bool wait(ipc::sync::mutex &mtx, std::uint64_t tm = ipc::invalid_value) noexcept;
30-
bool notify() noexcept;
31-
bool broadcast() noexcept;
30+
bool notify(ipc::sync::mutex &mtx) noexcept;
31+
bool broadcast(ipc::sync::mutex &mtx) noexcept;
3232

3333
private:
3434
class condition_;

src/CMakeLists.txt

+8-13
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
project(ipc)
22

3-
if(UNIX)
4-
file(GLOB SRC_FILES ${LIBIPC_PROJECT_DIR}/src/libipc/platform/*_linux.cpp)
5-
else()
6-
file(GLOB SRC_FILES ${LIBIPC_PROJECT_DIR}/src/libipc/platform/*_win.cpp)
7-
endif()
83
aux_source_directory(${LIBIPC_PROJECT_DIR}/src/libipc SRC_FILES)
94
aux_source_directory(${LIBIPC_PROJECT_DIR}/src/libipc/sync SRC_FILES)
5+
aux_source_directory(${LIBIPC_PROJECT_DIR}/src/libipc/platform SRC_FILES)
106

117
file(GLOB HEAD_FILES
128
${LIBIPC_PROJECT_DIR}/include/libipc/*.h
@@ -33,28 +29,27 @@ set_target_properties(${PROJECT_NAME}
3329
PROPERTIES
3430
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
3531
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
36-
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" )
32+
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
3733

3834
# set version
3935
set_target_properties(${PROJECT_NAME}
4036
PROPERTIES
41-
VERSION 1.1.0
42-
SOVERSION 2)
37+
VERSION 1.2.0
38+
SOVERSION 3)
4339

4440
target_include_directories(${PROJECT_NAME}
4541
PUBLIC ${LIBIPC_PROJECT_DIR}/include
4642
PRIVATE ${LIBIPC_PROJECT_DIR}/src
47-
)
43+
$<$<BOOL:UNIX>:${LIBIPC_PROJECT_DIR}/src/libipc/platform/linux>)
4844

4945
if(NOT MSVC)
5046
target_link_libraries(${PROJECT_NAME} PUBLIC
51-
pthread
52-
$<$<NOT:$<STREQUAL:${CMAKE_SYSTEM_NAME},Windows>>:rt>)
47+
$<$<NOT:$<STREQUAL:${CMAKE_SYSTEM_NAME},QNX>>:pthread>
48+
$<$<NOT:$<OR:$<STREQUAL:${CMAKE_SYSTEM_NAME},Windows>,$<STREQUAL:${CMAKE_SYSTEM_NAME},QNX>>>:rt>)
5349
endif()
5450

5551
install(
5652
TARGETS ${PROJECT_NAME}
5753
RUNTIME DESTINATION bin
5854
LIBRARY DESTINATION lib
59-
ARCHIVE DESTINATION lib
60-
)
55+
ARCHIVE DESTINATION lib)

src/libipc/ipc.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -687,8 +687,8 @@ buff_t chan_impl<Flag>::try_recv(ipc::handle_t h) {
687687
}
688688

689689
template struct chan_impl<ipc::wr<relat::single, relat::single, trans::unicast >>;
690-
template struct chan_impl<ipc::wr<relat::single, relat::multi , trans::unicast >>;
691-
template struct chan_impl<ipc::wr<relat::multi , relat::multi , trans::unicast >>;
690+
// template struct chan_impl<ipc::wr<relat::single, relat::multi , trans::unicast >>; // TBD
691+
// template struct chan_impl<ipc::wr<relat::multi , relat::multi , trans::unicast >>; // TBD
692692
template struct chan_impl<ipc::wr<relat::single, relat::multi , trans::broadcast>>;
693693
template struct chan_impl<ipc::wr<relat::multi , relat::multi , trans::broadcast>>;
694694

src/libipc/platform/detail.h

+22-25
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,22 @@
1-
#pragma once
1+
#ifndef LIBIPC_SRC_PLATFORM_DETAIL_H_
2+
#define LIBIPC_SRC_PLATFORM_DETAIL_H_
3+
4+
// detect platform
5+
6+
#if defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || \
7+
defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || \
8+
defined(WINCE) || defined(_WIN32_WCE)
9+
# define IPC_OS_WINDOWS_
10+
#elif defined(__linux__) || defined(__linux)
11+
# define IPC_OS_LINUX_
12+
#elif defined(__QNX__)
13+
# define IPC_OS_QNX_
14+
#elif defined(__APPLE__)
15+
#elif defined(__ANDROID__)
16+
// TBD
17+
#endif
18+
19+
#if defined(__cplusplus)
220

321
#include <memory>
422
#include <mutex>
@@ -22,18 +40,6 @@
2240
# error "IPC_CONSTEXPR_ has been defined."
2341
#endif
2442

25-
// detect platform
26-
27-
#if defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || \
28-
defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || \
29-
defined(WINCE) || defined(_WIN32_WCE)
30-
# define IPC_OS_WINDOWS_
31-
#endif/*WIN*/
32-
33-
#if defined(__linux__) || defined(__linux)
34-
# define IPC_OS_LINUX_
35-
#endif/*linux*/
36-
3743
#if __cplusplus >= 201703L
3844

3945
#define IPC_UNUSED_ [[maybe_unused]]
@@ -123,17 +129,8 @@ constexpr const T& (min)(const T& a, const T& b) {
123129

124130
#endif/*__cplusplus < 201703L*/
125131

126-
template <typename T, typename U>
127-
auto horrible_cast(U rhs) noexcept
128-
-> typename std::enable_if<std::is_trivially_copyable<T>::value
129-
&& std::is_trivially_copyable<U>::value, T>::type {
130-
union {
131-
T t;
132-
U u;
133-
} r = {};
134-
r.u = rhs;
135-
return r.t;
136-
}
137-
138132
} // namespace detail
139133
} // namespace ipc
134+
135+
#endif // defined(__cplusplus)
136+
#endif // LIBIPC_SRC_PLATFORM_DETAIL_H_

src/libipc/platform/linux/a0/LICENSE

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
This is free and unencumbered software released into the public domain.
2+
3+
Anyone is free to copy, modify, publish, use, compile, sell, or
4+
distribute this software, either in source code form or as a compiled
5+
binary, for any purpose, commercial or non-commercial, and by any
6+
means.
7+
8+
In jurisdictions that recognize copyright laws, the author or authors
9+
of this software dedicate any and all copyright interest in the
10+
software to the public domain. We make this dedication for the benefit
11+
of the public at large and to the detriment of our heirs and
12+
successors. We intend this dedication to be an overt act of
13+
relinquishment in perpetuity of all present and future rights to this
14+
software under copyright law.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22+
OTHER DEALINGS IN THE SOFTWARE.
23+
24+
For more information, please refer to <http://unlicense.org>
+213
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
<h1 align="center">
2+
<br>
3+
<img src="https://raw.githubusercontent.com/alephzero/logo/master/rendered/alephzero.svg" width="256px">
4+
<br>
5+
AlephZero
6+
</h1>
7+
8+
<h3 align="center">Simple, Robust, Fast IPC.</h3>
9+
10+
<p align="center">
11+
<a href="https://github.com/alephzero/alephzero/actions?query=workflow%3ACI"><img src="https://github.com/alephzero/alephzero/workflows/CI/badge.svg"></a>
12+
<a href="https://codecov.io/gh/alephzero/alephzero"><img src="https://codecov.io/gh/alephzero/alephzero/branch/master/graph/badge.svg"></a>
13+
<a href="https://alephzero.readthedocs.io/en/latest/?badge=latest"><img src="https://readthedocs.org/projects/alephzero/badge/?version=latest"></a>
14+
<a href="http://unlicense.org"><img src="https://img.shields.io/badge/license-Unlicense-blue.svg"></a>
15+
</p>
16+
17+
<p align="center">
18+
<a href="#overview">Overview</a> •
19+
<a href="#transport">Transport</a> •
20+
<a href="#protocol">Protocol</a> •
21+
<a href="#examples">Examples</a> •
22+
<a href="#installation">Installation</a> •
23+
<a href="#across-dockers">Across Dockers</a>
24+
</p>
25+
26+
# Overview
27+
28+
[Presentation from March 25, 2020](https://docs.google.com/presentation/d/12KE9UucjZPtpVnM1NljxOqBolBBKECWJdrCoE2yJaBw/edit#slide=id.p)
29+
30+
AlephZero is a library for message based communication between programs running on the same machine.
31+
32+
## Simple
33+
34+
AlephZero's main goal is to be simple to use. Nothing is higher priority.
35+
36+
There is no "master" process in between your nodes that is needed to do handshakes or exchanges of any kind. All you need is the topic name.
37+
38+
See the <a href="#examples">Examples</a>.
39+
40+
## Robust
41+
42+
This is probably the main value of AlephZero, above similar libraries.
43+
44+
AlephZero uses a lot of tricks to ensure the state of all channels is consistent, even when programs die. This includes double-buffering the state of the communication channel and [robustifying](https://man7.org/linux/man-pages/man3/pthread_mutexattr_setrobust.3.html) the locks and notification channels.
45+
46+
## Fast
47+
48+
AlephZero uses shared memory across multiple processes to read and write messages, minimizing the involvement of the kernel. The kernel only really gets involved in notifying a process that a new message exists, and for that we use futex (fast user-space mutex).
49+
50+
TODO: Benchmarks
51+
52+
# Transport
53+
54+
AlephZero, at its core, is a simple allocator on top of a contiguous region of memory. Usually, shared-memory. The allocator of choice is a circular-linked-list, which is fast, simple, and sufficient for the protocol listed below. It also plays well with the robustness requirement.
55+
56+
This has a number of implications. For one, this means that old messages are kept around until the space is needed. The oldest messages are always discarded before any more recent messages.
57+
58+
# Protocol
59+
60+
Rather than exposing the low-level transport directly, AlephZero provides a few higher level protocol:
61+
62+
* <b>PubSub</b>: Broadcast published messages. Subscribers get notified.
63+
* <b>RPC</b>: Request-response.
64+
* <b>PRPC (Progressive RPC)</b>: Request-streaming response.
65+
* <b>Sessions</b>: Bi-directional channel of communication. Not yet implemented. Let me know if you want this.
66+
67+
# Examples
68+
69+
Many more example and an interactive experience can be found at: https://github.com/alephzero/playground
70+
71+
For the curious, here are some simple snippets to get you started:
72+
73+
To begin with, we need to include AlephZero:
74+
```cc
75+
#include <a0.h>
76+
```
77+
78+
## PubSub
79+
80+
You can have as many publisher and subscribers on the same topic as you wish. They just need to agree on the filename.
81+
82+
```cc
83+
a0::Publisher p("my_pubsub_topic");
84+
p.pub("foo");
85+
```
86+
87+
You just published `"foo"` to the `"my_pubsub_topic"`.
88+
89+
To read those message, you can create a subscriber on the same topic:
90+
```cc
91+
a0::Subscriber sub(
92+
"my_pubsub_topic",
93+
A0_INIT_AWAIT_NEW, // or MOST_RECENT or OLDEST
94+
A0_ITER_NEWEST, // or NEXT
95+
[](a0::PacketView pkt_view) {
96+
std::cout << "Got: " << pkt_view.payload() << std::endl;
97+
});
98+
```
99+
The callback will trigger whenever a message is published.
100+
101+
The `Subscriber` object spawns a thread that will read the topic and call the callback.
102+
103+
The `A0_INIT` tells the subscriber where to start reading.
104+
* `A0_INIT_AWAIT_NEW`: Start with messages published after the creation of the subscriber.
105+
* `A0_INIT_MOST_RECENT`: Start with the most recently published message. Useful for state and configuration. But be careful, this can be quite old!
106+
* `A0_INIT_OLDEST`: Topics keep a history of 16MB (unless configures otherwise). Start with the oldest thing still in there.
107+
108+
The `A0_ITER` tells the subscriber how to continue reading messages. After each callback:
109+
* `A0_ITER_NEXT`: grab the sequentially next message. When you don't want to miss a thing.
110+
* `A0_ITER_NEWEST`: grab the newest available unread message. When you want to keep up with the firehose.
111+
112+
```cc
113+
a0::SubscriberSync sub_sync(
114+
"my_pubsub_topic",
115+
A0_INIT_OLDEST, A0_ITER_NEXT);
116+
while (sub_sync.has_next()) {
117+
auto pkt = sub_sync.next();
118+
std::cout << "Got: " << pkt.payload() << std::endl;
119+
}
120+
```
121+
122+
## RPC
123+
124+
Create an `RpcServer`:
125+
126+
```cc
127+
a0::RpcServer server(
128+
"my_rpc_topic",
129+
/* onrequest = */ [](a0::RpcRequest req) {
130+
std::cout << "Got: " << req.pkt().payload() << std::endl;
131+
req.reply("echo " + std::string(req.pkt().payload()));
132+
},
133+
/* oncancel = */ nullptr);
134+
```
135+
136+
Create an `RpcClient`:
137+
138+
```cc
139+
a0::RpcClient client("my_rpc_topic");
140+
client.send("client msg", [](a0::PacketView reply) {
141+
std::cout << "Got: " << reply.payload() << std::endl;
142+
});
143+
```
144+
145+
# Installation
146+
147+
## Install From Source
148+
149+
### Ubuntu Dependencies
150+
151+
```sh
152+
apt install g++ make
153+
```
154+
155+
### Alpine Dependencies
156+
157+
```sh
158+
apk add g++ linux-headers make
159+
```
160+
161+
### Download And Install
162+
163+
```sh
164+
git clone https://github.com/alephzero/alephzero.git
165+
cd alephzero
166+
make install -j
167+
```
168+
169+
## Install From Package
170+
171+
Coming soon-ish. Let me know if you want this and I'll prioritize it. External support is much appreciated.
172+
173+
## Integration
174+
175+
### Command Line
176+
177+
Add the following to g++ / clang commands.
178+
```sh
179+
-L${libdir} -lalephzero -lpthread
180+
```
181+
182+
### Package-cfg
183+
184+
```sh
185+
pkg-config --cflags --libs alephzero
186+
```
187+
188+
### CMake
189+
190+
Coming soon-ish. Let me know if you want this and I'll prioritize it. External support is much appreciated.
191+
192+
### Bazel
193+
194+
Coming soon-ish. Let me know if you want this and I'll prioritize it.
195+
196+
# Across Dockers
197+
198+
For programs running across different dockers to be able to communicate, we need to have them match up on two flags: `--ipc` and `--pid`.
199+
200+
* `--ipc` shares the `/dev/shm` filesystem. This is necessary to open the same file topics.
201+
* `--pid` shares the process id namespace. This is necessary for the locking and notification systems.
202+
203+
In the simplest case, you can set them both to `host` and talk through the system's global `/dev/shm` and process id namespace.
204+
```sh
205+
docker run --ipc=host --pid=host --name=foo foo_image
206+
docker run --ipc=host --pid=host --name=bar bar_image
207+
```
208+
209+
Or, you can mark one as `shareable` and have the others connect to it:
210+
```sh
211+
docker run --ipc=shareable --pid=shareable --name=foo foo_image
212+
docker run --ipc=container:foo --pid=container:foo --name=bar bar_image
213+
```

0 commit comments

Comments
 (0)