blob: ba9850286cb0c003126c8915a1bfa5cf58642dc8 [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>
James E. King, III7d211b82017-09-06 10:12:02 -070024#include <thrift/concurrency/Mutex.h>
Roger Meier49ff8b12012-04-13 09:12:31 +000025#include <thrift/concurrency/Util.h>
Marc Slemko8a40a762006-07-19 17:46:50 +000026
27#include <assert.h>
28#include <iostream>
James E. King, III7d211b82017-09-06 10:12:02 -070029#include <vector>
Marc Slemko8a40a762006-07-19 17:46:50 +000030
Konrad Grochowski16a23a62014-11-13 15:33:38 +010031namespace apache {
32namespace thrift {
33namespace concurrency {
34namespace test {
Marc Slemko8a40a762006-07-19 17:46:50 +000035
cyy316723a2019-01-05 16:35:14 +080036using std::shared_ptr;
T Jake Lucianib5e62212009-01-31 22:36:20 +000037using namespace apache::thrift::concurrency;
Marc Slemko8a40a762006-07-19 17:46:50 +000038
Mark Sleef5f2be42006-09-05 21:05:31 +000039/**
Marc Slemko3a3b53b2007-05-22 23:59:54 +000040 * ThreadManagerTests class
Mark Sleef5f2be42006-09-05 21:05:31 +000041 *
Mark Sleef5f2be42006-09-05 21:05:31 +000042 * @version $Id:$
43 */
Marc Slemko8a40a762006-07-19 17:46:50 +000044class ThreadFactoryTests {
45
Marc Slemko6f038a72006-08-03 18:58:09 +000046public:
Mark Sleef5f2be42006-09-05 21:05:31 +000047 /**
48 * Reap N threads
49 */
Konrad Grochowski16a23a62014-11-13 15:33:38 +010050 class ReapNTask : public Runnable {
Marc Slemko3a3b53b2007-05-22 23:59:54 +000051
Konrad Grochowski16a23a62014-11-13 15:33:38 +010052 public:
53 ReapNTask(Monitor& monitor, int& activeCount) : _monitor(monitor), _count(activeCount) {}
Marc Slemko3a3b53b2007-05-22 23:59:54 +000054
Marc Slemko8a40a762006-07-19 17:46:50 +000055 void run() {
Mark Sleef5f2be42006-09-05 21:05:31 +000056 Synchronized s(_monitor);
James E. King, III0ad20bd2017-09-30 15:44:16 -070057
58 if (--_count == 0) {
Mark Sleef5f2be42006-09-05 21:05:31 +000059 _monitor.notify();
Marc Slemko8a40a762006-07-19 17:46:50 +000060 }
61 }
62
63 Monitor& _monitor;
Marc Slemko8a40a762006-07-19 17:46:50 +000064 int& _count;
65 };
66
Konrad Grochowski16a23a62014-11-13 15:33:38 +010067 bool reapNThreads(int loop = 1, int count = 10) {
Marc Slemko8a40a762006-07-19 17:46:50 +000068
Konrad Grochowski16a23a62014-11-13 15:33:38 +010069 PlatformThreadFactory threadFactory = PlatformThreadFactory();
James E. King, III36200902016-10-05 14:47:18 -040070 shared_ptr<Monitor> monitor(new Monitor);
Marc Slemko8a40a762006-07-19 17:46:50 +000071
Konrad Grochowski16a23a62014-11-13 15:33:38 +010072 for (int lix = 0; lix < loop; lix++) {
Marc Slemko8a40a762006-07-19 17:46:50 +000073
James E. King, III0ad20bd2017-09-30 15:44:16 -070074 int activeCount = 0;
Marc Slemko8a40a762006-07-19 17:46:50 +000075
James E. King, III7d211b82017-09-06 10:12:02 -070076 std::vector<shared_ptr<Thread> > threads;
Marc Slemko67606e52007-06-04 21:01:19 +000077 int tix;
Marc Slemko8a40a762006-07-19 17:46:50 +000078
Marc Slemko67606e52007-06-04 21:01:19 +000079 for (tix = 0; tix < count; tix++) {
80 try {
James E. King, III0ad20bd2017-09-30 15:44:16 -070081 ++activeCount;
James E. King, III7d211b82017-09-06 10:12:02 -070082 threads.push_back(
James E. King, III0ad20bd2017-09-30 15:44:16 -070083 threadFactory.newThread(shared_ptr<Runnable>(new ReapNTask(*monitor, activeCount))));
Konrad Grochowski16a23a62014-11-13 15:33:38 +010084 } catch (SystemResourceException& e) {
85 std::cout << "\t\t\tfailed to create " << lix* count + tix << " thread " << e.what()
86 << std::endl;
Marc Slemko67606e52007-06-04 21:01:19 +000087 throw e;
88 }
Marc Slemko8a40a762006-07-19 17:46:50 +000089 }
Marc Slemkoa6479032007-06-05 22:20:14 +000090
Marc Slemko67606e52007-06-04 21:01:19 +000091 tix = 0;
James E. King, III7d211b82017-09-06 10:12:02 -070092 for (std::vector<shared_ptr<Thread> >::const_iterator thread = threads.begin();
Konrad Grochowski16a23a62014-11-13 15:33:38 +010093 thread != threads.end();
94 tix++, ++thread) {
Marc Slemko8a40a762006-07-19 17:46:50 +000095
Marc Slemko67606e52007-06-04 21:01:19 +000096 try {
97 (*thread)->start();
Konrad Grochowski16a23a62014-11-13 15:33:38 +010098 } catch (SystemResourceException& e) {
99 std::cout << "\t\t\tfailed to start " << lix* count + tix << " thread " << e.what()
100 << std::endl;
Marc Slemko67606e52007-06-04 21:01:19 +0000101 throw e;
102 }
103 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000104
Marc Slemko67606e52007-06-04 21:01:19 +0000105 {
106 Synchronized s(*monitor);
James E. King, III0ad20bd2017-09-30 15:44:16 -0700107 while (activeCount > 0) {
Marc Slemko67606e52007-06-04 21:01:19 +0000108 monitor->wait(1000);
109 }
110 }
James E. King, III7d211b82017-09-06 10:12:02 -0700111
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100112 std::cout << "\t\t\treaped " << lix* count << " threads" << std::endl;
Marc Slemko8a40a762006-07-19 17:46:50 +0000113 }
114
115 std::cout << "\t\t\tSuccess!" << std::endl;
Marc Slemko8a40a762006-07-19 17:46:50 +0000116 return true;
117 }
118
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100119 class SynchStartTask : public Runnable {
Marc Slemko8a40a762006-07-19 17:46:50 +0000120
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100121 public:
122 enum STATE { UNINITIALIZED, STARTING, STARTED, STOPPING, STOPPED };
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000123
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100124 SynchStartTask(Monitor& monitor, volatile STATE& state) : _monitor(monitor), _state(state) {}
Marc Slemko8a40a762006-07-19 17:46:50 +0000125
126 void run() {
Mark Sleef5f2be42006-09-05 21:05:31 +0000127 {
128 Synchronized s(_monitor);
David Reiss96d23882007-07-26 21:10:32 +0000129 if (_state == SynchStartTask::STARTING) {
130 _state = SynchStartTask::STARTED;
131 _monitor.notify();
132 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000133 }
134
Mark Sleef5f2be42006-09-05 21:05:31 +0000135 {
136 Synchronized s(_monitor);
137 while (_state == SynchStartTask::STARTED) {
David Reiss96d23882007-07-26 21:10:32 +0000138 _monitor.wait();
139 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000140
David Reiss96d23882007-07-26 21:10:32 +0000141 if (_state == SynchStartTask::STOPPING) {
Mark Sleef5f2be42006-09-05 21:05:31 +0000142 _state = SynchStartTask::STOPPED;
143 _monitor.notifyAll();
David Reiss96d23882007-07-26 21:10:32 +0000144 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000145 }
146 }
147
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100148 private:
Marc Slemko8a40a762006-07-19 17:46:50 +0000149 Monitor& _monitor;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100150 volatile STATE& _state;
Marc Slemko8a40a762006-07-19 17:46:50 +0000151 };
152
153 bool synchStartTest() {
154
155 Monitor monitor;
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000156
Marc Slemko8a40a762006-07-19 17:46:50 +0000157 SynchStartTask::STATE state = SynchStartTask::UNINITIALIZED;
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000158
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100159 shared_ptr<SynchStartTask> task
160 = shared_ptr<SynchStartTask>(new SynchStartTask(monitor, state));
Marc Slemko8a40a762006-07-19 17:46:50 +0000161
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100162 PlatformThreadFactory threadFactory = PlatformThreadFactory();
Marc Slemko8a40a762006-07-19 17:46:50 +0000163
Marc Slemko6f038a72006-08-03 18:58:09 +0000164 shared_ptr<Thread> thread = threadFactory.newThread(task);
Marc Slemko8a40a762006-07-19 17:46:50 +0000165
Mark Sleef5f2be42006-09-05 21:05:31 +0000166 if (state == SynchStartTask::UNINITIALIZED) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000167
168 state = SynchStartTask::STARTING;
169
170 thread->start();
171 }
172
Mark Sleef5f2be42006-09-05 21:05:31 +0000173 {
174 Synchronized s(monitor);
175 while (state == SynchStartTask::STARTING) {
David Reiss96d23882007-07-26 21:10:32 +0000176 monitor.wait();
Marc Slemko8a40a762006-07-19 17:46:50 +0000177 }
178 }
179
180 assert(state != SynchStartTask::STARTING);
181
Mark Sleef5f2be42006-09-05 21:05:31 +0000182 {
183 Synchronized s(monitor);
Marc Slemko8a40a762006-07-19 17:46:50 +0000184
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000185 try {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100186 monitor.wait(100);
ben-craigfae08e72015-07-15 11:34:47 -0500187 } catch (TimedOutException&) {
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000188 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000189
Mark Sleef5f2be42006-09-05 21:05:31 +0000190 if (state == SynchStartTask::STARTED) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000191
David Reiss96d23882007-07-26 21:10:32 +0000192 state = SynchStartTask::STOPPING;
Marc Slemko8a40a762006-07-19 17:46:50 +0000193
David Reiss96d23882007-07-26 21:10:32 +0000194 monitor.notify();
Marc Slemko8a40a762006-07-19 17:46:50 +0000195 }
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000196
Mark Sleef5f2be42006-09-05 21:05:31 +0000197 while (state == SynchStartTask::STOPPING) {
David Reiss96d23882007-07-26 21:10:32 +0000198 monitor.wait();
Marc Slemko8a40a762006-07-19 17:46:50 +0000199 }
200 }
201
202 assert(state == SynchStartTask::STOPPED);
203
Marc Slemkoc7782972006-07-25 02:26:35 +0000204 bool success = true;
205
206 std::cout << "\t\t\t" << (success ? "Success" : "Failure") << "!" << std::endl;
207
Marc Slemko8a40a762006-07-19 17:46:50 +0000208 return true;
209 }
210
James E. King, IIIdf899132016-11-12 15:16:30 -0500211 /**
212 * The only guarantee a monitor timeout can give you is that
213 * it will take "at least" as long as the timeout, no less.
214 * There is absolutely no guarantee around regaining execution
215 * near the timeout. On a busy system (like inside a third party
216 * CI environment) it could take quite a bit longer than the
217 * requested timeout, and that's ok.
218 */
Marc Slemkoc7782972006-07-25 02:26:35 +0000219
James E. King, IIIdf899132016-11-12 15:16:30 -0500220 bool monitorTimeoutTest(int64_t count = 1000, int64_t timeout = 2) {
Marc Slemkoc7782972006-07-25 02:26:35 +0000221
222 Monitor monitor;
223
Mark Slee9b82d272007-05-23 05:16:07 +0000224 int64_t startTime = Util::currentTime();
Marc Slemkoc7782972006-07-25 02:26:35 +0000225
James E. King, IIIdf899132016-11-12 15:16:30 -0500226 for (int64_t ix = 0; ix < count; ix++) {
Mark Sleef5f2be42006-09-05 21:05:31 +0000227 {
228 Synchronized s(monitor);
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000229 try {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100230 monitor.wait(timeout);
ben-craigfae08e72015-07-15 11:34:47 -0500231 } catch (TimedOutException&) {
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000232 }
Marc Slemkoc7782972006-07-25 02:26:35 +0000233 }
234 }
235
Mark Slee9b82d272007-05-23 05:16:07 +0000236 int64_t endTime = Util::currentTime();
Marc Slemkoc7782972006-07-25 02:26:35 +0000237
James E. King, IIIdf899132016-11-12 15:16:30 -0500238 bool success = (endTime - startTime) >= (count * timeout);
Marc Slemkoc7782972006-07-25 02:26:35 +0000239
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100240 std::cout << "\t\t\t" << (success ? "Success" : "Failure")
James E. King, IIIdf899132016-11-12 15:16:30 -0500241 << ": minimum required time to elapse " << count * timeout
242 << "ms; actual elapsed time " << endTime - startTime << "ms"
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100243 << std::endl;
Marc Slemkoc7782972006-07-25 02:26:35 +0000244
245 return success;
246 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000247
Marc Slemkoa6479032007-06-05 22:20:14 +0000248 class FloodTask : public Runnable {
249 public:
James E. King, III7d211b82017-09-06 10:12:02 -0700250 FloodTask(const size_t id, Monitor& mon) : _id(id), _mon(mon) {}
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100251 ~FloodTask() {
James E. King, IIIdf899132016-11-12 15:16:30 -0500252 if (_id % 10000 == 0) {
James E. King, III7d211b82017-09-06 10:12:02 -0700253 Synchronized sync(_mon);
Marc Slemkoa6479032007-06-05 22:20:14 +0000254 std::cout << "\t\tthread " << _id << " done" << std::endl;
255 }
256 }
257
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100258 void run() {
James E. King, IIIdf899132016-11-12 15:16:30 -0500259 if (_id % 10000 == 0) {
James E. King, III7d211b82017-09-06 10:12:02 -0700260 Synchronized sync(_mon);
Marc Slemkoa6479032007-06-05 22:20:14 +0000261 std::cout << "\t\tthread " << _id << " started" << std::endl;
262 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000263 }
264 const size_t _id;
James E. King, III7d211b82017-09-06 10:12:02 -0700265 Monitor& _mon;
Marc Slemkoa6479032007-06-05 22:20:14 +0000266 };
267
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100268 void foo(PlatformThreadFactory* tf) { (void)tf; }
Marc Slemkoa6479032007-06-05 22:20:14 +0000269
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100270 bool floodNTest(size_t loop = 1, size_t count = 100000) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000271
272 bool success = false;
James E. King, III7d211b82017-09-06 10:12:02 -0700273 Monitor mon;
274
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100275 for (size_t lix = 0; lix < loop; lix++) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000276
Roger Meier3faaedf2011-10-02 10:51:45 +0000277 PlatformThreadFactory threadFactory = PlatformThreadFactory();
Marc Slemkoa6479032007-06-05 22:20:14 +0000278 threadFactory.setDetached(true);
279
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100280 for (size_t tix = 0; tix < count; tix++) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000281
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100282 try {
Marc Slemkoa6479032007-06-05 22:20:14 +0000283
James E. King, III7d211b82017-09-06 10:12:02 -0700284 shared_ptr<FloodTask> task(new FloodTask(lix * count + tix, mon));
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100285 shared_ptr<Thread> thread = threadFactory.newThread(task);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100286 thread->start();
Marc Slemkoa6479032007-06-05 22:20:14 +0000287
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100288 } catch (TException& e) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000289
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100290 std::cout << "\t\t\tfailed to start " << lix* count + tix << " thread " << e.what()
291 << std::endl;
Marc Slemkoa6479032007-06-05 22:20:14 +0000292
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100293 return success;
Marc Slemkoa6479032007-06-05 22:20:14 +0000294 }
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100295 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000296
James E. King, III7d211b82017-09-06 10:12:02 -0700297 Synchronized sync(mon);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100298 std::cout << "\t\t\tflooded " << (lix + 1) * count << " threads" << std::endl;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100299 success = true;
Marc Slemkoa6479032007-06-05 22:20:14 +0000300 }
301
302 return success;
303 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000304};
Marc Slemko8a40a762006-07-19 17:46:50 +0000305
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100306}
307}
308}
309} // apache::thrift::concurrency::test