Home | History | Annotate | Download | only in synchronization
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/synchronization/lock_impl.h"
      6 
      7 #include <errno.h>
      8 #include <string.h>
      9 
     10 #include "base/debug/activity_tracker.h"
     11 #include "base/logging.h"
     12 #include "base/synchronization/lock.h"
     13 
     14 namespace base {
     15 namespace internal {
     16 
     17 // Determines which platforms can consider using priority inheritance locks. Use
     18 // this define for platform code that may not compile if priority inheritance
     19 // locks aren't available. For this platform code,
     20 // PRIORITY_INHERITANCE_LOCKS_POSSIBLE() is a necessary but insufficient check.
     21 // Lock::PriorityInheritanceAvailable still must be checked as the code may
     22 // compile but the underlying platform still may not correctly support priority
     23 // inheritance locks.
     24 #if defined(OS_NACL) || defined(OS_ANDROID)
     25 #define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 0
     26 #else
     27 #define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 1
     28 #endif
     29 
     30 LockImpl::LockImpl() {
     31   pthread_mutexattr_t mta;
     32   int rv = pthread_mutexattr_init(&mta);
     33   DCHECK_EQ(rv, 0) << ". " << strerror(rv);
     34 #if PRIORITY_INHERITANCE_LOCKS_POSSIBLE()
     35   if (PriorityInheritanceAvailable()) {
     36     rv = pthread_mutexattr_setprotocol(&mta, PTHREAD_PRIO_INHERIT);
     37     DCHECK_EQ(rv, 0) << ". " << strerror(rv);
     38   }
     39 #endif
     40 #ifndef NDEBUG
     41   // In debug, setup attributes for lock error checking.
     42   rv = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_ERRORCHECK);
     43   DCHECK_EQ(rv, 0) << ". " << strerror(rv);
     44 #endif
     45   rv = pthread_mutex_init(&native_handle_, &mta);
     46   DCHECK_EQ(rv, 0) << ". " << strerror(rv);
     47   rv = pthread_mutexattr_destroy(&mta);
     48   DCHECK_EQ(rv, 0) << ". " << strerror(rv);
     49 }
     50 
     51 LockImpl::~LockImpl() {
     52   int rv = pthread_mutex_destroy(&native_handle_);
     53   DCHECK_EQ(rv, 0) << ". " << strerror(rv);
     54 }
     55 
     56 bool LockImpl::Try() {
     57   int rv = pthread_mutex_trylock(&native_handle_);
     58   DCHECK(rv == 0 || rv == EBUSY) << ". " << strerror(rv);
     59   return rv == 0;
     60 }
     61 
     62 void LockImpl::Lock() {
     63   base::debug::ScopedLockAcquireActivity lock_activity(this);
     64   int rv = pthread_mutex_lock(&native_handle_);
     65   DCHECK_EQ(rv, 0) << ". " << strerror(rv);
     66 }
     67 
     68 void LockImpl::Unlock() {
     69   int rv = pthread_mutex_unlock(&native_handle_);
     70   DCHECK_EQ(rv, 0) << ". " << strerror(rv);
     71 }
     72 
     73 // static
     74 bool LockImpl::PriorityInheritanceAvailable() {
     75 #if PRIORITY_INHERITANCE_LOCKS_POSSIBLE() && defined(OS_MACOSX)
     76   return true;
     77 #else
     78   // Security concerns prevent the use of priority inheritance mutexes on Linux.
     79   //   * CVE-2010-0622 - wake_futex_pi unlocks incorrect, possible DoS.
     80   //     https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-0622
     81   //   * CVE-2012-6647 - Linux < 3.5.1, futex_wait_requeue_pi possible DoS.
     82   //     https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-6647
     83   //   * CVE-2014-3153 - Linux <= 3.14.5, futex_requeue, privilege escalation.
     84   //     https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3153
     85   //
     86   // If the above were all addressed, we still need a runtime check to deal with
     87   // the bug below.
     88   //   * glibc Bug 14652: https://sourceware.org/bugzilla/show_bug.cgi?id=14652
     89   //     Fixed in glibc 2.17.
     90   //     Priority inheritance mutexes may deadlock with condition variables
     91   //     during recacquisition of the mutex after the condition variable is
     92   //     signalled.
     93   return false;
     94 #endif
     95 }
     96 
     97 }  // namespace internal
     98 }  // namespace base
     99