15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Copyright (c) 2009, Google Inc. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Redistribution and use in source and binary forms, with or without 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * modification, are permitted provided that the following conditions are 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * met: 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * * Redistributions of source code must retain the above copyright 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * notice, this list of conditions and the following disclaimer. 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * * Redistributions in binary form must reproduce the above 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * in the documentation and/or other materials provided with the 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * distribution. 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * * Neither the name of Google Inc. nor the names of its 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * contributors may be used to endorse or promote products derived from 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * this software without specific prior written permission. 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * --- 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This file is a Linux-specific part of spinlock_internal.cc 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h> 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sched.h> 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <time.h> 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <limits.h> 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/linux_syscall_support.h" 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define FUTEX_WAIT 0 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define FUTEX_WAKE 1 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define FUTEX_PRIVATE_FLAG 128 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note: Instead of making direct system calls that are inlined, we rely 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// on the syscall() function in glibc to do the right thing. This 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is necessary to make the code compatible with the seccomp sandbox, 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// which needs to be able to find and patch all places where system 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// calls are made. Scanning through and patching glibc is fast, but 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// doing so on the entire Chrome binary would be prohibitively 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// expensive. 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is a notable change from the upstream version of tcmalloc, 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// which prefers direct system calls in order to improve compatibility 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// with older toolchains and runtime libraries. 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool have_futex; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int futex_private_flag = FUTEX_PRIVATE_FLAG; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct InitModule { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InitModule() { 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x = 0; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // futexes are ints, so we can use them only when 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that's the same size as the lockword_ in SpinLock. 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef __arm__ 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ARM linux doesn't support sys_futex1(void*, int, int, struct timespec*); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) have_futex = 0; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) have_futex = (sizeof (Atomic32) == sizeof (int) && 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syscall(__NR_futex, &x, FUTEX_WAKE, 1, 0) >= 0); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (have_futex && 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syscall(__NR_futex, &x, FUTEX_WAKE | futex_private_flag, 1, 0) < 0) { 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) futex_private_flag = 0; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} init_module; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // anonymous namespace 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base { 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace internal { 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpinLockDelay(volatile Atomic32 *w, int32 value, int loop) { 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (loop != 0) { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int save_errno = errno; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct timespec tm; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tm.tv_sec = 0; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (have_futex) { 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Wait between 0-16ms. 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tm.tv_nsec = base::internal::SuggestedDelayNS(loop); 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Note: since Unlock() is optimized to not do a compare-and-swap, 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // we can't expect explicit wake-ups. Therefore we shouldn't wait too 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // long here. 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syscall(__NR_futex, reinterpret_cast<int *>(const_cast<Atomic32 *>(w)), 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FUTEX_WAIT | futex_private_flag, 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value, reinterpret_cast<struct kernel_timespec *>(&tm)); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) tm.tv_nsec = 2000001; // above 2ms so linux 2.4 doesn't spin 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nanosleep(&tm, NULL); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errno = save_errno; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SpinLockWake(volatile Atomic32 *w, bool all) { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (have_futex) { 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syscall(__NR_futex, reinterpret_cast<int *>(const_cast<Atomic32 *>(w)), 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FUTEX_WAKE | futex_private_flag, 1, 0); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace internal 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace base 115