feisty meow concerns codebase 2.140
test_timer_driver.cpp
Go to the documentation of this file.
1/*****************************************************************************\
2* *
3* Name : t_timer_driver *
4* Author : Chris Koeritz *
5* *
6* Purpose: *
7* *
8* Tests the timer driver class from the operating system library. *
9* *
10*******************************************************************************
11* Copyright (c) 2005-$now By Author. This program is free software; you can *
12* redistribute it and/or modify it under the terms of the GNU General Public *
13* License as published by the Free Software Foundation; either version 2 of *
14* the License or (at your option) any later version. This is online at: *
15* http://www.fsf.org/copyleft/gpl.html *
16* Please send any updates to: fred@gruntose.com *
17\*****************************************************************************/
18
22#include <basis/functions.h>
23#include <basis/guards.h>
24#include <basis/astring.h>
27#include <loggers/file_logger.h>
28#include <mathematics/chaos.h>
29#include <processes/ethread.h>
31#include <structures/set.h>
34#include <timely/time_control.h>
35#include <timely/time_stamp.h>
36#include <timely/timer_driver.h>
37#include <unit_test/unit_base.h>
38
39using namespace application;
40using namespace basis;
41using namespace filesystem;
42using namespace loggers;
43using namespace processes;
44using namespace structures;
45using namespace timely;
46using namespace unit_test;
47
48#define LOG(s) STAMPED_EMERGENCY_LOG(program_wide_logger::get(), s)
49
51 // with no arguments to the test, we'll run timers for this very short duration.
52
53const int MAX_THREADS = 120;
54
56
57class timer_driver_tester : virtual public unit_base, virtual public application_shell
58{
59public:
60 timer_driver_tester()
61 : application_shell(), _in_progress(false) {}
62 DEFINE_CLASS_NAME("timer_driver_tester");
63 virtual ~timer_driver_tester() {}
64
65 int execute();
66
67 thread_cabinet &threads() { return _threads; }
68
69 bool in_progress() const { return _in_progress; }
70 // returns true if activity is currently occurring on the main thread.
71 // we don't expect this activity to be interrupted by timer events.
72
73private:
74 bool _in_progress;
75 // simple flag to check when a timer hits. if this is true, then a timer
76 // hit while we were doing actual functional operations, rather than
77 // just waiting in a sleep.
78 thread_cabinet _threads; // storage for our time_stamp testing threads.
79};
80
82
83class timer_test_thread : public ethread
84{
85public:
86 timer_test_thread(application_shell &parent)
87 : ethread(parent.randomizer().inclusive(8, 25)), _parent(parent)
89
90 DEFINE_CLASS_NAME("timer_test_thread");
91 void perform_activity(void *) {
92 FUNCDEF("perform_activity");
93 if (time_stamp() < _started)
94 deadly_error(class_name(), func, "start time is before current time.");
95 if (time_stamp() < _last)
96 deadly_error(class_name(), func, "last check is before current time.");
97 _last.reset(); // set the last time to right now.
98 time_stamp ted;
99 time_stamp jed;
100 if (ted > jed)
101 deadly_error(class_name(), func, "jed is less than test.");
102 }
103
104private:
105 application_shell &_parent;
106 time_stamp _started;
107 time_stamp _last;
108};
109
111
112class my_timer_handler : public timeable
113{
114public:
115 my_timer_handler(timer_driver_tester &parent, int id) : _id(id), _parent(parent) {}
116 virtual ~my_timer_handler() {}
117 DEFINE_CLASS_NAME("my_timer_handler");
118
119 virtual void handle_timer_callback() {
120 FUNCDEF("handle_timer_callback");
121 if (_parent.in_progress())
122 LOG("saw in progress flag set to true! we interrupted real "
123 "ops, not just sleep!");
124 LOG(a_sprintf("timer%d hit.", _id));
125 timer_test_thread *new_thread = new timer_test_thread(_parent);
126 unique_int id = _parent.threads().add_thread(new_thread, false, NULL_POINTER);
127 // the test thread auto-starts, so we don't let the cabinet start it.
128 if (!id)
129 deadly_error(class_name(), func, "failed to start a new thread.");
130
131 if (_parent.threads().threads() > MAX_THREADS) {
132 int gone_index = _parent.randomizer().inclusive(0, _parent.threads().threads() - 1);
133 unique_int gone_thread = _parent.threads().thread_ids()[gone_index];
134 _parent.threads().cancel_thread(gone_thread);
135 time_control::sleep_ms(100); // allow thread to start up.
136 }
137 _parent.threads().clean_debris(); // toss any dead threads.
138
139 LOG(a_sprintf("%d threads checking time_stamp.", _parent.threads().threads()));
140 }
141
142private:
143 int _id;
144 timer_driver_tester &_parent;
145};
146
148
149#define CREATE_TIMER(name, id, dur) \
150 my_timer_handler name(*this, id); \
151 program_wide_timer().set_timer(dur, &name); \
152 LOG(astring("created timer ") + #name + " which hits every " + #dur + " ms")
153
154#define ZAP_TIMER(name) \
155 program_wide_timer().zap_timer(&name)
156
157int timer_driver_tester::execute()
158{
159 int next_id = 1001; // we start issuing timer IDs at 1001 for this test.
160
161 int runtime_ms = DEFAULT_TEST_DURATION;
162 if (application::_global_argc >= 2) {
163 astring passed_runtime = application::_global_argv[1];
164 runtime_ms = passed_runtime.convert(DEFAULT_TEST_DURATION);
165 }
166
167 // some odd timer cycles below to avoid waiting longer than our short default.
168 CREATE_TIMER(timer1, unique_int(next_id++).raw_id(), 1 * SECOND_ms);
169 CREATE_TIMER(timer2, unique_int(next_id++).raw_id(), 250);
170 CREATE_TIMER(timer3, unique_int(next_id++).raw_id(), 3 * SECOND_ms);
171 CREATE_TIMER(timer4, unique_int(next_id++).raw_id(), 140);
172 CREATE_TIMER(timer5, unique_int(next_id++).raw_id(), 500);
173
174 LOG("pausing for a while...");
175 time_stamp when_done(runtime_ms);
176 while (time_stamp() < when_done) {
177 _in_progress = true;
178 // do some various calculations in here and see if we're interrupted
179 // during them. it's one thing to be interrupted in the middle of a
180 // sleep, but it's much different to be interrupted in mid operation.
181 int scrob = 1;
182 for (int i = 1; i < 50; i++) {
183 scrob *= i;
184 }
185 _in_progress = false;
186#ifdef __UNIX__
188#else
189 bool okay = event_extensions::poll();
190 if (!okay) break;
191#endif
192 }
193
194 ZAP_TIMER(timer1);
195 ZAP_TIMER(timer2);
196 ZAP_TIMER(timer3);
197 ZAP_TIMER(timer4);
198 ZAP_TIMER(timer5);
199
200 critical_events::alert_message(astring(class_name()) + ": works for those functions tested.");
201
202 return 0;
203}
204
206
207HOOPLE_MAIN(timer_driver_tester, )
208
#define LOG(s)
The application_shell is a base object for console programs.
virtual int execute()=0
< retrieves the command line from the /proc hierarchy on linux.
application_shell()
constructs an application_shell to serve as the root of the program.
a_sprintf is a specialization of astring that provides printf style support.
Definition astring.h:440
Provides a dynamically resizable ASCII character string.
Definition astring.h:35
int convert(int default_value) const
Converts the string into a corresponding integer.
Definition astring.cpp:760
static void alert_message(const char *info, const char *title="Alert Message")
shows the message in "info", with an optional "title" on the message.
Provides a platform-independent object for adding threads to a program.
Definition ethread.h:36
bool start(void *thread_data)
causes the thread to start, if it has not already been started.
Definition ethread.cpp:145
virtual void perform_activity(void *thread_data)=0
< invoked just after after start(), when the OS thread is created.
Manages a collection of threads.
A unique identifier based on integers.
Definition unique_id.h:97
static void sleep_ms(basis::un_int msec)
a system independent name for a forced snooze measured in milliseconds.
Represents a point in time relative to the operating system startup time.
Definition time_stamp.h:38
timeable is the base for objects that can be hooked into timer events.
virtual void handle_timer_callback()=0
this method is invoked when the timer period elapses for this object.
#define deadly_error(c, f, i)
#define NULL_POINTER
The value representing a pointer to nothing.
Definition definitions.h:32
#define DEFINE_CLASS_NAME(objname)
Defines the name of a class by providing a couple standard methods.
Definition enhance_cpp.h:42
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition enhance_cpp.h:54
Provides macros that implement the 'main' program of an application.
#define HOOPLE_MAIN(obj_name, obj_args)
options that should work for most unix and linux apps.
Definition hoople_main.h:61
Implements an application lock to ensure only one is running at once.
char ** _global_argv
The guards collection helps in testing preconditions and reporting errors.
Definition array.h:30
const int SECOND_ms
Number of milliseconds in a second.
A platform independent way to obtain the timestamp of a file.
A logger that sends to the console screen using the standard output device.
A dynamic container class that holds any kind of object via pointers.
Definition amorph.h:55
#include <time.h>
Useful support functions for unit testing, especially within hoople.
Definition unit_base.cpp:35
#define randomizer()
#define CREATE_TIMER(name, id, dur)
const int MAX_THREADS
const int DEFAULT_TEST_DURATION
#define LOG(s)
#define ZAP_TIMER(name)