37 using namespace basis;
81 #define LOG(to_print) CLASS_EMERGENCY_LOG(program_wide_logger::get(), to_print)
86 #undef UNIT_BASE_THIS_OBJECT
87 #define UNIT_BASE_THIS_OBJECT (*this)
109 #undef UNIT_BASE_THIS_OBJECT
110 #define UNIT_BASE_THIS_OBJECT c_testing
116 test_mutex &c_testing;
118 piranha(test_mutex &testing) :
ethread(0), c_testing(testing) {
133 void perform_activity(
void *
formal(data)) {
146 c_testing.test_recursive_locking(
_rando);
151 #ifdef ENABLE_CALLSTACK_TRACKING
164 class barracuda :
public ethread
168 test_mutex &c_testing;
170 barracuda(test_mutex &testing) :
ethread(0), c_testing(testing) {
177 virtual ~barracuda() {
185 void perform_activity(
void *
formal(data)) {
192 c_testing.test_recursive_locking(
_rando);
198 #ifdef ENABLE_CALLSTACK_TRACKING
210 #undef UNIT_BASE_THIS_OBJECT
211 #define UNIT_BASE_THIS_OBJECT (*this)
213 int test_mutex::execute()
218 LOG(
"entering execute method.");
238 double time_per_lock = (mutt_out.
value() - mutt_in.
value()) / run_count;
239 log(
a_sprintf(
"%.0f mutex lock & unlock pairs took %.3f seconds,",
240 run_count, full_run_time));
241 log(
a_sprintf(
"or %f ms per (lock+unlock).", time_per_lock));
242 ASSERT_TRUE(time_per_lock < 1.0,
"mutex lock timing should be super fast");
244 LOG(
"about to exit scope and dump automatic objects.");
247 #ifdef ENABLE_CALLSTACK_TRACKING
253 LOG(
"succeeded in exiting scope.");
261 t =
new piranha(*
this);
266 t =
new barracuda(*
this);
272 #ifdef ENABLE_CALLSTACK_TRACKING
278 ASSERT_EQUAL(q, t,
"amorph pointer equivalence is required");
280 LOG(
a_sprintf(
"indy %i: about to start new thread.", i));
285 LOG(
a_sprintf(
"indy %i: after new thread started.", i));
290 LOG(
"about to begin snoozing.");
295 time_control::sleep_ms(100);
302 LOG(
"now cancelling all threads.");
305 for (
int j = 0; j < thread_list.
elements(); j++) thread_list[j]->cancel();
308 LOG(
"now stopping all threads.");
311 for (
int k = 0; k < thread_list.
elements(); k++) thread_list[k]->stop();
313 int threads_active = 0;
314 for (
int k = 0; k < thread_list.
elements(); k++) {
315 if (thread_list[k]->thread_active()) threads_active++;
317 ASSERT_EQUAL(threads_active, 0,
"threads should actually have stopped by now");
320 LOG(
"resetting thread list.");
328 LOG(
"done exiting from all threads.");
330 #ifdef ENABLE_CALLSTACK_TRACKING
334 LOG(
astring(astring::SPRINTF,
"the accumulated string had %d characters "
335 "which means\nthere were %d thread activations from %d threads.",
340 return final_report();
346 void test_mutex::test_recursive_locking(
chaos &
_rando)
348 FUNCDEF(
"test_recursive_locking");
352 #ifdef ENABLE_CALLSTACK_TRACKING
355 for (
int i = 0; i < test_attempts; i++) {
368 for (
int j = 0; j < locked; j++) {
#define GET_AND_TEST_STACK_TRACE(header, failure_return)
The application_shell is a base object for console programs.
a_sprintf is a specialization of astring that provides printf style support.
Provides a dynamically resizable ASCII character string.
int length() const
Returns the current length of the string.
auto_synchronizer simplifies concurrent code by automatically unlocking.
void lock()
Clamps down on the mutex, if possible.
void unlock()
Gives up the possession of the mutex.
a platform-independent way to acquire random numbers in a specific range.
int inclusive(int low, int high) const
< Returns a pseudo-random number r, such that "low" <= r <= "high".
Provides a platform-independent object for adding threads to a program.
bool start(void *thread_data)
causes the thread to start, if it has not already been started.
int elements() const
the maximum number of elements currently allowed in this amorph.
basis::outcome append(const contents *data)
puts "data" on the end of this amorph.
void reset()
cleans out all of the contents.
Represents a point in time relative to the operating system startup time.
time_representation value() const
returns the time_stamp in terms of the lower level type.
#define formal(parameter)
This macro just eats what it's passed; it marks unused formal parameters.
#define NULL_POINTER
The value representing a pointer to nothing.
#define DEFINE_CLASS_NAME(objname)
Defines the name of a class by providing a couple standard methods.
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
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.
Implements an application lock to ensure only one is running at once.
The guards collection helps in testing preconditions and reporting errors.
const int SECOND_ms
Number of milliseconds in a second.
A logger that sends to the console screen using the standard output device.
An extension to floating point primitives providing approximate equality.
void safe_add(int &to_change, int addition)
thread-safe integer addition.
A dynamic container class that holds any kind of object via pointers.
Useful support functions for unit testing, especially within hoople.
const int MIN_SAME_THREAD_LOCKING_TESTS
const int MAX_SAME_THREAD_LOCKING_TESTS
const int THREAD_PAUSE_LOWEST
const int DEFAULT_RUN_TIME
const int THREAD_PAUSE_HIGHEST
const int MAX_MUTEX_TIMING_TEST
#define ASSERT_EQUAL(a, b, test_name)
#define ASSERT_TRUE(a, test_name)