From 0037a3e7f5a1e6c5f85495abf5d01fdd6928a793 Mon Sep 17 00:00:00 2001 From: Jacob Dufault Date: Thu, 23 Mar 2017 22:20:08 -0700 Subject: [PATCH] Add TypedBidiMessageQueue --- command_line.cc | 13 ++++ indexer.cpp | 12 ++++ src/typed_bidi_message_queue.h | 108 +++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 src/typed_bidi_message_queue.h diff --git a/command_line.cc b/command_line.cc index 9bd75628..4642aff0 100644 --- a/command_line.cc +++ b/command_line.cc @@ -11,6 +11,8 @@ #include "language_server_api.h" #include "test.h" +#include "src/typed_bidi_message_queue.h" + #include "third_party/tiny-process-library/process.hpp" #include "third_party/doctest/doctest/doctest.h" @@ -1025,7 +1027,18 @@ void PreMain() { MessageRegistry::instance()->Register(); } +struct MyMessageType { + static const lsMethodId id = lsMethodId::CancelRequest; +}; + int main(int argc, char** argv) { + // TODO: real impl + const int kQueueSize = 128; + TypedBidiMessageQueue t("foo", kQueueSize); + MyMessageType mm; + t.SendMessage(&t.for_client, lsMethodId::Initialize, &mm); + t.GetMessages(&t.for_client); + bool loop = false; while (loop) std::this_thread::sleep_for(std::chrono::milliseconds(10)); diff --git a/indexer.cpp b/indexer.cpp index 8a2064cf..8e5a6f03 100644 --- a/indexer.cpp +++ b/indexer.cpp @@ -1204,6 +1204,18 @@ void emptyIndexEntityReference(CXClientData client_data, IndexedFile Parse(std::string filename, std::vector args, bool dump_ast) { + // TODO!! + // TODO!! + // TODO!! + // TODO!!: Strip useless defs from IndexedFile before returning + // TODO!!: Strip useless defs from IndexedFile before returning + // TODO!!: Strip useless defs from IndexedFile before returning + // TODO!!: Strip useless defs from IndexedFile before returning + // TODO!!: Strip useless defs from IndexedFile before returning + // TODO!!: Strip useless defs from IndexedFile before returning + // TODO!! + // TODO!! + // TODO!! clang_toggleCrashRecovery(1); args.push_back("-std=c++11"); diff --git a/src/typed_bidi_message_queue.h b/src/typed_bidi_message_queue.h new file mode 100644 index 00000000..1b4485f4 --- /dev/null +++ b/src/typed_bidi_message_queue.h @@ -0,0 +1,108 @@ +#pragma once + +#include +#include +#include + +#include "buffer.h" +#include "message_queue.h" +#include "../serializer.h" + +// TypedBidiMessageQueue provides a type-safe server/client implementation on +// top of a couple MessageQueue instances. +template +struct TypedBidiMessageQueue { + using Serializer = std::function; + using Deserializer = + std::function(Reader& visitor)>; + + TypedBidiMessageQueue(const std::string& name, size_t buffer_size) + : for_server( + Buffer::CreateSharedBuffer(name + "_for_server", buffer_size), + false /*buffer_has_data*/), + for_client( + Buffer::CreateSharedBuffer(name + "_for_client", buffer_size), + true /*buffer_has_data*/) {} + + void RegisterId(TId id, + const Serializer& serializer, + const Deserializer& deseriaizer) { + assert(serializers_.find(id) == serializers_.end() && + deserializers_.find(id) == deserializers_.end() && + "Duplicate registration"); + + serializers_[id] = serializer; + deserializers_[id] = deserializer; + } + + void SendMessage(MessageQueue* destination, TId id, TMessage* message) { + // Create writer. + rapidjson::StringBuffer output; + rapidjson::PrettyWriter writer(output); + writer.SetIndent(' ', 0); + + // Serialize the message. + assert(serializers_.find(message->id) != serializers_.end() && + "No registered serializer"); + const Serializer& serializer = serializers_.find(id)->second; + serializer(writer, *message); + + // Send message. + void* payload = malloc(sizeof(MessageHeader) + output.GetSize()); + reinterpret_cast(payload)->id = id; + memcpy( + (void*)(reinterpret_cast(payload) + sizeof(MessageHeader)), + output.GetString(), output.GetSize()); + destination->Enqueue( + Message(payload, sizeof(MessageHeader) + output.GetSize())); + free(payload); + } + + // Retrieve all messages from the given |queue|. + std::vector> GetMessages( + MessageQueue* queue) const { + assert(queue == &for_server || queue == &for_client); + + std::vector> messages = queue->DequeueAll(); + std::vector> result; + result.reserve(messages.size()); + + for (std::unique_ptr& buffer : messages) { + MessageHeader* header = reinterpret_cast(buffer->data); + + // Parse message content. + rapidjson::Document document; + document.Parse( + reinterpret_cast(buffer->data) + sizeof(MessageHeader), + buffer->capacity - sizeof(MessageHeader)); + bool has_error = document.HasParseError(); + auto error = document.GetParseError(); + if (has_error) { + std::cerr << "[FATAL]: Unable to parse IPC message" << std::endl; + exit(1); + } + + // Deserialize it. + assert(deserializers_.find(header->id) != deserializers_.end() && + "No registered deserializer"); + const Deserializer& deserializer = + deserializers_.find(header->id)->second; + result.emplace_back(deserializer(document)); + } + + return result; + } + + // Messages which the server process should handle. + MessageQueue for_server; + // Messages which the client process should handle. + MessageQueue for_client; + + private: + struct MessageHeader { + TId id; + }; + + std::unordered_map serializers_; + std::unordered_map deserializers_; +}; \ No newline at end of file