#pragma once #include #include #include #include #include #include #include #include "platform.h" #include "serializer.h" #include "utils.h" // TODO: We need to add support for payloads larger than the maximum shared memory buffer size. enum class IpcId : int { // Invalid request id. Invalid = 0, Quit = 1, IsAlive, OpenProject, IndexTranslationUnitRequest, IndexTranslationUnitResponse, // This is a language server request. The actual request method // id is embedded within the request state. LanguageServerRequest, // TODO: remove DocumentSymbolsRequest, DocumentSymbolsResponse, WorkspaceSymbolsRequest, WorkspaceSymbolsResponse }; namespace std { template <> struct hash { size_t operator()(const IpcId& k) const { return hash()(static_cast(k)); } }; } struct IpcMessage { IpcMessage(IpcId ipc_id) : ipc_id(ipc_id) {} virtual ~IpcMessage() {} const IpcId ipc_id; virtual void Serialize(Writer& writer) = 0; virtual void Deserialize(Reader& reader) = 0; }; struct IpcRegistry { using Allocator = std::function; // Use unique_ptrs so we can initialize on first use // (static init order might not be right). std::unique_ptr> allocators; template void Register(IpcId id); std::unique_ptr Allocate(IpcId id); static IpcRegistry* instance() { if (!instance_) instance_ = new IpcRegistry(); return instance_; } static IpcRegistry* instance_; }; template void IpcRegistry::Register(IpcId id) { if (!allocators) allocators = MakeUnique>(); assert(allocators->find(id) == allocators->end() && "There is already an IPC message with the given id"); (*allocators)[id] = [id]() { return new T(); }; } struct IpcDirectionalChannel { // NOTE: We keep all pointers in terms of char* so pointer arithmetic is // always relative to bytes. explicit IpcDirectionalChannel(const std::string& name); ~IpcDirectionalChannel(); void PushMessage(IpcMessage* message); std::vector> TakeMessages(); struct MessageBuffer; struct ResizableBuffer; ResizableBuffer* CreateOrFindResizableBuffer(int id); void RemoveResizableBuffer(int id); std::unordered_map> resizable_buffers; // Pointer to process shared memory and process shared mutex. std::unique_ptr shared; std::unique_ptr mutex; // Pointer to process-local memory. std::unique_ptr local; std::unique_ptr shared_buffer; std::unique_ptr local_buffer; }; struct IpcServer { IpcServer(const std::string& name, int client_id); void SendToClient(IpcMessage* message); std::vector> TakeMessages(); private: IpcDirectionalChannel server_; IpcDirectionalChannel client_; }; struct IpcClient { IpcClient(const std::string& name, int client_id); void SendToServer(IpcMessage* message); std::vector> TakeMessages(); IpcDirectionalChannel* client() { return &client_; } private: IpcDirectionalChannel server_; IpcDirectionalChannel client_; };