ccls/ipc.h

154 lines
3.6 KiB
C
Raw Normal View History

#pragma once
#include <iostream>
#include <chrono>
#include <string>
#include <thread>
2017-03-03 08:12:11 +00:00
#include <unordered_map>
#include <rapidjson/document.h>
#include <rapidjson/prettywriter.h>
#include "platform.h"
#include "serializer.h"
2017-03-14 17:10:30 +00:00
#include "utils.h"
2017-03-05 19:48:05 +00:00
// TODO: We need to add support for payloads larger than the maximum shared memory buffer size.
2017-03-12 00:36:00 +00:00
enum class IpcId : int {
// Invalid request id.
Invalid = 0,
Quit = 1,
IsAlive,
OpenProject,
2017-03-14 08:33:39 +00:00
IndexTranslationUnitRequest,
IndexTranslationUnitResponse,
2017-03-12 00:36:00 +00:00
// This is a language server request. The actual request method
// id is embedded within the request state.
LanguageServerRequest,
// TODO: remove
DocumentSymbolsRequest,
DocumentSymbolsResponse,
2017-03-15 07:14:44 +00:00
DocumentCodeLensRequest,
DocumentCodeLensResponse,
CodeLensResolveRequest,
CodeLensResolveResponse,
2017-03-12 00:36:00 +00:00
WorkspaceSymbolsRequest,
WorkspaceSymbolsResponse
2017-03-05 02:16:23 +00:00
};
2017-03-14 17:10:30 +00:00
namespace std {
template <>
struct hash<IpcId> {
size_t operator()(const IpcId& k) const {
return hash<int>()(static_cast<int>(k));
}
};
}
2017-03-12 00:36:00 +00:00
struct IpcMessage {
IpcMessage(IpcId ipc_id) : ipc_id(ipc_id) {}
virtual ~IpcMessage() {}
2017-03-05 02:16:23 +00:00
2017-03-12 00:36:00 +00:00
const IpcId ipc_id;
virtual void Serialize(Writer& writer) = 0;
virtual void Deserialize(Reader& reader) = 0;
};
2017-03-03 08:12:11 +00:00
struct IpcRegistry {
2017-03-12 00:36:00 +00:00
using Allocator = std::function<IpcMessage*()>;
2017-03-03 08:12:11 +00:00
// Use unique_ptrs so we can initialize on first use
// (static init order might not be right).
2017-03-15 04:59:05 +00:00
std::unique_ptr<std::unordered_map<IpcId, Allocator>> allocators_;
2017-03-03 08:12:11 +00:00
template<typename T>
2017-03-12 00:36:00 +00:00
void Register(IpcId id);
2017-03-12 00:36:00 +00:00
std::unique_ptr<IpcMessage> Allocate(IpcId id);
2017-03-03 08:12:11 +00:00
static IpcRegistry* instance() {
2017-03-03 08:43:54 +00:00
if (!instance_)
instance_ = new IpcRegistry();
2017-03-03 08:12:11 +00:00
return instance_;
}
static IpcRegistry* instance_;
};
2017-03-03 08:12:11 +00:00
template<typename T>
2017-03-12 00:36:00 +00:00
void IpcRegistry::Register(IpcId id) {
2017-03-15 04:59:05 +00:00
if (!allocators_)
allocators_ = MakeUnique<std::unordered_map<IpcId, Allocator>>();
2017-03-03 08:12:11 +00:00
2017-03-15 04:59:05 +00:00
assert(allocators_->find(id) == allocators_->end() &&
2017-03-12 00:36:00 +00:00
"There is already an IPC message with the given id");
2017-03-15 04:59:05 +00:00
(*allocators_)[id] = [id]() {
2017-03-03 08:12:11 +00:00
return new T();
};
}
2017-03-03 06:16:28 +00:00
struct IpcDirectionalChannel {
// NOTE: We keep all pointers in terms of char* so pointer arithmetic is
// always relative to bytes.
2017-03-15 04:59:05 +00:00
explicit IpcDirectionalChannel(const std::string& name, bool initialize_shared_memory);
2017-03-03 06:16:28 +00:00
~IpcDirectionalChannel();
2017-03-12 00:36:00 +00:00
void PushMessage(IpcMessage* message);
std::vector<std::unique_ptr<IpcMessage>> TakeMessages();
2017-03-13 06:03:54 +00:00
struct MessageBuffer;
2017-03-14 06:30:41 +00:00
struct ResizableBuffer;
2017-03-12 20:28:19 +00:00
2017-03-14 06:30:41 +00:00
ResizableBuffer* CreateOrFindResizableBuffer(int id);
void RemoveResizableBuffer(int id);
std::unordered_map<int, std::unique_ptr<ResizableBuffer>> resizable_buffers;
2017-03-12 20:28:19 +00:00
// Pointer to process shared memory and process shared mutex.
std::unique_ptr<PlatformSharedMemory> shared;
std::unique_ptr<PlatformMutex> mutex;
// Pointer to process-local memory.
2017-03-13 06:03:54 +00:00
std::unique_ptr<char> local;
2017-03-12 20:28:19 +00:00
std::unique_ptr<MessageBuffer> shared_buffer;
std::unique_ptr<MessageBuffer> local_buffer;
2017-03-03 06:16:28 +00:00
};
struct IpcServer {
2017-03-15 04:59:05 +00:00
IpcServer(const std::string& name, int num_clients);
2017-03-03 06:16:28 +00:00
2017-03-15 04:59:05 +00:00
void SendToClient(int client_id, IpcMessage* message);
2017-03-12 00:36:00 +00:00
std::vector<std::unique_ptr<IpcMessage>> TakeMessages();
2017-03-03 06:16:28 +00:00
2017-03-15 04:59:05 +00:00
int num_clients() const { return clients_.size(); }
2017-03-03 06:16:28 +00:00
private:
2017-03-15 04:59:05 +00:00
IpcDirectionalChannel server_; // Local / us.
std::vector<std::unique_ptr<IpcDirectionalChannel>> clients_;
2017-03-03 06:16:28 +00:00
};
struct IpcClient {
IpcClient(const std::string& name, int client_id);
2017-03-12 00:36:00 +00:00
void SendToServer(IpcMessage* message);
std::vector<std::unique_ptr<IpcMessage>> TakeMessages();
2017-03-03 06:16:28 +00:00
2017-03-05 19:48:05 +00:00
IpcDirectionalChannel* client() { return &client_; }
2017-03-03 06:16:28 +00:00
private:
IpcDirectionalChannel server_;
IpcDirectionalChannel client_;
2017-03-14 17:10:30 +00:00
};