MMAP

Oitavo artigo da série comunicação entre processos, Descreve o uso do mmap, recurso que permite compartilhar uma quantidade de memória entre dois processos.

Introdução

O mmap cria um novo mapeamento de memória virtual, que pode ser de dois tipos: Mapeamento de arquivo, onde é necessário um arquivo para poder mapear essa memória, e o mapeamento anônimo, nesse caso não é necessário um arquivo para realizar o mapeamento. O mapeamento pode ser de dois tipos privado ou compartilhado, para que esse recurso possa ser usado na forma de IPC, precisa ser do tipo compartilhado, sendo esse o modo que será abordado no artigo. Se dois processos utilizarem o mesmo arquivo para mapear essa memória com o tipo compartilhado, um processo pode enxergar o que o outro está alterando, permitindo assim a troca de mensagem entre eles.

Criando um mapeamento de memória

Para realizar a criação desse mapeamento faz-se uso da system call mmap, onde o primeiro argumento representa o endereço onde esse mapeamento vai ser feito, o segundo argumento representa o tamanho dessa memória, o terceiro argumento representa a proteção dessa memória, o quarto o descritor do arquivo usado para esse mapeamento e por fim o quinto é o offset.

para mais informações sobre esse system call utilize o manual do linux

A imagem abaixo demonstra a interação entre dois processos compartilhando a mesma região de memória:

mmap

Destruindo um mapeamento de memória

Para destruir um mapeamento realizado, é utilizado a system call munmap, que libera essa porção de memória alocada.

Implementação

Para demonstrar o uso desse IPC, iremos utilizar o modelo Produtor/Consumidor, onde o processo Produtor(button_process) vai escrever seu estado interno no arquivo, e o Consumidor(led_process) vai ler o estado interno e vai aplicar o estado para si. Aplicação é composta por três executáveis sendo eles:

  • launch_processes – é responsável por lançar os processos button_process e led_process atráves da combinação fork e exec
  • button_interface – é reponsável por ler o GPIO em modo de leitura da Raspberry Pi e escrever o estado interno no arquivo
  • led_interface – é reponsável por ler do arquivo o estado interno do botão e aplicar em um GPIO configurado como saída

Para facilitar o desenvolvimento da aplicação, as funções pertinentes ao mmap foram abstraídas na forma de biblioteca para que facilite o uso na aplicação.

Biblioteca mapping

Essa biblioteca é um wrapper para as funções mmap, onde sua inicialização é comum para ambos os processos, para maior praticidade foram encapsuladas em duas funções, mapping file e mapping_cleanup.

Essa função retorna o endereço de uma memória compartilhada, a partir de um arquivo e o tamanho desejado

É Criado duas variáveis nesse ponto uma para guardar o descritor do arquivo, e um ponteiro genérico para guardar o endereço da memória que iremos alocar

Abrimos o descritor usando o nome do arquivo passado por argumento, e como permissão de leitura e escrita, caso o arquivo não exista, ele o cria, após sua criação preparamos o arquivo para ser do tamanho da memória que iremos utilizar

Criamos a memória usando descritor com permissão de escrita e do tipo compartilhado.

Por fim fechamos o descritor e retornamos o endereço da memória alocada

Essa função é responsável por liberar a memória alocada pelo mmap

launch_processes

No main criamos duas variáveis para armazenar o PID do button_process e do led_process, e mais duas variáveis para armazenar o resultado caso o exec venha a falhar.

Em seguida criamos um processo clone, se processo clone for igual a 0, criamos um array de strings com o nome do programa que será usado pelo exec, em caso o exec retorne, o estado do retorno é capturado e será impresso no stdout e aborta a aplicação. Se o exec for executado com sucesso o programa button_process será carregado.

O mesmo procedimento é repetido novamente, porém com a intenção de carregar o led_process.

button_interface

Definimos o tamanho que a memória e o caminho do arquivo e o nome do arquivo

Criamos uma função auxiliar para alternar o estado da variável que vai refletir no estado do LED

Criamos uma função auxiliar para escrever dados na memória compartilhada

No Button_Run definimos uma variável genérica para guardar o endereço da memória compartilhada

Inicializamos a interface button

Criamos a memória usando o nome e o tamanho, com o endereço da memória em mãos podemos escrever e ler os dados da memória compartilhada

Aguardamos o pressionamento do botão e executamos a escrita na memória usando a função auxiliar set_value passando o endereço da memória como argumento

Caso venha sair do loop liberamos a memória alocada

led_interface

Definimos o tamanho que a memória e o caminho do arquivo e o nome do arquivo

Criamos uma função auxiliar para ler o valor da memória compartilhada

Em LED_Run criamos três variáveis, duas para controlar o estado do LED e uma para armazenar o valor da memória compartilhada

Inicializamos a interface de LED

Criamos a memória usando o nome e o tamanho, com o endereço da memória em mãos podemos escrever e ler os dados da memória compartilhada

Ficamos fazendo polling lendo o conteúdo da memória e verificando se o estado anterior é diferente do estado atual, caso sim, então aplicamos o novo estado

Caso venha sair do loop liberamos a memória alocada

Compilando, Executando e Matando os processos

Para compilar e testar o projeto é necessário instalar a biblioteca de hardware necessária para resolver as dependências de configuração de GPIO da Raspberry Pi.

Compilando

Para facilitar a execução do exemplo, o exemplo proposto foi criado baseado em uma interface, onde é possível selecionar se usará o hardware da Raspberry Pi 3, ou se a interação com o exemplo vai ser através de input feito por FIFO e o output visualizado através de LOG.

Clonando o projeto

Pra obter uma cópia do projeto execute os comandos a seguir:

Selecionando o modo

Para selecionar o modo devemos passar para o cmake uma variável de ambiente chamada de ARCH, e pode-se passar os seguintes valores, PC ou RASPBERRY, para o caso de PC o exemplo terá sua interface preenchida com os sources presentes na pasta src/platform/pc, que permite a interação com o exemplo através de FIFO e LOG, caso seja RASPBERRY usará os GPIO’s descritos no artigo.

Modo PC

Modo RASPBERRY

Executando

Para executar a aplicação execute o processo launch_processes para lançar os processos button_process e led_process que foram determinados de acordo com o modo selecionado.

Uma vez executado podemos verificar se os processos estão rodando atráves do comando

O output

Interagindo com o exemplo

Dependendo do modo de compilação selecionado a interação com o exemplo acontece de forma diferente

MODO PC

Para o modo PC, precisamos abrir um terminal e monitorar os LOG’s

Dessa forma o terminal irá apresentar somente os LOG’s referente ao exemplo.

Para simular o botão, o processo em modo PC cria uma FIFO para permitir enviar comandos para a aplicação, dessa forma todas as vezes que for enviado o número 0 irá logar no terminal onde foi configurado para o monitoramento, segue o exemplo

Output do LOG quando enviado o comando algumas vezez

MODO RASPBERRY

Para o modo RASPBERRY a cada vez que o botão for pressionado irá alternar o estado do LED.

Matando os processos

Para matar os processos criados execute o script kill_process.sh

Conclusão

O mmap é um IPC bastante relevante para realizar troca de mensagens entre os processos, ele possui outras características interessantes que não foram abordadas, como por exemplo setorização. Esse mecanismo é de extrema importância para permitir o uso de memória compartilhada baseada em POSIX, porém necessita de polling para verificar se o dado presente foi alterado, necessitando de outros mecanismos para sincronização (como o Signal), o que gera overhead de verificação e dependendo da aplicação pode ser um fator impactante na performance.

Referência

Outros artigos da série

<< Signal – O que é e como usar?Socket TCP >>
Notificações
Notificar
guest
0 Comentários
Inline Feedbacks
View all comments

WEBINAR

Visão Computacional para a redução de erros em processos manuais

DATA: 23/09 ÀS 17:00 H