// -*- C++ -*- // EPOS-- Thread Abstraction Implementation // 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. #include #include __BEGIN_SYS // Class attributes Thread * volatile Thread::_running; Thread::Queue Thread::_ready; Thread::Queue Thread::_suspended; // Methods /* * EX1: * Join foi alterado de forma que ele obedecesse aos parametros dados * em ``traits.h'' (linha 195 desta versão). * * Trata da propriedade busy_waiting que vai determinar qual o * comportamento da espera. * * Relativo ao que se espera do trabalho: * * - condicional para saber se busy_waiting é requisitado * - chamada a wait() ao invez * de yield para quando busy_waiting nao * for requisitado * */ int Thread::join() { db(TRC) << "Thread::join(this=" << this << ",state=" << _state << ")\n"; while(_state != FINISHING){ if(Traits::busy_waiting){ yield(); } else { wait(); // <- EX1:isso foi adicionado!! veja Thread::wait() } } return *((int *)_stack); } void Thread::pass() { db(TRC) << "Thread::pass(this=" << this << ")\n"; if(Traits::active_scheduler) CPU::int_disable(); Thread * old = _running; old->_state = READY; _ready.insert(&old->_link, old->_priority); _ready.remove(this); _state = RUNNING; _running = this; // old->_context->save(); // can be used to force an update db(INF) << "old={" << old << "," << *old->_context << "}\n"; db(INF) << "new={" << _running << "," << *_running->_context << "}\n"; CPU::switch_context(&old->_context, _context); if(Traits::active_scheduler) CPU::int_enable(); } void Thread::suspend() { db(TRC) << "Thread::suspend(this=" << this << ")\n"; if(Traits::active_scheduler) CPU::int_disable(); if(_running != this) _ready.remove(this); _state = SUSPENDED; _suspended.insert(&_link,_priority); _running = _ready.remove()->object(); _running->_state = RUNNING; db(INF) << "old={" << this << "," << *_context << "}\n"; db(INF) << "new={" << _running << "," << *_running->_context << "}\n"; CPU::switch_context(&_context, _running->_context); if(Traits::active_scheduler) CPU::int_enable(); } void Thread::resume() { db(TRC) << "Thread::resume(this=" << this << ")\n"; if(Traits::active_scheduler) CPU::int_disable(); _suspended.remove(this); _state = READY; _ready.insert(&_link,_priority); if(Traits::active_scheduler) CPU::int_enable(); } void Thread::yield() { db(TRC) << "Thread::yield()\n"; if(Traits::active_scheduler) CPU::int_disable(); if(!_ready.empty()) { Thread * old = _running; old->_state = READY; _ready.insert(&old->_link, old->_priority); _running = _ready.remove()->object(); _running->_state = RUNNING; // old->_context->save(); // can be used to force an update db(INF) << "old={" << old << "," << *old->_context << "}\n"; db(INF) << "new={" << _running << "," << *_running->_context << "}\n"; CPU::switch_context(&old->_context, _running->_context); } if(Traits::active_scheduler) CPU::int_enable(); } void Thread::exit(int status) { db(TRC) << "Thread::exit(status=" << status << ")\n"; if(!Traits::active_scheduler) CPU::int_disable(); if(!Traits::busy_waiting){ _running->notify(); // EX1: Ok, estou para sair. Sai TODO mundo. Ver Thread::notify() } if(Traits::active_scheduler) CPU::int_disable(); Thread * old = _running; old->_state = FINISHING; *((int *)(void *)old->_stack) = status; _running = _ready.remove()->object(); _running->_state = RUNNING; // old->_context->save(); // can be used to force an update db(INF) << "old={" << old << "," << *old->_context << "}\n"; db(INF) << "new={" << _running << "," << *_running->_context << "}\n"; CPU::switch_context(&old->_context, _running->_context); if(Traits::active_scheduler) CPU::int_enable(); } /* * Ex2: * Thread::idle() * * Função que a thread idle executa. * Se não existe mais threads para serem escalonadas * na fila de ready, a thread idle ganha a cpu. * */ int Thread::idle() { db(TRC) << "Thread::idle()\n"; db(WRN) << "There are no runnable threads at the moment!\n"; db(WRN) << "Halting the CPU ...\n"; while(true){ //EX2 Fica em loop, halt na cpu para economizar energia db(WRN) << "Halting!\n"; CPU::halt(); } return 1; // nunca executa } /* * EX2: * Thread::wait() * * Correção feita por causa do conceito entregue em aula * Apenas 1 thread na espera de outra. */ void Thread::wait() { db(TRC) << "Thread("<< this <<")::wait(" << _running << " )::enter\n"; if(Traits::active_scheduler) CPU::int_disable(); // EX1: Salvaguarda contra auto-adição if (this == _running){ db(WRN) << "Cannot wait for myself!!"; return; } /* * EX1: * Registra a dependencia. * Acreditamos que isso é melhor do que manter um dicionário. * VER: destrutor Thread::~Thread() */ _waiting = _running; _waiting->_awaker= this; _waiting->suspend(); // the execution stops here _waiting->_awaker = 0; if(Traits::active_scheduler) CPU::int_enable(); db(TRC) << "Thread("<< this <<")::wait(" << _running << " )::exit\n"; } /* * EX2: * Thread::notify() * * Correção feita por causa do conceito entregue em aula * Apenas 1 thread na espera de outra. */ void Thread::notify() { db(TRC) << "Thread[this=" << this << "]::notify():enter\n"; if(Traits::active_scheduler) CPU::int_disable(); if (_waiting) { _waiting->resume(); _waiting = 0; } if(Traits::active_scheduler) CPU::int_enable(); } /* * EX2: * Thread::sleep(Queue) * * Nesse método, a fila passada é usada para colocar o runnning * atual. O método assinala o estado de running para SLEEP. * * A primeira thread da fila é, então, colocada em modo running * para continuar a execução. * * As interrupções são desabilitadas para evitar condições de * corrida injusta. Após o procedimento elas são reativadas. */ void Thread::sleep(FIFOQueue* q) { if(Traits::active_scheduler) CPU::int_disable(); // desabilita interrupções db(TRC) << "Thread("<< _running <<")::sleep(" << q << " )::enter\n"; Thread *t = _running; // ponteiro para a thread q estah rodando t->_sleeping = q; // faz com q a fila de running aponte para a fila passada por parametro t->_state = SLEEPING; // muda o estado para SLEEPING q->insert(&t->_fifo_link); // insere na fila db(TRC) << "Thread("<< _running <<")::sleep, _ready size:" << _ready.size() << "\n"; _running = _ready.remove()->object(); // escalonamento da fila de ready _running->_state = RUNNING; // muda o estado para RUNNING db(TRC) << "Thread("<< t <<")::sleep(" << q << " )::sleeping\n"; CPU::switch_context(&t->_context, _running->_context); // bota pra rodar db(TRC) << "Thread("<< _running <<")::sleep(" << q << " )::exit\n"; if(Traits::active_scheduler) CPU::int_enable(); // reabilita interrupções } /* * EX2: * Thread::wakeup(Queue) * * Esse método é usado para acordar a thread q estah na primeira * posição da fila. A thread eh posta na fila de ready para ser * rescalonada. * * As interrupções são desabilitadas para garantir corrição de corrida * justa. * */ void Thread::wakeup(FIFOQueue* q) { if(Traits::active_scheduler) CPU::int_disable(); // desabilita interrupções if (!q->empty()) { Thread* t = q->remove()->object(); // remove a primeira threa da fila db(TRC) << "Thread("<< t <<")::wakeup(" << q << " )::enter\n"; t->_sleeping = 0; // reseta a fila da thread removida t->_state = READY; // coloca seu estado em READY _ready.insert(&t->_link, t->_priority); // insere na fila de ready para ser escalonada db(TRC) << "Thread("<< t <<")::wakeup(" << q << " )::exit\n"; } if(Traits::active_scheduler) CPU::int_enable(); // reabilita interrupções } /* * EX2: * Thread::wakeup_all(Queue) * * Esse método varre a fila passada como parametro e coloca * as threads em ordem para serem rescalonadas. Isso garante * o principio da justiça. * * As interrupções são desabilitadas para evitar condição de * corrida desleal. * */ void Thread::wakeup_all(FIFOQueue* q) { if(Traits::active_scheduler) CPU::int_disable(); // desabilita interrupções db(TRC) << "Thread::wakeup(" << q << " )::enter\n"; db(TRC) << "before loop: q->size() = " << q->size() << "\n"; while (!q->empty()) { // enquanto a fila naum estiver vazia Thread* t = q->remove()->object(); // remove da cabeça t->_sleeping = 0; // reseta a fila da thread t->_state = READY; // seta estado para READY _ready.insert(&t->_link, t->_priority); // insere na fila de READY para ser escalonada } db(TRC) << "after loop: q->size() = " << q->size() << "\n"; db(TRC) << "Thread::wakeup(" << q << " )::exit\n"; if(Traits::active_scheduler) CPU::int_enable(); // reabilita interrupções } __END_SYS