1// Copyright 2018 The Abseil Authors. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14// 15// This file is a Linux-specific part of spinlock_wait.cc 16 17#include <linux/futex.h> 18#include <sys/syscall.h> 19#include <unistd.h> 20 21#include <atomic> 22#include <climits> 23#include <cstdint> 24#include <ctime> 25 26#include "absl/base/attributes.h" 27#include "absl/base/internal/errno_saver.h" 28 29// The SpinLock lockword is `std::atomic<uint32_t>`. Here we assert that 30// `std::atomic<uint32_t>` is bitwise equivalent of the `int` expected 31// by SYS_futex. We also assume that reads/writes done to the lockword 32// by SYS_futex have rational semantics with regard to the 33// std::atomic<> API. C++ provides no guarantees of these assumptions, 34// but they are believed to hold in practice. 35static_assert(sizeof(std::atomic<uint32_t>) == sizeof(int), 36 "SpinLock lockword has the wrong size for a futex"); 37 38// Some Android headers are missing these definitions even though they 39// support these futex operations. 40#ifdef __BIONIC__ 41#ifndef SYS_futex 42#define SYS_futex __NR_futex 43#endif 44#ifndef FUTEX_PRIVATE_FLAG 45#define FUTEX_PRIVATE_FLAG 128 46#endif 47#endif 48 49#if defined(__NR_futex_time64) && !defined(SYS_futex_time64) 50#define SYS_futex_time64 __NR_futex_time64 51#endif 52 53#if defined(SYS_futex_time64) && !defined(SYS_futex) 54#define SYS_futex SYS_futex_time64 55#endif 56 57extern "C" { 58 59ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)( 60 std::atomic<uint32_t> *w, uint32_t value, int loop, 61 absl::base_internal::SchedulingMode) { 62 absl::base_internal::ErrnoSaver errno_saver; 63 struct timespec tm; 64 tm.tv_sec = 0; 65 tm.tv_nsec = absl::base_internal::SpinLockSuggestedDelayNS(loop); 66 syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, &tm); 67} 68 69ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)( 70 std::atomic<uint32_t> *w, bool all) { 71 syscall(SYS_futex, w, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, all ? INT_MAX : 1, 0); 72} 73 74} // extern "C" 75