O documento descreve um exemplo de kernel cooperativo para gerenciar processos em um sistema embarcado. O kernel implementa um buffer circular para armazenar os processos, funções para adicionar e remover processos, e um loop infinito que executa os processos de forma cooperativa, reagendando aqueles que precisam ser executados repetidamente. O exercício propõe adaptar o código para a placa e testar o reagendamento e execução de processos que acionam saídas digitais.
1. ELT048 - SOE
Kernel Cooperativo
Rodrigo Almeida
Universidade Federal de Itajubá
2. Revisão
● Processos
typedef int (*ptrFunc)(void* param);
//código antigo
typedef struct {
char* nomeDoProcesso;
ptrFunc funcao;
int prioridade;
int tempo;
}process;
3. Exercício
● Adaptar o código e executá-lo no kit de
desenvolvimento.
● Reunir todas as funções relacionadas à
operação com o buffer circular numa
biblioteca.
● Utilizar o debugger da placa para verificar o
funcionamento do programa.
4. Exercício
void main (void){
process p1 = {"F1n",1,func1};
process p2 = {"F2n",2,func2};
long int i;
MCU_init();
ini = 0;
fim = 0;
PTJ = 0x00;
for(;;){
addProc(p1);
addProc(p2);
exec();
for(i=0;i<10000;i++);
removeProc();
exec();
for(i=0;i<10000;i++);
removeProc();
}
}
int func1(void* param){
PORTB=0xF0;
}
int func2(void* param){
PORTB=0x0F;
}
Inicialização do HW
5. Kernel
● Na área de computação o kernel é a parte
do código responsável por implementar e
gerenciar a interface entre o hardware e a
aplicação.
● Os recursos de hardware mais críticos
neste quesito são o processador, a
memória e os drivers.
7. Kernel
● Um kernel possui três responsabilidades
principais:
● Gerenciar e coordenar a execução dos
processos através de algum critério
● Manusear a memória disponível e coordenar o
acesso dos processos a ela
● Intermediar a comunicação entre os drivers de
hardware e os processos
8. Kernel
● Gerenciamento dos processos
● Deve levar em conta um critério para o
escalonemento do processo: tempo de
execução, prioridade, criticidade, “justiça”, etc.
● Os processos devem ser “armazenados” de
modo a ficarem facilmente disponíveis ao
kernel.
● O kernel deve prover funções para o
gerenciamento destes processos: adicionar,
remover, pausar, etc.
9. Kernel
● Gerenciamento da memória disponível
● A gestão do espaço disponível para cada
processo é de responsabilidade do kernel
● Um ponto crítico é garantir que cada processo
só possa acessar sua região de memória. Isto
só pode ser feito se houver um hardware
dedicado a este ponto: MMU
10. Kernel
● Intermediar a comunicação entre os drivers
de hardware e os processos
● O kernel deve prover uma camada de acesso
ao hardware.
● Esta camada é responsável por implementar as
questões de permissão e segurança, como
também padronizar as chamadas de aplicação.
11. Gestão dos processos
● A gestão dos
processo é feita
através de um
buffer circular
(process pool).
● O acesso a este
buffer deve ser
restrito ao kernel.
http://learnyousomeerlang.com/building-applications-with-otp
12. Gestão dos processos
● O exemplo a seguir apresenta um modelo de
gerenciamento de processos.
● Note que o pool é implementado como um buffer
circular utilizando a mesma estrutura das aulas
anteriores
● Uma das poucas diferenças é a mudança do pool
para ser um vetor de ponteiros para a struct
process
● Isto permite uma manipulação mais rápida e
simples dos elementos do pool
● Uma movimentação nas posições envolve apenas
uma cópia de ponteiros e não da estrutura inteira.
13. //definição do ponteiro de função
typedef int (*ptrFunc)(void* param);
//definição da estrutura processo
typedef struct {
char* nome;
void* ptr;
ptrFunc func;
} process;
//definição do pool
#define POOLSIZE 10
process* pool[POOLSIZE];
//a utilização de ponteiros de processo
//facilita a manipulação dos processos
Gestão dos processos
14. //função de adição de “process” no pool
void addProc(process nProcesso){
//checagem de espaço disponível
if ( ((fim+1)%POOLSIZE) != ini){
//Atualização da posição atual
buffer[fim] = nProcesso;
//incremento da posição
fim = (fim+1)%(POOLSIZE);
}
}
//função de remoção de um “process” do poolvoid
removeProc (void){
//checagem se existe alguem pra retirar
if ( ini != fim ){
//incremento da posição
ini = (ini+1)%(POOLSIZE);
}
}
Gestão dos processos
15. Escalonador
● É o responsável por escolher qual é o próximo
processo a ser executado.
● Existem alguns parâmetros a serem
considerados:
● Throughtput: quantidade de processos por tempo.
● Latência:
– Turnaround time – tempo entre o inicio e fim de um
processo.
– Response time: valor entre uma requisição e a primeira
resposta do processo.
● Fairness / Waiting Time – conceder uma
quantidade de tempo igual para cada processo.
16. Escalonador
● First in first out
● Shortest remaining time
● Fixed priority pre-emptive scheduling
● Round-robin scheduling
● Multilevel queue scheduling
18. Escalonador
Operating System Preemption Algorithm
Amiga OS Yes Prioritized Round-robin scheduling
FreeBSD Yes Multilevel feedback queue
Linux pre-2.6 Yes Multilevel feedback queue
Linux 2.6-2.6.23 Yes O(1) scheduler
Linux post-2.6.23 Yes Completely Fair Scheduler
Mac OS pre-9 None Cooperative Scheduler
Mac OS 9 Some Preemptive for MP tasks, Cooperative
Scheduler for processes and threads
Mac OS X Yes Multilevel feedback queue
NetBSD Yes Multilevel feedback queue
Solaris Yes Multilevel feedback queue
Windows 3.1x None Cooperative Scheduler
Windows 95, 98, Me Half Preemptive for 32-bit processes, Cooperative
Scheduler for 16-bit processes
Windows NT (XP,
Vista, 7, 2k)
Yes Multilevel feedback queue
19. Escalonadores
● Considerações para o ambiente embarcado
● Com a escassez de recursos computacionais,
um algoritmo muito complexo pode minar a
capacidade de processamento muito
rapidamente. Algoritmos mais simples são
preferidos.
● Os sistemas de tempo real possuem algumas
necessidades que em geral só são satisfeitas
por escalonadores “injustos” que possam
privilegiar alguns processos. Ex: priority based
scheduler
20. Kernel
● Preempção
● Permite ao kernel pausar um processo para
executar um segundo sem que as variáveis e
fluxo de código do primeiro sejam alteradas.
● Necessita de suporte de hardware por
interrupções
● Só é programado em assembly
21. Kernel
● Cooperativo
● É necessário que os processos terminem
dando oportunidade para outros processos
serem executados pelo processador
● Loops infinitos podem travar todo o sistema
● Pode ser programado inteiro em C e não
necessita de hardware especial
22. Kernel
● Reagendamento de processos
● Para um kernel cooperativo é importante que
todos os processos terminem voluntariamente
para ceder espaço na CPU para os outros
processos.
● Nos casos em que o processo precisa ser
executado constantemente ele deve ser
reagendado na CPU
23. Exemplo
● Exemplo de kernel cooperativo
● O código apresentado pode ser compilado em
qualquer compilador C
● O kernel é composto por três funções:
● KernelInit(): Inicializa as variáveis internas
● KernelAddProc(): Adiciona processos no pool
● KernelLoop(): Inicializa o gerenciador de
processos
– Esta função possui um loop infinito pois ela só
precisa terminar quando o equipamento/placa for
desligado.
25. char kernelInit(void){
ini = 0;
fim = 0;
return SUCCESS;
}
char kernelAddProc(process newProc){
//checking for free space
if ( ((fim+1)%POOL_SIZE) != ini){
pool[fim] = newProc;
fim = (fim+1)%POOL_SIZE;
return SUCCESS;
}
return FAIL;
}
Exemplo
26. void kernelLoop(void){
int i=0;
for(;;){
//Do we have any process to execute?
if (ini != fim){
printf("Ite. %d, Slot. %d: ", i, start);
//check if there is need to reschedule
if (pool[start]->Func() == REPEAT){
kernelAddProc(pool[ini]);
}
//prepare to get the next process;
ini = (ini+1)%POOL_SIZE;
i++; // only for debug;
}
}
}
Exemplo
28. void main(void){
//declaring the processes
process p1 = {tst1};
process p2 = {tst2};
process p3 = {tst3};
kernelInit();
//Test if the process was added successfully
if (kernelAddProc(p1) == SUCCESS){
printf("1st process addedn");}
if (kernelAddProc(p2) == SUCCESS){
printf("2nd process addedn");}
if (kernelAddProc(p3) == SUCCESS){
printf("3rd process addedn");}
kernelLoop();
}
Exemplo
29. Console Output:
---------------------------
1st process added
2nd process added
3rd process added
Ite. 0, Slot. 0: Process 1
Ite. 1, Slot. 1: Process 2
Ite. 2, Slot. 2: Process 3
Ite. 3, Slot. 3: Process 1
Ite. 4, Slot. 0: Process 3
Ite. 5, Slot. 1: Process 1
Ite. 6, Slot. 2: Process 3
Ite. 7, Slot. 3: Process 1
Ite. 8, Slot. 0: Process 3
...
---------------------------
Exemplo
30. Exercício
● Criar os arquivos kernel.c, kernel.h,
kernel_prm.h e kernel_types.h.
● Adaptar os códigos apresentados para a
placa.
● Testar o reagendamento dos processos.
● Criar um processo para ligar um segmento
do display de cada vez (PORTB).
● Criar um segundo processo para mudar de
display (PTJ)