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 49extern "C" { 50 51ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay( 52 std::atomic<uint32_t> *w, uint32_t value, int loop, 53 absl::base_internal::SchedulingMode) { 54 absl::base_internal::ErrnoSaver errno_saver; 55 struct timespec tm; 56 tm.tv_sec = 0; 57 tm.tv_nsec = absl::base_internal::SpinLockSuggestedDelayNS(loop); 58 syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, &tm); 59} 60 61ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(std::atomic<uint32_t> *w, 62 bool all) { 63 syscall(SYS_futex, w, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, all ? INT_MAX : 1, 0); 64} 65 66} // extern "C" 67