blob: 4fc688cc578152aae1e72b269424664085efde5d [file] [log] [blame]
David Reissea2cba82009-03-30 21:35:00 +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 */
Mark Slee9f0c6512007-02-28 23:58:26 +000019
Roger Meierba406d32013-07-15 22:41:34 +020020#include <thrift/thrift-config.h>
Roger Meier49ff8b12012-04-13 09:12:31 +000021#include <thrift/concurrency/Thread.h>
22#include <thrift/concurrency/PlatformThreadFactory.h>
23#include <thrift/concurrency/Monitor.h>
24#include <thrift/concurrency/Util.h>
Marc Slemko8a40a762006-07-19 17:46:50 +000025
26#include <assert.h>
27#include <iostream>
28#include <set>
29
Konrad Grochowski16a23a62014-11-13 15:33:38 +010030namespace apache {
31namespace thrift {
32namespace concurrency {
33namespace test {
Marc Slemko8a40a762006-07-19 17:46:50 +000034
Mark Slee5ea15f92007-03-05 22:55:59 +000035using boost::shared_ptr;
T Jake Lucianib5e62212009-01-31 22:36:20 +000036using namespace apache::thrift::concurrency;
Marc Slemko8a40a762006-07-19 17:46:50 +000037
Mark Sleef5f2be42006-09-05 21:05:31 +000038/**
Marc Slemko3a3b53b2007-05-22 23:59:54 +000039 * ThreadManagerTests class
Mark Sleef5f2be42006-09-05 21:05:31 +000040 *
Mark Sleef5f2be42006-09-05 21:05:31 +000041 * @version $Id:$
42 */
Marc Slemko8a40a762006-07-19 17:46:50 +000043class ThreadFactoryTests {
44
Marc Slemko6f038a72006-08-03 18:58:09 +000045public:
Mark Sleef5f2be42006-09-05 21:05:31 +000046 /**
47 * Reap N threads
48 */
Konrad Grochowski16a23a62014-11-13 15:33:38 +010049 class ReapNTask : public Runnable {
Marc Slemko3a3b53b2007-05-22 23:59:54 +000050
Konrad Grochowski16a23a62014-11-13 15:33:38 +010051 public:
52 ReapNTask(Monitor& monitor, int& activeCount) : _monitor(monitor), _count(activeCount) {}
Marc Slemko3a3b53b2007-05-22 23:59:54 +000053
Marc Slemko8a40a762006-07-19 17:46:50 +000054 void run() {
Mark Sleef5f2be42006-09-05 21:05:31 +000055 Synchronized s(_monitor);
Marc Slemko3a3b53b2007-05-22 23:59:54 +000056
Mark Sleef5f2be42006-09-05 21:05:31 +000057 _count--;
Marc Slemko3a3b53b2007-05-22 23:59:54 +000058
Konrad Grochowski16a23a62014-11-13 15:33:38 +010059 // std::cout << "\t\t\tthread count: " << _count << std::endl;
Marc Slemko3a3b53b2007-05-22 23:59:54 +000060
Mark Sleef5f2be42006-09-05 21:05:31 +000061 if (_count == 0) {
62 _monitor.notify();
Marc Slemko8a40a762006-07-19 17:46:50 +000063 }
64 }
65
66 Monitor& _monitor;
67
68 int& _count;
69 };
70
Konrad Grochowski16a23a62014-11-13 15:33:38 +010071 bool reapNThreads(int loop = 1, int count = 10) {
Marc Slemko8a40a762006-07-19 17:46:50 +000072
Konrad Grochowski16a23a62014-11-13 15:33:38 +010073 PlatformThreadFactory threadFactory = PlatformThreadFactory();
Marc Slemko8a40a762006-07-19 17:46:50 +000074
James E. King, III36200902016-10-05 14:47:18 -040075 shared_ptr<Monitor> monitor(new Monitor);
Marc Slemko8a40a762006-07-19 17:46:50 +000076
Konrad Grochowski16a23a62014-11-13 15:33:38 +010077 for (int lix = 0; lix < loop; lix++) {
Marc Slemko8a40a762006-07-19 17:46:50 +000078
Konrad Grochowski16a23a62014-11-13 15:33:38 +010079 int* activeCount = new int(count);
Marc Slemko8a40a762006-07-19 17:46:50 +000080
Marc Slemko67606e52007-06-04 21:01:19 +000081 std::set<shared_ptr<Thread> > threads;
Marc Slemko8a40a762006-07-19 17:46:50 +000082
Marc Slemko67606e52007-06-04 21:01:19 +000083 int tix;
Marc Slemko8a40a762006-07-19 17:46:50 +000084
Marc Slemko67606e52007-06-04 21:01:19 +000085 for (tix = 0; tix < count; tix++) {
86 try {
Konrad Grochowski16a23a62014-11-13 15:33:38 +010087 threads.insert(
88 threadFactory.newThread(shared_ptr<Runnable>(new ReapNTask(*monitor, *activeCount))));
89 } catch (SystemResourceException& e) {
90 std::cout << "\t\t\tfailed to create " << lix* count + tix << " thread " << e.what()
91 << std::endl;
Marc Slemko67606e52007-06-04 21:01:19 +000092 throw e;
93 }
Marc Slemko8a40a762006-07-19 17:46:50 +000094 }
Marc Slemkoa6479032007-06-05 22:20:14 +000095
Marc Slemko67606e52007-06-04 21:01:19 +000096 tix = 0;
Konrad Grochowski16a23a62014-11-13 15:33:38 +010097 for (std::set<shared_ptr<Thread> >::const_iterator thread = threads.begin();
98 thread != threads.end();
99 tix++, ++thread) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000100
Marc Slemko67606e52007-06-04 21:01:19 +0000101 try {
102 (*thread)->start();
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100103 } catch (SystemResourceException& e) {
104 std::cout << "\t\t\tfailed to start " << lix* count + tix << " thread " << e.what()
105 << std::endl;
Marc Slemko67606e52007-06-04 21:01:19 +0000106 throw e;
107 }
108 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000109
Marc Slemko67606e52007-06-04 21:01:19 +0000110 {
111 Synchronized s(*monitor);
112 while (*activeCount > 0) {
113 monitor->wait(1000);
114 }
115 }
Roger Meier3075ffc2011-08-04 22:36:07 +0000116 delete activeCount;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100117 std::cout << "\t\t\treaped " << lix* count << " threads" << std::endl;
Marc Slemko8a40a762006-07-19 17:46:50 +0000118 }
119
120 std::cout << "\t\t\tSuccess!" << std::endl;
121
122 return true;
123 }
124
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100125 class SynchStartTask : public Runnable {
Marc Slemko8a40a762006-07-19 17:46:50 +0000126
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100127 public:
128 enum STATE { UNINITIALIZED, STARTING, STARTED, STOPPING, STOPPED };
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000129
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100130 SynchStartTask(Monitor& monitor, volatile STATE& state) : _monitor(monitor), _state(state) {}
Marc Slemko8a40a762006-07-19 17:46:50 +0000131
132 void run() {
Mark Sleef5f2be42006-09-05 21:05:31 +0000133 {
134 Synchronized s(_monitor);
David Reiss96d23882007-07-26 21:10:32 +0000135 if (_state == SynchStartTask::STARTING) {
136 _state = SynchStartTask::STARTED;
137 _monitor.notify();
138 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000139 }
140
Mark Sleef5f2be42006-09-05 21:05:31 +0000141 {
142 Synchronized s(_monitor);
143 while (_state == SynchStartTask::STARTED) {
David Reiss96d23882007-07-26 21:10:32 +0000144 _monitor.wait();
145 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000146
David Reiss96d23882007-07-26 21:10:32 +0000147 if (_state == SynchStartTask::STOPPING) {
Mark Sleef5f2be42006-09-05 21:05:31 +0000148 _state = SynchStartTask::STOPPED;
149 _monitor.notifyAll();
David Reiss96d23882007-07-26 21:10:32 +0000150 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000151 }
152 }
153
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100154 private:
Marc Slemko8a40a762006-07-19 17:46:50 +0000155 Monitor& _monitor;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100156 volatile STATE& _state;
Marc Slemko8a40a762006-07-19 17:46:50 +0000157 };
158
159 bool synchStartTest() {
160
161 Monitor monitor;
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000162
Marc Slemko8a40a762006-07-19 17:46:50 +0000163 SynchStartTask::STATE state = SynchStartTask::UNINITIALIZED;
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000164
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100165 shared_ptr<SynchStartTask> task
166 = shared_ptr<SynchStartTask>(new SynchStartTask(monitor, state));
Marc Slemko8a40a762006-07-19 17:46:50 +0000167
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100168 PlatformThreadFactory threadFactory = PlatformThreadFactory();
Marc Slemko8a40a762006-07-19 17:46:50 +0000169
Marc Slemko6f038a72006-08-03 18:58:09 +0000170 shared_ptr<Thread> thread = threadFactory.newThread(task);
Marc Slemko8a40a762006-07-19 17:46:50 +0000171
Mark Sleef5f2be42006-09-05 21:05:31 +0000172 if (state == SynchStartTask::UNINITIALIZED) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000173
174 state = SynchStartTask::STARTING;
175
176 thread->start();
177 }
178
Mark Sleef5f2be42006-09-05 21:05:31 +0000179 {
180 Synchronized s(monitor);
181 while (state == SynchStartTask::STARTING) {
David Reiss96d23882007-07-26 21:10:32 +0000182 monitor.wait();
Marc Slemko8a40a762006-07-19 17:46:50 +0000183 }
184 }
185
186 assert(state != SynchStartTask::STARTING);
187
Mark Sleef5f2be42006-09-05 21:05:31 +0000188 {
189 Synchronized s(monitor);
Marc Slemko8a40a762006-07-19 17:46:50 +0000190
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000191 try {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100192 monitor.wait(100);
ben-craigfae08e72015-07-15 11:34:47 -0500193 } catch (TimedOutException&) {
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000194 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000195
Mark Sleef5f2be42006-09-05 21:05:31 +0000196 if (state == SynchStartTask::STARTED) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000197
David Reiss96d23882007-07-26 21:10:32 +0000198 state = SynchStartTask::STOPPING;
Marc Slemko8a40a762006-07-19 17:46:50 +0000199
David Reiss96d23882007-07-26 21:10:32 +0000200 monitor.notify();
Marc Slemko8a40a762006-07-19 17:46:50 +0000201 }
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000202
Mark Sleef5f2be42006-09-05 21:05:31 +0000203 while (state == SynchStartTask::STOPPING) {
David Reiss96d23882007-07-26 21:10:32 +0000204 monitor.wait();
Marc Slemko8a40a762006-07-19 17:46:50 +0000205 }
206 }
207
208 assert(state == SynchStartTask::STOPPED);
209
Marc Slemkoc7782972006-07-25 02:26:35 +0000210 bool success = true;
211
212 std::cout << "\t\t\t" << (success ? "Success" : "Failure") << "!" << std::endl;
213
Marc Slemko8a40a762006-07-19 17:46:50 +0000214 return true;
215 }
216
James E. King, IIIdf899132016-11-12 15:16:30 -0500217 /**
218 * The only guarantee a monitor timeout can give you is that
219 * it will take "at least" as long as the timeout, no less.
220 * There is absolutely no guarantee around regaining execution
221 * near the timeout. On a busy system (like inside a third party
222 * CI environment) it could take quite a bit longer than the
223 * requested timeout, and that's ok.
224 */
Marc Slemkoc7782972006-07-25 02:26:35 +0000225
James E. King, IIIdf899132016-11-12 15:16:30 -0500226 bool monitorTimeoutTest(int64_t count = 1000, int64_t timeout = 2) {
Marc Slemkoc7782972006-07-25 02:26:35 +0000227
228 Monitor monitor;
229
Mark Slee9b82d272007-05-23 05:16:07 +0000230 int64_t startTime = Util::currentTime();
Marc Slemkoc7782972006-07-25 02:26:35 +0000231
James E. King, IIIdf899132016-11-12 15:16:30 -0500232 for (int64_t ix = 0; ix < count; ix++) {
Mark Sleef5f2be42006-09-05 21:05:31 +0000233 {
234 Synchronized s(monitor);
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000235 try {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100236 monitor.wait(timeout);
ben-craigfae08e72015-07-15 11:34:47 -0500237 } catch (TimedOutException&) {
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000238 }
Marc Slemkoc7782972006-07-25 02:26:35 +0000239 }
240 }
241
Mark Slee9b82d272007-05-23 05:16:07 +0000242 int64_t endTime = Util::currentTime();
Marc Slemkoc7782972006-07-25 02:26:35 +0000243
James E. King, IIIdf899132016-11-12 15:16:30 -0500244 bool success = (endTime - startTime) >= (count * timeout);
Marc Slemkoc7782972006-07-25 02:26:35 +0000245
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100246 std::cout << "\t\t\t" << (success ? "Success" : "Failure")
James E. King, IIIdf899132016-11-12 15:16:30 -0500247 << ": minimum required time to elapse " << count * timeout
248 << "ms; actual elapsed time " << endTime - startTime << "ms"
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100249 << std::endl;
Marc Slemkoc7782972006-07-25 02:26:35 +0000250
251 return success;
252 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000253
Marc Slemkoa6479032007-06-05 22:20:14 +0000254 class FloodTask : public Runnable {
255 public:
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100256 FloodTask(const size_t id) : _id(id) {}
257 ~FloodTask() {
James E. King, IIIdf899132016-11-12 15:16:30 -0500258 if (_id % 10000 == 0) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000259 std::cout << "\t\tthread " << _id << " done" << std::endl;
260 }
261 }
262
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100263 void run() {
James E. King, IIIdf899132016-11-12 15:16:30 -0500264 if (_id % 10000 == 0) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000265 std::cout << "\t\tthread " << _id << " started" << std::endl;
266 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000267 }
268 const size_t _id;
269 };
270
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100271 void foo(PlatformThreadFactory* tf) { (void)tf; }
Marc Slemkoa6479032007-06-05 22:20:14 +0000272
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100273 bool floodNTest(size_t loop = 1, size_t count = 100000) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000274
275 bool success = false;
276
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100277 for (size_t lix = 0; lix < loop; lix++) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000278
Roger Meier3faaedf2011-10-02 10:51:45 +0000279 PlatformThreadFactory threadFactory = PlatformThreadFactory();
Marc Slemkoa6479032007-06-05 22:20:14 +0000280 threadFactory.setDetached(true);
281
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100282 for (size_t tix = 0; tix < count; tix++) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000283
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100284 try {
Marc Slemkoa6479032007-06-05 22:20:14 +0000285
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100286 shared_ptr<FloodTask> task(new FloodTask(lix * count + tix));
Marc Slemkoa6479032007-06-05 22:20:14 +0000287
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100288 shared_ptr<Thread> thread = threadFactory.newThread(task);
Marc Slemkoa6479032007-06-05 22:20:14 +0000289
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100290 thread->start();
Marc Slemkoa6479032007-06-05 22:20:14 +0000291
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100292 } catch (TException& e) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000293
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100294 std::cout << "\t\t\tfailed to start " << lix* count + tix << " thread " << e.what()
295 << std::endl;
Marc Slemkoa6479032007-06-05 22:20:14 +0000296
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100297 return success;
Marc Slemkoa6479032007-06-05 22:20:14 +0000298 }
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100299 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000300
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100301 std::cout << "\t\t\tflooded " << (lix + 1) * count << " threads" << std::endl;
Marc Slemkoa6479032007-06-05 22:20:14 +0000302
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100303 success = true;
Marc Slemkoa6479032007-06-05 22:20:14 +0000304 }
305
306 return success;
307 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000308};
Marc Slemko8a40a762006-07-19 17:46:50 +0000309
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100310}
311}
312}
313} // apache::thrift::concurrency::test