blob: 23e46e3de21953a022e1482df11858e4746f4598 [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>
cyyca8af9b2019-01-11 22:13:12 +080022#include <thrift/concurrency/ThreadFactory.h>
Roger Meier49ff8b12012-04-13 09:12:31 +000023#include <thrift/concurrency/Monitor.h>
James E. King, III7d211b82017-09-06 10:12:02 -070024#include <thrift/concurrency/Mutex.h>
Marc Slemko8a40a762006-07-19 17:46:50 +000025
26#include <assert.h>
27#include <iostream>
James E. King, III7d211b82017-09-06 10:12:02 -070028#include <vector>
Marc Slemko8a40a762006-07-19 17:46:50 +000029
Konrad Grochowski16a23a62014-11-13 15:33:38 +010030namespace apache {
31namespace thrift {
32namespace concurrency {
33namespace test {
Marc Slemko8a40a762006-07-19 17:46:50 +000034
cyy316723a2019-01-05 16:35:14 +080035using std::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
Sebastian Zenker042580f2019-01-29 15:48:12 +010054 void run() override {
Mark Sleef5f2be42006-09-05 21:05:31 +000055 Synchronized s(_monitor);
James E. King, III0ad20bd2017-09-30 15:44:16 -070056
57 if (--_count == 0) {
Mark Sleef5f2be42006-09-05 21:05:31 +000058 _monitor.notify();
Marc Slemko8a40a762006-07-19 17:46:50 +000059 }
60 }
61
62 Monitor& _monitor;
Marc Slemko8a40a762006-07-19 17:46:50 +000063 int& _count;
64 };
65
Konrad Grochowski16a23a62014-11-13 15:33:38 +010066 bool reapNThreads(int loop = 1, int count = 10) {
Marc Slemko8a40a762006-07-19 17:46:50 +000067
cyyca8af9b2019-01-11 22:13:12 +080068 ThreadFactory threadFactory = ThreadFactory();
James E. King, III36200902016-10-05 14:47:18 -040069 shared_ptr<Monitor> monitor(new Monitor);
Marc Slemko8a40a762006-07-19 17:46:50 +000070
Konrad Grochowski16a23a62014-11-13 15:33:38 +010071 for (int lix = 0; lix < loop; lix++) {
Marc Slemko8a40a762006-07-19 17:46:50 +000072
James E. King, III0ad20bd2017-09-30 15:44:16 -070073 int activeCount = 0;
Marc Slemko8a40a762006-07-19 17:46:50 +000074
James E. King, III7d211b82017-09-06 10:12:02 -070075 std::vector<shared_ptr<Thread> > threads;
Marc Slemko67606e52007-06-04 21:01:19 +000076 int tix;
Marc Slemko8a40a762006-07-19 17:46:50 +000077
Marc Slemko67606e52007-06-04 21:01:19 +000078 for (tix = 0; tix < count; tix++) {
79 try {
James E. King, III0ad20bd2017-09-30 15:44:16 -070080 ++activeCount;
James E. King, III7d211b82017-09-06 10:12:02 -070081 threads.push_back(
James E. King, III0ad20bd2017-09-30 15:44:16 -070082 threadFactory.newThread(shared_ptr<Runnable>(new ReapNTask(*monitor, activeCount))));
Konrad Grochowski16a23a62014-11-13 15:33:38 +010083 } catch (SystemResourceException& e) {
84 std::cout << "\t\t\tfailed to create " << lix* count + tix << " thread " << e.what()
85 << std::endl;
Gaurav Singh77c4afa2020-02-02 20:13:07 -050086 throw;
Marc Slemko67606e52007-06-04 21:01:19 +000087 }
Marc Slemko8a40a762006-07-19 17:46:50 +000088 }
Marc Slemkoa6479032007-06-05 22:20:14 +000089
Marc Slemko67606e52007-06-04 21:01:19 +000090 tix = 0;
James E. King, III7d211b82017-09-06 10:12:02 -070091 for (std::vector<shared_ptr<Thread> >::const_iterator thread = threads.begin();
Konrad Grochowski16a23a62014-11-13 15:33:38 +010092 thread != threads.end();
93 tix++, ++thread) {
Marc Slemko8a40a762006-07-19 17:46:50 +000094
Marc Slemko67606e52007-06-04 21:01:19 +000095 try {
96 (*thread)->start();
Konrad Grochowski16a23a62014-11-13 15:33:38 +010097 } catch (SystemResourceException& e) {
98 std::cout << "\t\t\tfailed to start " << lix* count + tix << " thread " << e.what()
99 << std::endl;
Gaurav Singh77c4afa2020-02-02 20:13:07 -0500100 throw;
Marc Slemko67606e52007-06-04 21:01:19 +0000101 }
102 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000103
Marc Slemko67606e52007-06-04 21:01:19 +0000104 {
105 Synchronized s(*monitor);
James E. King, III0ad20bd2017-09-30 15:44:16 -0700106 while (activeCount > 0) {
Marc Slemko67606e52007-06-04 21:01:19 +0000107 monitor->wait(1000);
108 }
109 }
James E. King, III7d211b82017-09-06 10:12:02 -0700110
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100111 std::cout << "\t\t\treaped " << lix* count << " threads" << std::endl;
Marc Slemko8a40a762006-07-19 17:46:50 +0000112 }
113
114 std::cout << "\t\t\tSuccess!" << std::endl;
Marc Slemko8a40a762006-07-19 17:46:50 +0000115 return true;
116 }
117
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100118 class SynchStartTask : public Runnable {
Marc Slemko8a40a762006-07-19 17:46:50 +0000119
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100120 public:
121 enum STATE { UNINITIALIZED, STARTING, STARTED, STOPPING, STOPPED };
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000122
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100123 SynchStartTask(Monitor& monitor, volatile STATE& state) : _monitor(monitor), _state(state) {}
Marc Slemko8a40a762006-07-19 17:46:50 +0000124
Sebastian Zenker042580f2019-01-29 15:48:12 +0100125 void run() override {
Mark Sleef5f2be42006-09-05 21:05:31 +0000126 {
127 Synchronized s(_monitor);
David Reiss96d23882007-07-26 21:10:32 +0000128 if (_state == SynchStartTask::STARTING) {
129 _state = SynchStartTask::STARTED;
130 _monitor.notify();
131 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000132 }
133
Mark Sleef5f2be42006-09-05 21:05:31 +0000134 {
135 Synchronized s(_monitor);
136 while (_state == SynchStartTask::STARTED) {
David Reiss96d23882007-07-26 21:10:32 +0000137 _monitor.wait();
138 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000139
David Reiss96d23882007-07-26 21:10:32 +0000140 if (_state == SynchStartTask::STOPPING) {
Mark Sleef5f2be42006-09-05 21:05:31 +0000141 _state = SynchStartTask::STOPPED;
142 _monitor.notifyAll();
David Reiss96d23882007-07-26 21:10:32 +0000143 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000144 }
145 }
146
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100147 private:
Marc Slemko8a40a762006-07-19 17:46:50 +0000148 Monitor& _monitor;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100149 volatile STATE& _state;
Marc Slemko8a40a762006-07-19 17:46:50 +0000150 };
151
152 bool synchStartTest() {
153
154 Monitor monitor;
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000155
Marc Slemko8a40a762006-07-19 17:46:50 +0000156 SynchStartTask::STATE state = SynchStartTask::UNINITIALIZED;
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000157
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100158 shared_ptr<SynchStartTask> task
159 = shared_ptr<SynchStartTask>(new SynchStartTask(monitor, state));
Marc Slemko8a40a762006-07-19 17:46:50 +0000160
cyyca8af9b2019-01-11 22:13:12 +0800161 ThreadFactory threadFactory = ThreadFactory();
Marc Slemko8a40a762006-07-19 17:46:50 +0000162
Marc Slemko6f038a72006-08-03 18:58:09 +0000163 shared_ptr<Thread> thread = threadFactory.newThread(task);
Marc Slemko8a40a762006-07-19 17:46:50 +0000164
Mark Sleef5f2be42006-09-05 21:05:31 +0000165 if (state == SynchStartTask::UNINITIALIZED) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000166
167 state = SynchStartTask::STARTING;
168
169 thread->start();
170 }
171
Mark Sleef5f2be42006-09-05 21:05:31 +0000172 {
173 Synchronized s(monitor);
174 while (state == SynchStartTask::STARTING) {
David Reiss96d23882007-07-26 21:10:32 +0000175 monitor.wait();
Marc Slemko8a40a762006-07-19 17:46:50 +0000176 }
177 }
178
179 assert(state != SynchStartTask::STARTING);
180
Mark Sleef5f2be42006-09-05 21:05:31 +0000181 {
182 Synchronized s(monitor);
Marc Slemko8a40a762006-07-19 17:46:50 +0000183
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000184 try {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100185 monitor.wait(100);
ben-craigfae08e72015-07-15 11:34:47 -0500186 } catch (TimedOutException&) {
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000187 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000188
Mark Sleef5f2be42006-09-05 21:05:31 +0000189 if (state == SynchStartTask::STARTED) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000190
David Reiss96d23882007-07-26 21:10:32 +0000191 state = SynchStartTask::STOPPING;
Marc Slemko8a40a762006-07-19 17:46:50 +0000192
David Reiss96d23882007-07-26 21:10:32 +0000193 monitor.notify();
Marc Slemko8a40a762006-07-19 17:46:50 +0000194 }
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000195
Mark Sleef5f2be42006-09-05 21:05:31 +0000196 while (state == SynchStartTask::STOPPING) {
David Reiss96d23882007-07-26 21:10:32 +0000197 monitor.wait();
Marc Slemko8a40a762006-07-19 17:46:50 +0000198 }
199 }
200
201 assert(state == SynchStartTask::STOPPED);
202
Marc Slemkoc7782972006-07-25 02:26:35 +0000203 bool success = true;
204
205 std::cout << "\t\t\t" << (success ? "Success" : "Failure") << "!" << std::endl;
206
Marc Slemko8a40a762006-07-19 17:46:50 +0000207 return true;
208 }
209
James E. King, IIIdf899132016-11-12 15:16:30 -0500210 /**
211 * The only guarantee a monitor timeout can give you is that
212 * it will take "at least" as long as the timeout, no less.
213 * There is absolutely no guarantee around regaining execution
214 * near the timeout. On a busy system (like inside a third party
215 * CI environment) it could take quite a bit longer than the
216 * requested timeout, and that's ok.
217 */
Marc Slemkoc7782972006-07-25 02:26:35 +0000218
James E. King, IIIdf899132016-11-12 15:16:30 -0500219 bool monitorTimeoutTest(int64_t count = 1000, int64_t timeout = 2) {
Marc Slemkoc7782972006-07-25 02:26:35 +0000220
221 Monitor monitor;
222
cyybfdbd032019-01-12 14:38:28 +0800223 int64_t startTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
Marc Slemkoc7782972006-07-25 02:26:35 +0000224
James E. King, IIIdf899132016-11-12 15:16:30 -0500225 for (int64_t ix = 0; ix < count; ix++) {
Mark Sleef5f2be42006-09-05 21:05:31 +0000226 {
227 Synchronized s(monitor);
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000228 try {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100229 monitor.wait(timeout);
ben-craigfae08e72015-07-15 11:34:47 -0500230 } catch (TimedOutException&) {
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000231 }
Marc Slemkoc7782972006-07-25 02:26:35 +0000232 }
233 }
234
cyybfdbd032019-01-12 14:38:28 +0800235 int64_t endTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
Marc Slemkoc7782972006-07-25 02:26:35 +0000236
James E. King, IIIdf899132016-11-12 15:16:30 -0500237 bool success = (endTime - startTime) >= (count * timeout);
Marc Slemkoc7782972006-07-25 02:26:35 +0000238
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100239 std::cout << "\t\t\t" << (success ? "Success" : "Failure")
James E. King, IIIdf899132016-11-12 15:16:30 -0500240 << ": minimum required time to elapse " << count * timeout
241 << "ms; actual elapsed time " << endTime - startTime << "ms"
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100242 << std::endl;
Marc Slemkoc7782972006-07-25 02:26:35 +0000243
244 return success;
245 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000246
Marc Slemkoa6479032007-06-05 22:20:14 +0000247 class FloodTask : public Runnable {
248 public:
James E. King, III7d211b82017-09-06 10:12:02 -0700249 FloodTask(const size_t id, Monitor& mon) : _id(id), _mon(mon) {}
Sebastian Zenker042580f2019-01-29 15:48:12 +0100250 ~FloodTask() override {
James E. King, IIIdf899132016-11-12 15:16:30 -0500251 if (_id % 10000 == 0) {
James E. King, III7d211b82017-09-06 10:12:02 -0700252 Synchronized sync(_mon);
Marc Slemkoa6479032007-06-05 22:20:14 +0000253 std::cout << "\t\tthread " << _id << " done" << std::endl;
254 }
255 }
256
Sebastian Zenker042580f2019-01-29 15:48:12 +0100257 void run() override {
James E. King, IIIdf899132016-11-12 15:16:30 -0500258 if (_id % 10000 == 0) {
James E. King, III7d211b82017-09-06 10:12:02 -0700259 Synchronized sync(_mon);
Marc Slemkoa6479032007-06-05 22:20:14 +0000260 std::cout << "\t\tthread " << _id << " started" << std::endl;
261 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000262 }
263 const size_t _id;
James E. King, III7d211b82017-09-06 10:12:02 -0700264 Monitor& _mon;
Marc Slemkoa6479032007-06-05 22:20:14 +0000265 };
266
cyyca8af9b2019-01-11 22:13:12 +0800267 void foo(ThreadFactory* tf) { (void)tf; }
Marc Slemkoa6479032007-06-05 22:20:14 +0000268
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100269 bool floodNTest(size_t loop = 1, size_t count = 100000) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000270
271 bool success = false;
James E. King, III7d211b82017-09-06 10:12:02 -0700272 Monitor mon;
273
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100274 for (size_t lix = 0; lix < loop; lix++) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000275
cyyca8af9b2019-01-11 22:13:12 +0800276 ThreadFactory threadFactory = ThreadFactory();
Marc Slemkoa6479032007-06-05 22:20:14 +0000277 threadFactory.setDetached(true);
278
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100279 for (size_t tix = 0; tix < count; tix++) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000280
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100281 try {
Marc Slemkoa6479032007-06-05 22:20:14 +0000282
James E. King, III7d211b82017-09-06 10:12:02 -0700283 shared_ptr<FloodTask> task(new FloodTask(lix * count + tix, mon));
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100284 shared_ptr<Thread> thread = threadFactory.newThread(task);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100285 thread->start();
Marc Slemkoa6479032007-06-05 22:20:14 +0000286
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100287 } catch (TException& e) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000288
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100289 std::cout << "\t\t\tfailed to start " << lix* count + tix << " thread " << e.what()
290 << std::endl;
Marc Slemkoa6479032007-06-05 22:20:14 +0000291
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100292 return success;
Marc Slemkoa6479032007-06-05 22:20:14 +0000293 }
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100294 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000295
James E. King, III7d211b82017-09-06 10:12:02 -0700296 Synchronized sync(mon);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100297 std::cout << "\t\t\tflooded " << (lix + 1) * count << " threads" << std::endl;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100298 success = true;
Marc Slemkoa6479032007-06-05 22:20:14 +0000299 }
300
301 return success;
302 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000303};
Marc Slemko8a40a762006-07-19 17:46:50 +0000304
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100305}
306}
307}
308} // apache::thrift::concurrency::test