diff options
-rw-r--r-- | absl/base/BUILD.bazel | 1 | ||||
-rw-r--r-- | absl/base/internal/spinlock_akaros.inc | 35 | ||||
-rw-r--r-- | absl/base/internal/spinlock_wait.cc | 2 | ||||
-rw-r--r-- | absl/base/internal/sysinfo.cc | 24 | ||||
-rw-r--r-- | absl/base/macros.h | 1 | ||||
-rw-r--r-- | absl/debugging/internal/elf_mem_image.cc | 5 | ||||
-rw-r--r-- | absl/debugging/internal/elf_mem_image.h | 7 | ||||
-rw-r--r-- | absl/debugging/internal/stacktrace_x86-inl.inc | 4 | ||||
-rw-r--r-- | absl/debugging/internal/vdso_support.cc | 73 |
9 files changed, 119 insertions, 33 deletions
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel index d68448daa5d2..e68c4500e561 100644 --- a/absl/base/BUILD.bazel +++ b/absl/base/BUILD.bazel @@ -28,6 +28,7 @@ licenses(["notice"]) # Apache 2.0 cc_library( name = "spinlock_wait", srcs = [ + "internal/spinlock_akaros.inc", "internal/spinlock_posix.inc", "internal/spinlock_wait.cc", "internal/spinlock_win32.inc", diff --git a/absl/base/internal/spinlock_akaros.inc b/absl/base/internal/spinlock_akaros.inc new file mode 100644 index 000000000000..051c8cf87fb6 --- /dev/null +++ b/absl/base/internal/spinlock_akaros.inc @@ -0,0 +1,35 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This file is an Akaros-specific part of spinlock_wait.cc + +#include <atomic> + +#include "absl/base/internal/scheduling_mode.h" + +extern "C" { + +ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay( + std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, + int /* loop */, absl::base_internal::SchedulingMode /* mode */) { + // In Akaros, one must take care not to call anything that could cause a + // malloc(), a blocking system call, or a uthread_yield() while holding a + // spinlock. Our callers assume will not call into libraries or other + // arbitrary code. +} + +ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake( + std::atomic<uint32_t>* /* lock_word */, bool /* all */) {} + +} // extern "C" diff --git a/absl/base/internal/spinlock_wait.cc b/absl/base/internal/spinlock_wait.cc index 0fd36286629d..8f951b66dc36 100644 --- a/absl/base/internal/spinlock_wait.cc +++ b/absl/base/internal/spinlock_wait.cc @@ -23,6 +23,8 @@ #if defined(_WIN32) #include "absl/base/internal/spinlock_win32.inc" +#elif defined(__akaros__) +#include "absl/base/internal/spinlock_akaros.inc" #else #include "absl/base/internal/spinlock_posix.inc" #endif diff --git a/absl/base/internal/sysinfo.cc b/absl/base/internal/sysinfo.cc index 9e0140fadb1f..00e98b662cc6 100644 --- a/absl/base/internal/sysinfo.cc +++ b/absl/base/internal/sysinfo.cc @@ -284,6 +284,30 @@ pid_t GetTID() { return syscall(SYS_gettid); } +#elif defined(__akaros__) + +pid_t GetTID() { + // Akaros has a concept of "vcore context", which is the state the program + // is forced into when we need to make a user-level scheduling decision, or + // run a signal handler. This is analogous to the interrupt context that a + // CPU might enter if it encounters some kind of exception. + // + // There is no current thread context in vcore context, but we need to give + // a reasonable answer if asked for a thread ID (e.g., in a signal handler). + // Thread 0 always exists, so if we are in vcore context, we return that. + // + // Otherwise, we know (since we are using pthreads) that the uthread struct + // current_uthread is pointing to is the first element of a + // struct pthread_tcb, so we extract and return the thread ID from that. + // + // TODO(dcross): Akaros anticipates moving the thread ID to the uthread + // structure at some point. We should modify this code to remove the cast + // when that happens. + if (in_vcore_context()) + return 0; + return reinterpret_cast<struct pthread_tcb *>(current_uthread)->id; +} + #else // Fallback implementation of GetTID using pthread_getspecific. diff --git a/absl/base/macros.h b/absl/base/macros.h index 31d1c02ecfa6..d41408727731 100644 --- a/absl/base/macros.h +++ b/absl/base/macros.h @@ -29,6 +29,7 @@ #ifndef ABSL_BASE_MACROS_H_ #define ABSL_BASE_MACROS_H_ +#include <cassert> #include <cstddef> #include "absl/base/port.h" diff --git a/absl/debugging/internal/elf_mem_image.cc b/absl/debugging/internal/elf_mem_image.cc index f6c6bc07d511..3dfef5e83e57 100644 --- a/absl/debugging/internal/elf_mem_image.cc +++ b/absl/debugging/internal/elf_mem_image.cc @@ -75,8 +75,9 @@ const T *GetTableElement(const ElfW(Ehdr) * ehdr, ElfW(Off) table_offset, } // namespace -const void *const ElfMemImage::kInvalidBase = - reinterpret_cast<const void *>(~0L); +// The value of this variable doesn't matter; it's used only for its +// unique address. +const int ElfMemImage::kInvalidBaseSentinel = 0; ElfMemImage::ElfMemImage(const void *base) { ABSL_RAW_CHECK(base != kInvalidBase, "bad pointer"); diff --git a/absl/debugging/internal/elf_mem_image.h b/absl/debugging/internal/elf_mem_image.h index 7f3dbb971bd6..20a32a490cb2 100644 --- a/absl/debugging/internal/elf_mem_image.h +++ b/absl/debugging/internal/elf_mem_image.h @@ -43,9 +43,14 @@ namespace debug_internal { // An in-memory ELF image (may not exist on disk). class ElfMemImage { + private: + // Sentinel: there could never be an elf image at &kInvalidBaseSentinel. + static const int kInvalidBaseSentinel; + public: // Sentinel: there could never be an elf image at this address. - static const void *const kInvalidBase; + static constexpr const void *const kInvalidBase = + static_cast<const void*>(&kInvalidBaseSentinel); // Information about a single vdso symbol. // All pointers are into .dynsym, .dynstr, or .text of the VDSO. diff --git a/absl/debugging/internal/stacktrace_x86-inl.inc b/absl/debugging/internal/stacktrace_x86-inl.inc index 6e1af017878e..9bdaa542ce27 100644 --- a/absl/debugging/internal/stacktrace_x86-inl.inc +++ b/absl/debugging/internal/stacktrace_x86-inl.inc @@ -114,7 +114,9 @@ static const int kMaxFrameBytes = 100000; // vuc is a ucontext_t *. We use void* to avoid the use // of ucontext_t on non-POSIX systems. static uintptr_t GetFP(const void *vuc) { -#if defined(__linux__) +#if !defined(__linux__) + static_cast<void>(vuc); // Avoid an unused argument compiler warning. +#else if (vuc != nullptr) { auto *uc = reinterpret_cast<const ucontext_t *>(vuc); #if defined(__i386__) diff --git a/absl/debugging/internal/vdso_support.cc b/absl/debugging/internal/vdso_support.cc index 5026e1c1a9c9..815e702f5699 100644 --- a/absl/debugging/internal/vdso_support.cc +++ b/absl/debugging/internal/vdso_support.cc @@ -20,10 +20,15 @@ #ifdef ABSL_HAVE_VDSO_SUPPORT // defined in vdso_support.h +#include <errno.h> #include <fcntl.h> #include <sys/syscall.h> #include <unistd.h> +#if __GLIBC_PREREQ(2, 16) // GLIBC-2.16 implements getauxval. +#include <sys/auxv.h> +#endif + #include "absl/base/dynamic_annotations.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/port.h" @@ -35,8 +40,10 @@ namespace absl { namespace debug_internal { +ABSL_CONST_INIT std::atomic<const void *> VDSOSupport::vdso_base_( debug_internal::ElfMemImage::kInvalidBase); + std::atomic<VDSOSupport::GetCpuFn> VDSOSupport::getcpu_fn_(&InitAndGetCPU); VDSOSupport::VDSOSupport() // If vdso_base_ is still set to kInvalidBase, we got here @@ -56,37 +63,44 @@ VDSOSupport::VDSOSupport() // Finally, even if there is a race here, it is harmless, because // the operation should be idempotent. const void *VDSOSupport::Init() { - if (vdso_base_.load(std::memory_order_relaxed) == - debug_internal::ElfMemImage::kInvalidBase) { - { - // Valgrind zaps AT_SYSINFO_EHDR and friends from the auxv[] - // on stack, and so glibc works as if VDSO was not present. - // But going directly to kernel via /proc/self/auxv below bypasses - // Valgrind zapping. So we check for Valgrind separately. - if (RunningOnValgrind()) { - vdso_base_.store(nullptr, std::memory_order_relaxed); - getcpu_fn_.store(&GetCPUViaSyscall, std::memory_order_relaxed); - return nullptr; - } - int fd = open("/proc/self/auxv", O_RDONLY); - if (fd == -1) { - // Kernel too old to have a VDSO. - vdso_base_.store(nullptr, std::memory_order_relaxed); - getcpu_fn_.store(&GetCPUViaSyscall, std::memory_order_relaxed); - return nullptr; - } - ElfW(auxv_t) aux; - while (read(fd, &aux, sizeof(aux)) == sizeof(aux)) { - if (aux.a_type == AT_SYSINFO_EHDR) { - vdso_base_.store(reinterpret_cast<void *>(aux.a_un.a_val), - std::memory_order_relaxed); - break; - } + const auto kInvalidBase = debug_internal::ElfMemImage::kInvalidBase; +#if __GLIBC_PREREQ(2, 16) + if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) { + errno = 0; + const void *const sysinfo_ehdr = + reinterpret_cast<const void *>(getauxval(AT_SYSINFO_EHDR)); + if (errno == 0) { + vdso_base_.store(sysinfo_ehdr, std::memory_order_relaxed); + } + } +#endif // __GLIBC_PREREQ(2, 16) + if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) { + // Valgrind zaps AT_SYSINFO_EHDR and friends from the auxv[] + // on stack, and so glibc works as if VDSO was not present. + // But going directly to kernel via /proc/self/auxv below bypasses + // Valgrind zapping. So we check for Valgrind separately. + if (RunningOnValgrind()) { + vdso_base_.store(nullptr, std::memory_order_relaxed); + getcpu_fn_.store(&GetCPUViaSyscall, std::memory_order_relaxed); + return nullptr; + } + int fd = open("/proc/self/auxv", O_RDONLY); + if (fd == -1) { + // Kernel too old to have a VDSO. + vdso_base_.store(nullptr, std::memory_order_relaxed); + getcpu_fn_.store(&GetCPUViaSyscall, std::memory_order_relaxed); + return nullptr; + } + ElfW(auxv_t) aux; + while (read(fd, &aux, sizeof(aux)) == sizeof(aux)) { + if (aux.a_type == AT_SYSINFO_EHDR) { + vdso_base_.store(reinterpret_cast<void *>(aux.a_un.a_val), + std::memory_order_relaxed); + break; } - close(fd); } - if (vdso_base_.load(std::memory_order_relaxed) == - debug_internal::ElfMemImage::kInvalidBase) { + close(fd); + if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) { // Didn't find AT_SYSINFO_EHDR in auxv[]. vdso_base_.store(nullptr, std::memory_order_relaxed); } @@ -135,6 +149,7 @@ long VDSOSupport::GetCPUViaSyscall(unsigned *cpu, // NOLINT(runtime/int) return syscall(SYS_getcpu, cpu, nullptr, nullptr); #else // x86_64 never implemented sys_getcpu(), except as a VDSO call. + static_cast<void>(cpu); // Avoid an unused argument compiler warning. errno = ENOSYS; return -1; #endif |