blob: 63d780fa1c0685b27739019a9c649e91c7bfb69f [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
22#include <boost/shared_ptr.hpp>
23#include <boost/test/unit_test.hpp>
24
Roger Meier49ff8b12012-04-13 09:12:31 +000025#include "thrift/concurrency/Mutex.h"
26#include "thrift/concurrency/PosixThreadFactory.h"
Roger Meier3fc48192011-12-11 21:05:35 +000027
28using boost::shared_ptr;
29using boost::unit_test::test_suite;
30using boost::unit_test::framework::master_test_suite;
31
32using namespace apache::thrift::concurrency;
33using namespace std;
34
Konrad Grochowski16a23a62014-11-13 15:33:38 +010035class Locker : public Runnable {
Roger Meier3fc48192011-12-11 21:05:35 +000036protected:
Konrad Grochowski16a23a62014-11-13 15:33:38 +010037 Locker(boost::shared_ptr<ReadWriteMutex> rwlock, bool writer)
38 : rwlock_(rwlock), writer_(writer), started_(false), gotLock_(false), signaled_(false) {}
Roger Meier3fc48192011-12-11 21:05:35 +000039
40public:
Konrad Grochowski16a23a62014-11-13 15:33:38 +010041 virtual void run() {
Roger Meier3fc48192011-12-11 21:05:35 +000042 started_ = true;
43 if (writer_) {
44 rwlock_->acquireWrite();
45 } else {
46 rwlock_->acquireRead();
47 }
48 gotLock_ = true;
49 while (!signaled_) {
50 usleep(5000);
51 }
52 rwlock_->release();
53 }
54
55 bool started() const { return started_; }
56 bool gotLock() const { return gotLock_; }
57 void signal() { signaled_ = true; }
58
59protected:
Roger Meier611f90c2011-12-11 22:08:51 +000060 boost::shared_ptr<ReadWriteMutex> rwlock_;
Roger Meier3fc48192011-12-11 21:05:35 +000061 bool writer_;
62 volatile bool started_;
63 volatile bool gotLock_;
64 volatile bool signaled_;
65};
66
Konrad Grochowski16a23a62014-11-13 15:33:38 +010067class Reader : public Locker {
Roger Meier3fc48192011-12-11 21:05:35 +000068public:
Konrad Grochowski16a23a62014-11-13 15:33:38 +010069 Reader(boost::shared_ptr<ReadWriteMutex> rwlock) : Locker(rwlock, false) {}
Roger Meier3fc48192011-12-11 21:05:35 +000070};
71
Konrad Grochowski16a23a62014-11-13 15:33:38 +010072class Writer : public Locker {
Roger Meier3fc48192011-12-11 21:05:35 +000073public:
Konrad Grochowski16a23a62014-11-13 15:33:38 +010074 Writer(boost::shared_ptr<ReadWriteMutex> rwlock) : Locker(rwlock, true) {}
Roger Meier3fc48192011-12-11 21:05:35 +000075};
76
Konrad Grochowski16a23a62014-11-13 15:33:38 +010077void test_starve(PosixThreadFactory::POLICY policy) {
Roger Meier3fc48192011-12-11 21:05:35 +000078 // the man pages for pthread_wrlock_rdlock suggest that any OS guarantee about
79 // writer starvation may be influenced by the scheduling policy, so let's try
80 // all 3 policies to see if any of them work.
81 PosixThreadFactory factory(policy);
82 factory.setDetached(false);
83
Roger Meier611f90c2011-12-11 22:08:51 +000084 boost::shared_ptr<ReadWriteMutex> rwlock(new NoStarveReadWriteMutex());
Roger Meier3fc48192011-12-11 21:05:35 +000085
Roger Meier611f90c2011-12-11 22:08:51 +000086 boost::shared_ptr<Reader> reader1(new Reader(rwlock));
87 boost::shared_ptr<Reader> reader2(new Reader(rwlock));
88 boost::shared_ptr<Writer> writer(new Writer(rwlock));
Roger Meier3fc48192011-12-11 21:05:35 +000089
Roger Meier611f90c2011-12-11 22:08:51 +000090 boost::shared_ptr<Thread> treader1 = factory.newThread(reader1);
91 boost::shared_ptr<Thread> treader2 = factory.newThread(reader2);
92 boost::shared_ptr<Thread> twriter = factory.newThread(writer);
Roger Meier3fc48192011-12-11 21:05:35 +000093
94 // launch a reader and make sure he has the lock
95 treader1->start();
96 while (!reader1->gotLock()) {
97 usleep(2000);
98 }
99
100 // launch a writer and make sure he's blocked on the lock
101 twriter->start();
102 while (!writer->started()) {
103 usleep(2000);
104 }
105 // tricky part... we can never be 100% sure that the writer is actually
106 // blocked on the lock, but we can pretty reasonably sure because we know
107 // he just executed the line immediately before getting the lock, and
108 // we'll wait a full second for him to get on it.
109 sleep(1);
110
111 // launch a second reader... if the RWMutex guarantees that writers won't
112 // starve, this reader should not be able to acquire the lock until the writer
113 // has acquired and released it.
114 treader2->start();
115 while (!reader2->started()) {
116 usleep(2000);
117 }
118 // again... can't be 100% sure the reader is waiting on (or has) the lock
119 // but we can be close.
120 sleep(1);
121
122 // tell reader 1 to let go of the lock
123 reader1->signal();
124
125 // wait for someone to get the lock
126 while (!reader2->gotLock() && !writer->gotLock()) {
127 usleep(2000);
128 }
129
130 // the test succeeded if the WRITER got the lock.
131 bool success = writer->gotLock();
132
133 // tell everyone we're done and wait for them to finish
134 reader2->signal();
135 writer->signal();
136 treader1->join();
137 treader2->join();
138 twriter->join();
139
140 // make sure it worked.
141 BOOST_CHECK_MESSAGE(success, "writer is starving");
142}
143
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100144BOOST_AUTO_TEST_SUITE(RWMutexStarveTest)
Roger Meier3fc48192011-12-11 21:05:35 +0000145
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100146BOOST_AUTO_TEST_CASE(test_starve_other) {
Roger Meier3fc48192011-12-11 21:05:35 +0000147 test_starve(PosixThreadFactory::OTHER);
148}
149
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100150BOOST_AUTO_TEST_CASE(test_starve_rr) {
Roger Meier3fc48192011-12-11 21:05:35 +0000151 test_starve(PosixThreadFactory::ROUND_ROBIN);
152}
153
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100154BOOST_AUTO_TEST_CASE(test_starve_fifo) {
Roger Meier3fc48192011-12-11 21:05:35 +0000155 test_starve(PosixThreadFactory::FIFO);
156}
157
158BOOST_AUTO_TEST_SUITE_END()