Changes imported from Abseil "staging" branch:
- fbff677ef850865ea67ed6771a8ed348be181e8e Modify sysinfo.cc to support GetTID on Akaros. by Abseil Team <absl-team@google.com> - f1c2929e08a3d4181e08cb5014c4a569306fd922 Two functions that did not refer to their arguments unles... by Abseil Team <absl-team@google.com> - ee43cc3bfdb4d84d40eee31fb25ecdc1aa060f47 Support Akaros (https://akaros.org) in the ABSL spinlock_... by Abseil Team <absl-team@google.com> - 6869c8c5253126459d6c7f0aa708d8612c8e5963 Make sure vdso_base_ is constant-intialized. by Abseil Team <absl-team@google.com> - d54e0366efc8d44cd5da5fd157734da966dc45e8 Add missing include for assert used by ABSL_ASSERT. by Derek Mauro <dmauro@google.com> - a5139775f3917bb5201e7fc838135766daa05b8d When building against GLIBC-2.16 or newer, use getauxval(... by Abseil Team <absl-team@google.com> GitOrigin-RevId: fbff677ef850865ea67ed6771a8ed348be181e8e Change-Id: Ie3549f6ef054783dd104304d2faf8d9800c16b83
This commit is contained in:
parent
5fcbe86e7b
commit
dedb4eec6c
9 changed files with 120 additions and 34 deletions
|
@ -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",
|
||||
|
|
35
absl/base/internal/spinlock_akaros.inc
Normal file
35
absl/base/internal/spinlock_akaros.inc
Normal file
|
@ -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"
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#ifndef ABSL_BASE_MACROS_H_
|
||||
#define ABSL_BASE_MACROS_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
|
||||
#include "absl/base/port.h"
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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__)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
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);
|
||||
}
|
||||
if (vdso_base_.load(std::memory_order_relaxed) ==
|
||||
debug_internal::ElfMemImage::kInvalidBase) {
|
||||
}
|
||||
#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) == 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
|
||||
|
|
Loading…
Reference in a new issue