blob: 3bfd9c2e5d2d69613a13091014466ade4794b0c2 [file] [log] [blame]
brettw@chromium.orge439a962011-01-02 08:16:20 +09001// Copyright (c) 2011 The Chromium Authors. All rights reserved.
license.botf003cfe2008-08-24 09:55:55 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
mmentovai@google.comf5a40002008-08-09 01:19:43 +09004
brettw@chromium.orge439a962011-01-02 08:16:20 +09005#include "base/synchronization/lock_impl.h"
mmentovai@google.comf5a40002008-08-09 01:19:43 +09006
ajwong@chromium.org4d1bc942013-08-13 21:04:02 +09007#include <string.h>
mmentovai@google.comf5a40002008-08-09 01:19:43 +09008
bcwhitea1569442016-08-10 12:10:03 +09009#include "base/debug/activity_tracker.h"
robliao6cc275c2016-08-02 05:59:42 +090010#include "base/synchronization/lock.h"
mmentovai@google.comf5a40002008-08-09 01:19:43 +090011
brettw@chromium.orge439a962011-01-02 08:16:20 +090012namespace base {
13namespace internal {
14
robliao6cc275c2016-08-02 05:59:42 +090015// 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.comf5a40002008-08-09 01:19:43 +090028LockImpl::LockImpl() {
erikkay@google.com3620e4c2008-08-12 00:38:27 +090029 pthread_mutexattr_t mta;
30 int rv = pthread_mutexattr_init(&mta);
ajwong@chromium.org4d1bc942013-08-13 21:04:02 +090031 DCHECK_EQ(rv, 0) << ". " << strerror(rv);
robliao6cc275c2016-08-02 05:59:42 +090032#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.orgd4eb87f2008-10-01 23:45:24 +090040 rv = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_ERRORCHECK);
ajwong@chromium.org4d1bc942013-08-13 21:04:02 +090041 DCHECK_EQ(rv, 0) << ". " << strerror(rv);
robliao6cc275c2016-08-02 05:59:42 +090042#endif
tfarina@chromium.orgbd138ea2013-09-14 14:27:08 +090043 rv = pthread_mutex_init(&native_handle_, &mta);
ajwong@chromium.org4d1bc942013-08-13 21:04:02 +090044 DCHECK_EQ(rv, 0) << ". " << strerror(rv);
erikkay@google.com3620e4c2008-08-12 00:38:27 +090045 rv = pthread_mutexattr_destroy(&mta);
ajwong@chromium.org4d1bc942013-08-13 21:04:02 +090046 DCHECK_EQ(rv, 0) << ". " << strerror(rv);
mmentovai@google.comf5a40002008-08-09 01:19:43 +090047}
48
49LockImpl::~LockImpl() {
tfarina@chromium.orgbd138ea2013-09-14 14:27:08 +090050 int rv = pthread_mutex_destroy(&native_handle_);
Ken Rockot048369b2017-08-22 07:03:40 +090051 DCHECK_EQ(rv, 0) << ". " << strerror(rv);
mmentovai@google.comf5a40002008-08-09 01:19:43 +090052}
53
54bool LockImpl::Try() {
tfarina@chromium.orgbd138ea2013-09-14 14:27:08 +090055 int rv = pthread_mutex_trylock(&native_handle_);
ajwong@chromium.org4d1bc942013-08-13 21:04:02 +090056 DCHECK(rv == 0 || rv == EBUSY) << ". " << strerror(rv);
mmentovai@google.comf5a40002008-08-09 01:19:43 +090057 return rv == 0;
58}
59
60void LockImpl::Lock() {
Brian White43d72ee2017-10-26 06:44:03 +090061 // 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
bcwhitea1569442016-08-10 12:10:03 +090072 base::debug::ScopedLockAcquireActivity lock_activity(this);
tfarina@chromium.orgbd138ea2013-09-14 14:27:08 +090073 int rv = pthread_mutex_lock(&native_handle_);
ajwong@chromium.org4d1bc942013-08-13 21:04:02 +090074 DCHECK_EQ(rv, 0) << ". " << strerror(rv);
mmentovai@google.comf5a40002008-08-09 01:19:43 +090075}
76
robliao6cc275c2016-08-02 05:59:42 +090077// static
78bool 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.orge439a962011-01-02 08:16:20 +0900101} // namespace internal
102} // namespace base