From b3a544e880547a9434c3e7caad526759dc6bdef0 Mon Sep 17 00:00:00 2001 From: Jacob Dufault Date: Fri, 3 Mar 2017 00:12:11 -0800 Subject: [PATCH] more wip ipc refactor --- command_line.cc | 173 +++++++++++++++++++++++++++++++++++++++++++++--- ipc.cc | 56 +++------------- ipc.h | 105 ++++++++++++++++++++--------- 3 files changed, 250 insertions(+), 84 deletions(-) diff --git a/command_line.cc b/command_line.cc index da7ad40e..fba35fa4 100644 --- a/command_line.cc +++ b/command_line.cc @@ -4,6 +4,7 @@ #include "compilation_database_loader.h" #include "indexer.h" +#include "ipc.h" #include "query.h" bool ParsePreferredSymbolLocation(const std::string& content, PreferredSymbolLocation* obj) { @@ -94,7 +95,13 @@ indexer.exe --index-file /work2/chrome/src/chrome/foo.cc } */ -#include "ipc.h" + +struct IpcMessage_IsAlive : public IpcMessage { + static IpcMessageId id; +}; + +IpcMessageId IpcMessage_IsAlive::id = "IsAlive"; + void IndexerServerMain() { IpcServer ipc("language_server"); @@ -104,15 +111,13 @@ void IndexerServerMain() { std::cout << "Server has " << messages.size() << " messages" << std::endl; for (auto& message : messages) { - switch (message->kind) { - case JsonMessage::Kind::IsAlive: - { + if (message->runtime_id == IpcMessage_IsAlive::id) { IpcMessage_IsAlive response; ipc.SendToClient(0, &response); // todo: make non-blocking break; } - default: - std::cerr << "Unhandled IPC message with kind " << static_cast(message->kind) << std::endl; + else { + std::cerr << "Unhandled IPC message with kind " << message->runtime_id << " (hash " << message->hashed_runtime_id << ")" << std::endl; exit(1); break; } @@ -123,6 +128,37 @@ void IndexerServerMain() { } } +void EmitReferences(IpcClient& ipc) { + +} + +// Separate thread whose only job is to read from stdin and +// dispatch read commands to the actual indexer program. This +// cannot be done on the main thread because reading from std::cin +// blocks. +void LanguageServerStdinToServerDispatcher(IpcClient& ipc) { + while (true) { + std::string input; + std::cin >> input; + + } +} + +// Main loop for the language server. |ipc| is connected to +// a server. +void LanguageServerLoop(IpcClient& ipc) { + while (true) { + std::string input; + std::cin >> input; + + std::cout << "got input " << input << std::endl << std::endl; + + if (input == "references") { + + } + } +} + void LanguageServerMain() { IpcClient ipc("language_server", 0); @@ -139,7 +175,7 @@ void LanguageServerMain() { std::vector> messages = ipc.TakeMessages(); bool has_server = false; for (auto& message : messages) { - if (message->kind == JsonMessage::Kind::IsAlive) { + if (message->runtime_id == IpcMessage_IsAlive::id) { has_server = true; break; } @@ -152,10 +188,131 @@ void LanguageServerMain() { } std::cout << "Found indexer server" << std::endl; + LanguageServerLoop(ipc); +} + + + + + +#if false + +struct IpcMessage_IsAlive : public BaseIpcMessage { + IpcMessage_IsAlive(); + + // BaseIpcMessage: + void Serialize(Writer& writer) override; + void Deserialize(Reader& reader) override; +}; + +struct IpcMessage_ImportIndex : public BaseIpcMessage { + std::string path; + + IpcMessage_ImportIndex(); + + // BaseMessage: + void Serialize(Writer& writer) override; + void Deserialize(Reader& reader) override; +}; + +struct IpcMessage_CreateIndex : public BaseIpcMessage { + std::string path; + std::vector args; + + IpcMessage_CreateIndex(); + + // BaseMessage: + void Serialize(Writer& writer) override; + void Deserialize(Reader& reader) override; +}; + + +IpcMessage_IsAlive::IpcMessage_IsAlive() { + kind = JsonMessage::Kind::IsAlive; +} + +void IpcMessage_IsAlive::Serialize(Writer& writer) {} + +void IpcMessage_IsAlive::Deserialize(Reader& reader) {} + +IpcMessage_ImportIndex::IpcMessage_ImportIndex() { + kind = JsonMessage::Kind::ImportIndex; +} + +void IpcMessage_ImportIndex::Serialize(Writer& writer) { + writer.StartObject(); + ::Serialize(writer, "path", path); + writer.EndObject(); +} +void IpcMessage_ImportIndex::Deserialize(Reader& reader) { + ::Deserialize(reader, "path", path); +} + +IpcMessage_CreateIndex::IpcMessage_CreateIndex() { + kind = JsonMessage::Kind::CreateIndex; +} + +void IpcMessage_CreateIndex::Serialize(Writer& writer) { + writer.StartObject(); + ::Serialize(writer, "path", path); + ::Serialize(writer, "args", args); + writer.EndObject(); +} +void IpcMessage_CreateIndex::Deserialize(Reader& reader) { + ::Deserialize(reader, "path", path); + ::Deserialize(reader, "args", args); +} + +// TODO: make it so we don't need an explicit list +// of available ipc message types. Maybe use string or +// a hash, not sure. + +struct IpcMessage_DocumentSymbolsRequest : public BaseIpcMessage { + std::string document; +}; + +struct IpcMessage_DocumentSymbolsResponse : public BaseIpcMessage { + +}; + + + + + + + +struct ListSymbols : public BaseType { + static IpcRegistry::Id id; +}; + +IpcRegistry::Id ListSymbols::id = "ListSymbols"; + +struct ListSymbol2s : public BaseType { + static IpcRegistry::Id id; +}; + +IpcRegistry::Id ListSymbol2s::id = "ListSymbols"; + +#endif + + +void main2() { + //ListSymbols l; + //auto& x = ListSymbols::register_; + //ListSymbol2s l2; + //auto& y = ListSymbol2s::register_; + + std::cout << "main2" << std::endl; + std::cin.get(); } int main(int argc, char** argv) { - if (argc == 1) + IpcMessage_IsAlive _; + + //main2(); + //return 0; + + if (argc == 2) LanguageServerMain(); else IndexerServerMain(); diff --git a/ipc.cc b/ipc.cc index a61a82e3..4bab034e 100644 --- a/ipc.cc +++ b/ipc.cc @@ -24,40 +24,19 @@ void JsonMessage::SetPayload(size_t payload_size, const char* payload) { memcpy(payload_dest, payload, payload_size); } -IpcMessage_IsAlive::IpcMessage_IsAlive() { - kind = JsonMessage::Kind::IsAlive; -} +BaseIpcMessage::BaseIpcMessage(BaseIpcMessage::DoNotDeriveDirectly) {} -void IpcMessage_IsAlive::Serialize(Writer& writer) {} +BaseIpcMessage::~BaseIpcMessage() {} -void IpcMessage_IsAlive::Deserialize(Reader& reader) {} +void BaseIpcMessage::Serialize(Writer& writer) {} -IpcMessage_ImportIndex::IpcMessage_ImportIndex() { - kind = JsonMessage::Kind::ImportIndex; -} +void BaseIpcMessage::Deserialize(Reader& reader) {} -void IpcMessage_ImportIndex::Serialize(Writer& writer) { - writer.StartObject(); - ::Serialize(writer, "path", path); - writer.EndObject(); -} -void IpcMessage_ImportIndex::Deserialize(Reader& reader) { - ::Deserialize(reader, "path", path); -} -IpcMessage_CreateIndex::IpcMessage_CreateIndex() { - kind = JsonMessage::Kind::CreateIndex; -} +IpcRegistry IpcRegistry::Instance; -void IpcMessage_CreateIndex::Serialize(Writer& writer) { - writer.StartObject(); - ::Serialize(writer, "path", path); - ::Serialize(writer, "args", args); - writer.EndObject(); -} -void IpcMessage_CreateIndex::Deserialize(Reader& reader) { - ::Deserialize(reader, "path", path); - ::Deserialize(reader, "args", args); +std::unique_ptr IpcRegistry::Allocate(int id) { + return std::unique_ptr((*allocators)[id]()); } IpcDirectionalChannel::IpcDirectionalChannel(const std::string& name) { @@ -100,12 +79,12 @@ void IpcDirectionalChannel::PushMessage(BaseIpcMessage* message) { if ((*shared->shared_bytes_used + sizeof(JsonMessage) + payload_size) >= shmem_size) continue; - get_free_message()->kind = message->kind; + get_free_message()->message_id = message->hashed_runtime_id; get_free_message()->SetPayload(payload_size, output.GetString()); *shared->shared_bytes_used += sizeof(JsonMessage) + get_free_message()->payload_size; assert(*shared->shared_bytes_used < shmem_size); - get_free_message()->kind = JsonMessage::Kind::Invalid; + get_free_message()->message_id = -1; break; } @@ -122,27 +101,14 @@ std::vector> IpcDirectionalChannel::TakeMessages memcpy(local_block, shared->shared_start, *shared->shared_bytes_used); *shared->shared_bytes_used = 0; - get_free_message()->kind = JsonMessage::Kind::Invalid; + get_free_message()->message_id = -1; } std::vector> result; char* message = local_block; while (remaining_bytes > 0) { - std::unique_ptr base_message; - switch (as_message(message)->kind) { - case JsonMessage::Kind::IsAlive: - base_message = std::make_unique(); - break; - case JsonMessage::Kind::CreateIndex: - base_message = std::make_unique(); - break; - case JsonMessage::Kind::ImportIndex: - base_message = std::make_unique(); - break; - default: - assert(false); - } + std::unique_ptr base_message = IpcRegistry::Instance.Allocate(as_message(message)->message_id); rapidjson::Document document; document.Parse(as_message(message)->payload(), as_message(message)->payload_size); diff --git a/ipc.h b/ipc.h index eb1cf802..36bd7ba6 100644 --- a/ipc.h +++ b/ipc.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -21,56 +22,98 @@ using Reader = rapidjson::Document; // completely different address. struct JsonMessage { - enum class Kind { - Invalid, - IsAlive, - CreateIndex, - ImportIndex, - }; - - Kind kind; + int message_id; size_t payload_size; const char* payload(); void SetPayload(size_t payload_size, const char* payload); }; +using IpcMessageId = std::string; + struct BaseIpcMessage { - JsonMessage::Kind kind; - virtual ~BaseIpcMessage() {} + virtual ~BaseIpcMessage(); - virtual void Serialize(Writer& writer) = 0; - virtual void Deserialize(Reader& reader) = 0; + virtual void Serialize(Writer& writer); + virtual void Deserialize(Reader& reader); + + IpcMessageId runtime_id; + int hashed_runtime_id; + + /* +private: + template + friend struct IpcMessage; + */ + + enum class DoNotDeriveDirectly { + DeriveFromIpcMessageInstead + }; + BaseIpcMessage(DoNotDeriveDirectly); }; -struct IpcMessage_IsAlive : public BaseIpcMessage { - IpcMessage_IsAlive(); +struct IpcRegistry { + using Allocator = std::function; - // BaseIpcMessage: - void Serialize(Writer& writer) override; - void Deserialize(Reader& reader) override; + // Use unique_ptrs so we can initialize on first use + // (static init order might not be right). + std::unique_ptr> allocators; + std::unique_ptr> hash_to_id; + + template + int RegisterAllocator(); + + std::unique_ptr Allocate(int id); + + static IpcRegistry* instance() { + // TODO: Remove static magic. Just call register explicitly. + return instance_; + } + static IpcRegistry* instance_; }; -struct IpcMessage_ImportIndex : public BaseIpcMessage { - std::string path; +template +int IpcRegistry::RegisterAllocator() { + if (!allocators) { + allocators = std::make_unique>(); + hash_to_id = std::make_unique>(); + } - IpcMessage_ImportIndex(); + IpcMessageId id = T::id; - // BaseMessage: - void Serialize(Writer& writer) override; - void Deserialize(Reader& reader) override; + int hash = std::hash()(id); + auto it = allocators->find(hash); + assert(allocators->find(hash) == allocators->end() && "There is already an IPC message with the given id"); + + (*hash_to_id)[hash] = id; + (*allocators)[hash] = []() { + return new T(); + }; + + return hash; +} + +template +struct IpcMessage : public BaseIpcMessage { + IpcMessage(); + + static int hashed_id_; }; -struct IpcMessage_CreateIndex : public BaseIpcMessage { - std::string path; - std::vector args; +template +int IpcMessage::hashed_id_ = IpcRegistry::Instance.RegisterAllocator(); + +template +IpcMessage::IpcMessage() + : BaseIpcMessage(DoNotDeriveDirectly::DeriveFromIpcMessageInstead) { + runtime_id = TChild::id; + hashed_runtime_id = hashed_id_; +} + + + - IpcMessage_CreateIndex(); - // BaseMessage: - void Serialize(Writer& writer) override; - void Deserialize(Reader& reader) override; -}; struct IpcDirectionalChannel { // NOTE: We keep all pointers in terms of char* so pointer arithmetic is