Skip to content

Instantly share code, notes, and snippets.

@Amanieu
Created February 5, 2014 11:59
Show Gist options
  • Save Amanieu/8822209 to your computer and use it in GitHub Desktop.
Save Amanieu/8822209 to your computer and use it in GitHub Desktop.
diff --git a/src/common/IPC.h b/src/common/IPC.h
index c3dbc5c..38778a1 100644
--- a/src/common/IPC.h
+++ b/src/common/IPC.h
@@ -46,9 +46,86 @@ Maryland 20850 USA.
#include "../engine/qcommon/q_shared.h"
#include "../engine/qcommon/qcommon.h"
+namespace IPC {
+
+// Maximum number of bytes that can be sent in a message
+static const size_t MSG_MAX_BYTES = 128 << 10;
+
+// Maximum number of handles that can be sent in a message
+static const size_t MSG_MAX_HANDLES = 8;
+
+// Operating system handle type
+#ifdef _WIN32
+// HANDLE is defined as void* in windows.h
+typedef void* OSHandleType;
+static const OSHandleType INVALID_HANDLE = NULL;
+#else
+typedef int OSHandleType;
+static const OSHandleType INVALID_HANDLE = -1;
+#endif
+
+// IPC descriptor which can be sent over a socket. You should treat this as an
+// opaque type and not access any of the fields directly.
+#ifdef __native_client__
+typedef int Desc;
+#else
+struct Desc {
+ OSHandleType handle;
+ int32_t type;
+ union {
+ uint64_t size;
+ int32_t flags;
+ };
+};
+#endif
+
+// Conversion between Desc and handles
+enum FileOpenMode {
+ MODE_READ,
+ MODE_WRITE,
+ MODE_RW,
+ MODE_WRITE_APPEND,
+ MODE_RW_APPEND
+};
+Desc DescFromFile(OSHandleType handle, FileOpenMode mode);
+OSHandleType DescToHandle(Desc desc);
+
+class Socket {
+public:
+ Desc GetDesc() const;
+ static Socket FromDesc(Desc desc);
+
+ bool SendMsg(const Writer& writer);
+ bool RecvMsg(Reader& reader);
+
+ static bool CreatePair(Socket& a, Socket& b);
+
+private:
+ OSHandleType handle;
+};
+
+class SharedMemory {
+public:
+ Desc GetDesc() const;
+ static SharedMemory FromDesc(Desc desc);
+
+ static SharedMemory Create(size_t size);
+
+ void* GetBase();
+ size_t GetSize();
+
+private:
+ OSHandleType handle;
+ void* base;
+ size_t size;
+};
+
+// Base type for serialization traits.
+template<typename T, typename = void> struct SerializeTraits {};
+
class Writer {
public:
- void Write(const void* p, size_t len)
+ void WriteData(const void* p, size_t len)
{
data.insert(data.end(), static_cast<const char*>(p), static_cast<const char*>(p) + len);
}
@@ -56,12 +133,15 @@ public:
{
if (size > std::numeric_limits<uint32_t>::max())
Com_Error(ERR_DROP, "Size out of range in IPC message");
- uint32_t realSize = size;
- Write(&realSize, sizeof(uint32_t));
+ Write<uint32_t>(size);
}
- void WriteHandle(NaCl::IPCHandle& h)
+ template<typename T, typename Arg> void Write(Arg&& value)
{
- handles.push_back(&h);
+ SerializeTraits<T>::Write(*this, std::forward<Arg>(value));
+ }
+ void WriteHandle(Desc h)
+ {
+ handles.push_back(h);
}
void Reset()
@@ -73,19 +153,19 @@ public:
{
return data;
}
- const std::vector<NaCl::IPCHandle*>& GetHandles() const
+ const std::vector<Desc>& GetHandles() const
{
return handles;
}
private:
std::vector<char> data;
- std::vector<NaCl::IPCHandle*> handles;
+ std::vector<Desc> handles;
};
class Reader {
public:
- void Read(void* p, size_t len)
+ void ReadData(void* p, size_t len)
{
if (pos + len <= data.size()) {
memcpy(p, &data[pos], len);
@@ -96,8 +176,7 @@ public:
template<typename T> size_t ReadSize()
{
// Check for multiplication overflows when reading a size
- uint32_t size;
- Read(&size, sizeof(uint32_t));
+ uint32_t size = this->Read<uint32_t>();
if (size > std::numeric_limits<uint32_t>::max() / sizeof(T))
Com_Error(ERR_DROP, "Size out of range in IPC message");
return size;
@@ -111,7 +190,11 @@ public:
} else
Com_Error(ERR_DROP, "IPC message too short");
}
- NaCl::IPCHandle ReadHandle()
+ template<typename T> decltype(SerializeTraits<T>::Read(std::declval<Reader&>())) Read()
+ {
+ return SerializeTraits<T>::Read(*this);
+ }
+ Desc ReadHandle()
{
if (handles_pos <= handles.size())
return std::move(handles[handles_pos++]);
@@ -128,32 +211,29 @@ public:
{
return data;
}
- std::vector<NaCl::IPCHandle>& GetHandles()
+ std::vector<Desc>& GetHandles()
{
return handles;
}
private:
std::vector<char> data;
- std::vector<NaCl::IPCHandle> handles;
+ std::vector<Desc> handles;
size_t pos;
size_t handles_pos;
};
-// Base type for serialization traits.
-template<typename T, typename = void> struct SerializeTraits {};
-
// Simple implementation for POD types
template<typename T>
struct SerializeTraits<T, typename std::enable_if<std::is_pod<T>::value>::type> {
static void Write(Writer& stream, const T& value)
{
- stream.Write(std::addressof(value), sizeof(value));
+ stream.WriteData(std::addressof(value), sizeof(value));
}
static T Read(Reader& stream)
{
T value;
- stream.Read(std::addressof(value), sizeof(value));
+ stream.ReadData(std::addressof(value), sizeof(value));
return value;
}
};
@@ -164,13 +244,13 @@ struct SerializeTraits<std::vector<T>, typename std::enable_if<std::is_pod<T>::v
static void Write(Writer& stream, const std::vector<T>& value)
{
stream.WriteSize(value.size());
- stream.Write(value.data(), value.size() * sizeof(T));
+ stream.WriteData(value.data(), value.size() * sizeof(T));
}
static std::vector<T> Read(Reader& stream)
{
std::vector<T> value;
value.resize(stream.ReadSize<T>());
- stream.Read(value.data(), value.size() * sizeof(T));
+ stream.ReadData(value.data(), value.size() * sizeof(T));
return value;
}
};
@@ -197,7 +277,7 @@ template<> struct SerializeTraits<std::string> {
static void Write(Writer& stream, Str::StringRef value)
{
stream.WriteSize(value.size());
- stream.Write(value.data(), value.size());
+ stream.WriteData(value.data(), value.size());
}
static Str::StringRef Read(Reader& stream)
{
@@ -211,8 +291,6 @@ template<> struct SerializeTraits<std::string> {
// IPC message, which automatically serializes and deserializes objects
template<uint32_t Major, uint32_t Minor, typename... T> class Message {
- typedef std::tuple<T...> TupleType;
-
template<size_t Index, typename Tuple> static void FillTuple(Tuple&, Reader&) {}
template<size_t Index, typename Type0, typename... Types, typename Tuple> static void FillTuple(Tuple& tuple, Reader& stream)
{
@@ -223,7 +301,7 @@ template<uint32_t Major, uint32_t Minor, typename... T> class Message {
template<size_t Index> static void SerializeImpl(Writer&) {}
template<size_t Index, typename Arg0, typename... Args> void SerializeImpl(Arg0&& arg0, Args&&... args)
{
- SerializeTraits<typename std::tuple_element<Index, TupleType>::type>::Write(stream, std::forward<Arg0>(arg0));
+ SerializeTraits<typename std::tuple_element<Index, std::tuple<T...>>::type>::Write(stream, std::forward<Arg0>(arg0));
SerializeImpl<Index + 1>(std::forward<Args>(args)...);
}
@@ -249,4 +327,6 @@ public:
}
};
+} // namespace IPC
+
#endif // COMMON_IPC_H_
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment