From 2a08552265402719f5bcc8c260794b16734adc2d Mon Sep 17 00:00:00 2001 From: Jacob Dufault Date: Fri, 3 Mar 2017 17:45:20 -0800 Subject: [PATCH] linux platform WIP --- CMakeLists.txt | 14 ++++-- command_line.cc | 18 +++---- ipc.cc | 15 +++--- ipc.h | 10 ++-- optional.h | 118 +++++++++++++++++++++++----------------------- platform_linux.cc | 118 ++++++++++++++++++++++++++++++++++++++++++++++ platform_win.cc | 10 ++-- utils.h | 10 +++- wscript | 18 +++++-- 9 files changed, 239 insertions(+), 92 deletions(-) create mode 100644 platform_linux.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ea5f1e5..52aa189a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,13 +25,21 @@ string(STRIP "${LIBCLANG_LIBDIR}" LIBCLANG_LIBDIR) find_library(LIBCLANG_LIBRARIES NAMES libclang clang PATHS ${LIBCLANG_LIBDIR}) + + + +set(LIBCLANG_INCLUDEDIR "/usr/local/google/home/jdufault/super-clang-index/clang+llvm-3.9.1-x86_64-linux-gnu-ubuntu-16.04/include") +set(LIBCLANG_LIBDIR "/usr/local/google/home/jdufault/super-clang-index/clang+llvm-3.9.1-x86_64-linux-gnu-ubuntu-16.04/lib") +set(LIBCLANG_LIBRARIES "/usr/local/google/home/jdufault/super-clang-index/clang+llvm-3.9.1-x86_64-linux-gnu-ubuntu-16.04/lib/libclang.so") + + # # Debugging # #message("SOURCE_FILES: " ${SOURCE_FILES} ) -#message("LIBCLANG_INCLUDEDIR: " ${LIBCLANG_INCLUDEDIR}) -#message("LIBCLANG_LIBDIR: " ${LIBCLANG_LIBDIR}) -#message("LIBCLANG_LIBRARIES: " ${LIBCLANG_LIBRARIES}) +message("LIBCLANG_INCLUDEDIR: " ${LIBCLANG_INCLUDEDIR}) +message("LIBCLANG_LIBDIR: " ${LIBCLANG_LIBDIR}) +message("LIBCLANG_LIBRARIES: " ${LIBCLANG_LIBRARIES}) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wall") diff --git a/command_line.cc b/command_line.cc index 67b135a3..7ea6dd05 100644 --- a/command_line.cc +++ b/command_line.cc @@ -164,7 +164,7 @@ namespace language_server_api { Boolean = 17, Array = 18 }; - + struct SymbolInfo { std::string name; SymbolKind kind; @@ -187,7 +187,7 @@ IpcMessageId IpcMessage_DocumentSymbolsResponse::id = "IpcMessage_DocumentSymbol void IndexerServerMain() { - IpcServer ipc("language_server"); + IpcServer ipc("languageserver"); while (true) { std::vector> messages = ipc.TakeMessages(); @@ -206,8 +206,7 @@ void IndexerServerMain() { } } - using namespace std::chrono_literals; - std::this_thread::sleep_for(20ms); + std::this_thread::sleep_for(std::chrono::milliseconds(20)); } } @@ -243,7 +242,7 @@ void LanguageServerLoop(IpcClient& ipc) { } void LanguageServerMain() { - IpcClient ipc("language_server", 0); + IpcClient ipc("languageserver", 0); // Discard any left-over messages from previous runs. ipc.TakeMessages(); @@ -251,8 +250,9 @@ void LanguageServerMain() { // Emit an alive check. Sleep so the server has time to respond. IpcMessage_IsAlive check_alive; ipc.SendToServer(&check_alive); - using namespace std::chrono_literals; - std::this_thread::sleep_for(50ms); // TODO: Tune this value or make it configurable. + + // TODO: Tune this value or make it configurable. + std::this_thread::sleep_for(std::chrono::milliseconds(20)); // Check if we got an IsAlive message back. std::vector> messages = ipc.TakeMessages(); @@ -372,7 +372,7 @@ int main(int argc, char** argv) { optionally by clients if there are multiple servers running. --print-config Emit all configuration data this executable is using. - + Server: --server If present, this binary will run in server mode. The binary @@ -389,7 +389,7 @@ int main(int argc, char** argv) { This value is optional; a good estimate is computed by default. - + Client: --command Execute a query command against the index. See --command-help for a listing of valid commands and a diff --git a/ipc.cc b/ipc.cc index bf39dea9..c77b025d 100644 --- a/ipc.cc +++ b/ipc.cc @@ -6,11 +6,11 @@ namespace { } std::string NameToServerName(const std::string& name) { - return name + "_server"; + return name + "server"; } std::string NameToClientName(const std::string& name, int client_id) { - return name + "_server_" + std::to_string(client_id); + return name + "client" + std::to_string(client_id); } } @@ -49,8 +49,8 @@ std::unique_ptr IpcRegistry::Allocate(int id) { IpcDirectionalChannel::IpcDirectionalChannel(const std::string& name) { local_block = new char[shmem_size]; - shared = CreatePlatformSharedMemory(name + "_memory"); - mutex = CreatePlatformMutex(name + "_mutex"); + shared = CreatePlatformSharedMemory(name + "memory"); + mutex = CreatePlatformMutex(name + "mutex"); } IpcDirectionalChannel::~IpcDirectionalChannel() { @@ -71,13 +71,12 @@ void IpcDirectionalChannel::PushMessage(BaseIpcMessage* message) { bool first = true; bool did_log = false; while (true) { - using namespace std::chrono_literals; if (!first) { if (!did_log) { std::cout << "[info]: shmem full, waiting" << std::endl; // TODO: remove did_log = true; } - std::this_thread::sleep_for(16ms); + std::this_thread::sleep_for(std::chrono::milliseconds(16)); } first = false; @@ -143,7 +142,7 @@ void IpcServer::SendToClient(int client_id, BaseIpcMessage* message) { // Find or create the client. auto it = clients_.find(client_id); if (it == clients_.end()) - clients_[client_id] = std::make_unique(NameToClientName(name_, client_id)); + clients_[client_id] = MakeUnique(NameToClientName(name_, client_id)); clients_[client_id]->PushMessage(message); } @@ -161,4 +160,4 @@ void IpcClient::SendToServer(BaseIpcMessage* message) { std::vector> IpcClient::TakeMessages() { return client_.TakeMessages(); -} \ No newline at end of file +} diff --git a/ipc.h b/ipc.h index 9d9c3ed4..ad9302b6 100644 --- a/ipc.h +++ b/ipc.h @@ -35,7 +35,7 @@ using IpcMessageId = std::string; // // class IpcMessage_Foo : public BaseIpcMessage { // static IpcMessageId id; -// +// // // BaseIpcMessage: // ... // } @@ -57,7 +57,7 @@ struct BaseIpcMessage { // Populated by IpcRegistry::RegisterAllocator. static IpcMessageId runtime_id_; - static int hashed_runtime_id_; + static int hashed_runtime_id_; }; struct IpcRegistry { @@ -84,8 +84,8 @@ struct IpcRegistry { template void IpcRegistry::Register() { if (!allocators) { - allocators = std::make_unique>(); - hash_to_id = std::make_unique>(); + allocators = MakeUnique>(); + hash_to_id = MakeUnique>(); } IpcMessageId id = T::id; @@ -152,4 +152,4 @@ struct IpcClient { private: IpcDirectionalChannel server_; IpcDirectionalChannel client_; -}; \ No newline at end of file +}; diff --git a/optional.h b/optional.h index 7b9148f3..bab5a4a1 100644 --- a/optional.h +++ b/optional.h @@ -101,6 +101,8 @@ namespace std{ namespace experimental{ +#define TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS + // BEGIN workaround for missing is_trivially_destructible # if defined TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ // leave it: it is already there @@ -212,7 +214,7 @@ struct has_overloaded_addressof { template constexpr static bool has_overload(...) { return false; } - + template ().operator&()) > constexpr static bool has_overload(bool) { return true; } @@ -232,10 +234,10 @@ T* static_addressof(T& ref) } -// the call to convert(b) has return type A and converts b to type A iff b decltype(b) is implicitly convertible to A +// the call to convert(b) has return type A and converts b to type A iff b decltype(b) is implicitly convertible to A template constexpr U convert(U v) { return v; } - + } // namespace detail @@ -352,12 +354,12 @@ class optional : private OptionalBase { static_assert( !std::is_same::type, nullopt_t>::value, "bad T" ); static_assert( !std::is_same::type, in_place_t>::value, "bad T" ); - + constexpr bool initialized() const noexcept { return OptionalBase::init_; } typename std::remove_const::type* dataptr() { return std::addressof(OptionalBase::storage_.value_); } constexpr const T* dataptr() const { return detail_::static_addressof(OptionalBase::storage_.value_); } - + # if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 constexpr const T& contained_val() const& { return OptionalBase::storage_.value_; } # if OPTIONAL_HAS_MOVE_ACCESSORS == 1 @@ -376,7 +378,7 @@ class optional : private OptionalBase if (initialized()) dataptr()->T::~T(); OptionalBase::init_ = false; } - + template void initialize(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) { @@ -439,7 +441,7 @@ public: clear(); return *this; } - + optional& operator=(const optional& rhs) { if (initialized() == true && rhs.initialized() == false) clear(); @@ -447,7 +449,7 @@ public: else if (initialized() == true && rhs.initialized() == true) contained_val() = *rhs; return *this; } - + optional& operator=(optional&& rhs) noexcept(is_nothrow_move_assignable::value && is_nothrow_move_constructible::value) { @@ -469,22 +471,22 @@ public: else { initialize(std::forward(v)); } return *this; } - - + + template void emplace(Args&&... args) { clear(); initialize(std::forward(args)...); } - + template void emplace(initializer_list il, Args&&... args) { clear(); initialize(il, std::forward(args)...); } - + // 20.5.4.4, Swap void swap(optional& rhs) noexcept(is_nothrow_move_constructible::value && noexcept(swap(declval(), declval()))) { @@ -494,30 +496,30 @@ public: } // 20.5.4.5, Observers - + explicit constexpr operator bool() const noexcept { return initialized(); } constexpr bool has_value() const noexcept { return initialized(); } - + constexpr T const* operator ->() const { return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr()); } - + # if OPTIONAL_HAS_MOVE_ACCESSORS == 1 OPTIONAL_MUTABLE_CONSTEXPR T* operator ->() { assert (initialized()); return dataptr(); } - + constexpr T const& operator *() const& { return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); } - + OPTIONAL_MUTABLE_CONSTEXPR T& operator *() & { assert (initialized()); return contained_val(); } - + OPTIONAL_MUTABLE_CONSTEXPR T&& operator *() && { assert (initialized()); return constexpr_move(contained_val()); @@ -526,42 +528,42 @@ public: constexpr T const& value() const& { return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); } - + OPTIONAL_MUTABLE_CONSTEXPR T& value() & { return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); } - + OPTIONAL_MUTABLE_CONSTEXPR T&& value() && { if (!initialized()) throw bad_optional_access("bad optional access"); return std::move(contained_val()); } - + # else T* operator ->() { assert (initialized()); return dataptr(); } - + constexpr T const& operator *() const { return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); } - + T& operator *() { assert (initialized()); return contained_val(); } - + constexpr T const& value() const { return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); } - + T& value() { return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); } - + # endif - + # if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 template @@ -569,7 +571,7 @@ public: { return *this ? **this : detail_::convert(constexpr_forward(v)); } - + # if OPTIONAL_HAS_MOVE_ACCESSORS == 1 template @@ -579,17 +581,17 @@ public: } # else - + template T value_or(V&& v) && { return *this ? constexpr_move(const_cast&>(*this).contained_val()) : detail_::convert(constexpr_forward(v)); } - + # endif - + # else - + template constexpr T value_or(V&& v) const { @@ -609,42 +611,42 @@ class optional static_assert( !std::is_same::value, "bad T" ); static_assert( !std::is_same::value, "bad T" ); T* ref; - + public: // 20.5.5.1, construction/destruction constexpr optional() noexcept : ref(nullptr) {} - + constexpr optional(nullopt_t) noexcept : ref(nullptr) {} - + constexpr optional(T& v) noexcept : ref(detail_::static_addressof(v)) {} - + optional(T&&) = delete; - + constexpr optional(const optional& rhs) noexcept : ref(rhs.ref) {} - + explicit constexpr optional(in_place_t, T& v) noexcept : ref(detail_::static_addressof(v)) {} - + explicit optional(in_place_t, T&&) = delete; - + ~optional() = default; - + // 20.5.5.2, mutation optional& operator=(nullopt_t) noexcept { ref = nullptr; return *this; } - + // optional& operator=(const optional& rhs) noexcept { // ref = rhs.ref; // return *this; // } - + // optional& operator=(optional&& rhs) noexcept { // ref = rhs.ref; // return *this; // } - + template auto operator=(U&& rhs) noexcept -> typename enable_if @@ -656,7 +658,7 @@ public: ref = rhs.ref; return *this; } - + template auto operator=(U&& rhs) noexcept -> typename enable_if @@ -665,40 +667,40 @@ public: optional& >::type = delete; - + void emplace(T& v) noexcept { ref = detail_::static_addressof(v); } - + void emplace(T&&) = delete; - - + + void swap(optional& rhs) noexcept { std::swap(ref, rhs.ref); } - + // 20.5.5.3, observers constexpr T* operator->() const { return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, ref); } - + constexpr T& operator*() const { return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref); } - + constexpr T& value() const { return ref ? *ref : (throw bad_optional_access("bad optional access"), *ref); } - + explicit constexpr operator bool() const noexcept { return ref != nullptr; } - + constexpr bool has_value() const noexcept { return ref != nullptr; } - + template constexpr typename decay::type value_or(V&& v) const { @@ -1028,18 +1030,18 @@ namespace std { typedef typename hash::result_type result_type; typedef std::experimental::optional argument_type; - + constexpr result_type operator()(argument_type const& arg) const { return arg ? std::hash{}(*arg) : result_type{}; } }; - + template struct hash> { typedef typename hash::result_type result_type; typedef std::experimental::optional argument_type; - + constexpr result_type operator()(argument_type const& arg) const { return arg ? std::hash{}(*arg) : result_type{}; } diff --git a/platform_linux.cc b/platform_linux.cc new file mode 100644 index 00000000..90db75fe --- /dev/null +++ b/platform_linux.cc @@ -0,0 +1,118 @@ +#include "platform.h" + +#include "utils.h" + +#include +#include +#include +#include + + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* For O_* constants */ +#include /* For mode constants */ +#include +#include +#include /* For mode constants */ +#include /* For O_* constants */ + +struct PlatformMutexLinux : public PlatformMutex { + sem_t* sem_ = nullptr; + + PlatformMutexLinux(const std::string& name) { + std::cout << "PlatformMutexLinux name=" << name << std::endl; + sem_ = sem_open(name.c_str(), O_CREAT, 0666 /*permission*/, 1 /*initial_value*/); + } + + ~PlatformMutexLinux() override { + sem_close(sem_); + } +}; + +struct PlatformScopedMutexLockLinux : public PlatformScopedMutexLock { + sem_t* sem_ = nullptr; + + PlatformScopedMutexLockLinux(sem_t* sem) : sem_(sem) { + std::cout << "PlatformScopedMutexLockLinux" << std::endl; + sem_wait(sem_); + } + + ~PlatformScopedMutexLockLinux() override { + sem_post(sem_); + } +}; + +struct PlatformSharedMemoryLinux : public PlatformSharedMemory { + std::string name_; + int fd_; + void* shared_start_real_; + + PlatformSharedMemoryLinux(const std::string& name) : name_(name) { + std::cout << "PlatformSharedMemoryLinux name=" << name << std::endl; + fd_ = shm_open(name_.c_str(), O_CREAT, O_RDWR); + std::cout << "shm_open errno=" << errno << std::endl; + std::cout << "1" << std::endl; + ftruncate(fd_, shmem_size); + std::cout << "ftruncate errno=" << errno << std::endl; + std::cout << "2" << std::endl; + + //void *mmap(void *addr, size_t length, int prot, int flags, + // int fd, off_t offset); + //int munmap(void *addr, size_t length); + // + //shmem_size + std::cout << "3" << std::endl; + shared_start_real_ = mmap(nullptr /*kernel assigned starting address*/, + shmem_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_, 0 /*offset*/); + std::cout << "mmap errno=" << errno << std::endl; + std::cout << "fd_ = " << fd_ << std::endl; + std::cout << "shared_start_real_ = " << shared_start_real_ << std::endl; + std::cout << "4" << std::endl; + + /* + int fd = shm_open("shmname", O_CREAT, O_RDWR); + sem_t *sem = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + ftruncate(fd_, shmem_size); + + sem_init(sem, 1, 1); + */ + + std::cout << "4a" << std::endl; + shared_bytes_used = reinterpret_cast(shared_start_real_); + std::cout << "4b" << std::endl; + *shared_bytes_used = 0; + std::cout << "4c" << std::endl; + shared_start = reinterpret_cast(shared_bytes_used + 1); + std::cout << "5" << std::endl; + } + + ~PlatformSharedMemoryLinux() override { + munmap(shared_start_real_, shmem_size); + shm_unlink(name_.c_str()); + } +}; + + + +std::unique_ptr CreatePlatformMutex(const std::string& name) { + std::string name2 = "/" + name; + return MakeUnique(name2); +} + +std::unique_ptr CreatePlatformScopedMutexLock(PlatformMutex* mutex) { + return MakeUnique(static_cast(mutex)->sem_); +} + +std::unique_ptr CreatePlatformSharedMemory(const std::string& name) { + std::string name2 = "/" + name; + return MakeUnique(name2); +} diff --git a/platform_win.cc b/platform_win.cc index a88f871f..a4206f52 100644 --- a/platform_win.cc +++ b/platform_win.cc @@ -1,3 +1,4 @@ +#if false #include "platform.h" #include @@ -59,13 +60,14 @@ struct PlatformSharedMemoryWin : public PlatformSharedMemory { std::unique_ptr CreatePlatformMutex(const std::string& name) { - return std::make_unique(name); + return MakeUnique(name); } std::unique_ptr CreatePlatformScopedMutexLock(PlatformMutex* mutex) { - return std::make_unique(static_cast(mutex)->raw_mutex); + return MakeUnique(static_cast(mutex)->raw_mutex); } std::unique_ptr CreatePlatformSharedMemory(const std::string& name) { - return std::make_unique(name); -} \ No newline at end of file + return MakeUnique(name); +} +#endif diff --git a/utils.h b/utils.h index 9f311a0c..ac2645b8 100644 --- a/utils.h +++ b/utils.h @@ -2,6 +2,7 @@ #include #include +#include std::vector GetFilesInFolder(std::string folder); std::vector ReadLines(std::string filename); @@ -10,4 +11,11 @@ void ParseTestExpectation(std::string filename, std::string* expected_output); void Fail(const std::string& message); -void WriteToFile(const std::string& filename, const std::string& content); \ No newline at end of file +void WriteToFile(const std::string& filename, const std::string& content); + +// note: this implementation does not disable this overload for array types +// See http://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique#Possible_Implementatiog +template +std::unique_ptr MakeUnique(Args&&... args) { + return std::unique_ptr(new T(std::forward(args)...)); +} diff --git a/wscript b/wscript index d23ab560..094ae58b 100644 --- a/wscript +++ b/wscript @@ -1,12 +1,17 @@ #! /usr/bin/env python # encoding: utf-8 +import urllib2 + VERSION='0.0.1' APPNAME='indexer' top = '.' out = 'build' +from waflib.Tools.compiler_cxx import cxx_compiler +cxx_compiler['linux'] = ['clang++', 'g++'] + def options(opt): opt.load('compiler_cxx') @@ -15,8 +20,10 @@ def configure(conf): conf.check(header_name='stdio.h', features='cxx cxxprogram', mandatory=True) # https://github.com/Andersbakken/rtags/blob/master/scripts/getclang.sh -def download_clang(): - #'http://releases.llvm.org/3.9.0/clang+llvm-3.9.0-x86_64-apple-darwin.tar.xz' +def download_clang(conf): + url = 'http://releases.llvm.org/3.9.0/clang+llvm-3.9.0-x86_64-apple-darwin.tar.xz' + response = urllib2.urlopen(url) + html = response.read() pass def build(bld): @@ -24,8 +31,11 @@ def build(bld): excl=['*tests/*', 'third_party/*']) bld.program( source=cc_files, - cxxflags=['-std=c++14'], - includes=['third_party/rapidjson/include'], + cxxflags=['-std=c++11'], + includes=['third_party/rapidjson/include', + '/usr/local/google/home/jdufault/super-clang-index/clang+llvm-3.9.0-x86_64-linux-gnu-ubuntu-14.04/include'], + lib=['clang', 'rt', 'pthread'], + libpath=['/usr/local/google/home/jdufault/super-clang-index/clang+llvm-3.9.0-x86_64-linux-gnu-ubuntu-14.04/lib'], target='app') #bld.shlib(source='a.cpp', target='mylib', vnum='9.8.7')