blob: 6ac9aa51cd522b4a88c97de55256651ee7e7fa0f [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
James E. King, III82ae9572017-08-05 12:23:54 -040036using stdcxx::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);
Marc Slemko3a3b53b2007-05-22 23:59:54 +000057
Mark Sleef5f2be42006-09-05 21:05:31 +000058 _count--;
Marc Slemko3a3b53b2007-05-22 23:59:54 +000059
Konrad Grochowski16a23a62014-11-13 15:33:38 +010060 // std::cout << "\t\t\tthread count: " << _count << std::endl;
Marc Slemko3a3b53b2007-05-22 23:59:54 +000061
Mark Sleef5f2be42006-09-05 21:05:31 +000062 if (_count == 0) {
63 _monitor.notify();
Marc Slemko8a40a762006-07-19 17:46:50 +000064 }
65 }
66
67 Monitor& _monitor;
68
69 int& _count;
70 };
71
Konrad Grochowski16a23a62014-11-13 15:33:38 +010072 bool reapNThreads(int loop = 1, int count = 10) {
Marc Slemko8a40a762006-07-19 17:46:50 +000073
Konrad Grochowski16a23a62014-11-13 15:33:38 +010074 PlatformThreadFactory threadFactory = PlatformThreadFactory();
Marc Slemko8a40a762006-07-19 17:46:50 +000075
James E. King, III36200902016-10-05 14:47:18 -040076 shared_ptr<Monitor> monitor(new Monitor);
Marc Slemko8a40a762006-07-19 17:46:50 +000077
Konrad Grochowski16a23a62014-11-13 15:33:38 +010078 for (int lix = 0; lix < loop; lix++) {
Marc Slemko8a40a762006-07-19 17:46:50 +000079
Konrad Grochowski16a23a62014-11-13 15:33:38 +010080 int* activeCount = new int(count);
Marc Slemko8a40a762006-07-19 17:46:50 +000081
James E. King, III7d211b82017-09-06 10:12:02 -070082 std::vector<shared_ptr<Thread> > threads;
Marc Slemko8a40a762006-07-19 17:46:50 +000083
Marc Slemko67606e52007-06-04 21:01:19 +000084 int tix;
Marc Slemko8a40a762006-07-19 17:46:50 +000085
Marc Slemko67606e52007-06-04 21:01:19 +000086 for (tix = 0; tix < count; tix++) {
87 try {
James E. King, III7d211b82017-09-06 10:12:02 -070088 threads.push_back(
Konrad Grochowski16a23a62014-11-13 15:33:38 +010089 threadFactory.newThread(shared_ptr<Runnable>(new ReapNTask(*monitor, *activeCount))));
90 } catch (SystemResourceException& e) {
91 std::cout << "\t\t\tfailed to create " << lix* count + tix << " thread " << e.what()
92 << std::endl;
Marc Slemko67606e52007-06-04 21:01:19 +000093 throw e;
94 }
Marc Slemko8a40a762006-07-19 17:46:50 +000095 }
Marc Slemkoa6479032007-06-05 22:20:14 +000096
Marc Slemko67606e52007-06-04 21:01:19 +000097 tix = 0;
James E. King, III7d211b82017-09-06 10:12:02 -070098 for (std::vector<shared_ptr<Thread> >::const_iterator thread = threads.begin();
Konrad Grochowski16a23a62014-11-13 15:33:38 +010099 thread != threads.end();
100 tix++, ++thread) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000101
Marc Slemko67606e52007-06-04 21:01:19 +0000102 try {
103 (*thread)->start();
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100104 } catch (SystemResourceException& e) {
105 std::cout << "\t\t\tfailed to start " << lix* count + tix << " thread " << e.what()
106 << std::endl;
Marc Slemko67606e52007-06-04 21:01:19 +0000107 throw e;
108 }
109 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000110
Marc Slemko67606e52007-06-04 21:01:19 +0000111 {
112 Synchronized s(*monitor);
113 while (*activeCount > 0) {
114 monitor->wait(1000);
115 }
116 }
James E. King, III7d211b82017-09-06 10:12:02 -0700117
Roger Meier3075ffc2011-08-04 22:36:07 +0000118 delete activeCount;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100119 std::cout << "\t\t\treaped " << lix* count << " threads" << std::endl;
Marc Slemko8a40a762006-07-19 17:46:50 +0000120 }
121
122 std::cout << "\t\t\tSuccess!" << std::endl;
123
124 return true;
125 }
126
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100127 class SynchStartTask : public Runnable {
Marc Slemko8a40a762006-07-19 17:46:50 +0000128
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100129 public:
130 enum STATE { UNINITIALIZED, STARTING, STARTED, STOPPING, STOPPED };
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000131
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100132 SynchStartTask(Monitor& monitor, volatile STATE& state) : _monitor(monitor), _state(state) {}
Marc Slemko8a40a762006-07-19 17:46:50 +0000133
134 void run() {
Mark Sleef5f2be42006-09-05 21:05:31 +0000135 {
136 Synchronized s(_monitor);
David Reiss96d23882007-07-26 21:10:32 +0000137 if (_state == SynchStartTask::STARTING) {
138 _state = SynchStartTask::STARTED;
139 _monitor.notify();
140 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000141 }
142
Mark Sleef5f2be42006-09-05 21:05:31 +0000143 {
144 Synchronized s(_monitor);
145 while (_state == SynchStartTask::STARTED) {
David Reiss96d23882007-07-26 21:10:32 +0000146 _monitor.wait();
147 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000148
David Reiss96d23882007-07-26 21:10:32 +0000149 if (_state == SynchStartTask::STOPPING) {
Mark Sleef5f2be42006-09-05 21:05:31 +0000150 _state = SynchStartTask::STOPPED;
151 _monitor.notifyAll();
David Reiss96d23882007-07-26 21:10:32 +0000152 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000153 }
154 }
155
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100156 private:
Marc Slemko8a40a762006-07-19 17:46:50 +0000157 Monitor& _monitor;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100158 volatile STATE& _state;
Marc Slemko8a40a762006-07-19 17:46:50 +0000159 };
160
161 bool synchStartTest() {
162
163 Monitor monitor;
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000164
Marc Slemko8a40a762006-07-19 17:46:50 +0000165 SynchStartTask::STATE state = SynchStartTask::UNINITIALIZED;
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000166
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100167 shared_ptr<SynchStartTask> task
168 = shared_ptr<SynchStartTask>(new SynchStartTask(monitor, state));
Marc Slemko8a40a762006-07-19 17:46:50 +0000169
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100170 PlatformThreadFactory threadFactory = PlatformThreadFactory();
Marc Slemko8a40a762006-07-19 17:46:50 +0000171
Marc Slemko6f038a72006-08-03 18:58:09 +0000172 shared_ptr<Thread> thread = threadFactory.newThread(task);
Marc Slemko8a40a762006-07-19 17:46:50 +0000173
Mark Sleef5f2be42006-09-05 21:05:31 +0000174 if (state == SynchStartTask::UNINITIALIZED) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000175
176 state = SynchStartTask::STARTING;
177
178 thread->start();
179 }
180
Mark Sleef5f2be42006-09-05 21:05:31 +0000181 {
182 Synchronized s(monitor);
183 while (state == SynchStartTask::STARTING) {
David Reiss96d23882007-07-26 21:10:32 +0000184 monitor.wait();
Marc Slemko8a40a762006-07-19 17:46:50 +0000185 }
186 }
187
188 assert(state != SynchStartTask::STARTING);
189
Mark Sleef5f2be42006-09-05 21:05:31 +0000190 {
191 Synchronized s(monitor);
Marc Slemko8a40a762006-07-19 17:46:50 +0000192
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000193 try {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100194 monitor.wait(100);
ben-craigfae08e72015-07-15 11:34:47 -0500195 } catch (TimedOutException&) {
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000196 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000197
Mark Sleef5f2be42006-09-05 21:05:31 +0000198 if (state == SynchStartTask::STARTED) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000199
David Reiss96d23882007-07-26 21:10:32 +0000200 state = SynchStartTask::STOPPING;
Marc Slemko8a40a762006-07-19 17:46:50 +0000201
David Reiss96d23882007-07-26 21:10:32 +0000202 monitor.notify();
Marc Slemko8a40a762006-07-19 17:46:50 +0000203 }
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000204
Mark Sleef5f2be42006-09-05 21:05:31 +0000205 while (state == SynchStartTask::STOPPING) {
David Reiss96d23882007-07-26 21:10:32 +0000206 monitor.wait();
Marc Slemko8a40a762006-07-19 17:46:50 +0000207 }
208 }
209
210 assert(state == SynchStartTask::STOPPED);
211
Marc Slemkoc7782972006-07-25 02:26:35 +0000212 bool success = true;
213
214 std::cout << "\t\t\t" << (success ? "Success" : "Failure") << "!" << std::endl;
215
Marc Slemko8a40a762006-07-19 17:46:50 +0000216 return true;
217 }
218
James E. King, IIIdf899132016-11-12 15:16:30 -0500219 /**
220 * The only guarantee a monitor timeout can give you is that
221 * it will take "at least" as long as the timeout, no less.
222 * There is absolutely no guarantee around regaining execution
223 * near the timeout. On a busy system (like inside a third party
224 * CI environment) it could take quite a bit longer than the
225 * requested timeout, and that's ok.
226 */
Marc Slemkoc7782972006-07-25 02:26:35 +0000227
James E. King, IIIdf899132016-11-12 15:16:30 -0500228 bool monitorTimeoutTest(int64_t count = 1000, int64_t timeout = 2) {
Marc Slemkoc7782972006-07-25 02:26:35 +0000229
230 Monitor monitor;
231
Mark Slee9b82d272007-05-23 05:16:07 +0000232 int64_t startTime = Util::currentTime();
Marc Slemkoc7782972006-07-25 02:26:35 +0000233
James E. King, IIIdf899132016-11-12 15:16:30 -0500234 for (int64_t ix = 0; ix < count; ix++) {
Mark Sleef5f2be42006-09-05 21:05:31 +0000235 {
236 Synchronized s(monitor);
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000237 try {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100238 monitor.wait(timeout);
ben-craigfae08e72015-07-15 11:34:47 -0500239 } catch (TimedOutException&) {
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000240 }
Marc Slemkoc7782972006-07-25 02:26:35 +0000241 }
242 }
243
Mark Slee9b82d272007-05-23 05:16:07 +0000244 int64_t endTime = Util::currentTime();
Marc Slemkoc7782972006-07-25 02:26:35 +0000245
James E. King, IIIdf899132016-11-12 15:16:30 -0500246 bool success = (endTime - startTime) >= (count * timeout);
Marc Slemkoc7782972006-07-25 02:26:35 +0000247
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100248 std::cout << "\t\t\t" << (success ? "Success" : "Failure")
James E. King, IIIdf899132016-11-12 15:16:30 -0500249 << ": minimum required time to elapse " << count * timeout
250 << "ms; actual elapsed time " << endTime - startTime << "ms"
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100251 << std::endl;
Marc Slemkoc7782972006-07-25 02:26:35 +0000252
253 return success;
254 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000255
Marc Slemkoa6479032007-06-05 22:20:14 +0000256 class FloodTask : public Runnable {
257 public:
James E. King, III7d211b82017-09-06 10:12:02 -0700258 FloodTask(const size_t id, Monitor& mon) : _id(id), _mon(mon) {}
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100259 ~FloodTask() {
James E. King, IIIdf899132016-11-12 15:16:30 -0500260 if (_id % 10000 == 0) {
James E. King, III7d211b82017-09-06 10:12:02 -0700261 Synchronized sync(_mon);
Marc Slemkoa6479032007-06-05 22:20:14 +0000262 std::cout << "\t\tthread " << _id << " done" << std::endl;
263 }
264 }
265
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100266 void run() {
James E. King, IIIdf899132016-11-12 15:16:30 -0500267 if (_id % 10000 == 0) {
James E. King, III7d211b82017-09-06 10:12:02 -0700268 Synchronized sync(_mon);
Marc Slemkoa6479032007-06-05 22:20:14 +0000269 std::cout << "\t\tthread " << _id << " started" << std::endl;
270 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000271 }
272 const size_t _id;
James E. King, III7d211b82017-09-06 10:12:02 -0700273 Monitor& _mon;
Marc Slemkoa6479032007-06-05 22:20:14 +0000274 };
275
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100276 void foo(PlatformThreadFactory* tf) { (void)tf; }
Marc Slemkoa6479032007-06-05 22:20:14 +0000277
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100278 bool floodNTest(size_t loop = 1, size_t count = 100000) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000279
280 bool success = false;
James E. King, III7d211b82017-09-06 10:12:02 -0700281 Monitor mon;
282
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100283 for (size_t lix = 0; lix < loop; lix++) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000284
Roger Meier3faaedf2011-10-02 10:51:45 +0000285 PlatformThreadFactory threadFactory = PlatformThreadFactory();
Marc Slemkoa6479032007-06-05 22:20:14 +0000286 threadFactory.setDetached(true);
287
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100288 for (size_t tix = 0; tix < count; tix++) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000289
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100290 try {
Marc Slemkoa6479032007-06-05 22:20:14 +0000291
James E. King, III7d211b82017-09-06 10:12:02 -0700292 shared_ptr<FloodTask> task(new FloodTask(lix * count + tix, mon));
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100293 shared_ptr<Thread> thread = threadFactory.newThread(task);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100294 thread->start();
Marc Slemkoa6479032007-06-05 22:20:14 +0000295
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100296 } catch (TException& e) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000297
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100298 std::cout << "\t\t\tfailed to start " << lix* count + tix << " thread " << e.what()
299 << std::endl;
Marc Slemkoa6479032007-06-05 22:20:14 +0000300
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100301 return success;
Marc Slemkoa6479032007-06-05 22:20:14 +0000302 }
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100303 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000304
James E. King, III7d211b82017-09-06 10:12:02 -0700305 Synchronized sync(mon);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100306 std::cout << "\t\t\tflooded " << (lix + 1) * count << " threads" << std::endl;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100307 success = true;
Marc Slemkoa6479032007-06-05 22:20:14 +0000308 }
309
310 return success;
311 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000312};
Marc Slemko8a40a762006-07-19 17:46:50 +0000313
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100314}
315}
316}
317} // apache::thrift::concurrency::test