
Os princípios básicos do trabalho dos planejadores do RTOS foram considerados no artigo "Tarefas e planejamento". Neste artigo, veremos os recursos que o Nucleus RTOS oferece, bem como os que o Nucleus SE fornece em mais detalhes.
Artigos anteriores da série:
Artigo 8. Núcleo SE: Projeto Interno e Implantação
Artigo # 7 Núcleo SE: Introdução
Artigo 6. Outros serviços RTOS
Artigo 5. Interação e sincronização de tarefas
Artigo 4. Tarefas, alternância de contexto e interrupções
Artigo # 3 Tarefas e planejamento
Artigo 2. RTOS: estrutura e modo em tempo real
Artigo 1. RTOS: introdução.
Planejamento no Nucleus RTOS
Como o Nucleus RTOS é um RTOS comercial completo e bem estabelecido, podemos assumir com segurança que o agendador foi desenvolvido de acordo com os requisitos desse produto. Esse sistema operacional complexo e flexível fornece ao desenvolvedor uma ampla gama de recursos para solucionar praticamente qualquer tarefa de programação em tempo real concebível.
O planejador pode suportar um número ilimitado de tarefas (limitado apenas pelos recursos disponíveis) e trabalhar com gerenciamento de prioridade. A tarefa pode receber uma prioridade de 0 a 255, onde 0 é a prioridade mais alta e 255 é a mais baixa. Uma tarefa tem uma prioridade dinâmica, ou seja, pode ser alterada em tempo de execução pela própria tarefa ou por outra. Várias tarefas podem ser atribuídas ao mesmo nível de prioridade. Em um caso extremo, todas as tarefas podem receber a mesma prioridade, o que torna possível implementar uma política de planejamento com base no princípio de Round Robin e Time-Slice.
Se houver várias tarefas com a mesma prioridade, elas serão agendadas usando o algoritmo Round Robin na ordem em que foram preparadas. A tarefa precisa pausar ou transferir o controle para que a próxima tarefa seja iniciada. Também é possível atribuir às tarefas intervalos de tempo que proporcionam uma separação mais controlada do tempo disponível do processador.
O planejamento de tarefas é 100% determinístico, o que é esperado de um núcleo semelhante. As tarefas também podem ser criadas e destruídas dinamicamente, o que, graças ao agendador, passa despercebido pelo usuário.
Planejamento no Nucleus SE
Desenvolvi todos os aspectos do Nucleus SE para que eles geralmente sejam compatíveis com o Nucleus RTOS, mas também sejam mais simples e mais eficientes em termos de memória. O planejador não é exceção. Ele fornece muitos dos recursos do Nucleus RTOS Scheduler, mas é um pouco limitado. A flexibilidade é obtida através da configuração durante a montagem.
Um aplicativo Nucleus SE pode ter no máximo 16 tarefas (e pelo menos uma). Embora teoricamente esse número possa ser aumentado, a eficiência dos algoritmos estará em risco; várias estruturas de dados dependem do armazenamento do número de índice da tarefa (de 0 a 15) em um petisco (quatro bits) e precisam ser processadas juntamente com o código correspondente.
Para alcançar um equilíbrio entre flexibilidade e simplicidade (e tamanho), em vez de ter um agendador com vários recursos, o Nucleus SE oferece um dos quatro tipos de agendadores para escolher: Executar para componente (RTC), Round Robin (RR), Time-Slice ( TS) e Prioridade. O planejador é selecionado estaticamente no momento da montagem. Detalhes sobre cada tipo de agendador estão descritos abaixo na seção "Tipos de agendador".
Como qualquer outro aspecto do Nucleus SE, as tarefas são objetos estáticos. Eles são determinados durante a configuração e sua prioridade (índice) não pode ser alterada.
Planejadores do Núcleo SE
Como afirmado acima, o Nucleus SE oferece um dos quatro tipos de agendadores para você escolher. Como a maioria dos aspectos da configuração do Nucleus SE, essa opção é determinada gravando nuse_config.h, o parâmetro NUSE_SCHEDULER_TYPE deve ser definido adequadamente, conforme mostrado neste fragmento do arquivo de configuração:

Independentemente de qual planejador estiver selecionado, seu código de inicialização é chamado imediatamente após a inicialização do sistema. Informações completas sobre a inicialização do Nucleus SE serão apresentadas no próximo artigo.
Executar para o Agendador de Conclusões
O RTC Scheduler é a solução mais fácil e adequada se atender aos requisitos do aplicativo. Cada tarefa deve concluir seu trabalho antes de executar a função de retorno e permitir que o planejador conclua a próxima tarefa.
Não há necessidade de uma pilha separada para cada tarefa. Todo o código é escrito em C, a linguagem assembly não é necessária. Abaixo está o código completo do agendador RTC.

O código é apenas um loop infinito que se revezam invocando cada tarefa. A matriz NUSE_Task_Start_Address [] contém ponteiros para a função externa de cada tarefa. A macro PF0 é uma conversão simples de um ponteiro nulo em um ponteiro em uma função nula sem parâmetros. Ele foi projetado para garantir a legibilidade do código.
A compilação condicional é usada para habilitar o suporte a funções adicionais: NUSE_SUSPEND_ENABLE determina se as tarefas podem ser suspensas; NUSE_SCHEDULE_COUNT_SUPPORT determina se um valor de contador é necessário sempre que uma tarefa é agendada. Mais informações sobre isso podem ser encontradas no próximo artigo.
Agendador Round Robin
Se for necessária uma flexibilidade um pouco maior do que a fornecida pelo planejador RTC, o planejador RR é adequado. Ele permite que a tarefa transfira o controle ou pause e continue a partir do mesmo ponto. A sobrecarga adicional, além da complexidade do código e da não portabilidade, é que cada tarefa requer sua própria pilha.
O código do planejador consiste em duas partes. O componente de inicialização é o seguinte:

Se o suporte ao estado inicial da tarefa estiver ativado (usando o parâmetro NUSE_INITIAL_TASK_STATE_SUPPOR T, consulte "Parâmetros" no próximo artigo), o planejamento será iniciado a partir da primeira tarefa concluída; caso contrário, será usada uma tarefa com índice 0. O contexto dessa tarefa será carregado usando NUSE_Context_Load () . Para obter mais informações sobre como salvar e restaurar um contexto, consulte a seção "Salvar contexto" no próximo artigo.
A segunda parte do planejador é o componente "re-planejamento":

Esse código é chamado quando a tarefa libera o processador central ou faz uma pausa.
O código seleciona a tarefa com o seguinte índice para iniciar e coloca o valor em NUSE_Task_Next, levando em consideração se a suspensão da tarefa está ativada ou não. A macro NUSE_CONTEXT_SWAP () é usada para chamar a alternância de contexto usando uma interrupção de software. Para obter mais informações sobre como salvar e restaurar um contexto, consulte a seção "Salvar contexto" no próximo artigo.
Programador prioritário
O Priority Scheduler no Nucleus SE, como outras opções, é projetado para fornecer a funcionalidade necessária, embora seja bastante simples. Como resultado, cada tarefa tem uma prioridade única, é impossível ter várias tarefas com um nível de prioridade. A prioridade é determinada pelo índice da tarefa, em que 0 é o nível de prioridade mais alto. O índice da tarefa é determinado por sua localização na matriz NUSE_Task_Start_Address []. O próximo artigo fornecerá informações mais detalhadas sobre a configuração de tarefas.
Como os agendadores RR e TS, o agendador de prioridade tem dois componentes. O componente de inicialização do planejador Prioritário é o mesmo que os planejadores RR e TS, conforme ilustrado acima. O componente de reagendamento é ligeiramente diferente:

Não há código condicional que possa desativar a suspensão de tarefas, pois esse recurso é obrigatório para o agendador de prioridades; qualquer alternativa seria ilógica. A função NUSE_Reschedule () aceita um parâmetro que "informa" qual tarefa pode ser agendada em seguida - new_task. Este valor é definido quando o reagendamento é chamado porque outra tarefa é chamada. O índice desta tarefa é passado como um parâmetro. O planejador pode determinar se é necessário executar a alternância de contexto comparando o valor de new_task com o índice da tarefa atual (NUSE_Task_Active) . Se o reagendamento for o resultado de uma pausa na tarefa, o parâmetro será definido como NUSE_NO_TASK e o agendador procurará a tarefa com a prioridade mais alta.
Estados da tarefa
Como regra, todos os sistemas operacionais têm o conceito de encontrar tarefas em um determinado "estado". Os detalhes variam dependendo do RTOS. Neste artigo, veremos como o Nucleus RTOS e o Nucleus SE usam estados de tarefa.
Estados-tarefa do RTOS do núcleo
O núcleo RTOS suporta 5 estados de tarefa.
- Execução: a tarefa atualmente gerenciando o processador. Obviamente, apenas uma tarefa pode ocupar esse estado.
- Prontidão: uma tarefa pronta para execução (ou para continuar a execução) antes que o planejador decida iniciá-la. Normalmente, uma tarefa tem uma prioridade mais baixa que a que está sendo executada.
- Suspensão: a tarefa "adormecida". Ele não é levado em consideração durante o planejamento até que seja ativado e, nesse momento, estará "pronto" e poderá continuar sendo executado posteriormente. Geralmente, uma tarefa está no estado de "suspensão" porque está aguardando algo: quando o recurso fica disponível, quando o período de tempo definido expira ou quando outra tarefa o ativa.
- Cancelar: a tarefa foi "eliminada". Isso não é levado em consideração durante o planejamento até que seja redefinido, após o qual a tarefa estará "pronta" ou "suspensa".
- Finalização: a tarefa é concluída e saiu de sua função externa simplesmente saindo da unidade externa ou executando a instrução de retorno. Isso não é levado em consideração durante o planejamento até que seja redefinido, após o qual a tarefa estará "pronta" ou "suspensa".
Como o Nucleus RTOS suporta a criação e destruição dinâmicas de objetos, incluindo tarefas, a tarefa também pode ser considerada em um estado "remoto". No entanto, uma vez que a tarefa é excluída, todos os recursos do sistema deixam de existir e a tarefa em si não existe mais, ela não pode ter um estado. O código da tarefa pode estar disponível, mas o objeto da tarefa deve ser criado novamente.
Estados de tarefa no Nucleus SE
O modelo de estado da tarefa no Nucleus SE é um pouco mais simples. Normalmente, existem apenas três estados: Execução, Disponibilidade e Pausa. O status de cada tarefa é armazenado em
NUSE_Task_Status [] , que possui valores do tipo
NUSE_READY , embora nunca tenha um valor que reflita o status de Execução. Se a suspensão da tarefa não estiver ativada (consulte "Opções" no próximo artigo), apenas dois estados da tarefa serão possíveis e essa matriz estará ausente.
Existem vários tipos de tarefas de pausa. Se uma tarefa for explicitamente suspensa sozinha ou por outra tarefa, isso será chamado de "suspensão pura" e será representado pelo status NUSE_PURE_SUSPEND. Se o estado “inativo” estiver ativado e a tarefa for suspensa por um determinado período de tempo, ela terá o status
NUSE_SLEEP_SUSPEND . Se a função de bloqueio de chamadas de API estiver ativada (via
NUSE_BLOCKING_ENABLE , consulte “Parâmetros” no próximo artigo), a tarefa poderá ser suspensa até que o recurso fique disponível. Cada tipo de objeto tem seu próprio status de suspensão de tarefa, por exemplo, na forma de
NUSE_MAILBOX_SUSPEND. No Nucleus SE, uma tarefa pode ser bloqueada em uma partição de memória, grupo de eventos, caixa de correio, fila, canal ou semáforo.
Status do segmento
Ao discutir o comportamento da tarefa, as palavras "Status" e "Status" geralmente são usadas livremente. Há um fator adicional, que pode ser chamado condicionalmente de "estado do fluxo". Essa é a variável global
NUSE_Thread_State, que contém uma indicação da natureza do código que está sendo executado. Isso se aplica ao comportamento de muitas chamadas de API. Valores possíveis:
- NUSE_TASK_CONTEXT - A chamada da API foi feita a partir de uma tarefa.
- NUSE_STARTUP_CONTEXT - a chamada da API foi feita a partir do código de inicialização; o planejador ainda não foi iniciado.
- NUSE_NISR_CONTEXT e NUSE_MISR_CONTEXT - a chamada da API foi feita a partir do manipulador de interrupções. Interrupções no Nucleus SE serão discutidas no próximo artigo.
O próximo artigo detalhará os recursos avançados do agendador no Nucleus SE, além de manter o contexto.
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 , e-mail: colin_walls@mentor.com