// -*- C++ -*- // EPOS-- Thread Abstraction Declarations // This work is licensed under the Creative Commons // Attribution-NonCommercial-NoDerivs License. To view a copy of this license, // visit http://creativecommons.org/licenses/by-nc-nd/2.0/ or send a letter to // Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA. #ifndef __thread_h #define __thread_h #include #include #include #include #include #include __BEGIN_SYS class Thread { private: typedef Traits Traits; static const Type_Id TYPE = Type::TYPE; typedef Queue FIFOQueue; typedef Ordered_Queue Queue; static const unsigned int STACK_SIZE = __SYS(Traits)::APPLICATION_STACK_SIZE; typedef CPU::Log_Addr Log_Addr; typedef CPU::Context Context; public: enum Self {SELF}; typedef short State; enum { RUNNING, READY, SUSPENDED, SLEEPING,//EX2: Novo estado. FINISHING }; typedef short Priority; enum { HIGH = 0, NORMAL = 15, LOW = 31, IDLE = 47 }; public: // The int left on the stack between thread's arguments and its context // is due to the fact that the thread's function believes it's a normal // function that will be invoked with a call, which pushes the return // address on the stack Thread(int (* entry)(), const State & state = READY, const Priority & priority = NORMAL, unsigned int stack_size = STACK_SIZE) : _stack(malloc(stack_size)), _context(new (_stack + stack_size - sizeof(int) - sizeof(Context)) Context(entry)), _state(state), _priority(priority), _link(this), _fifo_link(this), _alarm(this, &Thread::resume) { header(entry, stack_size); Log_Addr sp = _stack + stack_size; sp -= sizeof(int); *static_cast(sp) = reinterpret_cast(&implicit_exit); body(); } template Thread(int (* entry)(T1 a1), T1 a1, const State & state = READY, const Priority & priority = NORMAL, unsigned int stack_size = STACK_SIZE) : _stack(malloc(stack_size)), _context(new (_stack + stack_size - sizeof(T1) - sizeof(int) - sizeof(Context)) Context(entry)), _state(state), _priority(priority), _link(this), _fifo_link(this), _alarm(this, &Thread::resume) { header(entry, stack_size); Log_Addr sp = _stack + stack_size; sp -= sizeof(T1); *static_cast(sp) = a1; sp -= sizeof(int); *static_cast(sp) = reinterpret_cast(&implicit_exit); body(); } template Thread(int (* entry)(T1 a1, T2 a2), T1 a1, T2 a2, const State & state = READY, const Priority & priority = NORMAL, unsigned int stack_size = STACK_SIZE) : _stack(malloc(stack_size)), _context(new (_stack + stack_size - sizeof(T2) - sizeof(T1) - sizeof(int) - sizeof(Context)) Context(entry)), _state(state), _priority(priority), _link(this), _fifo_link(this), _alarm(this, &Thread::resume) { header(entry, stack_size); Log_Addr sp = _stack + stack_size; sp -= sizeof(T2); *static_cast(sp) = a2; sp -= sizeof(T1); *static_cast(sp) = a1; sp -= sizeof(int); *static_cast(sp) = reinterpret_cast(&implicit_exit); body(); } template Thread(int (* entry)(T1 a1, T2 a2, T3 a3), T1 a1, T2 a2, T3 a3, const State & state = READY, const Priority & priority = NORMAL, unsigned int stack_size = STACK_SIZE) : _stack(malloc(stack_size)), _context(new (_stack + stack_size - sizeof(T3) - sizeof(T2) - sizeof(T1) - sizeof(int) - sizeof(Context)) Context(entry)), _state(state), _priority(priority), _link(this), _fifo_link(this), _alarm(this, &Thread::resume) { header(entry, stack_size); Log_Addr sp = _stack + stack_size; sp -= sizeof(T3); *static_cast(sp) = a3; sp -= sizeof(T2); *static_cast(sp) = a2; sp -= sizeof(T1); *static_cast(sp) = a1; sp -= sizeof(int); *static_cast(sp) = reinterpret_cast(&implicit_exit); body(); } ~Thread() { _ready.remove(this); _suspended.remove(this); /* * EX1: * Em caso de Busy_waiting ... * * 1- notifique todo mundo. NOTA: Ver se isso (notify()) funciona * numa destruição inesperada, existem elementos esperando * retorno!!! * * 2- se remove da lista de espera de outra Thread e remove a * referecia * * EX2: * * Se a thread estiver na fila de sleepers, se remove para evitar * problemas com ponteiros. * */ if(!Traits::busy_waiting) { if(Traits::active_scheduler) CPU::int_disable(); if (_awaker){ _awaker->_waiting = 0; _awaker = 0; } if (_sleeping) { _sleeping->remove(this); _sleeping=0; } if(Traits::active_scheduler) CPU::int_enable(); } if (_state != FINISHING) { exit(-1); } free(_stack); } volatile const State & state() const { return _state; } volatile const Priority & priority() const { return _priority; } void priority(const Priority & priority); int join(); void pass(); void suspend(); void resume(); Alarm* alarm(){ // db(TRC) << "Thread::alarm()\n"; return &_alarm; } static void yield(); static void exit(int status = 0); static void sleep(FIFOQueue* q); //EX2: coloca _runnning na fila passada por parametro static void wakeup(FIFOQueue* q); //EX2: retira o primeiro da fila e bota pra rodar static void wakeup_all(FIFOQueue* q); //EX2: varre a fila e acorda todo mundo static Thread * volatile & running() { return _running; } static void running(Thread * r) { _running = r; } static int init(System_Info * si); private: void header(Log_Addr entry, unsigned int stack_size) { db(TRC) << "Thread(this=" << this << ",entry=" << (void *)entry << ",state=" << _state << ",priority=" << _priority << ",stack={b=" << _stack << ",s=" << stack_size << ",context={b=" << _context << "," << *_context << "})\n"; } void body() { if(Traits::active_scheduler) CPU::int_disable(); switch(_state) { case RUNNING: break; case SUSPENDED: _suspended.insert(&_link,_priority); break; default: _ready.insert(&_link,_priority); } if(Traits::active_scheduler) CPU::int_enable(); } // Coloca para _running dormir void wait(); // Acorda Threads em _waiting void notify(); static void implicit_exit() { exit(CPU::fr()); } static void reschedule() { yield(); } static int idle(); private: Log_Addr _stack; Context * volatile _context; volatile State _state; volatile Priority _priority; Queue::Element _link; FIFOQueue::Element _fifo_link; Alarm _alarm; Thread* _awaker; // EX1: Referencia para quem esta Thread está esperando Thread* _waiting; // EX1: Espera para esta Thread. FIFOQueue* _sleeping; // EX2: Referencia para a fila de espera. 1 fila por thread, afinal ela está esperando static Thread * volatile _running; static Queue _ready; static Queue _suspended; }; __END_SYS #endif