| 30 |
ashish |
1 |
/*
|
|
|
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 |
|
|
|
20 |
#include <concurrency/TimerManager.h>
|
|
|
21 |
#include <concurrency/PosixThreadFactory.h>
|
|
|
22 |
#include <concurrency/Monitor.h>
|
|
|
23 |
#include <concurrency/Util.h>
|
|
|
24 |
|
|
|
25 |
#include <assert.h>
|
|
|
26 |
#include <iostream>
|
|
|
27 |
|
|
|
28 |
namespace apache { namespace thrift { namespace concurrency { namespace test {
|
|
|
29 |
|
|
|
30 |
using namespace apache::thrift::concurrency;
|
|
|
31 |
|
|
|
32 |
/**
|
|
|
33 |
* ThreadManagerTests class
|
|
|
34 |
*
|
|
|
35 |
* @version $Id:$
|
|
|
36 |
*/
|
|
|
37 |
class TimerManagerTests {
|
|
|
38 |
|
|
|
39 |
public:
|
|
|
40 |
|
|
|
41 |
static const double ERROR;
|
|
|
42 |
|
|
|
43 |
class Task: public Runnable {
|
|
|
44 |
public:
|
|
|
45 |
|
|
|
46 |
Task(Monitor& monitor, int64_t timeout) :
|
|
|
47 |
_timeout(timeout),
|
|
|
48 |
_startTime(Util::currentTime()),
|
|
|
49 |
_monitor(monitor),
|
|
|
50 |
_success(false),
|
|
|
51 |
_done(false) {}
|
|
|
52 |
|
|
|
53 |
~Task() { std::cerr << this << std::endl; }
|
|
|
54 |
|
|
|
55 |
void run() {
|
|
|
56 |
|
|
|
57 |
_endTime = Util::currentTime();
|
|
|
58 |
|
|
|
59 |
// Figure out error percentage
|
|
|
60 |
|
|
|
61 |
int64_t delta = _endTime - _startTime;
|
|
|
62 |
|
|
|
63 |
|
|
|
64 |
delta = delta > _timeout ? delta - _timeout : _timeout - delta;
|
|
|
65 |
|
|
|
66 |
float error = delta / _timeout;
|
|
|
67 |
|
|
|
68 |
if(error < ERROR) {
|
|
|
69 |
_success = true;
|
|
|
70 |
}
|
|
|
71 |
|
|
|
72 |
_done = true;
|
|
|
73 |
|
|
|
74 |
std::cout << "\t\t\tTimerManagerTests::Task[" << this << "] done" << std::endl; //debug
|
|
|
75 |
|
|
|
76 |
{Synchronized s(_monitor);
|
|
|
77 |
_monitor.notifyAll();
|
|
|
78 |
}
|
|
|
79 |
}
|
|
|
80 |
|
|
|
81 |
int64_t _timeout;
|
|
|
82 |
int64_t _startTime;
|
|
|
83 |
int64_t _endTime;
|
|
|
84 |
Monitor& _monitor;
|
|
|
85 |
bool _success;
|
|
|
86 |
bool _done;
|
|
|
87 |
};
|
|
|
88 |
|
|
|
89 |
/**
|
|
|
90 |
* This test creates two tasks and waits for the first to expire within 10%
|
|
|
91 |
* of the expected expiration time. It then verifies that the timer manager
|
|
|
92 |
* properly clean up itself and the remaining orphaned timeout task when the
|
|
|
93 |
* manager goes out of scope and its destructor is called.
|
|
|
94 |
*/
|
|
|
95 |
bool test00(int64_t timeout=1000LL) {
|
|
|
96 |
|
|
|
97 |
shared_ptr<TimerManagerTests::Task> orphanTask = shared_ptr<TimerManagerTests::Task>(new TimerManagerTests::Task(_monitor, 10 * timeout));
|
|
|
98 |
|
|
|
99 |
{
|
|
|
100 |
|
|
|
101 |
TimerManager timerManager;
|
|
|
102 |
|
|
|
103 |
timerManager.threadFactory(shared_ptr<PosixThreadFactory>(new PosixThreadFactory()));
|
|
|
104 |
|
|
|
105 |
timerManager.start();
|
|
|
106 |
|
|
|
107 |
assert(timerManager.state() == TimerManager::STARTED);
|
|
|
108 |
|
|
|
109 |
// Don't create task yet, because its constructor sets the expected completion time, and we
|
|
|
110 |
// need to delay between inserting the two tasks into the run queue.
|
|
|
111 |
shared_ptr<TimerManagerTests::Task> task;
|
|
|
112 |
|
|
|
113 |
{
|
|
|
114 |
Synchronized s(_monitor);
|
|
|
115 |
|
|
|
116 |
timerManager.add(orphanTask, 10 * timeout);
|
|
|
117 |
|
|
|
118 |
try {
|
|
|
119 |
// Wait for 1 second in order to give timerManager a chance to start sleeping in response
|
|
|
120 |
// to adding orphanTask. We need to do this so we can verify that adding the second task
|
|
|
121 |
// kicks the dispatcher out of the current wait and starts the new 1 second wait.
|
|
|
122 |
_monitor.wait (1000);
|
|
|
123 |
assert (0 == "ERROR: This wait should time out. TimerManager dispatcher may have a problem.");
|
|
|
124 |
} catch (TimedOutException &ex) {
|
|
|
125 |
}
|
|
|
126 |
|
|
|
127 |
task.reset (new TimerManagerTests::Task(_monitor, timeout));
|
|
|
128 |
|
|
|
129 |
timerManager.add(task, timeout);
|
|
|
130 |
|
|
|
131 |
_monitor.wait();
|
|
|
132 |
}
|
|
|
133 |
|
|
|
134 |
assert(task->_done);
|
|
|
135 |
|
|
|
136 |
|
|
|
137 |
std::cout << "\t\t\t" << (task->_success ? "Success" : "Failure") << "!" << std::endl;
|
|
|
138 |
}
|
|
|
139 |
|
|
|
140 |
// timerManager.stop(); This is where it happens via destructor
|
|
|
141 |
|
|
|
142 |
assert(!orphanTask->_done);
|
|
|
143 |
|
|
|
144 |
return true;
|
|
|
145 |
}
|
|
|
146 |
|
|
|
147 |
friend class TestTask;
|
|
|
148 |
|
|
|
149 |
Monitor _monitor;
|
|
|
150 |
};
|
|
|
151 |
|
|
|
152 |
const double TimerManagerTests::ERROR = .20;
|
|
|
153 |
|
|
|
154 |
}}}} // apache::thrift::concurrency
|
|
|
155 |
|