aboutsummaryrefslogtreecommitdiff
path: root/absl/synchronization/mutex_test.cc
diff options
context:
space:
mode:
authorAbseil Team <absl-team@google.com>2023-08-29 23:57:04 -0700
committerCopybara-Service <copybara-worker@google.com>2023-08-29 23:57:48 -0700
commitb06ab1f3554eee58fa0eac046ea79f4b572fa502 (patch)
tree7d4ebec1fb206bf471bbdd3a9885f1ae4aa0d911 /absl/synchronization/mutex_test.cc
parentf6fc4efa6edf7285512797a5e68373994dd2df27 (diff)
downloadabseil-b06ab1f3554eee58fa0eac046ea79f4b572fa502.tar.gz
abseil-b06ab1f3554eee58fa0eac046ea79f4b572fa502.tar.bz2
abseil-b06ab1f3554eee58fa0eac046ea79f4b572fa502.zip
absl: fix a priority bug in CondVar wait morphing
Enqueue updates priority of the queued thread. It was assumed that the queued thread is the current thread. But it's not the case in CondVar wait morhping, where we requeue an existing CondVar waiter on the Mutex. As the result one thread can falsely get priority of another thread. Fix this by not updating priority in this case. And make the assumption explicit and checked. PiperOrigin-RevId: 561249402 Change-Id: I9476c047757090b893a88a2839b795b85fe220ad
Diffstat (limited to 'absl/synchronization/mutex_test.cc')
-rw-r--r--absl/synchronization/mutex_test.cc60
1 files changed, 60 insertions, 0 deletions
diff --git a/absl/synchronization/mutex_test.cc b/absl/synchronization/mutex_test.cc
index b585c342..0bca46c5 100644
--- a/absl/synchronization/mutex_test.cc
+++ b/absl/synchronization/mutex_test.cc
@@ -36,10 +36,16 @@
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "absl/memory/memory.h"
+#include "absl/synchronization/internal/create_thread_identity.h"
#include "absl/synchronization/internal/thread_pool.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
+#ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM
+#include <pthread.h>
+#include <string.h>
+#endif
+
namespace {
// TODO(dmauro): Replace with a commandline flag.
@@ -1868,6 +1874,60 @@ TEST(Mutex, WriterPriority) {
EXPECT_TRUE(saw_wrote.load());
}
+#ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM
+TEST(Mutex, CondVarPriority) {
+ // A regression test for a bug in condition variable wait morphing,
+ // which resulted in the waiting thread getting priority of the waking thread.
+ int err = 0;
+ sched_param param;
+ param.sched_priority = 7;
+ std::thread test([&]() {
+ err = pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);
+ });
+ test.join();
+ if (err) {
+ // Setting priority usually requires special privileges.
+ GTEST_SKIP() << "failed to set priority: " << strerror(err);
+ }
+ absl::Mutex mu;
+ absl::CondVar cv;
+ bool locked = false;
+ bool notified = false;
+ bool waiting = false;
+ bool morph = false;
+ std::thread th([&]() {
+ EXPECT_EQ(0, pthread_setschedparam(pthread_self(), SCHED_FIFO, &param));
+ mu.Lock();
+ locked = true;
+ mu.Await(absl::Condition(&notified));
+ mu.Unlock();
+ EXPECT_EQ(absl::synchronization_internal::GetOrCreateCurrentThreadIdentity()
+ ->per_thread_synch.priority,
+ param.sched_priority);
+ mu.Lock();
+ mu.Await(absl::Condition(&waiting));
+ morph = true;
+ absl::SleepFor(absl::Seconds(1));
+ cv.Signal();
+ mu.Unlock();
+ });
+ mu.Lock();
+ mu.Await(absl::Condition(&locked));
+ notified = true;
+ mu.Unlock();
+ mu.Lock();
+ waiting = true;
+ while (!morph) {
+ cv.Wait(&mu);
+ }
+ mu.Unlock();
+ th.join();
+ EXPECT_NE(absl::synchronization_internal::GetOrCreateCurrentThreadIdentity()
+ ->per_thread_synch.priority,
+ param.sched_priority);
+}
+#endif
+
TEST(Mutex, LockWhenWithTimeoutResult) {
// Check various corner cases for Await/LockWhen return value
// with always true/always false conditions.