Signal – O que é e como usar?

Sétimo artigo da série Comunicação entre processos. Este artigo apresenta uma explicação do que é Signal e como usá-lo

Introdução

Signal é uma notificação que avisa um determinado processo que um evento ocorreu. Signal é considerado uma interrupção por software, similar a interrupção via hardware, onde quando há um evento, o fluxo do programa é alterado, normalmente chamando uma função que foi registrada para ser invocada quando esse sinal acontecer. Signal pode ser considerado um IPC porém não transmite dados, e são assíncronos, mas quando um processo o recebe, interrompe o processamento atual para atender o evento, ou seja, assim que um evento é recebido, o processamento é imediato, como boa prática os handlers registrados para os sinais devem possui uma rotina muito pequena para o tratamento desse sinal, para que possa retornar rapidamente para o ponto onde foi interrompido. Existem mais de 31 sinais sendo que alguns deles podem ser gerados através do teclado como o SIGINT, os sinais existentes estão definidos em /usr/include/bits/signum.h para 32bits, /usr/include/x86_64-linux-gnu/bits/signum.h para 64 bits e /usr/include/arm-linux-gnueabihf/bits/signum.h para ARM.

Registrando uma Callback para um Signal

Para realizar um registro de uma callback faz-se o uso da system call signal que recebe dois argumentos o SIG[TIPO] que é o evento, e a callback que será executado quando houver o evento, onde a callback deve respeitar a assinatura do sighandler, que recebe um argumento do tipo int e não retorna nada

Para uma explicação mais detalhada dos tipos de Signals, pesquise no manual do Linux

Emitindo um Signal

Com Signal é possível emitir o evento para si mesmo através da system call

ou para um processo externo, nesse caso é necessário conhecer o pid do processo no qual se quer enviar

Aguardando um Signal

Para fazer com que o programa somente processe mediante a um evento, pode-se usar a system call

que permite que o programa entre em sleep até que um Signal seja recebido para assim acordar e processar.

Funcionamento da recepção de um Signal

Para exemplificar melhor é apresentado uma imagem animada que demonstra o fluxo de um programa em execução, e como é realizado o tratamento do evento:

Signal 2

Pode-se se notar no programa que, em nenhum momento é chamado o handler, mas mediante o registro prévio do callback, quando o evento é gerado, o callback é invocado, trata o sinal e retoma o fluxo normal após o tratamento do evento.

Implementação

Para demonstrar o uso desse IPC, iremos utilizar um esquema de notifição, onde o processo Notificador (button_process) vai notificar o processo Consumidor(led_process) que está em sleep aguardando a notificação para alterar seu estado, essa aplicação é composta por 3 executáveis:

  • launch_processes – é responsável por lançar os processos button_process e led_process através da combinação fork e exec
  • button_interface – é responsável por ler o GPIO em modo de leitura da Raspberry Pi e enviar um evento Signal
  • led_interface – é responsável por aguardar um Signal e mudar o estado do GPIO configurado como saída

launch_processes

No main criamos duas variáveis para armazenar o PID do button_process e do led_process, e um buffer que vai ser formatado para enviar argumentos para o processo button_process

Em seguida lançamos o processo led_process

Nesse ponto temos o pid do processo led_process, que será passado para o processo button_process como argumento para que seja possível notificá-lo

button_interface

Definimos a variável que vai receber o argumento recebido via exec

Verificamos se o argumento é válido

Inicializamos a interface de botão

Recuperamos o pid do processo led_process

Aguardamos o pressionamento do botão e por fim notificamos o processo led_process através do kill

led_interface

Definimos uma variável para controlar o estado interno do LED

Registramos o sinal que desejamos receber

Inicializamos a interface de LED

Aplicamos o estado inicial do LED, alteramos o estado interno e colocamos o processo em modo sleep, que aguarda um evento para aplicar o novo estado

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 através 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 vezes

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

Signal é um IPC bastante versátil, apesar de não trafegar dados, permite de forma rápida e simples a sincronização entre os processos, como no Shared File, que é usado o polling para verificar se o arquivo está em uso, podemos remover o polling e usar a notificação para que o processo leia quando e somente for atualizado, reduzindo assim processamento desnecessário.

Referência

Outros artigos da série

<< Shared FileMMAP >>
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