MMAP

mmap

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 >>
Veja + conteúdo

Engenheiro Elétrico de Formação mas é Engenheiro de Software de profissão, Pós Graduado em Sistemas Embarcados. Apaixonado por Idiomas, mas o idioma que mais lhe fascina é a Linguagem C.
Jogador de CTF, mas prefire Battlefield 1, exige menos da capacidade cognitiva :P. Atualmente atua como desenvolvedor de sistemas distribuídos no ramo aeronáutico. Quando está de bobeira fica desenhando personagens de Anime ou pedalando pela cidade de São Paulo.

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Comentários:
Notificações
Notificar
guest
0 Comentários
Inline Feedbacks
View all comments
Talvez você goste:

Nenhum resultado encontrado.

Séries



Outros da Série

Menu