00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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
00036
00037 const int DEFAULT_RUN_TIME = 142 * SECOND_ms;
00038
00039
00040 int concurrent_biters = 0;
00041
00042
00043
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
00056
00057 class lotus_blossom : public schedulable
00058 {
00059 public:
00060
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
00073
00074 class actor_thread : public ithread, public schedule_actor
00075 {
00076 public:
00077 int _uid;
00078 int_set _scheduled;
00079
00080 actor_thread(int uid) : ithread(0), schedule_actor(), _uid(uid),
00081 _scheduled() {}
00082
00083 IMPLEMENT_CLASS_NAME("actor_thread");
00084
00085
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
00095
00096 return schedule_actor::OKAY;
00097 }
00098
00099 outcome actor_thread::expiration(schedulable &formal(to_expire))
00100 {
00101
00102 return schedule_actor::OKAY;
00103 }
00104
00105 void actor_thread::postprocess(schedulable &formal(to_process))
00106 {
00107
00108
00109
00110
00111
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
00136
00137 void perform_activity(void *) {
00138 FUNCDEF("perform_activity");
00139 LOG(istring(istring::SPRINTF, "performing %d", _uid));
00140
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
00172
00173 void perform_activity(void *formal(data)) {
00174 FUNCDEF("perform_activity");
00175 LOG(istring(istring::SPRINTF, "performing %d", _uid));
00176
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
00194
00195 bool zap(int id);
00196
00197
00198 actor_thread *lock_thread(int id);
00199
00200
00201
00202 void unlock_thread(actor_thread * &to_put);
00203
00204
00205
00206 void stop_all();
00207
00208
00209
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
00241 _protector.unlock();
00242 return NIL;
00243 }
00244
00245 void thread_mapper::unlock_thread(actor_thread * &to_put)
00246 {
00247 if (!to_put) return;
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;
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
00289
00290 identor();
00291
00292 thread_mapper mapper;
00293
00294
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;
00310
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
00324
00325
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