
Neste artigo, continuaremos a considerar filas.
Serviços de Fila Secundária
O Nucleus RTOS possui quatro chamadas de API que fornecem funções auxiliares relacionadas a filas: redefinir uma fila, obter informações da fila, obter o número de filas em um aplicativo e obter ponteiros para todas as filas em um aplicativo. As três primeiras funções são implementadas no Nucleus SE.
Artigos anteriores da série:
Artigo 23. Filas: introdução e serviços básicosArtigo 22. Caixas de correio: serviços auxiliares e estruturas de dadosArtigo 21. Caixas de correio: Introdução e serviços básicosArtigo 20. Semáforos: Serviços Auxiliares e Estruturas de DadosArtigo 19. Semáforos: introdução e serviços básicosArtigo # 18 Grupos de Sinalizadores de Eventos: Serviços Auxiliares e Estruturas de DadosArtigo 17. Grupos de Sinalizadores de Eventos: Introdução e Serviços BásicosArtigo 16. SignalsArtigo 15. Partições de memória: serviços e estruturas de dadosArtigo 14. Seções de memória: introdução e serviços básicosArtigo 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.Redefinição de fila
Essa chamada de API redefine a fila para seu estado original e não utilizado. Quaisquer mensagens armazenadas na fila serão perdidas. Todas as tarefas pausadas na fila serão retomadas com o código de retorno
NUSE_QUEUE_WAS_RESET .
Chamada de redefinição de fila no Nucleus RTOSProtótipo de chamada de serviço:
STATUS NU_Reset_Queue (fila NU_QUEUE *);Parâmetros:
fila - um ponteiro para um bloco de controle de fila fornecido pelo usuário.
Valor de retorno:
NU_SUCCESS - a chamada foi concluída com sucesso;
NU_INVALID_QUEUE - ponteiro de fila inválido.
Chamada de redefinição de fila no Nucleus SEEssa chamada de utilitário suporta a funcionalidade principal da API Nucleus RTOS.
Protótipo de chamada de serviço:
STATUS NUSE_Queue_Reset (fila NUSE_QUEUE);Parâmetros:
fila - índice (ID) da fila despejada.
Valor de retorno:
NUSE_SUCCESS - a chamada foi concluída com sucesso;
NUSE_INVALID_QUEUE - índice de fila inválido.
Implementando redefinição de fila no Nucleus SEO código da função
NUSE_Queue_Reset (depois de verificar os parâmetros) é bastante simples. Os índices da cabeça e cauda da fila, bem como o contador de mensagens na fila, recebem um valor zero.
Se o bloqueio de tarefas estiver ativado, um código adicional será responsável por restaurar as tarefas suspensas:
while (NUSE_Queue_Blocking_Count[queue] != 0) { U8 index; /* check whether any tasks are blocked */ /* on this queue */ for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_QUEUE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == queue)) { NUSE_Task_Blocking_Return[index] = NUSE_QUEUE_WAS_RESET; NUSE_Task_Status[index] = NUSE_READY; break; } } NUSE_Queue_Blocking_Count[queue]--; } #if NUSE_SCHEDULER_TYPE == NUSE_PRIORITY_SCHEDULER NUSE_Reschedule(NUSE_NO_TASK); #endif
Cada tarefa em pausa na fila recebe um status de "pronto" com um código de retorno
NUSE_QUEUE_WAS_RESET . Após a conclusão desse processo, se o agendador de prioridade for usado, a função
NUSE_Reschedule () será
chamada , pois uma ou mais tarefas com alta prioridade podem estar prontas para serem executadas.
Obtendo informações da fila
Esta chamada de serviço fornece informações da fila. A implementação dessa chamada no Nucleus SE difere do Nucleus RTOS, pois retorna menos informações, pois a nomeação de objetos, o comprimento variável das mensagens e a ordem de pausa da tarefa não são suportados e o bloqueio de tarefas pode ser desativado.
Chamada para informações da fila no núcleo RTOSProtótipo de chamada de serviço:
STATUS NU_Queue_Information (fila NU_QUEUE *, CHAR * nome, VOID ** start_address, UNSIGNED * queue_size, UNSIGNED * disponível, mensagens UNSIGNED *, OPTION * message_type, UNSIGNED * message_size, OPTION * suspend_type, UNSIGNED * first_tasktask_Parâmetros:
fila - um ponteiro para um bloco de controle de fila fornecido pelo usuário;
nome - ponteiro para a região de 8 caracteres para o nome da mensagem na fila;
start_address - um ponteiro para um ponteiro no qual o endereço do início da área de dados da fila será gravado;
queue_size - um ponteiro para uma variável para armazenar o número total de elementos
UNSIGNED na fila;
available - um ponteiro para uma variável para armazenar o número de elementos
UNSIGNED disponíveis na fila;
messages - um ponteiro para uma variável para armazenar o número atual de mensagens na fila;
message_type - um ponteiro para uma variável para armazenar o tipo de mensagens suportadas pela fila. Os valores válidos são
NU_FIXED_SIZE e
NU_VARIABLE ;
message_size - um ponteiro para uma variável para armazenar o número de elementos de dados
UNSIGNED em cada mensagem da fila. Se a fila suportar mensagens de tamanho variável, esse número indica o tamanho máximo da mensagem;
suspend_type - um ponteiro para uma variável para armazenar o tipo de suspensão de tarefas. Os valores válidos são
NU_FIFO e
NU_PRIORITY ;
tasks_waiting - um ponteiro para uma variável para armazenar o número de tarefas suspensas nessa fila;
first_task - ponteiro para o ponteiro da tarefa, no qual o ponteiro da primeira tarefa suspensa é colocado.
Valor de retorno:
NU_SUCCESS - a chamada foi concluída com sucesso;
NU_INVALID_QUEUE - ponteiro de fila inválido.
Chamada para obter informações da fila no Nucleus SEEssa chamada de API suporta a funcionalidade principal da API do Nucleus RTOS.
Protótipo de chamada de serviço:
STATUS NUSE_Queue_Information (fila NUSE_QUEUE, ADDR * endereço_admin, U8 * tamanho da fila, U8 * disponível, U8 * disponível, mensagens U8 *, U8 * tarefas_a espera, NUSE_TASK * primeira_tarefa);Parâmetros:
fila - índice da fila sobre a qual as informações são solicitadas;
start_address - ponteiro para uma variável do tipo
ADDR , que armazenará o endereço do início da área de dados da fila;
queue_size - um ponteiro para uma variável do tipo
U8 , que armazenará o número total de mensagens que podem caber na fila;
disponível - um ponteiro para uma variável do tipo
U8 , que armazenará o número de locais livres na fila;
messages - um ponteiro para uma variável do tipo
U8 , que armazenará o número atual de mensagens na fila;
tasks_waiting - um ponteiro para uma variável na qual o número de tarefas suspensas nessa fila será armazenado (nada será retornado se o bloqueio de tarefas estiver desativado);
first_task - um ponteiro para uma variável do tipo
NUSE_TASK na qual o índice da primeira tarefa suspensa será armazenado (nada será retornado se o bloqueio da tarefa estiver desativado).
Valor de retorno:
NUSE_SUCCESS - a chamada foi concluída com sucesso;
NUSE_INVALID_QUEUE - índice de fila inválido;
NUSE_INVALID_POINTER - um ou mais parâmetros do ponteiro estão incorretos.
Implementando a exibição de informações da fila no Nucleus SEA implementação desta chamada de API é bastante simples:
*start_address = NUSE_Queue_Data[queue]; *queue_size = NUSE_Queue_Size[queue]; *available = NUSE_Queue_Size[queue] - NUSE_Queue_Items[queue]; *messages = NUSE_Queue_Items[queue]; #if NUSE_BLOCKING_ENABLE *tasks_waiting = NUSE_Queue_Blocking_Count[queue]; if (NUSE_Queue_Blocking_Count[queue] != 0) { U8 index; for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_QUEUE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == queue)) { *first_task = index; break; } } } else { *first_task = 0; } #else *tasks_waiting = 0; *first_task = 0; #endif
A função retorna o status da fila. Em seguida, se o bloqueio de tarefas estiver ativado, o número de tarefas pendentes e o índice da primeira delas serão retornados (caso contrário, os dois parâmetros serão definidos como 0).
Obtendo o número de filas
Essa chamada de utilitário retorna o número de filas configuradas no aplicativo. No núcleo RTOS, seu número pode mudar com o tempo e o valor de retorno indicará o número atual de filas. No Nucleus SE, o valor de retorno é definido durante a fase de construção e não pode ser alterado.
Chamando o contador de filas no Nucleus RTOSProtótipo de chamada de serviço:
NU_Established_Queues NÃO ASSINADOS (VOID);Parâmetros:
Estão ausentes.
Valor de retorno:
O número de filas criadas no sistema.
Chamando o contador de filas no Nucleus SEEssa chamada de API suporta a funcionalidade principal da API do Nucleus RTOS.
Protótipo de chamada de serviço:
U8 NUSE_Queue_Count (nulo);Parâmetros:
Estão ausentes.
Valor de retorno:
O número de filas configuradas no aplicativo.
Implementando o contador de filas no Nucleus SEA implementação desta chamada de API é muito simples: o valor do símbolo
#define NUSE_QUEUE_NUMBER é
retornado .
Estruturas de dados
As filas usam cinco ou seis estruturas de dados (que estão na RAM ou na ROM), que são conjuntos de tabelas (como outros objetos do Nucleus SE), cujo número e tamanho correspondem ao número de filas no aplicativo e aos parâmetros selecionados.
Dados do kernel na RAM
Esses dados têm a seguinte estrutura:
NUSE_Queue_Head [] é uma matriz de ponteiros do tipo
U8 , possui uma entrada para cada fila configurada e aponta para o início da fila de mensagens. Usado como um índice de endereço em
NUSE_Queue_Data [] (veja abaixo);
NUSE_Queue_Tail [] é uma matriz do tipo
U8 , possui uma entrada para cada fila configurada no aplicativo e aponta para o final da fila de mensagens. Usado como um índice de endereço em
NUSE_Queue_Data [] (veja abaixo);
NUSE_Queue_Items [] é uma matriz do tipo
U8 , possui uma entrada para cada fila configurada e é um contador de mensagens na fila. Esses dados podem ser considerados redundantes, pois esses valores podem ser obtidos através dos índices do início e do fim da fila, no entanto, armazenar o contador simplifica o código;
NUSE_Queue_Blocking_Count [] - essa matriz do tipo
U8 contém contadores do número de tarefas suspensas em cada fila. Essa matriz é criada apenas se o suporte ao bloqueio de tarefas estiver ativado.
Essas estruturas de dados são inicializadas em zeros pela função
NUSE_Init_Queue () quando o Nucleus SE é iniciado. Isso é lógico, pois todas as filas são criadas vazias (não usadas).
A seguir, estão as definições dessas estruturas no arquivo
nuse_init.c :
RAM U8 NUSE_Queue_Head[NUSE_QUEUE_NUMBER]; RAM U8 NUSE_Queue_Tail[NUSE_QUEUE_NUMBER]; RAM U8 NUSE_Queue_Items[NUSE_QUEUE_NUMBER]; #if NUSE_BLOCKING_ENABLE RAM U8 NUSE_Queue_Blocking_Count[NUSE_QUEUE_NUMBER]; #endif
Dados do usuário da RAM
O usuário é responsável por fornecer uma área de RAM para armazenar cada fila. O tamanho dessa área deve conter uma matriz do tipo
ADDR , na qual cada registro corresponde a uma mensagem na fila
Dados ROM
Esses dados têm a seguinte estrutura:
NUSE_Queue_Data [] - uma matriz do tipo
ADDR , possui uma entrada para cada fila configurada e aponta para a área de dados da fila (consulte. Dados da RAM do usuário);
NUSE_Queue_Size [] - uma matriz do tipo
U8 , possui uma entrada para cada fila configurada e mostra o número máximo de mensagens que cada fila pode receber.
Essas estruturas de dados são declaradas e inicializadas (estaticamente) no arquivo
nuse_config.c :
ROM ADDR *NUSE_Queue_Data[NUSE_QUEUE_NUMBER] = { /* addresses of queue data areas ------ */ }; ROM U8 NUSE_Queue_Size[NUSE_QUEUE_NUMBER] = { /* queue sizes ------ */ };
A quantidade de memória para filas
Como todos os objetos do kernel do Nucleus SE, a quantidade de memória necessária para as filas é facilmente previsível.
A quantidade de dados na ROM (em bytes) para todas as filas no aplicativo pode ser calculada da seguinte maneira:
NUSE_QUEUE_NUMBER * (sizeof (ADDR) + 1)A quantidade de dados do kernel na RAM (em bytes) para todas as filas no aplicativo com bloqueio de tarefas ativado é calculada da seguinte maneira:
NUSE_QUEUE_NUMBER * 3Se o bloqueio estiver desativado:
NUSE_QUEUE_NUMBER * 4A quantidade de dados do usuário na RAM (em bytes) para a fila com o índice da
fila :
NUSE_Queue_Size [fila] * sizeof (ADDR)Chamadas de API não realizadas
Quatro chamadas de API que podem ser encontradas no Nucleus RTOS não são implementadas no Nucleus SE:
Criação de fila
Essa chamada de API cria uma fila; no Nucleus SE, isso não é necessário, pois as filas são criadas estaticamente.
Protótipo de chamada de serviço:
STATUS NU_Create_Queue (NU_QUEUE * fila, char * nome, VOID * start_address, UNSIGNED queue_size, OPTION message_type, OPTION message_type, UNSIGNED message_size, OPTION suspend_type);Parâmetros:
fila - um ponteiro para uma unidade de controle fornecida pelo usuário, usado para gerenciar filas em outras chamadas de API;
nome - um ponteiro para um nome de fila de 7 caracteres com um byte final nulo;
endereço_início - endereço do início da fila;
message_type - tipo de mensagem suportado pela fila. Pode levar os valores
NU_FIXED_SIZE ou
NU_VARIABLE_SIZE ;
message_size - se a fila suportar mensagens de tamanho fixo, esse parâmetro definirá o tamanho exato de cada mensagem; caso contrário, se a fila suportar mensagens de tamanho variável, esse valor será o tamanho máximo da mensagem;
suspend_type - Determina o tipo de tarefas de suspensão na fila. Pode levar os valores
NU_FIFO e
NU_PRIORITY , que significam o princípio de FIFO (primeiro a
entrar , primeiro a sair) ou o princípio de prioridade da suspensão de tarefas, respectivamente.
Valor de retorno:
NU_SUCCESS - a chamada foi concluída com sucesso;
NU_INVALID_QUEUE - ponteiro nulo para o bloco de controle de fila (
NULL ) ou o ponteiro já está em uso;
NU_INVALID_MEMORY - área de memória inválida especificada no
endereço_início ;
NU_INVALID_MESSAGE - parâmetro
message_type inválido;
NU_INVALID_SIZE - a fila não suporta mensagens desse tamanho ou o tamanho da fila e / ou tamanho da mensagem é 0;
NU_INVALID_SUSPEND - parâmetro
suspend_type inválido.
Excluir fila
Essa chamada de API exclui a fila criada anteriormente. O Núcleo SE não precisa disso porque as filas são criadas estaticamente e não podem ser excluídas.
Protótipo de chamada de serviço:
STATUS NU_Delete_Queue (fila NU_QUEUE *);Parâmetros:
fila - um ponteiro para um bloco de controle de fila.
Valor de retorno:
NU_SUCCESS - a chamada foi concluída com sucesso;
NU_INVALID_QUEUE - ponteiro de fila inválido.
Ponteiros de fila
Essa chamada de API cria uma lista seqüencial de ponteiros para todas as filas no sistema. O Nucleus SE não precisa disso porque as filas são identificadas usando um índice simples, não um ponteiro.
Protótipo de chamada de serviço:
UNSIGNED NU_Queue_Pointers (NU_QUEUE ** lista_do_intervalo, UNSIGNED maximum_pointers);Parâmetros:
pointer_list - ponteiro para uma matriz de ponteiros
NU_QUEUE . Essa matriz será preenchida com ponteiros para filas criadas no sistema;
maximum_pointers - o número máximo de ponteiros na matriz.
Valor de retorno:
O número de ponteiros
NU_QUEUE na matriz.
Enfileiramento (Broadcast to Queue)
Essa chamada de API passa a mensagem para todas as tarefas suspensas na fila que aguardam mensagens da fila especificada. Esse recurso não é implementado no Nucleus SE, pois adiciona redundância.
Protótipo de chamada de serviço:
STATUS NU_Broadcast_To_Queue (fila NU_QUEUE *, mensagem VOID *, tamanho NÃO ASSINADO, suspensão NÃO ASSINADA);Parâmetros:
fila - um ponteiro para um bloco de controle de fila;
message - ponteiro para a mensagem transmitida;
size - o número de elementos
UNSIGNED na mensagem. Se a fila suportar mensagens de tamanho variável, esse parâmetro deverá ser igual ou menor que o tamanho da mensagem suportada pela fila. Se a fila suportar mensagens de tamanho fixo, esse parâmetro deverá ser igual ao tamanho da mensagem suportada pela fila;
suspender - indica se a tarefa de chamada deve ser suspensa se a fila já estiver cheia. Pode ser
NU_NO_SUSPEND ,
NU_SUSPEND ou um valor de tempo limite.
Valor de retorno:
NU_SUCCESS - a chamada foi concluída com sucesso;
NU_INVALID_QUEUE - ponteiro de fila inválido;
NU_INVALID_POINTER - ponteiro nulo para uma mensagem (
NULL );
NU_INVALID_SIZE - o comprimento da mensagem especificado não é compatível com o comprimento especificado ao criar a fila;
NU_INVALID_SUSPEND - tente pausar uma tarefa de um thread não associado à tarefa;
NU_QUEUE_FULL - não há espaço suficiente na fila para a mensagem;
NU_TIMEOUT - a fila ainda está cheia após o tempo limite expirar;
NU_QUEUE_DELETED - a fila foi excluída enquanto a tarefa estava suspensa;
NU_QUEUE_RESET - A fila foi redefinida enquanto a tarefa estava suspensa.
Compatível com núcleo RTOS
Como com todos os outros objetos do Nucleus SE, meu objetivo era maximizar a compatibilidade do código do aplicativo com o Nucleus RTOS. As filas não são exceção e, do ponto de vista do usuário, são implementadas da mesma maneira que no Nucleus RTOS. Há também uma certa incompatibilidade, que eu considerei aceitável, já que, como resultado, o código se tornará mais compreensível e mais eficiente em termos da quantidade de memória necessária. Caso contrário, as chamadas da API do Nucleus RTOS poderão ser portadas quase diretamente para o Nucleus SE.
Identificadores de objeto
No Nucleus RTOS, todos os objetos são descritos por uma estrutura de dados (unidades de controle) que possui um tipo de dados específico. Um ponteiro para esta unidade de controle é o identificador da fila. Decidi que no Nucleus SE é necessária uma abordagem diferente para o uso eficiente da memória: todos os objetos do kernel são descritos por um conjunto de tabelas na RAM e / ou ROM. O tamanho dessas tabelas é determinado pelo número de objetos configurados de cada tipo. O identificador de um objeto específico é o índice nesta tabela. Então, eu defini
NUSE_QUEUE como o equivalente a
U8 , uma variável (não um ponteiro) desse tipo serve como identificador da fila. Essa pequena incompatibilidade é fácil de lidar se o código for portado do Nucleus SE para o Nucleus RTOS e vice-versa. Normalmente, nenhuma operação é executada nos identificadores de objeto além de mover e armazenar.
O núcleo RTOS também suporta a nomeação de filas. Esses nomes são usados apenas para depuração. Excluí-os do Nucleus SE para economizar memória.
Tamanho e tipo da mensagem
No Nucleus RTOS, uma fila pode ser configurada para processar mensagens que consistem em qualquer número de elementos
não assinados . No Nucleus SE, as filas são simplificadas e suportam apenas mensagens do tipo
ADDR . Os canais de dados do Nucleus SE são um pouco mais flexíveis e, em alguns casos, podem ser uma alternativa útil às filas. Os canais serão abordados nos próximos dois artigos desta série.
O Núcleo SE também suporta filas de mensagens de tamanho variável, que especificam apenas o tamanho máximo da mensagem durante a criação. Comprimentos de mensagem variáveis não são suportados pelo Nucleus SE
Tamanho da fila
No Núcleo SE, o número máximo de mensagens em uma fila é 256, pois todas as variáveis e constantes são do tipo
U8 . O núcleo RTOS não tem essas limitações.
Chamadas de API não realizadas
O núcleo RTOS suporta dez chamadas de gerenciamento de filas. Destes, quatro não estão implementados no Nucleus SE. Detalhes dessas chamadas, bem como os motivos de tal decisão, podem ser encontrados neste artigo acima, na seção "Chamadas de API não realizadas".
O próximo artigo discutirá os canais de transmissão de dados.
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.