00001 #include "scheduler.h"
00002 #include "thread.h"
00003 #include "system/config.h"
00004 #include "utility/queue.h"
00005 #include "utility/malloc.h"
00006 #include "cpu.h"
00007 #include "mmu.h"
00008 #include "alarm.h"
00009 #include "system/kmalloc.h"
00010 #include "scheduler_disabler.h"
00011
00012 __BEGIN_SYS
00013
00014 #define DEBUG_CONTEXT(__old) do { db<Thread>(INF) << "old={" << (__old) << "," \
00015 << *(__old)->_context << "}\n";\
00016 db<Thread>(INF) << "new={" << _running << "," \
00017 << *_running->_context << "}\n"; } while(0)
00018
00019
00020 Scheduler Scheduler::_instance;
00021
00027 struct ThreadComparator {
00031 inline ThreadComparator() {}
00032
00038 inline int operator()(const Thread* t1, const Thread* t2) const {
00039 int comparison = 0;
00040 comparison -= (t1->priority() < t2 ->priority());
00041 comparison += (t1->priority() > t2 ->priority());
00042
00043 return comparison;
00044 }
00045 };
00046
00047 inline void Scheduler::insertOnReady(Thread* thread) {
00048 thread->_state = Thread::READY;
00049
00050
00051 _readyP->pushBack(thread, ThreadComparator());
00052 db<Thread>(TRC) << "inserted thread address: " << thread << "\n";
00053
00054 }
00055
00056 static int dummyhalt() {
00057 while (true) Thread::idle();
00058 return 0;
00059 }
00060
00061 int Scheduler::init(System_Info * si) {
00062 db<Init>(TRC) << "Thread::init(entry="
00063 << (void *)si->lmm.app_entry << ")\n";
00064
00065 Scheduler::getInstance()._readyP = new ThreadCircVec();
00066 if(Traits<Thread>::active_scheduler)
00067 Alarm::master(Traits<Thread>::quantum, &Scheduler::schedule);
00068
00069 Scheduler::getInstance()._main = new(malloc(sizeof(Thread)))
00070 Thread(reinterpret_cast<int (*)()>(si->lmm.app_entry), Thread::RUNNING);
00071 Scheduler::getInstance()._running = Scheduler::getInstance()._main;
00072
00073 db<Thread>(TRC) << "IdleThread creation\n";
00074 new Thread(dummyhalt, Thread::READY, Thread::IDLE);
00075
00076 db<Thread>(TRC) << "AlarmThread creation\n";
00077 new Thread(&Alarm::alarmLoop);
00078
00079 db<Thread>(TRC) << "IdleThread created\n";
00080 Scheduler::getInstance()._running->_context->load();
00081
00082 return 0;
00083 }
00084
00085 void Scheduler::pass(Thread* thread) {
00086 db<Thread>(TRC) << "Thread::pass(this=" << thread << ")\n";
00087
00088 DISABLE_SCHED {
00089 Thread * old = &getRunning();
00090 insertOnReady(old);
00091
00092 thread->_state = Thread::RUNNING;
00093 _running = thread;
00094
00095 DEBUG_CONTEXT(old);
00096
00097 if (old != _running)
00098 CPU::switch_context(&old->_context, thread->_context);
00099 }
00100 }
00101
00102 void Scheduler::cacheThreadStack(CPU::Log_Addr stack) {
00103 db<Thread>(TRC) << "Thread::cachedThreadStack " << stack << "\n";
00104 DISABLE_SCHED {
00105 _stackCache.cache(stack);
00106 }
00107 db<Thread>(TRC) << "cache size " << _stackCache.size() << "\n";
00108
00109 }
00110
00111 CPU::Log_Addr Scheduler::getThreadStack(unsigned int size) {
00112 CPU::Log_Addr result;
00113
00114 db<Thread>(TRC) << "Thread::getThreadStack() ThreadStack size " << _stackCache.size() << "\n";
00115 DISABLE_SCHED {
00116 result = (_stackCache.size()) ? _stackCache.uncache() : CPU::Log_Addr(malloc(size));
00117 }
00118
00119 return result;
00120 }
00121
00122 inline Thread* Scheduler::getNext() {
00123 Thread* result = NULL;
00124
00125 if (!_readyP->isEmpty()) {
00126 result = _readyP->front();
00127 _readyP->popFront();
00128 }
00129
00130 db<Thread>(TRC) << "result: " << result << "\n";
00131
00132 return result;
00133 }
00134
00135 void Scheduler::yield() {
00136 db<Thread>(TRC) << "Thread::yield()\n";
00137
00138 DISABLE_SCHED {
00139 Thread* old = _running;
00140 Thread* next = getNext();
00141
00142 if (next == NULL) return;
00143
00144 insertOnReady(old);
00145
00146 _running = next;
00147 _running->_state = Thread::RUNNING;
00148
00149 db<Thread>(TRC) << "Threads priority [" << old->priority() << ", " << _running->priority() << "]\n";
00150
00151 DEBUG_CONTEXT(old);
00152
00153 CPU::switch_context(&old->_context, _running->_context);
00154 }
00155 }
00156
00157 void Scheduler::resume(Thread* thread) {
00158 db<Thread>(TRC) << "Thread::resume(this=" << thread << ")\n";
00159
00160 DISABLE_SCHED {
00161 if (thread->_state == Thread::SUSPENDED) {
00162 _suspended.remove(thread);
00163 insertOnReady(thread);
00164 }
00165 }
00166 }
00167
00168 void Scheduler::addThread(Thread* thread) {
00169 DISABLE_SCHED {
00170 switch(thread->state()) {
00171 case Thread::RUNNING:
00172 break;
00173 case Thread::SUSPENDED:
00174 _suspended.insert(&thread->_link);
00175 break;
00176 default:
00177 insertOnReady(thread);
00178 }
00179 }
00180 }
00181
00182 void Scheduler::exit(int status) {
00183 db<Thread>(TRC) << "Thread::exit(status=" << status << ")\n";
00184 if (_running == Scheduler::getInstance()._main) {
00185 DISABLE_SCHED {
00186 kout << "EPOS shutting down..." << "\n";
00187 CPU::shutdown();
00188 }
00189 }
00190
00191
00192 if(_running->_waitingThread) _running->_waitingThread->resume();
00193 _running->_state = Thread::FINISHING;
00194 _suspended.remove(_running);
00195
00196
00197 DISABLE_SCHED {
00198 Thread* old = _running;
00199 Thread* next = getNext();
00200
00201 if (next == NULL || (next->priority() > _running->priority())) return;
00202
00203 _running = next;
00204 _running->_state = Thread::RUNNING;
00205
00206 db<Thread>(TRC) << "Threads priority [" << old->priority() << ", " << _running->priority() << "]\n";
00207
00208 DEBUG_CONTEXT(old);
00209
00210 CPU::switch_context(&old->_context, _running->_context);
00211 }
00212 }
00213
00214 void Scheduler::exit(Thread* thread, int status) {
00215 DISABLE_SCHED {
00216 if (thread == &getRunning()) {
00217 exit(status);
00218 }
00219 else {
00220 thread->_state = Thread::FINISHING;
00221 _suspended.remove(thread);
00222 _readyP->remove(thread);
00223 if (thread->_waitingThread) thread->_waitingThread->resume();
00224 }
00225 }
00226 }
00227
00228 void Scheduler::suspend(Thread* thread) {
00229 db<Thread>(TRC) << "Thread::suspend(this=" << thread << ")\n";
00230
00231 DISABLE_SCHED {
00232 if (_running != thread)
00233 _readyP->remove(thread);
00234 thread->_state = Thread::SUSPENDED;
00235 _suspended.insert(&thread->_link);
00236
00237 if (thread == _running) {
00238 DISABLE_SCHED {
00239 Thread* old = _running;
00240 Thread* next = getNext();
00241
00242 if (next == NULL) return;
00243
00244 _running = next;
00245 _running->_state = Thread::RUNNING;
00246
00247 db<Thread>(TRC) << "Threads priority [" << old->priority() << ", " << _running->priority() << "]\n";
00248
00249 DEBUG_CONTEXT(old);
00250
00251 CPU::switch_context(&old->_context, _running->_context);
00252 }
00253 }
00254 }
00255 }
00256
00257
00258
00259 __END_SYS