00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include <basis/array.cpp>
00016 #include <basis/chaos.h>
00017 #include <basis/guards.h>
00018 #include <basis/istring.h>
00019 #include <basis/mutex.h>
00020 #include <mechanisms/ithread.h>
00021 #include <mechanisms/safe_roller.h>
00022 #include <mechanisms/rw_lock.h>
00023 #include <mechanisms/time_stamp.h>
00024 #include <opsystem/application_shell.h>
00025 #include <opsystem/path_configuration.h>
00026 #include <data_struct/static_memory_gremlin.h>
00027
00028 HOOPLE_STARTUP_CODE;
00029
00030
00031
00032
00033
00034
00035 typedef int protectee;
00036
00037
00038 const int DEFAULT_LIFE_TIME = 2 * MINUTE_ms;
00039
00040
00041 const int NUMBER_OF_CHECKERS = 28;
00042
00043
00044
00045
00047
00048 chaos rando;
00049
00051
00052
00053
00054
00055 class hold_globals
00056 {
00057 public:
00058 hold_globals();
00059 ~hold_globals();
00060
00061
00062
00063 time_stamp when_to_exit;
00064 bool sleep_mode;
00065 reader_writer_lock protection;
00066
00067 bool exit_now;
00068 int thread_count;
00069
00070 protectee safe_guy;
00071
00072 };
00073
00074 hold_globals::hold_globals()
00075 : when_to_exit(DEFAULT_LIFE_TIME),
00076
00077 sleep_mode(false),
00078 protection(),
00079 exit_now(false),
00080 thread_count(0),
00081 safe_guy(0)
00082 {
00083 }
00084
00085 hold_globals::~hold_globals()
00086 {
00087 }
00088
00089 static hold_globals global_data;
00090
00092
00093
00094 class test_rw_lock;
00095
00096
00097 class rw_lock_thread : public ithread
00098 {
00099 public:
00100 test_rw_lock &_parent;
00101 rw_lock_thread(test_rw_lock &parent) : ithread(100), _parent(parent) {}
00102 void perform_activity(void *unused);
00103 };
00104
00105
00106 class adder_thread : public ithread
00107 {
00108 public:
00109 test_rw_lock &_parent;
00110 adder_thread(test_rw_lock &parent) : ithread(), _parent(parent) {}
00111 void perform_activity(void *non);
00112 };
00113
00114 class checker_thread : public ithread
00115 {
00116 public:
00117 test_rw_lock &_parent;
00118 checker_thread(test_rw_lock &parent) : ithread(), _parent(parent) {}
00119 void perform_activity(void *non);
00120 };
00121
00123
00124 class test_rw_lock : public application_shell
00125 {
00126 public:
00127 test_rw_lock() : application_shell("t_rw_lock"), _periodic(*this) {}
00128
00129 IMPLEMENT_CLASS_NAME("test_rw_lock");
00130
00131 virtual ~test_rw_lock() {
00132 _periodic.stop();
00133 for (int i = 0; i < _threads.length(); i++) _threads[i]->stop();
00134 for (int k = 0; k < _threads.length(); k++) WHACK(_threads[k]);
00135 }
00136
00137 int execute();
00138
00139 void add_thread(ithread *to_add);
00140
00141
00142 private:
00143 rw_lock_thread _periodic;
00144 mutex _list_lock;
00145 array<ithread *> _threads;
00146 };
00147
00149
00150 #undef LOG
00151 #ifdef DEBUG_RW_LOCK
00152
00153 #define LOG(to_print) _parent.log(timestamp(true) + istring(to_print))
00154 #else
00155 #define LOG(to_print) {}
00156 #endif
00157
00158 void rw_lock_thread::perform_activity(void *formal(unused)) {
00159
00160 if (global_data.when_to_exit < time_stamp()) {
00161
00162
00163 cancel();
00164 return;
00165 }
00166
00167
00168 if (global_data.sleep_mode) {
00169
00170 LOG("main loop zzzz...");
00171 if (rando.inclusive(1, 100) > 95) global_data.sleep_mode = false;
00172 if (!global_data.sleep_mode) { LOG("<waking up.>"); }
00173 } else if (rando.inclusive(0, 100) == 58) {
00174
00175 global_data.sleep_mode = true;
00176 LOG("<going to sleep.>");
00177 } else {
00178 int selector = rando.inclusive(1, 100);
00179
00180
00181 if ( (selector >= 14) && (selector <= 28) ) {
00182 LOG("launching an adder.");
00183 _parent.add_thread(new adder_thread(_parent));
00184
00185
00186
00187 }
00188
00189 }
00190 }
00191
00193
00194 void adder_thread::perform_activity(void *)
00195 {
00197 safe_add(global_data.thread_count, 1);
00198 LOG(istring(istring::SPRINTF, "adder is thread %d.", global_data.thread_count));
00199
00200 global_data.protection.begin_write();
00201 global_data.safe_guy++;
00202 LOG(istring(istring::SPRINTF, "in write: adder incrementing to %d.", global_data.safe_guy));
00203 global_data.protection.end_write();
00204
00205 LOG("exiting adder");
00206 safe_add(global_data.thread_count, -1);
00207 }
00208
00210
00211 void checker_thread::perform_activity(void *) {
00212 safe_add(global_data.thread_count, 1);
00213 LOG(istring(istring::SPRINTF, "checker is thread %d.", global_data.thread_count));
00214
00215 protectee val = 0;
00216
00217 while (!global_data.exit_now) {
00218
00219 global_data.protection.begin_read();
00220 LOG("in reader: got read access.");
00221 if (global_data.safe_guy < val)
00222 deadly_error("checker", "test", "value was not increasing!");
00223 val = global_data.safe_guy;
00224 LOG("in reader: giving up read access.");
00225 global_data.protection.end_read();
00226 LOG("in reader: after gave up read access.");
00227
00228 int milliseconds_to_sleep = rando.inclusive(200, 828);
00229 portable::sleep_ms(milliseconds_to_sleep);
00230
00231
00232
00233
00234
00235
00236
00237 }
00238 LOG("exiting checker.");
00239 safe_add(global_data.thread_count, -1);
00240 }
00241
00243
00244 #undef LOG
00245 #ifdef DEBUG_RW_LOCK
00246 #define LOG(to_print) log(timestamp(true) + istring(to_print))
00247 #else
00248 #define LOG(to_print) {}
00249 #endif
00250
00251 void test_rw_lock::add_thread(ithread *to_add)
00252 {
00253 auto_synchronizer l(_list_lock);
00254 _threads += to_add;
00255 to_add->start(NIL);
00256 }
00257
00258 int test_rw_lock::execute()
00259 {
00260 log(""); log(""); log("");
00261 LOG("starting test.");
00262 log("testing in progress... please hang on.");
00263
00264 _periodic.start(NIL);
00265
00266
00267 for (int i = 0; i < NUMBER_OF_CHECKERS; i++)
00268 _threads += new checker_thread(*this);
00269
00270 while (time_stamp() < global_data.when_to_exit) {
00271
00272 portable::sleep_ms(42);
00273 }
00274
00275 global_data.exit_now = true;
00276
00277
00278 LOG("now exiting from all threads...");
00279 while (global_data.thread_count > 0) { portable::sleep_ms(0); }
00280 LOG("done exiting from all threads.");
00281
00282 LOG("ending test.");
00283 _periodic.stop();
00284 log("test completed.");
00285
00286 guards::alert_message("reader_writer_lock:: works for those functions tested.");
00287 return 0;
00288 }
00289
00291
00292 int main(int formal(argc), char *formal(argv)[])
00293 {
00294 test_rw_lock tester;
00295 return tester.execute();
00296 }
00297