Identificadores de tarefas
Você deve poder identificar cada tarefa no sistema. Esse requisito é importante para outros objetos do kernel, mas existem algumas nuances nas tarefas que correspondem ao tópico deste artigo.

Os desenvolvedores do RTOS usam abordagens diferentes para identificar tarefas, mas quatro estratégias gerais podem ser distinguidas:
- A tarefa é identificada usando um ponteiro para seu "bloco de controle". Os ponteiros são sempre exclusivos e também convenientes de usar, pois o acesso à unidade de controle é necessário para muitas chamadas de API. Isso implica que todos os dados da tarefa são armazenados na memória de acesso aleatório (RAM), que pode ser ineficiente. Um ponteiro normalmente ocupa cerca de 32 bits de memória.
- Uma tarefa pode ser definida usando um "número de índice" arbitrário. Esse valor pode ser útil ao conceder acesso a registros em determinadas tabelas. Esse identificador pode ocupar oito ou menos bits de memória, dependendo das limitações no número de tarefas que o RTOS suporta.
- Alguns RTOSs permitem apenas uma tarefa por nível de prioridade e, portanto, usam a prioridade para identificar exclusivamente uma tarefa. Isso significa que a prioridade da tarefa não pode ser alterada. Essa abordagem é uma variação da abordagem anterior.
- As tarefas podem ter nomes que são cadeias de caracteres. Isso pode ser útil para depuração, mas é improvável que seja um meio eficaz de identificar exclusivamente uma tarefa. Os RTOSs que oferecem suporte à nomeação de tarefas geralmente têm um identificador adicional (como um ponteiro) usado pelas chamadas da API etc. Para a maioria dos sistemas incorporados, os nomes de texto estão sobrecarregados; um bom depurador permite chamá-los localmente no host.
Artigos anteriores da série:
Artigo # 3 Tarefas e planejamentoArtigo 2. RTOS: estrutura e modo em tempo real
Artigo 1. RTOS: introdução.
Mudança de contexto
A alternância de contexto é o processo de transferência de controle de uma tarefa para outra. Vale a pena explorar esse tópico mais de perto, pois o funcionamento da alternância de contexto é um princípio fundamental do RTOS.
O que é uma tarefa?
Sabemos que uma tarefa é um programa quase independente que compartilha o tempo do processador com várias outras tarefas sob o controle do RTOS. Mas você precisa pensar sobre o que realmente caracteriza a tarefa.
Conjunto de registros
Uma tarefa é, em última análise, um conjunto exclusivo de valores de registro do processador. Eles são carregados nos registros do processador (ou seja, a tarefa é atual) ou armazenados em algum lugar até o tempo de execução agendado. Em um mundo ideal, um processador central teria vários conjuntos de registros e cada um poderia ser atribuído a uma tarefa separada. Isso foi implementado para ocasiões especiais. Muitos anos atrás, a série Texas Instruments TI 9900 possuía muitos conjuntos de registros para cada tarefa, mas eles foram implementados na memória principal, o que limitava o desempenho. A arquitetura SPARC (anteriormente usada em sistemas desktop Unix) suporta muitos conjuntos de registros na "estrutura em anel", mas o número de conjuntos ainda é limitado.
Dados internos
A tarefa provavelmente terá sua própria pilha, cujo tamanho pode ser definido separadamente para cada tarefa ou pode ser um parâmetro global para todas as tarefas no sistema. Isso, juntamente com os registros, fornece armazenamento de dados para tarefas específicas. Pode haver outras áreas da memória para armazenar dados para uma tarefa específica.
Recursos compartilhados
Praticamente qualquer recurso pode ser compartilhado entre tarefas. O código pode ser geral: certas funções ou todo o código da tarefa. É necessário garantir que o código seja reentrante, antes de tudo, variáveis estáticas não devem ser usadas (especificadas como estáticas ou apenas fora da função). Tenha cuidado com os módulos de biblioteca padrão que não se destinam ao uso interno; eles geralmente têm muitas funções não confiáveis.
O compartilhamento de dados também é possível, mas é necessário um controle de acesso cuidadoso. Idealmente, apenas uma tarefa é o "proprietário" dos dados a qualquer momento.
Como manter o contexto
Quando uma tarefa é reprogramada (ou seja, deixa de ser atual), seu conjunto de registros precisa ser salvo em algum lugar. Existem pelo menos duas possibilidades:
- Os registros podem ser armazenados em uma tabela especial para tarefas. Pode fazer parte de um bloco de controle de tarefas (TCB). Tamanho é um valor previsível e constante (para uma arquitetura específica da CPU).
- Os registros podem ser enviados para a pilha de tarefas. Isso requer a alocação de espaço de pilha adicional suficiente e armazenamento do ponteiro (possivelmente no TCB).
A escolha do mecanismo depende dos recursos de um RTOS específico e do processador de destino. Alguns dispositivos (geralmente 32 bits) podem acessar a pilha com eficiência; o restante (por exemplo, 8 bits) pode ser mais ideal ao trabalhar com tabelas.
Criação dinâmica de tarefas
O principal aspecto da arquitetura RTOS é que o RTOS é "estático" ou "dinâmico".
Ao usar um RTOS estático, tudo é determinado durante a criação do aplicativo, em particular, o número de tarefas no sistema. Esta é uma solução lógica para aplicativos incorporados, que geralmente têm funcionalidade limitada.
O RTOS dinâmico inicia uma tarefa (que pode ser uma tarefa "principal" especializada)) e também cria e exclui outras tarefas, conforme necessário. Isso permite que o sistema se adapte às mudanças de requisitos e é um análogo mais próximo do sistema de desktop, que se comporta dessa maneira. A exibição estática / dinâmica também se aplica a outros objetos do kernel.
Requisito de criação de tarefas dinâmicas
Esse recurso está incluído na maioria dos RTOS comerciais. No entanto, apenas uma pequena parte dos aplicativos realmente precisa de um modo dinâmico de operação. Muitas vezes, o sistema é iniciado, cria todas as tarefas necessárias (e outros objetos) e nunca mais cria e destrói o código do aplicativo. A capacidade de criar tarefas dinâmicas tornou-se uma formalidade. Um fornecedor apresentou, todos os outros seguiram o exemplo.
Vale ressaltar que o padrão OSEK / VDX requer uma arquitetura estática, mesmo que isso possa se aplicar a aplicativos bastante complexos. O resultado desses requisitos é a incapacidade de implementar o OSEK / VDX com um invólucro, uma camada intermediária sobre um RTOS regular (dinâmico).
Armadilhas da criação dinâmica de tarefas
Há vários problemas no modo dinâmico de operação que podem ser preocupantes.
Primeiro, o sistema se torna mais complexo, o que significa que, para estruturas de dados que descrevem tarefas (TCBs), são necessárias informações adicionais. Como regra, eles são implementados na forma de listas bidirecionais, o que leva a custos associados à quantidade de memória.
Todos os dados que descrevem a tarefa devem ser armazenados na RAM. Isso é ineficiente, pois a maioria deles pode ser simplesmente dados persistentes copiados da ROM. Além disso, em processadores de nível inferior (microcontroladores), pode não haver memória RAM.
Provavelmente o mais preocupante é a possibilidade de uma falta imprevisível de recursos, o que pode levar à incapacidade de criar novos objetos. Como a essência de um sistema em tempo real é sua previsibilidade, isso é inaceitável. Portanto, deve-se tomar cuidado ao usar a criação de tarefas dinâmicas (e outros objetos).
Interrupções
É possível que um sistema incorporado em tempo real possa ser implementado sem o uso de interrupções, mas isso não é típico.
Interrupções e Kernel
Ao usar o RTOS, um manipulador de interrupção (ISR) é o mais fácil possível para "roubar" a quantidade mínima de tempo do processador das tarefas agendadas. Muitas vezes, um dispositivo pode simplesmente ser reparado e qualquer tarefa necessária será colocada na fila para processamento. Além disso, é difícil falar em geral sobre interrupções e sua interação com os kernels, simplesmente porque eles variam muito. Por um lado, o desenvolvedor do RTOS pode garantir que as interrupções não estejam relacionadas ao kernel, e o programador terá que garantir que o agendador de tarefas não esteja sobrecarregado, usando muito tempo do processador no ISR. Por outro lado, o RTOS pode controlar completamente todo o subsistema de interrupção. Nenhuma das abordagens descritas está certa ou errada, elas são apenas diferentes.
Salvando Contexto
Os ISRs sempre precisam manter um "contexto" para que o código interruptível não seja afetado pelos cálculos do ISR. Em um sistema implementado sem um RTOS, é simplesmente uma questão de salvar todos os registros usados pelo ISR (geralmente na pilha) e restaurá-los antes de retornar. Alguns processadores possuem uma pilha ISR dedicada, enquanto outros simplesmente usam a mesma pilha que o código do aplicativo.
Ao usar o RTOS, a abordagem pode ser exatamente a mesma. Da mesma forma, a pilha usada pelo ISR pode ser "emprestada" da tarefa atual ou pode ser outra pilha alocada para interrupções. Alguns núcleos implementam esse recurso, mesmo que o próprio processador não suporte a pilha de interrupções. A situação é complicada se o ISR fizer uma chamada de API que afeta o agendador de tarefas. Isso pode fazer com que a interrupção retorne a outra tarefa daquela iniciada quando a interrupção ocorreu.
Interrupções e agendador
Há várias circunstâncias nas quais o código de execução ISR pode retornar para outra tarefa:
- O ISR pode atribuir uma prioridade mais alta a uma tarefa já concluída, em vez da atual, se o agendador de tarefas prioritárias for usado.
- O ISR pode pausar a tarefa atual.
- Usando o Agendador de fatias de tempo (TS), o manipulador de interrupção do timer do sistema controlará os intervalos de tempo e poderá chamar o agendador, se necessário.
Temporizador (Tick Clock)
Em sistemas embarcados, o uso de um "relógio temporizador" periódico (intervalo de tempo) é frequentemente encontrado. Em alguns RTOS, é um componente necessário. Normalmente, a presença de um timer de relógio é opcional e sua ausência simplesmente exclui a disponibilidade de determinados serviços. O manipulador de interrupção do timer geralmente fornece quatro funcionalidades:
- Se um agendador de intervalo de tempo for usado, o manipulador de interrupção do timer controlará o contador de tempo e agendará uma nova tarefa cada vez que o tempo acabar.
- Fornece suporte de horário do sistema. Essa é principalmente uma variável de 32 bits que é incrementada por um timer e pode ser predefinida ou solicitada por tarefas.
- Se o RTOS fornecer aos cronômetros os aplicativos, ele será suportado por um manipulador de interrupção do cronômetro que será responsável pela expiração e reagendamento.
- Se o RTOS suportar tempos limite no bloqueio de chamadas da API ou as tarefas estiverem no estado de suspensão, esses intervalos de tempo serão suportados pelo manipulador de interrupção do timer.
Quando trabalhamos em nosso próprio sistema operacional OSRV MAX em tempo real (artigos publicados anteriormente sobre ele), nossa equipe encontrou o blog de Colin Walls, especialista em microeletrônica e firmware da Mentor Graphics. Os artigos pareciam interessantes, os traduziam por si mesmos, mas, para não "escrever para a mesa", eles decidiram publicar. Espero que eles também sejam úteis para você. Nesse caso, planejamos publicar todos os artigos traduzidos da série.
Sobre o autor: Colin Walls trabalha na indústria eletrônica há mais de trinta anos, dedicando a maior parte de seu tempo ao firmware. Ele agora é engenheiro de firmware na Mentor Embedded (uma divisão da Mentor Graphics). Colin Walls frequentemente fala em conferências e seminários, autor de vários artigos técnicos e dois livros sobre firmware. Vive no Reino Unido. Blog profissional de Colin: blogs.mentor.com/colinwalls, e-mail: colin_walls@mentor.com
Leia o
primeiro, o segundo e o
terceiro artigos da série publicada anteriormente.