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( | cc_library( | ||||||
|     name = "spinlock_wait", |     name = "spinlock_wait", | ||||||
|     srcs = [ |     srcs = [ | ||||||
|  |         "internal/spinlock_akaros.inc", | ||||||
|         "internal/spinlock_posix.inc", |         "internal/spinlock_posix.inc", | ||||||
|         "internal/spinlock_wait.cc", |         "internal/spinlock_wait.cc", | ||||||
|         "internal/spinlock_win32.inc", |         "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) | #if defined(_WIN32) | ||||||
| #include "absl/base/internal/spinlock_win32.inc" | #include "absl/base/internal/spinlock_win32.inc" | ||||||
|  | #elif defined(__akaros__) | ||||||
|  | #include "absl/base/internal/spinlock_akaros.inc" | ||||||
| #else | #else | ||||||
| #include "absl/base/internal/spinlock_posix.inc" | #include "absl/base/internal/spinlock_posix.inc" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -284,6 +284,30 @@ pid_t GetTID() { | ||||||
|   return syscall(SYS_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 | #else | ||||||
| 
 | 
 | ||||||
| // Fallback implementation of GetTID using pthread_getspecific.
 | // Fallback implementation of GetTID using pthread_getspecific.
 | ||||||
|  |  | ||||||
|  | @ -29,6 +29,7 @@ | ||||||
| #ifndef ABSL_BASE_MACROS_H_ | #ifndef ABSL_BASE_MACROS_H_ | ||||||
| #define ABSL_BASE_MACROS_H_ | #define ABSL_BASE_MACROS_H_ | ||||||
| 
 | 
 | ||||||
|  | #include <cassert> | ||||||
| #include <cstddef> | #include <cstddef> | ||||||
| 
 | 
 | ||||||
| #include "absl/base/port.h" | #include "absl/base/port.h" | ||||||
|  |  | ||||||
|  | @ -75,8 +75,9 @@ const T *GetTableElement(const ElfW(Ehdr) * ehdr, ElfW(Off) table_offset, | ||||||
| 
 | 
 | ||||||
| }  // namespace
 | }  // namespace
 | ||||||
| 
 | 
 | ||||||
| const void *const ElfMemImage::kInvalidBase = | // The value of this variable doesn't matter; it's used only for its
 | ||||||
|     reinterpret_cast<const void *>(~0L); | // unique address.
 | ||||||
|  | const int ElfMemImage::kInvalidBaseSentinel = 0; | ||||||
| 
 | 
 | ||||||
| ElfMemImage::ElfMemImage(const void *base) { | ElfMemImage::ElfMemImage(const void *base) { | ||||||
|   ABSL_RAW_CHECK(base != kInvalidBase, "bad pointer"); |   ABSL_RAW_CHECK(base != kInvalidBase, "bad pointer"); | ||||||
|  |  | ||||||
|  | @ -43,9 +43,14 @@ namespace debug_internal { | ||||||
| 
 | 
 | ||||||
| // An in-memory ELF image (may not exist on disk).
 | // An in-memory ELF image (may not exist on disk).
 | ||||||
| class ElfMemImage { | class ElfMemImage { | ||||||
|  |  private: | ||||||
|  |   // Sentinel: there could never be an elf image at &kInvalidBaseSentinel.
 | ||||||
|  |   static const int kInvalidBaseSentinel; | ||||||
|  | 
 | ||||||
|  public: |  public: | ||||||
|   // Sentinel: there could never be an elf image at this address.
 |   // 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.
 |   // Information about a single vdso symbol.
 | ||||||
|   // All pointers are into .dynsym, .dynstr, or .text of the VDSO.
 |   // 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
 | // vuc is a ucontext_t *.  We use void* to avoid the use
 | ||||||
| // of ucontext_t on non-POSIX systems.
 | // of ucontext_t on non-POSIX systems.
 | ||||||
| static uintptr_t GetFP(const void *vuc) { | 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) { |   if (vuc != nullptr) { | ||||||
|     auto *uc = reinterpret_cast<const ucontext_t *>(vuc); |     auto *uc = reinterpret_cast<const ucontext_t *>(vuc); | ||||||
| #if defined(__i386__)
 | #if defined(__i386__)
 | ||||||
|  |  | ||||||
|  | @ -20,10 +20,15 @@ | ||||||
| 
 | 
 | ||||||
| #ifdef ABSL_HAVE_VDSO_SUPPORT     // defined in vdso_support.h
 | #ifdef ABSL_HAVE_VDSO_SUPPORT     // defined in vdso_support.h
 | ||||||
| 
 | 
 | ||||||
|  | #include <errno.h> | ||||||
| #include <fcntl.h> | #include <fcntl.h> | ||||||
| #include <sys/syscall.h> | #include <sys/syscall.h> | ||||||
| #include <unistd.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/dynamic_annotations.h" | ||||||
| #include "absl/base/internal/raw_logging.h" | #include "absl/base/internal/raw_logging.h" | ||||||
| #include "absl/base/port.h" | #include "absl/base/port.h" | ||||||
|  | @ -35,8 +40,10 @@ | ||||||
| namespace absl { | namespace absl { | ||||||
| namespace debug_internal { | namespace debug_internal { | ||||||
| 
 | 
 | ||||||
|  | ABSL_CONST_INIT | ||||||
| std::atomic<const void *> VDSOSupport::vdso_base_( | std::atomic<const void *> VDSOSupport::vdso_base_( | ||||||
|     debug_internal::ElfMemImage::kInvalidBase); |     debug_internal::ElfMemImage::kInvalidBase); | ||||||
|  | 
 | ||||||
| std::atomic<VDSOSupport::GetCpuFn> VDSOSupport::getcpu_fn_(&InitAndGetCPU); | std::atomic<VDSOSupport::GetCpuFn> VDSOSupport::getcpu_fn_(&InitAndGetCPU); | ||||||
| VDSOSupport::VDSOSupport() | VDSOSupport::VDSOSupport() | ||||||
|     // If vdso_base_ is still set to kInvalidBase, we got here
 |     // If vdso_base_ is still set to kInvalidBase, we got here
 | ||||||
|  | @ -56,9 +63,18 @@ VDSOSupport::VDSOSupport() | ||||||
| // Finally, even if there is a race here, it is harmless, because
 | // Finally, even if there is a race here, it is harmless, because
 | ||||||
| // the operation should be idempotent.
 | // the operation should be idempotent.
 | ||||||
| const void *VDSOSupport::Init() { | const void *VDSOSupport::Init() { | ||||||
|   if (vdso_base_.load(std::memory_order_relaxed) == |   const auto kInvalidBase = debug_internal::ElfMemImage::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[]
 |     // Valgrind zaps AT_SYSINFO_EHDR and friends from the auxv[]
 | ||||||
|     // on stack, and so glibc works as if VDSO was not present.
 |     // on stack, and so glibc works as if VDSO was not present.
 | ||||||
|     // But going directly to kernel via /proc/self/auxv below bypasses
 |     // But going directly to kernel via /proc/self/auxv below bypasses
 | ||||||
|  | @ -84,9 +100,7 @@ const void *VDSOSupport::Init() { | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     close(fd); |     close(fd); | ||||||
|     } |     if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) { | ||||||
|     if (vdso_base_.load(std::memory_order_relaxed) == |  | ||||||
|         debug_internal::ElfMemImage::kInvalidBase) { |  | ||||||
|       // Didn't find AT_SYSINFO_EHDR in auxv[].
 |       // Didn't find AT_SYSINFO_EHDR in auxv[].
 | ||||||
|       vdso_base_.store(nullptr, std::memory_order_relaxed); |       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); |   return syscall(SYS_getcpu, cpu, nullptr, nullptr); | ||||||
| #else | #else | ||||||
|   // x86_64 never implemented sys_getcpu(), except as a VDSO call.
 |   // x86_64 never implemented sys_getcpu(), except as a VDSO call.
 | ||||||
|  |   static_cast<void>(cpu);  // Avoid an unused argument compiler warning.
 | ||||||
|   errno = ENOSYS; |   errno = ENOSYS; | ||||||
|   return -1; |   return -1; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue