
Seções de memória foram mencionadas anteriormente em um dos artigos anteriores (# 6), onde foi feita uma comparação com a função padrão da linguagem C
malloc () . Uma partição é uma região de memória obtida de um conjunto de partições (conjunto de memórias). O compartilhamento de memória fornece uma maneira flexível de alocar e liberar de forma confiável e determinística.
Artigos anteriores da série:
Artigo 13. Estruturas de dados da tarefa e chamadas de API não suportadasArtigo 12. Serviços para trabalhar com tarefasArtigo 11. Tarefas: configuração e introdução à APIArtigo 10. Agendador: recursos avançados e preservação de contextoArtigo 9. Agendador: implementaçãoArtigo 8. Núcleo SE: Projeto Interno e ImplantaçãoArtigo # 7 Núcleo SE: IntroduçãoArtigo 6. Outros serviços RTOSArtigo 5. Interação e sincronização de tarefasArtigo 4. Tarefas, alternância de contexto e interrupçõesArtigo # 3 Tarefas e planejamentoArtigo 2. RTOS: estrutura e modo em tempo real
Artigo 1. RTOS: introdução.
Usando seções
No Nucleus SE, os conjuntos de partições são configurados no momento da criação. Um único aplicativo pode ter até 16 conjuntos de partições. Se eles não estiverem configurados, estruturas de dados e chamadas de serviço relacionadas a esses conjuntos não serão incluídas no aplicativo.
Um conjunto de partições é uma área de memória dividida em um determinado número de blocos de tamanho fixo. O desenvolvedor tem controle total sobre o tamanho e o número de partições em cada pool. As tarefas podem solicitar seções alocadas da memória e receber um ponteiro para a área de armazenamento e não devem gravar dados fora da seção alocada. Uma seção pode ser liberada por qualquer tarefa ao passar um ponteiro para uma função da API. Uma solicitação para alocar uma partição quando não houver partições livres pode levar a um erro ou suspensão da solicitação, dependendo dos parâmetros de chamada da API selecionados e da configuração do Nucleus SE.
Configurando partições de memória
Número de conjuntos de partições
Como na maioria dos objetos do Nucleus SE, a configuração do pool de partições é feita principalmente usando a diretiva
#define em
nuse_config.h . O parâmetro principal é
NUSE_PARTITION_POOL_NUMBER , que determina quantos conjuntos de partições estão definidos no aplicativo. O valor padrão é 0 (ou seja, conjuntos de partições não são usados), o desenvolvedor pode definir qualquer valor de 0 a 16. Outros valores levarão a um erro de compilação, que foi detectado durante a verificação em
nuse_config_check.h (incluído em
nuse_config.c , e , portanto, compila com este módulo), o que leva à compilação da diretiva
#error .
Escolher um valor diferente de zero é uma maneira prioritária de ativar os conjuntos de partições. Isso leva à definição de estruturas de dados e à atribuição do tamanho apropriado. As estruturas de dados na ROM devem ser inicializadas com os valores apropriados que descrevem cada conjunto de partições. Mais detalhes sobre estruturas de dados estarão no próximo artigo. Essa seleção também ativa as configurações da API.
Ativar chamadas de API
Cada função da API (chamada de utilitário) no Nucleus SE é ativada pela diretiva
#define em
nuse_config.h . Para conjuntos de partições, eles incluem:
NUSE_PARTITION_ALLOCATENUSE_PARTITION_DEALLOCATENUSE_PARTITION_POOL_INFORMATIONNUSE_PARTITION_POOL_COUNTPor padrão, todos estão configurados como
FALSE , desativando cada chamada de serviço e impedindo a inclusão de um código de implementação. Para configurar os conjuntos de partições no aplicativo, é necessário selecionar as chamadas de API necessárias e definir as diretivas correspondentes como
TRUE .
A seguir, um trecho do arquivo
nuse_config.h padrão:

Se a função API do Partition Pools estiver ativada, mas os pools não estiverem configurados, ocorrerá um erro de compilação (exceto
NUSE_Partition_Pool_Count () , que sempre está ativado). Se o seu código usar uma chamada de API que não foi ativada, ocorrerá um erro de layout porque o código de implementação não foi incluído no aplicativo.
Chamadas do utilitário de conjunto de partições
O Nucleus RTOS suporta sete chamadas de utilitários relacionadas aos conjuntos de partições, que fornecem a seguinte funcionalidade:
Descrição funcional | Núcleo RTOS | Núcleo SE |
---|
Seleção de seção | NU_Allocate_Partition () | NUSE_Partition_Allocate () |
Seção Liberação | NU_Deallocate_Partition () | NUSE_Partition_Deallocate () |
Fornecendo informações sobre um conjunto de partições específico | NU_Partition_Pool_Information () | NUSE_Partition_Pool_Information () |
Retornar o valor da quantidade (atualmente) configurada pools de aplicativos | NU_Established_Partition_Pools () | NUSE_Partition_Pool_Count () |
Adicionando (criando) um novo pool de partições ao aplicativo | NU_Create_Partition_Pool () | Não implementado. |
Alterando (excluindo) um pool de partições de um aplicativo | NU_Delete_Partition_Pool () | Não implementado. |
Retornando ponteiros para todos os conjuntos de partições atualmente existentes no aplicativo | NU_Partition_Pool_Pointers () | Não implementado. |
A implementação de cada chamada será discutida em detalhes.
Vale ressaltar que nem o Nucleus RTOS nem o Nucleus SE possuem uma função de reinicialização. Isso é feito de propósito. Muitas vezes, uma tarefa aloca uma seção e passa um ponteiro para outra tarefa (que pode ser liberada posteriormente). Se você recarregar o conjunto de partições, todas as partições serão marcadas como não utilizadas; no entanto, não há mecanismo para monitorar e notificar todas as tarefas que podem usar partições.
Serviços de Partição e Liberação
As operações fundamentais com conjuntos de partições são a alocação de partições no conjunto (ou seja, marcando a partição como usada e retornando seu endereço) e liberando a partição (ou seja, a partição é marcada como não utilizada). O Nucleus RTOS e o Nucleus SE fornecem duas chamadas de API básicas para essas operações, descritas abaixo.
Seleção de seção
Chamar a API Nucleus RTOS para alocar uma partição é muito flexível, o que permite aos desenvolvedores pausar tarefas por um período indefinido ou sem tempo limite, se a operação não puder ser concluída imediatamente, por exemplo, quando você tenta alocar uma partição de um pool no qual todas as partições já estão distribuídas. O Nucleus SE fornece o mesmo serviço, apenas a pausa nas tarefas é opcional e o tempo limite não é implementado.
Chamada de API do núcleo RTOS para partição
Protótipo de chamada:
STATUS NU_Allocate_Partition (pool NU_PARTITION_POOL *, VOID ** return_pointer, suspensão UNSIGNED);Valor de retorno:
NU_SUCCESS - a chamada foi concluída com sucesso;
NU_NO_PARTITION - nenhuma seção está disponível;
NU_INVALID_POOL - ponteiro inválido do conjunto de partições;
NU_INVALID_POINTER - passou um ponteiro nulo para os dados retornados (
NULL );
NU_INVALID_SUSPEND - foi feita uma tentativa de suspender uma tarefa a partir de um encadeamento não associado à tarefa;
NU_TIMEOUT - nenhuma partição está disponível, mesmo após a suspensão pelo período de espera especificado;
NU_POOL_DELETED - O pool de partições foi excluído quando a tarefa foi suspensa.
Chamada da API do Nucleus SE para destacar uma partição
Essa chamada de API suporta a funcionalidade principal da API do Nucleus RTOS.
Protótipo de chamada:
STATUS NUSE_Partition_Allocate (pool NUSE_PARTITION_POOL, ADDR * return_pointer, U8 suspende);Parâmetros:
pool - índice (ID) do pool de partições usado;
return_pointer - ponteiro para uma variável do tipo
ADDR , que leva o endereço da seção selecionada;
suspend - parâmetro para pausar a tarefa e pode assumir os valores
NUSE_NO_SUSPEND ou
NUSE_SUSPEND .
Valor de retorno:
NUSE_SUCCESS - a chamada foi concluída com sucesso;
NUSE_NO_PARTITION - nenhuma seção está disponível;
NUSE_INVALID_POOL - índice do conjunto de partições inválido;
NUSE_INVALID_POINTER - passou um ponteiro nulo para os dados retornados (
NULL );
NUSE_INVALID_SUSPEND - Foi feita uma tentativa de suspender uma tarefa a partir de um thread que não estava associado à tarefa ou quando as APIs de bloqueio foram desativadas.
Implementação de alocação de partição no Nucleus SE
O código de função da API
NUSE_Partition_Allocate é selecionado usando a compilação condicional após a verificação dos parâmetros, dependendo se a chamada da API para bloquear (suspender tarefas) está ativada ou não. Abaixo, consideraremos separadamente essas duas opções.
Se as chamadas de bloqueio estão desativadas, a chamada da API é bastante simples:

Primeiro, a disponibilidade de partições livres é verificada. Se não houver essas partições, um erro será retornado (
NUSE_NO_PARTITION ). Depois, há uma enumeração de seções, durante as quais os primeiros bytes são verificados quanto a valores zero (o que indica que a seção não é usada). Quando uma partição é encontrada, é atribuído o sinalizador "usado", que inclui o índice do pool de partições (consulte "Liberar a partição" abaixo) e retorna um ponteiro para o próximo byte (o início da área de dados reais). Explicações sobre as estruturas de dados dos conjuntos de partições serão apresentadas no próximo artigo na seção Estruturas de Dados.
Se o bloqueio estiver ativado, o código para esta chamada de API se tornará um pouco mais complicado:

O código é colocado em um
loop do ... while , que continua sendo executado enquanto o parâmetro de pausa for
NUSE_SUSPEND .
Se nenhuma partição estiver disponível e o parâmetro pause for
NUSE_NO_SUSPEND , a chamada da API será interrompida e retornará
NUSE_NO_PARTITION . Se o parâmetro pause foi definido como
NUSE_SUSPEND , a tarefa é pausada. Ao retornar (por exemplo, quando uma tarefa é retomada), o valor de retorno de
NUSE_SUCCESS indica que a tarefa foi retomada porque a seção de memória foi liberada e o código retorna ao início do loop. Como não há funções de API para recarregar conjuntos de partições, as tarefas não podem ser retomadas por outros motivos, mas para a estabilidade de bloquear outros tipos de objetos, o processo de verificação
NUSE_Task_Blocking_Return [] é salvo.
Seção Liberação
O lançamento da seção no Nucleus RTOS e Nucleus SE torna novamente disponível. Antes do lançamento, ele não verifica se esta seção é usada por alguma tarefa ou não, o programador do aplicativo é responsável por isso. Apenas um ponteiro para uma área de dados é necessário para liberar uma seção.
Chamada da API do núcleo RTOS para partição livre
Protótipo de chamada:
STATUS NU_Deallocate_Partition (partição VOID *);Parâmetros:
partição - um ponteiro para a área de dados (retornada pela função
NU_Allocate_Partition () ) da partição a ser liberada;
Valor de retorno:
NU_SUCCESS - a chamada foi concluída com sucesso;
NU_INVALID_POINTER - ponteiro de seção NULL ou não indica uma seção válida usada.
Chamada da API do Nucleus SE para liberar partição
Essa chamada de API suporta a funcionalidade principal da API do Nucleus RTOS.
Protótipo de chamada:
STATUS NUSE_Partition_Deallocate (partição ADDR);Parâmetros:
partição - um ponteiro para a área de dados (retornada pela função
NUSE_Partition_Allocate () ) da partição a ser liberada
Valor de retorno:
NUSE_SUCCESS - a chamada foi concluída com sucesso;
NUSE_INVALID_POINTER - o ponteiro da seção é nulo (
NULL ) ou não indica uma seção válida usada
Implementação
Em vez de implementar usando as funções da API de bloqueio e não bloqueio, a função
NUSE_Partition_Deallocate () simplesmente contém uma seção compilada condicionalmente, responsável por desbloquear tarefas. Este código implementa a liberação de seções:

Primeiro, o índice de seção é recuperado do byte de status. Em seguida, o estado da partição muda para "não utilizado", o contador das partições usadas diminui e a função relata a conclusão bem-sucedida da operação.
Se o bloqueio estiver ativado, o código a seguir será usado para retomar as tarefas que aguardam o pool de partições disponível:

Se as tarefas foram bloqueadas ao alocar partições nesse pool, a primeira tabela é retomada.
No próximo artigo, falaremos sobre chamadas de API adicionais relacionadas a partições de memória, bem como estruturas de dados relacionadas.
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.