blob: 849e078bd2ab05c4c4f9c96d18a031fd7ed882a6 [file] [log] [blame]
Roger Meier3fc48192011-12-11 21:05:35 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
James E. King, III00d42522017-04-04 09:32:45 -040020// This is linked into the UnitTests test executable
Roger Meier3fc48192011-12-11 21:05:35 +000021
Roger Meier3fc48192011-12-11 21:05:35 +000022#include <boost/test/unit_test.hpp>
23
Roger Meier49ff8b12012-04-13 09:12:31 +000024#include "thrift/concurrency/Mutex.h"
25#include "thrift/concurrency/PosixThreadFactory.h"
James E. King, III82ae9572017-08-05 12:23:54 -040026#include <thrift/stdcxx.h>
Roger Meier3fc48192011-12-11 21:05:35 +000027
James E. King, III82ae9572017-08-05 12:23:54 -040028using apache::thrift::stdcxx::shared_ptr;
Roger Meier3fc48192011-12-11 21:05:35 +000029using boost::unit_test::test_suite;
30using boost::unit_test::framework::master_test_suite;
31
32using namespace apache::thrift::concurrency;
Roger Meier3fc48192011-12-11 21:05:35 +000033
Konrad Grochowski16a23a62014-11-13 15:33:38 +010034class Locker : public Runnable {
Roger Meier3fc48192011-12-11 21:05:35 +000035protected:
James E. King, III82ae9572017-08-05 12:23:54 -040036 Locker(shared_ptr<ReadWriteMutex> rwlock, bool writer)
Konrad Grochowski16a23a62014-11-13 15:33:38 +010037 : rwlock_(rwlock), writer_(writer), started_(false), gotLock_(false), signaled_(false) {}
Roger Meier3fc48192011-12-11 21:05:35 +000038
39public:
Konrad Grochowski16a23a62014-11-13 15:33:38 +010040 virtual void run() {
Roger Meier3fc48192011-12-11 21:05:35 +000041 started_ = true;
42 if (writer_) {
43 rwlock_->acquireWrite();
44 } else {
45 rwlock_->acquireRead();
46 }
47 gotLock_ = true;
48 while (!signaled_) {
49 usleep(5000);
50 }
51 rwlock_->release();
52 }
53
54 bool started() const { return started_; }
55 bool gotLock() const { return gotLock_; }
56 void signal() { signaled_ = true; }
57
58protected:
James E. King, III82ae9572017-08-05 12:23:54 -040059 shared_ptr<ReadWriteMutex> rwlock_;
Roger Meier3fc48192011-12-11 21:05:35 +000060 bool writer_;
61 volatile bool started_;
62 volatile bool gotLock_;
63 volatile bool signaled_;
64};
65
Konrad Grochowski16a23a62014-11-13 15:33:38 +010066class Reader : public Locker {
Roger Meier3fc48192011-12-11 21:05:35 +000067public:
James E. King, III82ae9572017-08-05 12:23:54 -040068 Reader(shared_ptr<ReadWriteMutex> rwlock) : Locker(rwlock, false) {}
Roger Meier3fc48192011-12-11 21:05:35 +000069};
70
Konrad Grochowski16a23a62014-11-13 15:33:38 +010071class Writer : public Locker {
Roger Meier3fc48192011-12-11 21:05:35 +000072public:
James E. King, III82ae9572017-08-05 12:23:54 -040073 Writer(shared_ptr<ReadWriteMutex> rwlock) : Locker(rwlock, true) {}
Roger Meier3fc48192011-12-11 21:05:35 +000074};
75
Konrad Grochowski16a23a62014-11-13 15:33:38 +010076void test_starve(PosixThreadFactory::POLICY policy) {
Roger Meier3fc48192011-12-11 21:05:35 +000077 // the man pages for pthread_wrlock_rdlock suggest that any OS guarantee about
78 // writer starvation may be influenced by the scheduling policy, so let's try
79 // all 3 policies to see if any of them work.
80 PosixThreadFactory factory(policy);
81 factory.setDetached(false);
82
James E. King, III82ae9572017-08-05 12:23:54 -040083 shared_ptr<ReadWriteMutex> rwlock(new NoStarveReadWriteMutex());
Roger Meier3fc48192011-12-11 21:05:35 +000084
James E. King, III82ae9572017-08-05 12:23:54 -040085 shared_ptr<Reader> reader1(new Reader(rwlock));
86 shared_ptr<Reader> reader2(new Reader(rwlock));
87 shared_ptr<Writer> writer(new Writer(rwlock));
Roger Meier3fc48192011-12-11 21:05:35 +000088
James E. King, III82ae9572017-08-05 12:23:54 -040089 shared_ptr<Thread> treader1 = factory.newThread(reader1);
90 shared_ptr<Thread> treader2 = factory.newThread(reader2);
91 shared_ptr<Thread> twriter = factory.newThread(writer);
Roger Meier3fc48192011-12-11 21:05:35 +000092
93 // launch a reader and make sure he has the lock
94 treader1->start();
95 while (!reader1->gotLock()) {
96 usleep(2000);
97 }
98
99 // launch a writer and make sure he's blocked on the lock
100 twriter->start();
101 while (!writer->started()) {
102 usleep(2000);
103 }
104 // tricky part... we can never be 100% sure that the writer is actually
105 // blocked on the lock, but we can pretty reasonably sure because we know
106 // he just executed the line immediately before getting the lock, and
107 // we'll wait a full second for him to get on it.
108 sleep(1);
109
110 // launch a second reader... if the RWMutex guarantees that writers won't
111 // starve, this reader should not be able to acquire the lock until the writer
112 // has acquired and released it.
113 treader2->start();
114 while (!reader2->started()) {
115 usleep(2000);
116 }
117 // again... can't be 100% sure the reader is waiting on (or has) the lock
118 // but we can be close.
119 sleep(1);
120
121 // tell reader 1 to let go of the lock
122 reader1->signal();
123
124 // wait for someone to get the lock
125 while (!reader2->gotLock() && !writer->gotLock()) {
126 usleep(2000);
127 }
128
129 // the test succeeded if the WRITER got the lock.
130 bool success = writer->gotLock();
131
132 // tell everyone we're done and wait for them to finish
133 reader2->signal();
134 writer->signal();
135 treader1->join();
136 treader2->join();
137 twriter->join();
138
139 // make sure it worked.
140 BOOST_CHECK_MESSAGE(success, "writer is starving");
141}
142
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100143BOOST_AUTO_TEST_SUITE(RWMutexStarveTest)
Roger Meier3fc48192011-12-11 21:05:35 +0000144
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100145BOOST_AUTO_TEST_CASE(test_starve_other) {
Roger Meier3fc48192011-12-11 21:05:35 +0000146 test_starve(PosixThreadFactory::OTHER);
147}
148
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100149BOOST_AUTO_TEST_CASE(test_starve_rr) {
Roger Meier3fc48192011-12-11 21:05:35 +0000150 test_starve(PosixThreadFactory::ROUND_ROBIN);
151}
152
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100153BOOST_AUTO_TEST_CASE(test_starve_fifo) {
Roger Meier3fc48192011-12-11 21:05:35 +0000154 test_starve(PosixThreadFactory::FIFO);
155}
156
157BOOST_AUTO_TEST_SUITE_END()