7 Sistemas operativos de tempo real
Os sistemas operativos de tempo real têm como objectivo garantir que o sistema tenha uma resposta a um acontecimento externo dentro de um intervalo de tempo limitado e previamente especificado.
Tal já não é garantido por um sistema operativo de tempo partilhado (por vezes também chamado de tempo virtual), onde o que se pretende é obter um bom tempo de resposta em termos médio, embora não previsível.
7.1 Modelo do núcleo
Qualquer núcleo de sistema operativo multi-tarefa deve disponibilizar 3 funções:
• Escalonamento de processos ou tarefas (Scheduling) determina qual a tarefa seguinte que tomará conta do CPU (será executada)
• Lançamento ou despacho de processos ou tarefas (Dispatching) Faz a comutação de contexto e outras operações necessárias para retirar uma tarefa de execução e substituir por outra.
• Comunicação (e sincronização) entre processos ou tarefas
Quando o núcleo é referido, normalmente está-se a referir à menor parte do sistema operativo que disponibiliza estas funções. Mas um sistema operativo pode ser representado por camadas de abstracção desde o hardware até ao interface com as aplicações.
Dependendo das funções que são disponibilizadas, pode-se ter:
• Um nano-kernel disponibiliza apenas o dispatching e a gestão de interrupções.
• Um micro-kernel, adiciona o escalonamento das tarefas, de modo que se têm uma gestão de processos completa, onde a máquina física é multiplexada, de modo que cada processo pode ser visto como uma máquina virtual que executa um programa.
• Quando é disponibilizada a comunicação entre tarefas e a sua sincronização têm-se um kernel ou núcleo.
• Um executivo já disponibiliza também um Sub-sistema de entradas/saídas (E/S) e um
Sub-sistema de ficheiros.
• Finalmente um sistema operativo, disponibiliza também um interpretador de comandos ou shell, e um interface para que as aplicações possam aceder a funções de sistema (API). Na realidade esta API costuma existir sempre entre o núcleo, qualquer que este seja, e a shell ou outra aplicação. Pode no entanto em sistemas pequenos, fazer parte de um compilador (uma biblioteca) que gere aplicações para o sistema em causa.
Fig. 7-1: Camadas de um sistema operativo
Por vezes é distinguida mais uma camada no núcleo, responsável pela gestão de memória física e / ou virtual, entre a comunicação e sincronização de tarefas e a gestão de processos.
Se bem que hoje em dia sejam comuns os sistemas operativos multi-tarefa e multi-utilizador existem outros tipos de sistemas operativos, que podem ser utilizados para executar aplicações de tempo real. A próxima secção irá abordar estes vários tipos sendo os sistemas operativos multi-tarefa e multi -utilizador tratados numa secção posterior.
Controlo de processos (Interrupções, dispatching)
Nano-Kernel Escalonamento de tarefas
Micro-Kernel Comunicação e sincronização
entre tarefas
Kernel Sub-sistema de ficheiros
Sub-sistema de E/S
Executivo SHELL
Interface de sistema (API)
Sistema operativo
Hardware Aplicações
Gestão de
processos
7.2 Tipos de Sistemas operativos de tempo real
7.2.1 Sistemas Polled loop
Estes sistemas consistem no núcleo de tempo-real mais simples. Permitem rápidas respostas para periféricos isolados. Podem ser resumidos a um teste repetitivo a uma flag (que indica que um acontecimento qualquer sucedeu).
No exemplo seguinte quando flag é verdadeira indica que chegou um dado pacote de dados.
Este deve ser copiado para a memória do CPU, através de DMA, pelo procedimento process_data:
while TRUE do begin
if flag then
begin
process_data;
flag := FALSE;
end;
end;
Como só existe uma única tarefa não existe necessidade de escalonamento ou sincronização de tarefas.
Estes sistemas operam bem quando um único CPU é dedicado a tratar a entrada-saída de um periférico rápido, e não é comum sucederem eventos diferentes ao mesmo tempo.
7.2.2 Sistemas mono-tarefa
Neste caso têm-se um sistema operativo completo, incluindo um interpretador de comandos e possivelmente uma API, mas mais uma vez sem necessidade de escalonamento ou sincronização de tarefas, de modo que o núcleo se resume a gestão de memória e tratamento de interrupções. Possívelmente terá também um executivo que trate das entradas-saídas.
Exemplos de sistemas deste género são o CP/M e o MS-DOS, embora não sejam sistemas operativos de tempo-real. No caso do primeiro é composto principalmente por três secções:
• console command processor (CCP)
• basic input/output system (BIOS)
• basic disk operating system (BDOS)
No BIOS reside todo o código para efectuar E/S com os periféricos, incluindo os drivers e a gestão de interrupções. Pode-se considerar o BIOS como o núcleo e o BDOS como o executivo.
Embora existam um conjunto de chamadas de sistema, isto é chamadas ao BDOS, não existe uma API bem definida e nenhuma segurança em termos de acesso ao sistema, de modo que uma aplicação pode aceder directamente a todo o sistema, se bem que esse acesso tenha de ser programado num segmento de código em assembler.
Nestes sistemas, bem como é normal na maior parte, existem dois tipos de periféricos:
• Sequenciais ou caracter onde os dados são transmitidos byte a byte.
(impressoras, teclados ...)
• Bloco onde os dados são transferidos em blocos. No caso do CP/M 128 bytes / bloco.
(disk drives ...)
7.2.3 Sistemas foreground / background
Se bem que o tipo anterior de sistemas não permitam nativamente multi-tarefa, estes podem ser levados a executar outras aplicações em foreground ao mesmo tempo que executam uma
CCP
Aplicação
BDOS
BIOS
Hardware
(CPU, Disco, periféricos)
Utilizador
em background, se for desviado o vector de interrupção para que seja executado um dado segmento de código. Normalmente é desviada a rotina de tratamento do teclado, pois é um periférico lento, que é verificado periodicamente. Assim antes de processar o tratamento da interrupção poderá ser chamada uma ou um conjunto de rotinas.
Fig. 7-2: Tratamento de tarefas em background e foreground
A tarefa em backgroung segue o processamento normal, um ciclo infinito com aquisição de dados, actualização do display e algum tratamento da informação. Quando sucede uma interrupção de teclado é suspensa esta tarefa e a(s) tarefa(s) executada(s) em background.
Nos sistemas MS-Dos este tipo de aplicações são chamadas TSR (Terminate and stay resident). Alguns problemas podem suceder se se tentar utilizar o BIOS, sem desligar as interrupções. Além disso a mudança de contexto, deve ser efectuada pelo programador,
Background task loop forever
update display
user input
do something
Interrupt vector ...
Keyboard ...
keyboard handler handle keyboard RTI
Foreground task A do something
JMP keyboard handler
returns to Background task
guardando pelo menos os registos do processador antes de se chamar uma dada rotina que será executada em foreground.
Num sistema de tempo-real deste tipo, tarefas críticas em termos de tempo de execução, devem ser executadas em foreground.
7.2.4 Sistemas orientados por interrupções
Estes são sistemas multi-tarefa onde o programa principal é um ciclo infinito ou um jump to self:
SELF:
JMP SELF
As tarefas são escalonadas por interrupções de software ou de hardware, ao passo que o despacho é normalmente efectuado pelas rotinas de tratamento de interrupções (podendo no entanto também estar implementado em hardware). Estes sistemas são classificados quanto à ocorrência das interrupções como:
• fixed-rate ou periódicos onde as interrupções são apenas periódicas
• Esporádicos onde as interrupções são apenas aperiódicas
• Híbridos onde as interrupções ocorrem tanto periodicamente como aperiodicamente
Sempre que uma dada tarefa é atribuída a um processador outra terá de ser retirada. Assim tem de ser guardada o estado da máquina, de modo que quando essa tarefa volte a ser atribuída ao CPU, possa continuar o processamento onde tinha parado. A este processo é chamada mudança de contexto.
O estado da máquina ou contexto da tarefa, é normalmente guardado numa pilha. Esta
operação é crítica para o desempenho do sistema, pois é efectuada constantemente. Em
sistema periódicos o time slice mínimo deve ser também ajustado de modo que a operação de
mudança de contexto não seja significativa quando comparada a este. A informação que deve
ser guardada e trocada deve ser mínima e normalmente refere-se aos registos do processador:
• Registos gerais do CPU
• Programa Counter
• Flags (registo de estado do CPU)
• Registos de Memoria (segmentos ou páginas)
• Registos do co-processador (FPU)
No entanto em alguns sistemas podem ser guardadas também ponteiros para as zonas de E/S mapeadas (memory mapped I/O) e outras variáveis especiais dependentes do sistema.
Esta operação é efectuada pelo despacho, de modo que está codificada nas rotinas de interrupção.
As interrupções devem ser desligadas durante esta operação, para garantir que todo o contexto é trocado.
7.2.4.1 Sistemas periódicos
Em sistemas round-robin os processos são executados sequencialmente até ao fim, de um modo cíclico. Se a cada tarefa for atribuído um quantum de tempo fixo ou time slice, estas detêm o CPU por esse tempo, após o qual são comutadas com a tarefa seguinte numa maneira circular.
Nestes casos é utilizado um relógio com um tempo fixo que inicia uma dada interrupção. As tarefas executáveis são colocadas numa fila circular:
Fig. 7-3: Fila de tarefas executáveis circular
de modo que o diagrama de activação é o seguinte:
T
0T
1T
2... T
nFig. 7-4: Activação de tarefas segundo uma estratégia round-robin
7.2.4.2 Sistemas aperiódicos ou preemptivos
À possibilidade de uma tarefa de alta prioridade interromper outra de prioridade inferior chama-se preempção. Assim em sistemas orientados por interrupções, a prioridade de uma dada tarefa está associada à a prioridade de uma dada interrupção.
Fig. 7-5: Preempção de tarefas
Neste caso como a tarefa T
1é mais prioritária que T
0interrompe-a até que se complete. Após T
1estar completa é que T
0pode-se completar.
A prioridade das interrupções pode ser fixa ou dinâmica, tendo-se um escalonamento com a mesma designação.
T
0T
1T
0t ...
pr io ri da de
T
0T
1T
2T
nT
0T
1t ...
o rd em d e atr ib u iç ão ao C P U
time slice
Exemplo:
Sistemas com prioridade dinâmica são úteis por exemplo em sistemas de gestão de ameaças, como os presentes num avião militar, onde são seguidos vários aviões inimigos, cada um por um processo. Periodicamente a ameaça relativa de cada avião inimigo é recalculada, baseada na proximidade e postura entre outros factores, de modo que as prioridades de cada processo indicam qual o avião inimigo mais perigoso.
7.2.4.2.1 Sistemas Rate-monotonic
Um tipo especial de sistema operativo de tempo real orientado por interrupções, preemptivo e com prioridade fixa é chamado Rate-monotonic. Nestes sistemas as prioridades são atribuídas de modo que quanto maior fôr a frequência de execução maior é a prioridade.
Exemplo:
Num sistema de navegação de uma aeronave, a tarefa que lê o acelerómetro cada 5 ms têm a maior prioridade e a tarefa que lê o giroscópio cada 40 ms tem a segunda prioridade mais alta. Já a tarefa que actualiza o display em cada segundo têm a prioridade mais baixa.
O escalonamento rate-monotonic representa o método óptimo para este tipo de sistemas com prioridade fixa (Liu e Layland, 1973) de modo que se não for possível obter uma estratégia de escalonamento bem sucedida, com nenhuma outra técnica de escalonamento com prioridade fixa se conseguirá.
Por outro lado, analises teóricas demonstram que se a utilização do CPU for menor que log 2, (este valor é obtido pela construção e análise de uma árvore de acontecimentos, daí o log 2) isto é aproximadamente 70%, todas as deadlines serão cumpridas.
No entanto esta análise não toma em conta casos práticos como o tempo necessário para a mudança de contexto, contenção (não disponibilidade temporária) de recursos, etc.
7.2.4.3 Sistemas Híbridos
Nestes sistemas as interrupções podem ser periódicas ou aperiódicas. As interrupções esporádicas são normalmente utilizadas para lançar uma tarefa que trate uma dada situação que requer atenção imediata, como um erro crítico.
Alguns sistemas híbridos comerciais são uma combinação de Round-robin e sistemas
preemptivos.
Estes sistemas são normalmente utilizados em sistemas integrados ou embebidos (embedded systems). Sistemas orientados por interrupções são fáceis de escrever pois o escalonamento pode ser todo efectuado por hardware, no entanto o jmt to self processado contínuamente pode consumir demasiado tempo e a implementação de serviços mais avançados é difícil.
São exemplo disso drivers mais complexos, interfaces com redes multi-camada, etc.
No entanto estes serviços estão disponíveis num sistema operativo de tempo-real multi-tarefa e multi-utilizador comercial.
7.3 Sistemas operativos de tempo real multi-tarefa e multi- utilizador
Nesta secção são tratadas principalmente as seguintes funções de um núcleo multi-tarefa e multi-utilizador de tempo-real:
• Gestão de tarefas (incluí gestão de interrupções)
• Gestão de memória
• Sincronização e comunicação entre tarefas (incluindo partilha de código e de periféricos)
Vão ser abordados sistemas simultaneamente multi-tarefa e multi-utilizador, no entanto não é obrigatório que um sistema operativo tenha ambas as características. A figura seguinte ilustra um sistema multi-utilizador:
Fig. 7-6: SO multi-utilizador SO multi-utilizador
Hardware Dados
Código
programa
Utilizador 0
Dados Código
programa
Utilizador n
Neste caso cada utilizador corre apenas um programa, como se detivesse todos os recursos do computador só para si. No entanto cada utilizador de alguma forma partilha o CPU, e o sistema operativo garante que cada utilizador têm um ambiente protegido de modo que um programa não interfere com o outro.
Já um sistema operativo também multi-tarefa, tem de garantir que cada utilizador pode lançar mais que um processo, que cada um destes tem um área de dados local, mas também pode comunicar com os outros processos, quer por um segmento de memória partilhada ou por mensagens.
Fig. 7-7: SO multi-tarefa
A figura seguinte mostra o diagrama de blocos de um sistema operativo de tempo-real multi- utilizador e multi-tarefa genérico, a partir de agora chamado apenas sistema operativo ou SOTR.
Dados 0 Código 0
Tarefa 0
Dados n Código n
Tarefa n
Utilizador n
Memória partilhada SO multi-tarefa
Hardware
mensagem
Fig. 7-8: SO de tempo real genérico
7.3.1 Gestão de tarefas
Normalmente o escalonamento é efectuado utilizando uma estratégia de round-robin e/ou preemptivo com prioridade, onde o sistema operativo consiste na tarefa com maior prioridade.
As tarefas são descritas um por TCB (task control block) ou descritor de processo. A informação que consta neste varia de sistema para sistema mas normalmente consiste em:
• ID (pid)
• Prioridade da tarefa (inteiro)
• Estado da tarefa (Ready, active, suspended, existent)
• Contexto (PC, Registos do CPU, etc)
Shell Sub-sistema
de ficheiros
Tarefas de sistema Aplicação nível de
utilizador
Sub-sistema de E/S
Gestão de recursos (sincronização,
memória ...)
Gestão de processos (escalonamento e
despacho)
Rotinas de tratamento de
interrupções relógio de
tempo real nível de
sistema
nível de hardware
executivo
núcleo
• Localização (endereço de memória física quando carregada na RAM e endereço no disco ou página da memória virtual)
Portanto este descritor pode ser usado também para guardar o contexto, quando uma tarefa é retirada do CPU.
Normalmente o sistema tem filas (possivelmente circulares) que guardam os TCBs das tarefas activas, prontas, existentes e suspensas:
Fig. 7-9: Filas circulares para os estados das tarefas T
ntail head Suspended
tail head Ready
tail head Active
tail
head
Existent
Deste modo ao passar uma tarefa de um estado para outro, como por exemplo de Ready para Suspended, é bastante rápido pois apenas é necessário actualizar os ponteiros de modo que seja passada de uma fila para o fim da outra
A forma como o estado das tarefas varia pode ser visto pelo seguinte diagrama, se bem que este não seja único, pois esta é uma parte crítica do SO sujeita a aprefeiçoamento:
Activa suspender ou
completada
Não existente Pronta
Existente Suspensa
suspender
desligar
desligar
ligar
destruir
criar desligar activar
despacho ou interrupção
Fig. 7-10: Diagrama de estados das tarefas para um SOTR típico
Assim uma tarefa pode estar em quatro estados:
Activa ou executável (active, running): A tarefa que tem o controlo do CPU.
Pronta (ready, runnable on): Numa fila pronta a ser executada. È movida para o
estado de activa pelo despacho, para ser executada durante um quantum de tempo, ou
por uma interrupção.
Suspensa ou bloqueada (suspended, blocked): Numa fila de processos suspensos, à espera de um determinado recurso (pode ter sido bloqueada por um mecanismo de sincronização, como por exemplo um semáforo).
Ou então por preempção (se um outra tarefa a interromper). Neste caso um par de primitivas (suspender, acordar) é utilizado para mover a tarefa entre a fila pronta e a fila de suspensa e para a activar. (estas primitivas só poderão ser chamadas por tarefas que têm algum privilégio sobre a tarefa a suspender, como tarefas de sistema.
No caso de tarefas de utilizador, estas só podem suspender outras tarefas do mesmo utilizador).
Existente ou dormente (existent, dorment, off): O sistema operativo sabe da existência da tarefa mas não lhe foi ainda atribuída uma prioridade e colocada na fila de executáveis ou pronta. Pode ser colocada ou retirada dessa fila com o par de primitivas (ligar, desligar).
Não Existente (terminated): O sistema operativo ainda não sabe da existência da tarefa, isto é, ainda não foi criado o TCB, no entanto esta pode estar residente na memória principal. Para criar um TCB é usada a primitiva (criar), passando a Existente. Para terminar uma tarefa e disponibilizar a memória (embora não necessariamente apagá-la) pode ser usada a primitiva (destruir).
Em alguns casos o núcleo de tempo real é preemptivo puro, isto é, não implementa a partilha do processador com base num quantum de tempo ou time slice. Assim uma tarefa só abandona o processador quando é se auto-suspende ou outra tarefa mais prioritária se tornou executável e a suspende.
7.3.1.1 Prioridades das tarefas
As prioridades das tarefas podem ser divididas em classes, que poderão também ser divididas em vários níveis de prioridade. Assim por ordem de prioridade mais elevada para a menor têm-se:
• Interrupção Tarefas que requerem resposta muito rápida, na ordem do mili-
segundos. Como exemplo têm-se tarefas do SO como o dispatcher e o relógio de tempo real. Este último pode consistir apenas no incremento periódico de um dado contador na memória principal.
Como já se viu as interrupções forçam o re-escalonamento das tarefas, e o sistema não tem controlo sobre a altura destas. É assim necessário manter o processamento das rotinas de interrupção a um mínimo de modo que normalmente apenas preservam a informação necessária, e passam-na para uma rotina de interrupção de mais baixa prioridade, ao nível de relógio ou mesmo base.
As rotinas de interrupção devem preservar o contexto da tarefa interrompida. É pois comum que os registos do processador utilizados pela rotina de tratamento de interrupção sejam colocados na pilha quando se entra nela, e retirados desta imediatamente antes de se retornar da interrupção, isto é antes da instrução RTI.
• Relógio Tarefas que são repetitivas ou com alturas de execução muito precisas, como por exemplo tarefas de amostragem e tarefas de controlo. Por vezes a prioridade do scheduler pertence a esta classe.
Podem-se dividir estas tarefas em:
Cíclicas: as que requerem sincronização precisa com o mundo exterior.
Para garantir esta sincronização quanto maior é a precisão requerida maior é a prioridade da tarefa.
Delay (atrasadas): As que desejam ter um atraso ou intervalo de tempo fixo entre sucessivas repetições, ou que pretendem atrasar o seu processamento por um dado período de tempo, para aguardar que um acontecimento externo se complete como por exemplo o fecho de um relé (tipicamente 20 ms)
Uma forma de implementar isto é colocar os TCBs destas
tarefas numa fila de espera por ordem da primeira a necessitar
de ser executada. Uma tarefa ao nível de prioridade de relógio verifica periodicamente se chegou a altura de executar a primeira tarefa da fila.
Fig. 7-11: Colocação de mais um TCB na fila delayed
Para isso consulta o relógio de tempo real, compara-o com o tempo previsto para a execução da primeira tarefa da fila delayed, que pode estar indicado no TCB, e se for altura de execução sinaliza-o ao despacho.
A medida de tempo utilizada é normalmente o tick, que corresponde a um impulso do relógio, e é o menor intervalo de tempo conhecido pelo sistema. No entanto numa linguagem de alto nível é comum indicar um atraso em segundos ou mili- segundos, que serão posteriormente convertidos para ticks.
Deste modo têm-se mais um estado de tarefas, normalmente chamado delayed. Estas tarefas circulam normalmente entre este estado e Ready.
• Base Tarefas de baixa prioridade, que não têm deadline ou esta não é rígida.
São normalmente iniciadas por alguma pedido em vez de periódicas.
Este pedido pode ser devido a input por parte do utilizador, ou algum acontecimento externo.
t=2 t=5 t=8
tail head Delayed
t=6