Pergunta

Eu estou escrevendo um sistema de controle embutido em C que consiste em várias tarefas que enviam mensagens uns aos outros (um idioma bastante comum, eu acredito!), Mas eu estou tendo um momento difícil conceber um mecanismo que:

  • é puro
  • é genérico
  • é relativamente eficiente
  • mais importante: é independente de plataforma (especificamente, não viola as questões estritas-aliasing ou alinhamento)

Conceitualmente, eu gostaria de representar cada tipo de mensagem como uma definição struct separado, e eu gostaria de um sistema com as seguintes funções (simplificado):

void sendMsg(queue_t *pQueue, void *pMsg, size_t size);
void *dequeueMsg(queue_t *pQueue);

onde um queue_t compreende uma lista ligada de nós, cada um com um campo char buf[MAX_SIZE]. O sistema que eu estou em não ter uma implementação malloc(), por isso não precisa ser um conjunto global de nós livres, e, em seguida, um dos seguintes (questões percebidas em negrito):

  1. sendMsg() faz um memcpy da mensagem recebida no buffer de um nó livre.
    O meu entendimento é que isso terá problemas de alinhamento menos que o chamador de dequeueMsg() faz mais um memcpy no valor de retorno.
  2. ou haverá uma função void *getFreeBuffer() que retorna o buf[] do próximo nó livre, que o chamador (o remetente) será convertido para o tipo de ponteiro-a-caso.
    O meu entendimento é que este agora terá problemas de alinhamento no caminho, e ainda requer um memcpy após dequeueMsg() a problemas de alinhamento evitar na saída.
  3. ou redefinir o tampão em nós queue_t como (por exemplo) uint32_t buf[MAX_SIZE].
    O meu entendimento é que isso viola aliasing estrito, e não é independente de plataforma.

A única outra opção que eu posso ver é criar uma união de todos os tipos de mensagens, juntamente com char buf[MAX_SIZE], mas eu não conto isso como "pura"!

Assim, a minha pergunta é: como é que uma pessoa fazer isso corretamente?

Foi útil?

Solução

A forma como lidamos com isso é ter nossa lista livre consistir inteiramente de nós alinhados. Na verdade, temos várias listas livres para diferentes tamanhos de nó, por isso temos listas que estão alinhados em 2 de byte, 4 byte, e 16 limites de byte (nossa plataforma não se preocupa com o alinhamento maior do que um vector SIMD). Qualquer alocação fica arredondado para um desses valores e colocar em um nó devidamente alinhados. Assim, SENDMSG sempre copia os dados para um nó alinhados. Desde que você está escrevendo a lista livre, você pode facilmente aplicar alinhamento.

Também seria usar um #pragma ou declspec para forçar que a matriz de char buf [MAX_SIZE] para ser alinhada com pelo menos um limite de palavra no interior do nó queue_t struct.

Isso pressupõe, naturalmente, que os dados de entrada está alinhada, mas se por algum motivo você está passando em uma mensagem que espera para ser (digamos) 3 bytes fora do alinhamento, você pode sempre detectar que com um módulo e retornar um deslocamento no nó livre.

Com essa concepção subjacente temos interfaces que suportam tanto a opção 1 e 2 acima. Mais uma vez, nós condição prévia para que os dados de entrada é sempre nativamente alinhadas, de modo a retirar da fila de curso retorna um ponteiro alinhados; Mas se você precisa estranhamente alinhados dados, novamente, apenas deslocamento no nó livre e retornar o ponteiro offset.

Isso mantém você lidar em void * s evitando assim os seus problemas aliasing estritas. (Em geral, porém eu acho que você pode precisar para relaxar os requisitos aliasing estritas ao escrever seus próprios alocadores de memória, uma vez que, por natureza, eles borrar tipos internamente.)

Outras dicas

Eu não entendo por que 1 apresenta um problema de alinhamento - contanto que cada elemento buf[MAX_SIZE] está alinhado com o maior tipo natural única primitiva que ocorre em suas estruturas de mensagem (provavelmente 32 ou 64 bits), então não importa o que o conteúdo de cada tipo de mensagem é; como ele vai ser sempre alinhado a esse tamanho.

Editar

Na verdade, é ainda mais simples do que isso. Como cada elemento em sua fila de mensagens é MAX_SIZE de comprimento, em seguida, assumindo que você começar cada mensagem no seu próprio buf (ou seja, você não embalá-los se uma mensagem é

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top