t_scheduler.cpp

Go to the documentation of this file.
00001 /*****************************************************************************\
00002 *                                                                             *
00003 *  Name   : test_scheduler                                                    *
00004 *  Author : Chris Koeritz                                                     *
00005 *                                                                             *
00006 *******************************************************************************
00007 * Copyright (c) 2001-$now By Author.  This program is free software; you can  *
00008 * redistribute it and/or modify it under the terms of the GNU General Public  *
00009 * License as published by the Free Software Foundation; either version 2 of   *
00010 * the License or (at your option) any later version.  This is online at:      *
00011 *     http://www.fsf.org/copyleft/gpl.html                                    *
00012 * Please send any updates to: fred@gruntose.com                               *
00013 \*****************************************************************************/
00014 
00015 #include <basis/chaos.h>
00016 #include <basis/function.h>
00017 #include <basis/guards.h>
00018 #include <basis/istring.h>
00019 #include <basis/mutex.h>
00020 #include <basis/set.cpp>
00021 #include <data_struct/amorph.cpp>
00022 #include <mechanisms/ithread.h>
00023 #include <mechanisms/safe_roller.h>
00024 #include <mechanisms/time_stamp.h>
00025 #include <opsystem/application_shell.h>
00026 #include <loggers/console_logger.h>
00027 #include <loggers/file_logger.h>
00028 #include <opsystem/path_configuration.h>
00029 #include <data_struct/static_memory_gremlin.h>
00030 #include <scheduling/schedulable.h>
00031 #include <scheduling/schedule_actor.h>
00032 #include <scheduling/scheduler.h>
00033 
00034 const int DEFAULT_FISH = 64;
00035   // the number of threads, by default.
00036 
00037 const int DEFAULT_RUN_TIME = 142 * SECOND_ms;
00038   // the length of time to run the program.
00039 
00040 int concurrent_biters = 0;
00041   // the number of threads that are currently active.
00042 
00043 // thresholds for thread sleep.
00044 const int LOWER_SLEEP = 0;
00045 const int HIGHER_SLEEP = 82;
00046 
00047 #define LOG(to_print) CLASS_EMERGENCY_LOG(program_wide_logger(), to_print)
00048 
00049 chaos rando;
00050 
00051 safe_roller &identor() { static safe_roller _ids; return _ids; }
00052 
00054 
00055 // this class does something...
00056 
00057 class lotus_blossom : public schedulable
00058 {
00059 public:
00060 //add some record keeping?
00061   lotus_blossom(const scheduling_id &sched_id, int actor_id,
00062           const periodicity &when_to_schedule)
00063   : schedulable(sched_id, actor_id, when_to_schedule) {}
00064 
00065   virtual istring schedulable_text_form() const {
00066     return istring("lotus_blossom");
00067   }
00068 };
00069 
00071 
00072 // the actor thread is the base class for our test threads.
00073 
00074 class actor_thread : public ithread, public schedule_actor
00075 {
00076 public:
00077   int _uid;  // the unique id for this thread.
00078   int_set _scheduled;  // these items are in the scheduler, we think.
00079 
00080   actor_thread(int uid) : ithread(0), schedule_actor(), _uid(uid),
00081       _scheduled() {}
00082 
00083   IMPLEMENT_CLASS_NAME("actor_thread");
00084 
00085   // inherited requirements.
00086   virtual int actor_id() const { return _uid; }
00087   virtual outcome preprocess(schedulable &to_process);
00088   virtual outcome expiration(schedulable &to_expire);
00089   virtual void postprocess(schedulable &to_process);
00090 };
00091 
00092 outcome actor_thread::preprocess(schedulable &formal(to_process))
00093 {
00094 //pick a random response.
00095 // most of the time, allow it to be scheduled.
00096 return schedule_actor::OKAY;
00097 }
00098 
00099 outcome actor_thread::expiration(schedulable &formal(to_expire))
00100 {
00101 //randomly decide whether to keep or not.
00102 return schedule_actor::OKAY;
00103 }
00104 
00105 void actor_thread::postprocess(schedulable &formal(to_process))
00106 {
00107 //chuck this item out of the list of scheds in our thread.
00108 
00109 //or maybe tell it to be postponed from deletion.
00110 //later the thread can try to restart it.
00111 // like move it to a "postponed" id list.
00112 }
00113 
00115 
00116 class land_shark : public actor_thread
00117 {
00118 public:
00119   land_shark(int uid) : actor_thread(uid)
00120   {
00121     FUNCDEF("constructor");
00122     safe_add(concurrent_biters, 1);
00123 LOG(istring(istring::SPRINTF, "starting %d", _uid));
00124   }
00125 
00126   virtual ~land_shark() {
00127     FUNCDEF("destructor");
00128     safe_add(concurrent_biters, -1); 
00129 LOG(istring(istring::SPRINTF, "closing %d", _uid));
00130   }
00131 
00132   IMPLEMENT_CLASS_NAME("land_shark");
00133 
00134   virtual outcome activate(schedulable &to_activate, int time_allowed);
00135     // a schedule item wants us to play with it now.  how cute.
00136 
00137   void perform_activity(void *) {
00138     FUNCDEF("perform_activity");
00139 LOG(istring(istring::SPRINTF, "performing %d", _uid));
00140 //uhhh?
00141     portable::sleep_ms(rando.inclusive(LOWER_SLEEP, HIGHER_SLEEP));
00142   }
00143 };
00144 
00145 outcome land_shark::activate(schedulable &formal(to_activate), int formal(time_allowed))
00146 {
00147 return schedule_actor::OKAY;
00148 }
00149 
00151 
00152 class minnow : public actor_thread
00153 {
00154 public:
00155   minnow(int uid) : actor_thread(uid)
00156   {
00157     FUNCDEF("constructor");
00158     safe_add(concurrent_biters, 1);
00159 LOG(istring(istring::SPRINTF, "starting %d", _uid));
00160   }
00161 
00162   virtual ~minnow() {
00163     FUNCDEF("destructor");
00164     safe_add(concurrent_biters, -1);
00165 LOG(istring(istring::SPRINTF, "closing %d", _uid));
00166   }
00167 
00168   IMPLEMENT_CLASS_NAME("minnow");
00169 
00170   virtual outcome activate(schedulable &to_activate, int time_allowed);
00171     // process the schedule item.
00172 
00173   void perform_activity(void *formal(data)) {
00174     FUNCDEF("perform_activity");
00175 LOG(istring(istring::SPRINTF, "performing %d", _uid));
00176 //what are we doing with these exactly?
00177   }
00178 };
00179 
00180 outcome minnow::activate(schedulable &formal(to_activate), int formal(time_allowed))
00181 {
00182 return schedule_actor::OKAY;
00183 }
00184 
00186 
00187 class thread_mapper : public actor_mapper
00188 {
00189 public:
00190   virtual ~thread_mapper() {}
00191 
00192   void add(actor_thread *to_add);
00193     // puts a new thread into the list.
00194 
00195   bool zap(int id);
00196     // zaps a thread in the list.  true is returned if it was there.
00197 
00198   actor_thread *lock_thread(int id);
00199     // this turns an id into a thread pointer, locking the list while the
00200     // pointer is out.
00201 
00202   void unlock_thread(actor_thread * &to_put);
00203     // it is crucial that lock_thread is always followed by unlock_thread and
00204     // that no more than one lock_thread is active at a time.
00205 
00206   void stop_all();
00207     // stops all threads and resets the list.
00208 
00209   // inherited responsibilities.
00210   virtual actor_mapping *open_actor(int actor_id);
00211   virtual void close_actor(actor_mapping *to_close);
00212 
00213 private:
00214   mutex _protector;
00215   amorph<actor_thread> _thread_list;
00216 };
00217 
00218 void thread_mapper::add(actor_thread *to_add)
00219 {
00220   auto_synchronizer l(_protector);
00221   _thread_list.append(to_add);
00222 }
00223 
00224 bool thread_mapper::zap(int id)
00225 {
00226   auto_synchronizer l(_protector);
00227   for (int i = 0; i < _thread_list.elements(); i++)
00228     if (_thread_list.borrow(i)->_uid == id) {
00229       _thread_list.zap(i, i);
00230       return true;
00231     }
00232   return false;
00233 }
00234 
00235 actor_thread *thread_mapper::lock_thread(int id)
00236 {
00237   _protector.lock();
00238   for (int i = 0; i < _thread_list.elements(); i++)
00239     if (_thread_list.borrow(i)->_uid == id) return _thread_list.borrow(i);
00240   // didn't find it so no lock.
00241   _protector.unlock();
00242   return NIL;
00243 }
00244 
00245 void thread_mapper::unlock_thread(actor_thread * &to_put)
00246 {
00247   if (!to_put) return;  // do nothing; they didn't get a lock.
00248   to_put = NIL;
00249   _protector.unlock();
00250 }
00251 
00252 void thread_mapper::stop_all()
00253 {
00254   for (int i = _thread_list.elements() - 1; i >= 0; i--) {
00255     _thread_list.borrow(i)->stop();
00256     _thread_list.zap(i, i);
00257   }
00258 }
00259 
00260 actor_mapping *thread_mapper::open_actor(int actor_id)
00261 {
00262   actor_thread *at = lock_thread(actor_id); 
00263   if (!at) return NIL;
00264   return new actor_mapping(*at);
00265 }
00266 
00267 void thread_mapper::close_actor(actor_mapping *to_close)
00268 {
00269   if (!to_close) return;  // not any good.
00270   actor_thread *real_actor = dynamic_cast<actor_thread *>(&to_close->_actor);
00271   unlock_thread(real_actor);
00272   WHACK(to_close);
00273 }
00274 
00276 
00277 class test_scheduler : public application_shell
00278 {
00279 public:
00280   test_scheduler() : application_shell(class_name()) {}
00281   IMPLEMENT_CLASS_NAME("t_scheduler");
00282   virtual int execute();
00283 };
00284 
00285 int test_scheduler::execute()
00286 {
00287   FUNCDEF("main");
00288   // force these to be created before threads are started.
00289 //hmmm: use safe static.
00290   identor();
00291 
00292   thread_mapper mapper;  // our thread management.
00293 
00294 //hmmm: create scheduler
00295 
00296   LOG("starting addition of threads...");
00297 
00298   for (int i = 0; i < DEFAULT_FISH; i++) {
00299     actor_thread *t = NIL;
00300     int id = identor().next_id();
00301     if (i % 2)
00302       t = new land_shark(id);
00303     else
00304       t = new minnow(id);
00305     mapper.add(t);
00306     actor_thread *q = mapper.lock_thread(id);
00307     if (!q || (q != t))
00308       deadly_error(class_name(), func, "amorph has incorrect pointer!");
00309     t = NIL;  // reset since this is now owned by mapper.
00310     // start the thread we added.
00311     q->start(NIL);
00312     mapper.unlock_thread(q);
00313   }
00314 
00315   time_stamp when_to_leave(DEFAULT_RUN_TIME);
00316   while (when_to_leave > time_stamp()) {
00317 
00318     portable::sleep_ms(rando.inclusive(LOWER_SLEEP, HIGHER_SLEEP));
00319   }
00320 
00321   LOG("test done; now exiting from all threads...");
00322 
00323 //hmmm: stop scheduler.
00324 
00325   // stop all the threads.
00326   mapper.stop_all();
00327 
00328   if (concurrent_biters != 0)
00329     deadly_error(class_name(), func, "threads were still active supposedly!");
00330 
00331   LOG("done exiting from all threads.");
00332 
00333   guards::alert_message("scheduler:: works for all functions tested.");
00334   return 0;
00335 }
00336 
00337 HOOPLE_MAIN(test_scheduler, )
00338 

Generated on Fri Nov 21 04:30:15 2008 for HOOPLE Libraries by  doxygen 1.5.1