Toda a verdade sobre o RTOS. Artigo 15. Partições de memória: serviços e estruturas de dados



Neste artigo, continuamos a revisar as seções de memória do RTOS.

O Nucleus RTOS possui três chamadas de API que fornecem funções utilitárias relacionadas aos conjuntos de partições de armazenamento: retornando informações sobre conjuntos de partições, retornando o número de conjuntos de partições em um aplicativo e retornando ponteiros para todos os conjuntos de partições em um aplicativo. Os dois primeiros desafios são implementados no Nucleus SE.

Artigos anteriores da série:
Artigo 14. Seções de memória: introdução e serviços básicos
Artigo 13. Estruturas de dados da tarefa e chamadas de API não suportadas
Artigo 12. Serviços para trabalhar com tarefas
Artigo 11. Tarefas: configuração e introdução à API
Artigo 10. Agendador: recursos avançados e preservação de contexto
Artigo 9. Agendador: implementação
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.

Recuperando informações do conjunto de partições


Esta chamada de serviço fornece informações parciais sobre o conjunto de partições. A implementação do Nucleus SE difere do Nucleus RTOS, pois retorna menos informações porque os objetos de nomeação e as solicitações de pausa não são suportados e a tarefa não pode ser pausada.

Chamando informações do pool de partições no Nucleus RTOS


Protótipo de chamada:

STATUS NU_Partition_Pool_Information (NU_PARTITION_POOL * pool, CHAR * nome, VOID ** start_address, UNSIGNED * pool_size, UNSIGNED * partition_size, UNSIGNED * disponível, UNSIGNED * alocado, OPTION * suspend_type, UNSIGNED * tasks_waiting ** first_task;

Parâmetros:

pool - um ponteiro para o pool de partições sobre o qual as informações são solicitadas;
nome - ponteiro para a área de destino de 8 caracteres para o nome do conjunto de partições; inclui um local para terminar zero;
start_address - um ponteiro para uma variável que recebe um ponteiro para o início da área de dados do pool de partições;
pool_size - um ponteiro para uma variável que recebe o tamanho do pool de partições (em bytes);
partition_size - ponteiro para uma variável que obtém o tamanho das partições em um determinado pool;
available - um ponteiro para uma variável que recebe o número de partições atualmente disponíveis nesse pool;
alocado - um ponteiro para uma variável que recebe o número de partições usadas atualmente em um determinado pool;
suspend_type - ponteiro para uma variável para obter o tipo de suspensão da tarefa; tipos de suspensão válidos: NU_FIFO e NU_PRIORITY ;
task_waiting - um ponteiro para uma variável que recebe o número de tarefas suspensas em um determinado conjunto de partições;
first_task - ponteiro para o ponteiro da tarefa em que o ponteiro da primeira tarefa suspensa está localizado.

Valor de retorno:

NU_SUCCESS - chamada concluída com sucesso;
NU_INVALID_POOL - ponteiro inválido para o conjunto de partições.

Chamando Informações do Conjunto de Partições no Nucleus SE


Protótipo de chamada:

STATUS NUSE_Partition_Pool_Information (pool NUSE_PARTITION_POOL, ADDR * endereço_address, U32 * tamanho_do_s Pool, U16 * tamanho_de_partição, U8 * disponível, U8 * alocado, U8 * tarefas_a espera, NUSE_TASK * first_task)

Parâmetros:

pool - o índice do pool de partições sobre o qual as informações são solicitadas;
start_address - um ponteiro para uma variável que recebe um ponteiro para o início da área de dados do pool de partições;
pool_size - um ponteiro para uma variável que recebe o tamanho do pool de partições (em bytes);
partition_size - ponteiro para uma variável que obtém o tamanho das partições em um determinado pool;
available - um ponteiro para uma variável que recebe o número de partições atualmente disponíveis nesse pool;
alocado - um ponteiro para uma variável que recebe o número de partições usadas atualmente em um determinado pool;
tasks_waiting - um ponteiro para uma variável que recebe o número de tarefas suspensas nesse conjunto de partições (se a suspensão da tarefa estiver desativada, 0 será retornado);
first_task - um ponteiro para uma variável do tipo NUSE_TASK , que recebe o índice da primeira tarefa suspensa (se a suspensão da tarefa estiver desativada, 0 será retornado).

Valor de retorno:

NUSE_SUCCESS - chamada concluída com sucesso;
NUSE_INVALID_POOL - índice do conjunto de partições inválido;
NUSE_INVALID_POINTER - um ou mais dos ponteiros transmitidos são inválidos.

Implementando recuperação de informações e pool de partições no Nucleus SE


A implementação de uma chamada de API é simples de executar:



A função retorna o status do conjunto de partições. Se o bloqueio de chamadas da API estiver ativado, o número de tarefas pendentes e o índice da primeira delas serão retornados (caso contrário, esses parâmetros serão definidos como 0).

Obtendo o número de conjuntos de partições


Essa chamada retorna informações sobre o número de conjuntos de partições configurados no aplicativo. Enquanto no Nucleus RTOS esse número muda com o tempo e o valor de retorno representa o número atual de conjuntos, no Nucleus SE o valor de retorno é definido durante a montagem e permanece inalterado.

O desafio de obter o número de conjuntos de partições no Nucleus RTOS


A chamada suporta a funcionalidade principal da API Nucleus RTOS.

Protótipo de chamada:

UNSIGNED NU_Established_Partition_Pools (VOID);

Parâmetros:

Estão ausentes.

Valor de retorno:

O número de conjuntos de partições criados no aplicativo.

O desafio de obter o número de conjuntos de partições no Nucleus SE


Essa chamada de utilitário suporta a funcionalidade principal da API Nucleus RTOS.

Protótipo de chamada:

U8 NUSE_Partition_Pool_Count (nulo);

Parâmetros:

Estão ausentes

Valor de retorno:

O número de conjuntos de partições criados no aplicativo.

Implementação


A implementação desta chamada de API é extremamente simples: o valor #define do símbolo NUSE_PARTITION_POOL_NUMBER é retornado .

Estruturas de dados


Como todos os outros objetos do Nucleus SE, os conjuntos de partições usam matrizes de estrutura na ROM e na RAM, cujo número depende do número de conjuntos especificado nas configurações.

Eu recomendo fortemente que o código do aplicativo acesse essas estruturas de dados por meio de funções da API e não diretamente. Isso evita incompatibilidade com versões futuras do Nucleus SE e efeitos colaterais indesejados, além de simplificar a portabilidade do aplicativo para o Nucleus RTOS. A seguir, é apresentada uma descrição detalhada das estruturas de dados para facilitar o entendimento do código de chamada de serviço e da depuração.

Estrutura dos dados do kernel colocados na RAM


Essas estruturas de dados incluem:

NUSE_Partition_Pool_Partition_Used [] - uma matriz do tipo U8 , com uma entrada para cada conjunto de partições configurado, contendo um contador dos conjuntos usados ​​no momento;
NUSE_Partition_Pool_Blocking_Count [] - uma matriz do tipo U8 que contém um contador de tarefas bloqueadas em cada pool de partições. Essa matriz existe se for possível bloquear a chamada da API.

Tais estruturas de dados são inicializadas em zeros usando NUSE_Init_ Partition_Pool () ao iniciar o Nucleus SE. Isso é lógico, pois torna cada partição em cada pool não utilizada (gratuita). O artigo a seguir fornecerá uma descrição completa dos procedimentos de inicialização no Nucleus SE.

A seguir, são apresentadas descrições das estruturas de dados no arquivo nuse_init.c .



Dados do usuário da RAM


O usuário precisa alocar uma área na RAM para armazenar dados para cada conjunto de partições. A quantidade de espaço na RAM deve corresponder ao volume de partições configuradas (consulte "Dados na ROM" abaixo) com um byte adicional para cada partição no pool. Cada seção da área de dados é precedida por um byte de status.

Dados ROM


Estes incluem:

NUSE_Partition_Pool_Data_Address [] - uma matriz do tipo ADDR , com uma entrada para cada pool de partições configurado, contendo o endereço do início da área de armazenamento de dados;
NUSE_Partition_Pool_Partition_Number [] - uma matriz do tipo U8 com uma entrada para cada conjunto de partições configurado, contendo informações sobre o número de partições no conjunto;
NUSE_Partition_Pool_Partition_Size [] - uma matriz do tipo U16 com uma entrada para cada conjunto de partições configurado, contendo o tamanho das partições para os conjuntos.

Tais estruturas de dados são declaradas e inicializadas (estaticamente) em nuse_config.c :



Pegada de dados para o conjunto de partições


Como em todos os objetos principais do Nucleus SE, a quantidade de memória necessária para os conjuntos de partições é previsível.

O tamanho da ROM (em bytes) para todos os conjuntos de partições de aplicativos pode ser calculado da seguinte maneira:

NUSE_PARTITION_POOL_NUMBER * (tamanho de (ADDR) + 2)

A quantidade de dados do kernel na RAM para todos os conjuntos de partições de aplicativos quando o bloqueio de chamadas da API é ativado leva apenas 2 bytes por conjunto de partições e, quando o bloqueio não é ativado, são necessários 1 byte.

A quantidade de memória para armazenar dados do usuário na RAM varia para cada conjunto de partições, embora, como já mencionado, para um conjunto com índice n possa ser calculado como:

NUSE_Partition_Pool_Partition_Number [n] *
(NUSE_Partition_Pool_Partition_Size [n] + 1)

Chamadas de API não realizadas


Três chamadas de API para conjuntos de partições implementadas no Nucleus RTOS não são suportadas no Nucleus SE.

Criar conjunto de partições


Essa chamada de API cria um conjunto de partições. O Nucleus SE não precisa disso porque as tarefas são criadas estaticamente.

Protótipo de chamada:

STATUS NU_Create_Partition_Pool (NU_PARTITION_POOL * pool, nome CHAR *, VOID * start_address, UNSIGNED pool_size, UNSIGNED pool_size, UNSIGNED partition_size, OPTION suspend_type);

Parâmetros:

pool - um ponteiro para uma unidade de controle de pool de partições definida pelo usuário; usado como um identificador para o conjunto de partições em outras chamadas de API;
nome - um ponteiro para o nome do conjunto de partições, uma cadeia de 7 caracteres com um zero final;
start_address - define o endereço inicial da área de memória do pool de partições;
pool_size - quantidade total de memória em bytes;
partition_size - a quantidade de memória em bytes para cada partição no pool. Além disso, uma pequena quantidade adicional de memória é alocada associada a cada seção, o que é conseguido graças aos dois ponteiros de dados usados.
suspend_type - determina como as tarefas são suspensas no conjunto de partições; As opções de parâmetro válidas são NU_FIFO e NU_PRIORITY .

Valor de retorno:

NU_SUCCESS - indica uma conclusão bem-sucedida da chamada;
NU_INVALID_POOL - indica o valor zero da unidade de controle do conjunto de partições ( NULL );
NU_INVALID_MEMORY - indica o valor zero da área de memória definida pelo endereço start_ ( NULL );
NU_INVALID_SIZE - indica que o tamanho da partição é 0 ou maior que a memória alocada para a partição;
NU_INVALID_SUSPEND - valor inválido de suspend_type .

Excluindo pool de partições


Essa chamada de API exclui um conjunto de partições criado anteriormente. O Nucleus SE não precisa dele porque os objetos são criados estaticamente e não podem ser excluídos.

Protótipo de chamada:

STATUS NU_Delete_Partition_Pool (pool NU_PARTITION_POOL *);

Parâmetros:

pool - ponteiro para a unidade de controle do pool de partições;

Valor de retorno:

NU_SUCCESS - indica uma conclusão bem-sucedida da chamada;
NU_INVALID_POOL - indica um valor inválido para o ponteiro do conjunto de partições;

Ponteiros do Conjunto de Partições


Essa chamada de API cria uma lista seqüencial de ponteiros para todos os conjuntos de partições no sistema. O Núcleo SE não precisa disso porque os objetos são identificados por um índice, não por um ponteiro.

Protótipo de chamada:

UNSIGNED NU_Partition_Pool_Pointers (NU_PARTITION_POOL ** pointer_list, UNSIGNED maximum_pointers);

Parâmetros:

pointer_list - ponteiro para uma matriz de ponteiros NU_PARTITION_POOL ; a matriz é preenchida com ponteiros para conjuntos configurados no sistema;
maximum_pointers - o número máximo de ponteiros que podem ser colocados na matriz.

Valor de retorno:

O número de ponteiros NU_PARTITION_POOL colocados na matriz.

Compatível com núcleo RTOS


Ao desenvolver o Nucleus SE, uma das principais tarefas foi garantir um alto nível de compatibilidade de código com o Nucleus RTOS. Os pools de partições não foram exceção e, do ponto de vista do desenvolvedor, eles são implementados da mesma maneira que no Nucleus RTOS. Algumas áreas existentes de incompatibilidade são aceitáveis, embora valha a pena considerar que o código final é mais fácil de entender e mais eficiente em termos de memória. No entanto, as chamadas da API do Nucleus RTOS podem ser usadas quase diretamente como chamadas do Nucleus SE. Um artigo futuro é planejado com informações sobre o uso do Nucleus SE pelos usuários do Nucleus RTOS.

Identificadores de objeto


No Nucleus RTOS, todos os objetos são descritos por estruturas de dados (unidades de controle) de um tipo específico. Um ponteiro para esse bloco de controle é usado como um identificador para o conjunto de partições. Decidi que o Nucleus SE exigia uma abordagem diferente para um uso mais eficiente da memória. Todos os objetos do kernel são descritos por várias tabelas na RAM e / ou ROM. Os tamanhos dessas tabelas são determinados pelo número de tipos configuráveis ​​de todos os objetos. O identificador para um objeto específico é o índice nessas tabelas. Portanto, defini NUSE_PARTITION_POOL como equivalente a U8 , após o qual uma variável (não um ponteiro) desse tipo serve como identificador da tarefa. Essa leve incompatibilidade é fácil de descobrir se o código é portado de ou para o Nucleus RTOS. Os identificadores de objetos geralmente são armazenados e transmitidos inalterados.

O Nucleus RTOS também suporta nomear pools de partições. Esses nomes são usados ​​apenas para depuração. Excluí-os do Nucleus SE para economizar memória.

Número de seções e seu volume


No Nucleus RTOS, o pool de partições é configurado com base no volume total do pool e no volume de partições (que carregam mais 2 ponteiros). Esses parâmetros são definidos como UNSIGNED (aproximadamente 32 bits). No Nucleus SE, o conjunto de partições é configurado com base no tamanho da partição (para a qual um byte extra foi adicionado) e no número total de partições. Esses parâmetros são definidos como U16 e U8, respectivamente.

Chamadas de API não realizadas


O Nucleus RTOS suporta 7 chamadas para trabalhar com conjuntos de partições, 3 das quais não são implementadas no Nucleus SE. Mais detalhes sobre esses desafios e os motivos de sua exclusão estão descritos acima.

O próximo artigo será sobre sinais.

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.

Source: https://habr.com/ru/post/pt426477/


All Articles