Você está na página 1de 5

1

MC504 - Projeto 2: Kernel Calls


Felipe Vicentin – 248283, Gabrielle Barbosa – 233862, João Victor Pátaro – 237763, João Augusto Pimentel
Barbosa – 248341

Resumo—Neste segundo projeto de Sistemas Operacionais, este projeto, seriam necessários 10 GiB. Após esse primeiro
tivemos a oportunidade de continuar exercitando conhecimentos passo, entrou-se no escopo do trabalho em si, que foi dividido
utilizando Minix. O objetivo principal foi entender o funciona- em algumas seções: criação da kernel call, criação de um
mento de chamadas de sistema e estados de processos.
Inicialmente, baseado na documentação do Minix e no tutorial programa que executa a kernel call, uma tarefa simples para
fornecido pela própria proposta, foi desenvolvida uma kernel a função executar e retornar para o programa e, por fim, uma
call chamada kpadmon, chamada pelo serviço spadmon, também aplicação em nı́vel de usuário.
desenvolvido. Juntos, realizavam uma tarefa simples: somar dois
números. O spadmon recebia os inteiros via argumento, tratava II. C RIAÇ ÃO DA K ERNELL C ALL K PADMON
o dado e enviava via mensagem para a kernel call, que retornava
o resultado, também utilizando a estrutura de mensagem. Nessa primeira etapa, foram executados os passos ne-
Terminada essa etapa inicial, foi proposta a criação do cessários para criar a kernel call propriamente dita, que foi
padmon, um programa que deveria ser chamado via terminal chamada de kpadmon. A princı́pio, a sua única função era
e realizar algumas tarefas relacionadas a processos, em suma:
listagem e mudanças de estado. Esta foi a parte mais complexa
logar no terminal uma mensagem, sinalizando que foi execu-
e desafiadora do trabalho, que exigiu bastante pesquisa e estudo tada.
de documentação, além de colaboração e troca de informações Não houve muita dificuldade ao seguir os passos sugeridos
pelos próprios alunos da disciplina. dessa etapa inicial. Os arquivos do repositório foram editados
fora da máquina virtual, no Visual Studio Code e commitados,
I. I NTRODUÇ ÃO enquanto os arquivos do próprio Minix foram editados dentro
da VM, obviamente, mas utilizando uma conexão ssh com o
O Sistema Operacional (SO) é uma camada de software
Putty.
que gerencia o hardware de uma máquina. Como estudado
No diretório /usr/src/minix/kernel, no arquivo
em sala de aula, ele precisa exercer o papel de árbitro, juiz e,
system.h, foi adicionado o protótipo da função,
finalmente, cola. O cerne do SO é o seu Kernel, que abstrai
do kpadmon, que recebe dois argumentos: caller e m ptr.
a maior parte das funcionalidades do sistema para tornar o
Ainda nesse diretório, na pasta system, foi adicionada a
desenvolvimento de aplicações mais intuitivo e transparente.
implementação da função, no arquivo do_kpadmon.c e a
De fato, é o Kernel que gerencia atividades como leitura de
sua referência foi adicionada ao Makefile.inc. Por fim,
arquivos, acesso à memória real e faz a ponte para dispositivos
no arquivo system.c, foi feito o mapeamento da função.
I/O.
No diretório /usr/src/minix/include/minix, foi
Para usufruir de tais abstrações, os processos do sistema
adicionado o protótipo da função no arquivo syslib.h
devem ser capazes de se comunicarem com o Kernel para que
e, no arquivo com.h, foi criado o número de uma nova
este realize as tarefas abstraı́das. Esta comunicação ocorre por
kernel call e incrementada a quantidade de chamadas exis-
meio de system calls, ou chamadas de sistema. Resumida-
tentes. Esse passo também precisou ser replicado nos arqui-
mente, o processo voluntariamente abre mão de sua execução
vos correspondentes da própria máquina virtual, no diretório
para que o Kernel possa oferecer e realizar qualquer serviço
/usr/include/minix.
que foi requisitado pelo processo. Uma vez que tal serviço é
finalizado, o processo volta a executar normalmente.
Dessa maneira, no presente projeto, tivemos por objetivo nos
familiarizarmos com chamadas de sistema e gerenciamento
de processos, utilizando o mesmo SO do projeto anterior, o
Minix. Nosso objetivo era implementar uma chamada de sis-
tema kpadmon que realizasse uma tarefa simples, um servidor
spadmon e codificar uma aplicação de usuário padmon. A
ideia era desenvolver um pequeno gerenciador de processos,
que tivesse as seguintes funcionalidades:
• Listar os processos rodando, com seus Process IDs (PIDs)
e estados; e
• Permitir a troca de estados de qualquer processo, baseado Figura 1. Adição do novo código para a kernel call no arquivo com.h
em seu PID.
Para tanto, primeiramente, foi necessário realizar os passos No diretório src/minix/commands/minix-service,
de setup do sistema novamente, pois a máquina utilizada a kernel call foi adicionada no arquivo parse.c, e o
anteriormente tinha um espaço muito pequeno (4 GiB) e, para Makefile foi executado para instalar a nova informação.
2

Por fim, no diretório /usr/src/minix/lib/libsys, usuário da seção 4 da proposta, descobrimos que, para corrigir
foi escrita a implementação da função sys_kpadmon.c, tal erro, era preciso utilizar a função sef startup no inı́cio da
que também foi adicionada ao Makefile. Após esse último função main e rodar o serviço com o comando run ao invés
passo, em /usr/src/releasetools, foram rodados mais do up (para executar uma única vez, caso contrário, ficava
comandos do Makefile para persistir tudo que foi imple- realizando a mesma tarefa várias vezes).
mentado. Em relação ao resto da implementação, os números foram
convertidos utilizando a função atoi do C, e passados para
III. C RIAÇ ÃO DO S ERVIÇO S PADMON a kernel call via os campos m1 i1 e m1 i2 do objeto de
Com a kernel call implementada, chegou o momento de mensagem (segundo argumento da função). O resultado da
desenvolver um serviço para chamá-la, o spadmon. kernel call foi passado também da mesma forma, com o valor
Para essa etapa, primeiramente foi criado o diretótio spad- adicionado ao campo m1 i3 da mensagem.
mon em /usr/src/minix/servers, onde foi criado o
Makefile, a implementação do serviço no arquivo spadmon.c
e a configuração do mesmo em spadmon.conf. A nova pasta
também foi adicionada ao Makefile do diretório servers. Então,
o Makefile de spadmon foi executado.
Para subir o serviço, basta executar o comando minix-
service up /service/spadmon. Entretanto, na primeira vez, ele
não executou a kernel call, apenas o seu próprio texto apareceu
no terminal e ocorreu um erro. Após verificar todos os arquivos
dos passos anteriores, inclusive do kpadmon, e notar que não
havia nada errado, surgiu a ideia de dar um reboot na VM.
Depois de reiniciar, o comando passou a funcionar.
Figura 4. Código final do spadmon

Figura 2. Execução de spadmon

IV. C RIANDO DE UMA TAREFA S IMPLES


Com kpadmon e spadmon implementados e funcionando
corretamente, chegou a etapa de atribuir uma funcionalidade
para exemplificar o funcionamento da system call, que por
enquanto só imprimia no terminal.
Foi implementada a função de somar dois números, como Figura 5. Código final do kpadmon
sugerido no enunciado. O serviço spadmon recebe dois
números via argumento no terminal, transforma-os em inteiros
e os envia a kpadmon, que realiza a soma e devolve o
resultado. Obviamente, tal função nem tinha a necessidade de
ser uma kernel call, mas foi importante para entender o fluxo
que é executado em uma chamada de sistema.
Figura 6. Funcionalidade completa, imprimindo o resultado no terminal
A parte mais difı́cil foi encontrar como se passava os valores
para spadmon via terminal, visto que tinhamos encontrado a
flag -args, entretanto a mesma quebrava quando tentávamos V. I MPLEMENTAÇ ÃO DO PADMON
passar mais de um argumento. Depois de muita pesquisa, pois Como dito na introdução, nosso objetivo aqui era fazer
não conseguia encontrar nenhuma fonte que exemplificasse o um gerenciador de processos bem simples, para estudar os
uso desse comando especı́fico, descobrimos que era necessário estados de um processo. A ideia era codificar um programa
aspas para passar mais de um argumento. PADMON que, passando-se os seguintes argumentos, realizasse
as respectivas ações:
1) O argumento -ps deve listar todos os processos do sis-
tema. Cada um deles deve vir acompanhado do estado,
que pode ser qualquer um destes 5: D (Ininterrompı́vel),
R (Executável), S (Interrompı́vel), T (Detido) ou Z
Figura 3. Execução de spadmon passando os argumentos, que foram impres-
(Zumbi);
sos no terminal para verificação 2) O argumento -r, acompanhado de um PID, deve tornar
o processo de tal PID executável;
É possı́vel notar que há um erro no final do comando 3) O argumento -s, acompanhado de um PID, deve fazer o
executado. Mais tarde, no desenvolvimento do programa de processo entrar no modo “dormindo”;
3

4) O argumento -t, acompanhado de um PID, deve tornar • Opções curtas começam com um traço (-), contém ape-
o processo de tal PID detido; nas uma única letra como nome e, possivelmente, um
5) O argumento -z, acompanhado de um PID, deve tornar argumento (e.g. ls -a).
o processo de tal PID um “zumbi”; • Opções ditas longas começam com dois traços (--), segui-
6) O argumento -e, acompanhado de um PID, deve encerrar das do nome da opção e, possivelmente, um argumento
o processo de tal PID; (e.g. ls --width 0);
7) O argumento -v, deve ativar a opção de verbose, isto é, Dessa maneira, as funções getopt e getopt long ajudam-nos
as operações serão acompanhadas de mensagens infor- a lidar com estes tipos de opção. Infelizmente, a especificação
mativas; e dos projeto requisitava tratamento de argumentos fora do
8) O argumento -help, deve exibir uma mensagem de ajuda padrão estabelecido para linha de comando e, por isso, o uso
que mostra como usar o programa. das funções prontas do C precisou ser limitado (mesmo que
Por conta da seção 4.2 do documento de proposta para ele ainda tenha sido usado para algumas das opções).
este projeto, acreditávamos que as funções de listagem de Usando a função atoi, previamente descrita, conseguimos
processos e mudança de estados deveriam ser implementadas extrair o PID passado como argumento para o programa e com
na kernel call kpadmon. Por causa disto, dezenas de horas de outras funções da biblioteca string.h, determinamos a opção
trabalho foram perdidas, na tentativa de fazer com que esta (ou opções, no caso do verbose) passadas como argumento.
chamada conseguisse recuperar os processos com seus PIDs. A princı́pio, a impressão de informações dos processos do
De fato, o Kernel do Minix conta com um dado compartilhado sistema foi implementada dentro do spadmon. Por conta disso,
proc, que é um vetor da struct proc, que armazena informações mesmo que ao testar o programa dentro da VM o resultado
sobre todos os processos do sistema, isto é, proc é a tabela de aparecesse como esperado, o mesmo não acontecia dentro de
processos do Minix. uma sessão ssh. Cremos que este seja o caso pois os comandos
Contudo, o PID associado a cada processo é, de fato, printf encontravam-se dentro do servidor.
criado pelo Process Manager (PM) do Minix, que é um Para resolver isso e tornar a aplicação um pouco mais
servidor (como o spadmon). Por meio de terceiros em nossa transparente, decidimos mover a impressão para o programa
turma, descobrimos que o PED da disciplina orientou os de usuário padmon. Com o objetivo de fazê-lo, criamos uma
alunos a tentarem usar a função getsysinfo para tentar obter as struct spadmon proc, que armazena o PID de um processo e
informações relevantes dos processos e que esta função retorna seu estado como um char. A ideia tornou-se, então, alocar um
algo similar à um vetor de PCBs. vetor desta struct na aplicação do usuário e passar um ponteiro
Analisando outros trechos do código fonte do Minix em para o servidor. Ele, por sua vez, copiaria as informações dos
que esta função era utilizada, percebemos que a estrutura que processos para o processo que o requisitasse e, desta forma,
representava os PCBs dos processos era a struct mproc e, além o processo poderia, ele mesmo, imprimir tais informações. Os
disso, a função getsysinfo é usada em conjunto de um vetor detalhes desta implementação serão tratados na próxima seção.
deste tipo, a fim de preenchê-lo com a tabela de processos. Além disso, o servidor spadmon disponibiliza um enum que
Infelizmente, todas as nossas tentativas de utilizar esta função criamos. Tal enum permite o programa de usuário comunicar
ou até mesmo o vetor de mproc foram frustradas. ao servidor qual operação ele gostaria que fosse feita.
Depois de muito tempo, também descobrimos que o enun- Por fim, vale destacar que, como o enunciado do projeto
ciado do projeto continha um erro nesta seção (4.2) e que, de não especificava como a comunicação entre o programa de
fato, as operações envolvendo gerenciamento de processos que usuário e o servidor deveria ser feita, tomamos a liberdade
deveriam ser implementadas precisariam ser feitas no spad- de implementá-la usando o protocolo IPC, que é a sigla de
mon ao invés de serem codificadas na kernel call kpadmon. Inter Process Communication. Com tal protocolo, pudemos
Testando a função getsysinfo dentro do servidor implementado, usar a struct message que havı́amos utilizado, anteriormente,
conseguimos obter a tabela de processos e acessar seus PIDs para fazer a comunicação entre o spadmon e o kpadmon.
e flags, que revelam seus estados.
B. Desenvolvimento do servidor de gerenciamento de proces-
A. Desenvolvimento do programa de usuário sos
Para a criação da contraparte do usuário do padmon, Para o serviço spadmon, foi criada uma estrutura na qual
decidimos usar a linguagem de programação C, visto que a função principal permanece em um loop, aguardando a che-
nosso grupo já estava familiarizado com esta linguagem. Este gada de uma mensagem via IPC. Os argumentos da mensagem
programa deveria ser responsável por tratar a entrada do são então obtidos: o primeiro é a instrução, o segundo é o
usuário e transformá-la em dados para que o spadmon pudesse argumento e o terceiro é a opção verbose. É feito, então, um
realizar as operações com a ajuda do Kernel. switch entre todas as instruções possı́veis e os argumentos são
As bibliotecas padrões do C possuem funções que nos direcionados a funções especı́ficas.
ajudam a lidar com opções passadas por meio de argumentos A maneira com a qual fizemos a comunicação de opções en-
na linha de comando, como a função getopt e getopt long. tre o padmon e o spadmon foi usando um enum definido em
Elas existem porque a maneira com que usuários interagem /usr/src/minix/include/spadmon.h. Além disso,
com aplicativos de linha de comando foi padronizada há muito este arquivo .h define uma struct spadmon proc que faz
tempo e funciona da seguinte maneira: armazena as informações relevantes sobre os processos. Foi
4

exatamente esta struct que nos ajudou a resolver o problema A função help não foi implementada no serviço, visto que
de impressão descrito anteriormente. A ideia é que o padmon é apenas uma opção de instrução do usuário, portanto está
instancia, em seu heap, um vetor desta struct e passa-a, usando totalmente no padmon e é mostrada tanto quando há o uso
a mensagem do IPC, para o spadmon. Este, por sua vez, da flag quanto quando há algum erro.
preenche tal vetor com as informações da tabela de processos. A parte mais complicada, provavelmente do projeto todo,
Vale destacar que a passagem foi usada com um campo na foi a implementação da mudança de estados dos processos.
struct chamado m1_ull1, que é um uint64_t. Sabemos À princı́pio, a ideia foi utilizar sinais. As funções sys kill e
que este não é um tipo usado para armazenar ponteiros, sigsend foram testadas, entretanto não conseguimos modificar
mas o escolhemos pela facilidade de acesso e pelo tamanho os processos com elas. Para a opção de interromper o processo,
de 64 bits, que é suficiente para guardar qualquer ponteiro. a função sys kill com o sinal SIGKILL teve o resultado
Podemos destacar que, na função ps, por conta da adição esperado, mas para as demais opções, não encontramos um
do parâmetro de tamanho do vetor passado pelo processo do sinal que realizasse o comportamento esperado. Além disso,
usuário, tivemos a oportunidade de controlar a quantidade de para a mudança para o estado stopped, o sinal que parecia
processos que deveriam ser impressos no padmon. Isto, por apropriado era o SIGSTOP, entretanto após muitos testes
sua vez, nos ajudou a tirar fotos do código funcionando, com nos quais o processo não tinha o comportamento esperado,
sua tabela de processos. apenas sumia ao invés de mudar de estado, encontramos na
Para a listagem de processos, como já mencionado anteri- documentação do Minix que este sinal não é implementado e
ormente, foi utilizada a struct mproc, obtida com a chamada quando utilizado tem a mesma função do kill. Outro ponto,
de sistema getsysinfo. Utilizando a flag mp flags da tabela de foi que os sinais disponı́veis não pareciam realizar todas as
processos, os estados foram condensados para os pedidos no operações de mudança esperadas.
enunciado: D (uninterruptable), R (executando), S (interrupta- Descartada a possibilidade do envio dos sinais e pesqui-
ble), T (detido) e Z (zumbi). sando pelas documentações do Minix, que são difı́ceis de
entender e muitas vezes incompletas, encontramos a chamada
de sistema sys update, que recebe dois endpoints e um estado
por parâmetro. Essa função não possui descrição de uso na
documentação do Minix, apenas o que realiza: “Update state
of a system process”, que era uma informação promissora.

Figura 7. Função para tradução dos estados do processo

Figura 9. Documentação disponı́vel sobre o SYS UPDATE

Para utilização do SYS UPDATE, inicialmente tentamos


chamá-la no serviço spadmon, entretanto recebemos o código
de erro -1 (permissão) ao tentar alterar um processo. Com
isso, tentamos voltar à ideia do uso da syscall kpadmon,
e implementamos a função passando o endpoint e estado
esperado via mensagem pelo spadmon. Apesar de parecer o
caminho correto, quando testado em processos de usuário, pa-
receu não modificar o seu estado, e quando tentamos modificar
o serviço padmontest (serviço que executa um loop infinito,
criado apenas para o teste da aplicação), houve um erro de
kernel e foi preciso reiniciar o Minix.
Finalmente, conversando diretamente com o PED da dis-
ciplina, nos foi dito que nem todos os processos deveriam
obedecer à mudança de estados e que essa função deveria ser
Figura 8. Execução do PS, foi criado um argumento opcional que definia a chamada do spadmon, pois uma system call dentro de outra
quantidade de processos a ser exibida, neste caso passado como 15 system call realmente pode causar um Kernel Panic. Assim o
5

fizemos e, de fato, apenas um seleto subconjunto de processos


permitia a execução do sys update sem erros. Mesmo assim,
seu estado não mudava. Imaginamos que, imediatamente de-
pois de ter o sys update executado, o escalonador do Minix
muda-o de estado, antes mesmo de podermos verificar a
alteração. A função de exit foi a única que funcionou como Figura 15. Erro da chamada de zombie para um processo sem permissão
”esperado”, visto que o escalonador não tem mais o processo
para reescaloná-lo (pois ele foi terminado).

Figura 10. Sucesso da chamada para mudar o estado do processo para stopped Figura 16. Sucesso da chamada de exit para um processo

Como é possı́vel observar nas evidências trazidas acima,


apesar de obter sucesso nas chamadas de sys update, logo
após essa mudanças, atualizamos a mproc e imprimimos o
estado, que permaneceu running.
Além disso, conseguimos pegar um estado interessante, ao
chamar sys kill em um processo, este foi para o estado sleep
Figura 11. Erro ao tentar mudar um processo não permitido para stopped antes de ser terminado. Quando fizemos o ps novamente, ele
já havia sido finalizado. Retiramos esse log final para o exit,
pois notamos que às vezes o processo já havia sido encerrado
e obtı́amos erro ao tentar acessar a memória e recuperar seu
estado.

VI. C ONCLUS ÃO


Com a realização deste projeto, pudemos ter uma noção
maior sobre como os processos e seus PCBs são representados
em memória, dentro do Kernel. Ao criar uma system call,
entendemos o procedimento que o Kernel segue para realizá-
la e, finalmente, ao desenvolver o programa padmon, tivemos
Figura 12. Sucesso da chamada de sleep para um processo
a oportunidade de estudar as flags e estados dos processos do
sistema.
Infelizmente, a nossa solução não foi geral e não funcionou
para todos os processos em execução no sistema, mas, con-
seguimos alterar o estado de alguns processos que tinham a
permissão para a mudança de estados passadas pelas flags.

Figura 13. Erro da chamada de sleep para um processo sem permissão


VII. D IVIS ÃO DO TRABALHO
A tabela I apresenta a divisão de trabalho que a equipe
utilizou para a realização do projeto.

Tabela I
D IVIS ÃO DA EQUIPE

Atividade Integrantes
Criação do kpadmon Gabrielle
Criação do spadmon inicial Gabrielle
Criação do spadmon final Gabrielle, João Pátaro, João Augusto, Felipe
Criação do padmon Felipe, João Augusto
Escrita do relatório Felipe, Gabrielle
Figura 14. Sucesso da chamada de zombie para um processo

Você também pode gostar