No que diz respeito às tarefas prontas para execução, estas são organizadas num
array das listas, onde o índice do array corresponde a uma certa prioridade e
cada lista é tratada como sendo FIFO. Ou seja, pode ser dito que as tarefas pron- tas para execução são organizadas numa estrutura, frequentemente denominada como estrutura multi-FIFO (Jeffrey Liu, Insop Song, 2007). Uma representação esquemática da referida estrutura de dados pode ser vista na Figura 4.5.
As tarefas que estão a espera de um evento temporal são guardadas na lista xDe-
layedTaskList ordenada pelo valor correspondente ao número de ticks. Esta, por
sua vez, é separada em duas listas idênticas: xDelayedTaskList1 e xDelayedTas-
kList2. Tal separação resulta de uma solução não trivial do fenómeno associado ao overflow do temporizador. Existe então apontador pxDelayedTaskList que aponta
para a lista que está atualmente em uso e um outro apontador pxOverflowDelayed-
TaskList que aponta para a lista que guarda as tarefas para quais ocorreu overflow
aquando a sua inserção. Esta última lista passará a ser a atual e vice-versa (os apontadores vão trocar das listas) quando ocorrer o overflow do temporizador. As outras três listas: xPendingReadyList, xTasksWaitingTermination e xSuspen-
EMPTY
EMPTY
...
Linked List of Tasks for each Priority
Priority
[MAX] [0] [1] [2] [MAX-1] [MAX-2] [3]Figura 4.5: Representação esquemática da lista multi-FIFO das tarefas prontas para execução
O escalonador possui e manuseia as listas de tarefas referidas acima, sobrando apenas um tipo de tarefas: tarefas bloqueadas a espera de um recurso de sincro- nização. Da mesma forma como no sistema operativo ADEOS, cada recurso de sincronização possui e manuseia uma própria lista de tarefas por este bloqueadas. Como já foi referido na secção 4.2.2, FreeRTOS implementa um vasto número de recursos da sincronização: filas (queue), semáforos binários, semáforos de conta- gem, semáforos recursivos, recursos da exclusão mutua (mutex). O mecanismo complexo associado ao recurso da sincronização denominado fila (queue) é im- plementado no ficheiro queue.c, sendo que os restantes recursos de sincronização derivam deste e são implementados como sendo casos particulares de uma fila.
4.2.4
Escalonamento
O escalonador do sistema operativo FreeRTOS possui dois modos de funciona- mento: escalonamento preemptivo baseado nas prioridades e escalonamento coo- perativo. O modo do escalonamento deve ser escolhido pelo utilizador através da definição obrigatória do parâmetro configUSE_PREEMPTION no ficheiro FreeR-
TOSConfig.h e é inalterável após compilação. Se o dito parâmetro for definido
com valor “1” o escalonamento preemptivo será usado, caso contrario, será usado escalonamento cooperativo. Algoritmo do escalonamento preemptivo baseado nas prioridades é relativamente simples e já foi discutido ao longo desta dissertação. Seguindo (Barry, 2009) este algoritmo pode ser resumido nos quatro pontos:
• Cada tarefa tem uma prioridade associada.
• Cada tarefa existe num dos estados (ver Figura 4.4).
• A qualquer momento apenas uma tarefa se encontra em execução (estado
Runnning).
• O escalonador escolha para execução sempre a tarefa mais prioritária das prontas para execução (cujo estado é Ready).
Da mesma forma como no caso do ADEOS, pode ser dito que estamos perante algoritmo fixed-priority preemptive scheduling, onde fixed-priority significa que as prioridades assinadas para as tarefas não são alteradas pelo kernel e que podem ser alteradas apenas a partir do contexto de execução de uma tarefa (esta última afirmação é inaplicável no caso do ADEOS, pois este não implementa função API que permita alteração da prioridade da tarefa após a sua criação). Como já foi referido na secção 4.2.2, FreeRTOS não impõe limitações na forma como priori- dades são assinadas às tarefas, permitindo que várias tarefas partilham a mesma prioridade. Quando ocorrer o consequente empate das prioridades, o escalonador resolve-o recorrendo à estratégia round-robin com time slice, fazendo com que as tarefas com a mesma prioridade partilham o acesso ao CPU ao executar alterna- damente. A duração do time slice é inversamente proporcional à frequência do
system tick que é definida através do parâmetro configTICK_RATE_HZ.
No caso da utilização do modo de escalonamento cooperativo, uma tarefa deixa o estado Running e ocorre uma comutação de contexto só se esta tarefa fica a espera de um evento (entra no estado Blocked) ou chama explicitamente a função API
taskYIELD() (ou acaba a sua existência com a chamada do vTaskDelete()). Sendo
assim, no modo cooperativo uma tarefa nunca é preemptida.
4.2.5
Pontos de escalonamento e Comutação de contexto
Ao contrário do caso do sistema operativo ADEOS, os pontos do escalonamento no FreeRTOS não consistem numa chamada explicita de uma rotina nos pontos
relevantes do código do kernel, mas sim baseiam-se na salvaguarda e restauro do contexto da tarefa aquando atendimento a um pedido de interrupção.
A explicação do mecanismo utilizado pode ser feita em termos genéricos mas, para tornar a descrição mais apelativa e informativa, esta será feita com base no exemplo do porting do FreeRTOS para o processador PPC405 presente no dispositivo FPGA da família Virtex4 do produtor Xilinx (FreeRTOS, b).
Recorrendo às macros definidas no BSP (board support package) gerado pelas fer- ramentas Xilinx aquando definição do SoC em causa, no ficheiro port.c as rotinas
vPortYield(), vPortTickISR() e vPortISRWrapper() são assinadas como sendo han- dlers (rotinas de atendimento) para os casos de exceção system call, interrupção
do temporizador programável e uma interrupção externa não crítica, respetiva- mente. As linhas do código que correspondem a afirmação anterior e que foram retiradas do código associado ao ficheiro portável port.c relativo ao porting para o processodor PPC405 podem ser encontradas na Listagem 4.12.
// ... X E x c _ R e g i s t e r H a n d l e r ( X E X C _ I D _ S Y S T E M _ C A L L , ( X E x c e p t i o n H a n d l e r ) v P o r t Y i e l d , (v o i d*) 0); // ... X E x c _ R e g i s t e r H a n d l e r ( X E X C _ I D _ P I T _ I N T , ( X E x c e p t i o n H a n d l e r ) v P o r t T i c k I S R , (v o i d*) 0); // ... X E x c _ R e g i s t e r H a n d l e r ( X E X C _ I D _ N O N _ C R I T I C A L _ I N T , ( X E x c e p t i o n H a n d l e r ) v P o r t I S R W r a p p e r , N U L L );
Listagem 4.12: Assinatura dos handlers das exceções/interrupções no porting para