Aquino escreveu:Eu entendi a tua idéia, é basicamente uma autômato com troca de estados por processamento de mensagens, não é?
É interessante também, eu costumo implementar coisas simples utilizando autômatos, porém, não utilizo filas de mensagens.
pois eh, eu realmente nao sei se tem vantagem ou nao! em teoria, sim, deveria ser um negocio bacana, pq vc monta um software grande sem pensar muito e tem tudo padronizado... mas sera que realmente eh? se for pensar em um sistema de comunicacao simples, por exemplo, um gateway entre duas interfaces ethernet.
uma abordagem direta seria na propria interrupcao de tratamento do frame recebido chamar as funcoes necessarias (firewall e roteamento, por exemplo) ateh o frame ser encaminhado para fora, algo como:
- Código: Selecionar todos
interrupt void ethernet_recv()
{
frame *p;
while(p = get_frame())
{
firewall(p);
}
}
void firewall(frame *p)
{
if(check(p)
{
forward(p);
}
}
void forward(frame *p)
{
ethernet_xmit(p, get_iface_by_route(p));
}
o ruim disso eh que o processo eh completamente atomico do inicio ao fim, pq o tratamento de interrupcao nao eh quebrado. e no caso de um sistema SMP eh dificil fazer o hardware espalhar o processamento de interrupcoes. no caso de um sistema com dois cores e duas interfaces, eh mais facil atribuir um core por interface. mas se o trafego for assimetrico, temos perda de performance em funcao da assimetria.
colocar uma fila de mensagens permitiria eliminar essa atomizacao do processamento de pacote na interrupcao e granularizar melhor o processamento em um sistema SMP:
- Código: Selecionar todos
interrupt void ethernet_recv()
{
frame *p;
while(p = get_frame())
{
send(p,firewall);
}
}
void firewall()
{
frame *p = recv();
if(check(p))
{
send(p,forward);
}
}
void forward()
{
frame *p = recv();
send(p, get_iface_by_route(p));
}
desta forma, o tempo preso na interrupcao diminui. a interrupcao vai colocar algumas mensagens no escalonador de processos e eles vao ser processados pelo firewall, que vai devolver mensagens para o roteamento e assim por diante. assim, mesmo que as interrupcoes fiquem fixas em um determinado core, o processamento pode ser espalhado nos outros cores.
Agora, como ficaria na tua implementação quando uma das tasks precisa de temporizações? Utilizaria diretamente os timers ou teria que entrar dentro do switch, processar a mensagem e verificar que a contagem ainda não chegou a zero e pular fora? Dessa forma o escalonador ganha, pois a fila de tarefas bloqueada, dependendo da implementação, decrementa apenas o primeiro nodo e os outros vem atrás...
pois eh, se for necessario funcionalidade de tempo real, nao tem jeito, tem que ter um timer de hardware associado. eu acho que o modelo ideal nesse caso eh cada processo enviar uma mensagem para um processo de gerenciamento de timer se registrando. o processo de gerenciamento de timer entao utiliza uma interrupcao de timer para gerar uma referencia de tempo e decrementa cada timer registrado, enviando uma mensagem para o processo que se registrou originalmente.
eu pensei em algo como:
- Código: Selecionar todos
interrupt rtc_recv()
{
static frame p = RTC_WAKEUP;
send(p,rtc);
}
vod rtc()
{
frame *aux, *p = recv();
static frame *clients = NULL;
switch(p->event)
{
RTC_WAKEUP_EVENT:
for(aux = clients; aux; aux = aux->next;
if(!aux->counter--)
send(aux,aux->src);
break;
RTC_REGISTER:
add(p,clients);
break;
}
}
os processos se registram com uma mensagem que contem o valor do contador. se a referencia do timer eh 1ms, o valor de counter vai ser um multiplo e vai ser decrementado cada vez q a interrupcao do timer enviar uma mensagem para o processo principal de timer. quando counter chega a zero, ele envia uma mensagem para o processo que pediu.
daih com isso vc tem uma especie de soft-timer, onde um timer de referencia pode ser compartilhado por varios processos. por outro lado, em processadores muito pequenos este conceito ainda eh abstrado demais e consome memoria demais. daih acho que algo mais simples acaba sendo necessario.