t_timer_driver.cpp

Go to the documentation of this file.
00001 /*****************************************************************************\
00002 *                                                                             *
00003 *  Name   : t_timer_driver                                                    *
00004 *  Author : Chris Koeritz                                                     *
00005 *                                                                             *
00006 *  Purpose:                                                                   *
00007 *                                                                             *
00008 *    Tests the timer driver class from the operating system library.          *
00009 *                                                                             *
00010 *******************************************************************************
00011 * Copyright (c) 2005-$now By Author.  This program is free software; you can  *
00012 * redistribute it and/or modify it under the terms of the GNU General Public  *
00013 * License as published by the Free Software Foundation; either version 2 of   *
00014 * the License or (at your option) any later version.  This is online at:      *
00015 *     http://www.fsf.org/copyleft/gpl.html                                    *
00016 * Please send any updates to: fred@gruntose.com                               *
00017 \*****************************************************************************/
00018 
00019 #include <basis/chaos.h>
00020 #include <basis/function.h>
00021 #include <basis/guards.h>
00022 #include <basis/istring.h>
00023 #include <basis/log_base.h>
00024 #include <basis/set.cpp>
00025 #include <data_struct/unique_id.h>
00026 #include <mechanisms/ithread.h>
00027 #include <mechanisms/thread_cabinet.h>
00028 #include <mechanisms/time_stamp.h>
00029 #include <opsystem/application_shell.h>
00030 #include <opsystem/event_extensions.h>
00031 #include <loggers/file_logger.h>
00032 #include <data_struct/static_memory_gremlin.h>
00033 #include <opsystem/timer_driver.h>
00034 
00035 #define LOG(s) STAMPED_EMERGENCY_LOG(program_wide_logger(), s)
00036 
00037 const int TEST_DURATION = 3 * MINUTE_ms;
00038 
00039 const int MAX_THREADS = 120;
00040 
00042 
00043 class timer_driver_tester : public application_shell
00044 {
00045 public:
00046   timer_driver_tester()
00047       : application_shell(static_class_name()), _in_progress(false) {}
00048   IMPLEMENT_CLASS_NAME("timer_driver_tester");
00049   virtual ~timer_driver_tester() {}
00050 
00051   int execute();
00052 
00053   thread_cabinet &threads() { return _threads; }
00054 
00055   bool in_progress() const { return _in_progress; }
00056     // returns true if activity is currently occurring on the main thread.
00057     // we don't expect this activity to be interrupted by timer events.
00058 
00059 private:
00060   bool _in_progress;
00061     // simple flag to check when a timer hits.  if this is true, then a timer
00062     // hit while we were doing actual functional operations, rather than
00063     // just waiting in a sleep.
00064   thread_cabinet _threads;  // storage for our time_stamp testing threads.
00065 };
00066 
00068 
00069 class timer_test_thread : public ithread
00070 {
00071 public:
00072   timer_test_thread(application_shell &parent)
00073       : ithread(parent.randomizer().inclusive(20, 480)), _parent(parent)
00074   { start(NIL); }
00075 
00076   IMPLEMENT_CLASS_NAME("timer_test_thread");
00077   void perform_activity(void *) {
00078     FUNCDEF("perform_activity");
00079     if (time_stamp() < _started)
00080       deadly_error(class_name(), func, "start time is before current time.");
00081     if (time_stamp() < _last) 
00082       deadly_error(class_name(), func, "last check is before current time.");
00083     _last.reset();  // set the last time to right now.
00084     time_stamp ted;
00085     time_stamp jed;
00086     if (ted > jed)
00087       deadly_error(class_name(), func, "jed is less than test.");
00088   }
00089 
00090 private:
00091   application_shell &_parent;
00092   time_stamp _started;
00093   time_stamp _last;
00094 };
00095 
00097 
00098 class my_timer_handler : public timed_object
00099 {
00100 public:
00101   my_timer_handler(timer_driver_tester &parent, int id) : _id(id), _parent(parent) {}
00102   virtual ~my_timer_handler() {}
00103   IMPLEMENT_CLASS_NAME("my_timer_handler");
00104 
00105   virtual void handle_timer_callback() {
00106     FUNCDEF("handle_timer_callback");
00107     if (_parent.in_progress())
00108       LOG("saw in progress flag set to true!  we interrupted real "
00109           "ops, not just sleep!");
00110     LOG(isprintf("timer%d hit.", _id));
00111     timer_test_thread *new_thread = new timer_test_thread(_parent);
00112     unique_int id = _parent.threads().add_thread(new_thread, false, NIL);
00113       // the test thread auto-starts, so we don't let the cabinet start it.
00114     if (!id)
00115       deadly_error(class_name(), func, "failed to start a new thread.");
00116 
00117     if (_parent.threads().threads() > MAX_THREADS) {
00118       int gone_index = _parent.randomizer().inclusive(0, _parent.threads().threads() - 1);
00119       unique_int gone_thread = _parent.threads().thread_ids()[gone_index];
00120       _parent.threads().cancel_thread(gone_thread);
00121       portable::sleep_ms(100);  // allow thread to start up.
00122     }
00123     _parent.threads().clean_debris();  // toss any dead threads.
00124 
00125     LOG(isprintf("%d threads checking time_stamp.", _parent.threads().threads()));
00126   }
00127 
00128 private:
00129   int _id;
00130   timer_driver_tester &_parent;
00131 };
00132 
00134 
00135 #define CREATE_TIMER(name, id, dur) \
00136   my_timer_handler name(*this, id); \
00137   program_wide_timer().set_timer(dur, &name); \
00138   LOG(istring("timer ") + #name + " hitting every " \
00139       + #dur + " ms")
00140 
00141 #define ZAP_TIMER(name) \
00142   program_wide_timer().zap_timer(&name)
00143 
00144 int timer_driver_tester::execute()
00145 {
00146   SET_DEFAULT_COMBO_LOGGER;
00147 
00148   CREATE_TIMER(timer1, 1, 500);
00149 //  CREATE_TIMER(timer1, 1, 10);
00150   CREATE_TIMER(timer2, 2, SECOND_ms);
00151   CREATE_TIMER(timer3, 3, 3 * SECOND_ms);
00152   CREATE_TIMER(timer4, 4, 8 * SECOND_ms);
00153   CREATE_TIMER(timer5, 5, 12 * SECOND_ms);
00154 
00155   LOG("pausing for a while...");
00156   time_stamp when_done(TEST_DURATION);
00157   while (time_stamp() < when_done) {
00158     _in_progress = true;
00159     // do some various calculations in here and see if we're interrupted
00160     // during them.  it's one thing to be interrupted in the middle of a
00161     // sleep, but it's much different to be interrupted in mid operation.
00162     int scrob = 1;
00163     for (int i = 1; i < 50; i++) {
00164       scrob *= i;
00165     }
00166     _in_progress = false;    
00167 #ifdef __UNIX__
00168     portable::sleep_ms(100);
00169 #else
00170     bool okay = event_extensions::poll();
00171     if (!okay) break;
00172 #endif
00173   }
00174 
00175   guards::alert_message("timer_driver:: works for all functions tested (if messages seem appropriate).");
00176 
00177   ZAP_TIMER(timer1);
00178   ZAP_TIMER(timer2);
00179   ZAP_TIMER(timer3);
00180   ZAP_TIMER(timer4);
00181   ZAP_TIMER(timer5);
00182 
00183   return 0;
00184 }
00185 
00187 
00188 HOOPLE_MAIN(timer_driver_tester, )
00189 

Generated on Fri Nov 28 04:29:39 2008 for HOOPLE Libraries by  doxygen 1.5.1