brettw@chromium.org | e439a96 | 2011-01-02 08:16:20 +0900 | [diff] [blame] | 1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
license.bot | f003cfe | 2008-08-24 09:55:55 +0900 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
mmentovai@google.com | f5a4000 | 2008-08-09 01:19:43 +0900 | [diff] [blame] | 4 | |
brettw@chromium.org | e439a96 | 2011-01-02 08:16:20 +0900 | [diff] [blame] | 5 | #include "base/synchronization/lock_impl.h" |
mmentovai@google.com | f5a4000 | 2008-08-09 01:19:43 +0900 | [diff] [blame] | 6 | |
ajwong@chromium.org | 4d1bc94 | 2013-08-13 21:04:02 +0900 | [diff] [blame] | 7 | #include <string.h> |
mmentovai@google.com | f5a4000 | 2008-08-09 01:19:43 +0900 | [diff] [blame] | 8 | |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 9 | #include "base/debug/activity_tracker.h" |
robliao | 6cc275c | 2016-08-02 05:59:42 +0900 | [diff] [blame] | 10 | #include "base/synchronization/lock.h" |
mmentovai@google.com | f5a4000 | 2008-08-09 01:19:43 +0900 | [diff] [blame] | 11 | |
brettw@chromium.org | e439a96 | 2011-01-02 08:16:20 +0900 | [diff] [blame] | 12 | namespace base { |
| 13 | namespace internal { |
| 14 | |
robliao | 6cc275c | 2016-08-02 05:59:42 +0900 | [diff] [blame] | 15 | // Determines which platforms can consider using priority inheritance locks. Use |
| 16 | // this define for platform code that may not compile if priority inheritance |
| 17 | // locks aren't available. For this platform code, |
| 18 | // PRIORITY_INHERITANCE_LOCKS_POSSIBLE() is a necessary but insufficient check. |
| 19 | // Lock::PriorityInheritanceAvailable still must be checked as the code may |
| 20 | // compile but the underlying platform still may not correctly support priority |
| 21 | // inheritance locks. |
| 22 | #if defined(OS_NACL) || defined(OS_ANDROID) |
| 23 | #define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 0 |
| 24 | #else |
| 25 | #define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 1 |
| 26 | #endif |
| 27 | |
mmentovai@google.com | f5a4000 | 2008-08-09 01:19:43 +0900 | [diff] [blame] | 28 | LockImpl::LockImpl() { |
erikkay@google.com | 3620e4c | 2008-08-12 00:38:27 +0900 | [diff] [blame] | 29 | pthread_mutexattr_t mta; |
| 30 | int rv = pthread_mutexattr_init(&mta); |
ajwong@chromium.org | 4d1bc94 | 2013-08-13 21:04:02 +0900 | [diff] [blame] | 31 | DCHECK_EQ(rv, 0) << ". " << strerror(rv); |
robliao | 6cc275c | 2016-08-02 05:59:42 +0900 | [diff] [blame] | 32 | #if PRIORITY_INHERITANCE_LOCKS_POSSIBLE() |
| 33 | if (PriorityInheritanceAvailable()) { |
| 34 | rv = pthread_mutexattr_setprotocol(&mta, PTHREAD_PRIO_INHERIT); |
| 35 | DCHECK_EQ(rv, 0) << ". " << strerror(rv); |
| 36 | } |
| 37 | #endif |
| 38 | #ifndef NDEBUG |
| 39 | // In debug, setup attributes for lock error checking. |
deanm@chromium.org | d4eb87f | 2008-10-01 23:45:24 +0900 | [diff] [blame] | 40 | rv = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_ERRORCHECK); |
ajwong@chromium.org | 4d1bc94 | 2013-08-13 21:04:02 +0900 | [diff] [blame] | 41 | DCHECK_EQ(rv, 0) << ". " << strerror(rv); |
robliao | 6cc275c | 2016-08-02 05:59:42 +0900 | [diff] [blame] | 42 | #endif |
tfarina@chromium.org | bd138ea | 2013-09-14 14:27:08 +0900 | [diff] [blame] | 43 | rv = pthread_mutex_init(&native_handle_, &mta); |
ajwong@chromium.org | 4d1bc94 | 2013-08-13 21:04:02 +0900 | [diff] [blame] | 44 | DCHECK_EQ(rv, 0) << ". " << strerror(rv); |
erikkay@google.com | 3620e4c | 2008-08-12 00:38:27 +0900 | [diff] [blame] | 45 | rv = pthread_mutexattr_destroy(&mta); |
ajwong@chromium.org | 4d1bc94 | 2013-08-13 21:04:02 +0900 | [diff] [blame] | 46 | DCHECK_EQ(rv, 0) << ". " << strerror(rv); |
mmentovai@google.com | f5a4000 | 2008-08-09 01:19:43 +0900 | [diff] [blame] | 47 | } |
| 48 | |
| 49 | LockImpl::~LockImpl() { |
tfarina@chromium.org | bd138ea | 2013-09-14 14:27:08 +0900 | [diff] [blame] | 50 | int rv = pthread_mutex_destroy(&native_handle_); |
Ken Rockot | 048369b | 2017-08-22 07:03:40 +0900 | [diff] [blame] | 51 | DCHECK_EQ(rv, 0) << ". " << strerror(rv); |
mmentovai@google.com | f5a4000 | 2008-08-09 01:19:43 +0900 | [diff] [blame] | 52 | } |
| 53 | |
| 54 | bool LockImpl::Try() { |
tfarina@chromium.org | bd138ea | 2013-09-14 14:27:08 +0900 | [diff] [blame] | 55 | int rv = pthread_mutex_trylock(&native_handle_); |
ajwong@chromium.org | 4d1bc94 | 2013-08-13 21:04:02 +0900 | [diff] [blame] | 56 | DCHECK(rv == 0 || rv == EBUSY) << ". " << strerror(rv); |
mmentovai@google.com | f5a4000 | 2008-08-09 01:19:43 +0900 | [diff] [blame] | 57 | return rv == 0; |
| 58 | } |
| 59 | |
| 60 | void LockImpl::Lock() { |
Brian White | 43d72ee | 2017-10-26 06:44:03 +0900 | [diff] [blame] | 61 | // The ScopedLockAcquireActivity below is relatively expensive and so its |
| 62 | // actions can become significant due to the very large number of locks |
| 63 | // that tend to be used throughout the build. To avoid this cost in the |
| 64 | // vast majority of the calls, simply "try" the lock first and only do the |
| 65 | // (tracked) blocking call if that fails. Since "try" itself is a system |
| 66 | // call, and thus also somewhat expensive, don't bother with it unless |
| 67 | // tracking is actually enabled. |
| 68 | if (base::debug::GlobalActivityTracker::IsEnabled()) |
| 69 | if (Try()) |
| 70 | return; |
| 71 | |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 72 | base::debug::ScopedLockAcquireActivity lock_activity(this); |
tfarina@chromium.org | bd138ea | 2013-09-14 14:27:08 +0900 | [diff] [blame] | 73 | int rv = pthread_mutex_lock(&native_handle_); |
ajwong@chromium.org | 4d1bc94 | 2013-08-13 21:04:02 +0900 | [diff] [blame] | 74 | DCHECK_EQ(rv, 0) << ". " << strerror(rv); |
mmentovai@google.com | f5a4000 | 2008-08-09 01:19:43 +0900 | [diff] [blame] | 75 | } |
| 76 | |
robliao | 6cc275c | 2016-08-02 05:59:42 +0900 | [diff] [blame] | 77 | // static |
| 78 | bool LockImpl::PriorityInheritanceAvailable() { |
| 79 | #if PRIORITY_INHERITANCE_LOCKS_POSSIBLE() && defined(OS_MACOSX) |
| 80 | return true; |
| 81 | #else |
| 82 | // Security concerns prevent the use of priority inheritance mutexes on Linux. |
| 83 | // * CVE-2010-0622 - wake_futex_pi unlocks incorrect, possible DoS. |
| 84 | // https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-0622 |
| 85 | // * CVE-2012-6647 - Linux < 3.5.1, futex_wait_requeue_pi possible DoS. |
| 86 | // https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-6647 |
| 87 | // * CVE-2014-3153 - Linux <= 3.14.5, futex_requeue, privilege escalation. |
| 88 | // https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3153 |
| 89 | // |
| 90 | // If the above were all addressed, we still need a runtime check to deal with |
| 91 | // the bug below. |
| 92 | // * glibc Bug 14652: https://sourceware.org/bugzilla/show_bug.cgi?id=14652 |
| 93 | // Fixed in glibc 2.17. |
| 94 | // Priority inheritance mutexes may deadlock with condition variables |
| 95 | // during recacquisition of the mutex after the condition variable is |
| 96 | // signalled. |
| 97 | return false; |
| 98 | #endif |
| 99 | } |
| 100 | |
brettw@chromium.org | e439a96 | 2011-01-02 08:16:20 +0900 | [diff] [blame] | 101 | } // namespace internal |
| 102 | } // namespace base |