so-17

Table of Contents

Curso sistemas operacionais 2017 PCS3746 prof. Jorge Kinoshita.

Aulas segunda: 14:00-15:40H, sala B2-4 sexta: 10:20-12:00H, sala B2-12

1 Programação aula a aula.

1.1 <2017-05-08> ) 1.1 O que é um sistema operacional, 1.2 História dos sistemas operacionais

Apresentacao do curso: programacao aula a aula. Apresentacao do material didatico: livros do Tanenbaum e Silberzchatz. Criterio de avaliacao.

O site http://www.cs.vu.nl/~ast/ é do prof. Tanenbaum. Em seu site, ele deixou o conjunto de transparênicas: http://www.cs.vu.nl/~ast/books/mos2/mos2-ppt.zip que vamos utilizar no curso.

transparencia a ser usada: Chapter-01.ppt slides 1-8.

Pedir para os alunos se dividirem em grupos. Da proxima vez pedir grupos com o minimo de alunos e depois acrescenta. Extra: história do Minix, Linux e comentários sobre os projetos da fase 1.

1.2 <2017-05-12> ) Visao do hardware

Chapter-01.ppt 9-14 - Computer Hardware Review - interrupcao. comentários sobre os projetos da fase 1. Alocacao das turmas. Extra: comentario sobre o minix - o microkernel, processos do SO e processos de usuario; o linux como sistema monolitico. Incentivar que as turmas comecem os trabalhos.

1.3 <2017-05-15> ) conceitos de sistema operacional; 1.4 chamadas de sistema

transparencias Chapter-01.ppt 15-21 hardware da aula passada: memoria.

Codigo relativo: os labels ainda nao foram definidos pelo linker. Codigo absoluto: os lables foram definidos pelo linker. O programa em codigo absoluto ao ser colocado na memoria deve entrar de forma "relativa" a algum endereco (um endereco definido em um registrador base).

Quando se faz uma system call, no final a pilha deve ser limpa incrementando o SP. Explicar que tem 4 formas de se implementar push e pop em pilha.

Termina a aula procurando explicar o melhor possivel como funciona interrupcao no computador. Explicar interrupcao de software e de hardware. Relacionar com o projeto de SO. Bater a foto da losa.

1.4 <2017-05-19> ) 1.4 chamadas de sistema 1.5 estrutra do sistema operacional.

Finalizar Chapter-01,ppt 21-35 system calls comentar sobre máquinas virtuais. sistemas monolíticos (linux) x microkernel (minix). falar sobre o projeto: os alunos devem mostrar em que código (arquivo fonte) está a interrupcao de software quando ocorre a system call. No linux, processo usuario nao eh debugado, mesmo se compilado com opcao -g; somente o kernel eh debugado.

1.5 <2017-05-22> ) => apresentação dos projetos (fase 1) : grupos ímpares

TRAZER: apresentacao em powerpoint relatorio; enviar para mim via email no dia da apresentacao. relacionar a apresentacao com o codigo do linux e minix quando apropriado.

Se sobrar tempo: Filme: https://www.youtube.com/watch?v=iBVgcjhYV2A Revolution OS https://www.youtube.com/watch?v=xHu7qI1gDPA

1.6 <2017-05-26> ) - apresentação dos projetos (fase 1) : grupos pares

1.7 <2017-05-29> ) 2.1 introdução aos processos

transparencias "Processes and Threads". 1-24. Se sobrar tempo falar sobre os exercicios que passei. resumir explicacao sobre a diferenca entre treads e processos: basta colocar as transparencias principais sobre thread de kernel e de usuário. Ao explicar sobre threads seja mais rápido em afirmar que existe uma parte que cuida da execucao (PC, registradores, ponteiro de pilha) e outra que cuida dos recursos (memoria, arquivos). process group - lidar com signals de processos em foreground e background. Serah que eh usado muito hoje em dia com o X-windows? group id. Coloquei tudo em um desenho: vetor de interrupcao e tabela de processos.

1.8 <2017-06-02> ) 2.2 comunicação interprocesso até semaforos

transparencias "interprocess communication", 1-10,11 Solucao de Peterson: 3 casos: 1- a regiao critica eh acessada em momentos diferentes - sem problema 2- a regiao critica serah acessada quase ao mesmo tempo, mas nao hah conflito em enterregion (o processo 0 ou 1 nao chaveia em enterregion) - sem problema. 3- a regiao critica serah acessada quase ao mesmo tempo e hah conflito em enterregion: o último a fazer turn=process eh o que fica em loop e nao entra na regiao critica.

Sleep and Wakeup Para pensar:

  • explique a perda de wakeup com o buffer cheio.
  • como corrigir o código adicionando uma flag informando que o sinal foi perdido?

Semáforos: Explicar como exclusao mutua pode ser feita usando semáforos. Mostrar o caso em rede de Petri.

1.9 <2017-06-05> ) de semaforos a 2.3 problemas clássicos de CIP

A aula retoma o que seja o up e o down em semaforos. transparencias "interprocess communication", 11-25 explicar exclusao mutua com semaforos modelado em redes de Petri. explicar semaforos para resolver o problema do consumidor produtor.

static class: a declaracao permite que uma classe declarada dentro de outra seja visivel fora da classe-pai. http://www.programcreek.com/2009/02/notify-and-wait-example/ wait( ) tells the calling thread to give up the monitor and go to sleep until some other thread enters the same monitor and calls notify( ). notify( ) wakes up the first thread that called wait( ) on the same object. notifyAll( ) wakes up all the threads that called wait( ) on the same object. The highest priority thread will run first. Monitores, condition variables: http://en.wikipedia.org/wiki/Monitor_%28synchronization%29

1.10 <2017-06-09> ) 2.4 agendamento de processo + problema reader/writer.

  1. Transparencias "scheduling - introduction to scheduling"

Explicar melhor o conflito no batch system entre turnround time e throuput. Ao colocar jobs mais curtos na frente diminuo o tempo de retorno medio (mean turnround time) pg 109 - minix3. Ao colocar jobs mais curto na frente aumento a vazao, pg 107; porem posso ter tempos de retorno terriveis para processos longos.

  1. filosofos jantando.

1.11 <2017-06-12> ) => Projetos 2.5 visão geral de processos em minix (fase 2)

equipes pares

1.12 <2017-06-16> -> feriado

1.13 <2017-06-19> ) => Projetos 2.5 visão geral de processos em minix (fase 2)

equipes ímpares

1.14 <2017-06-23> ) prova 1

1.15 <2017-06-26> ) 3.1 Hardware Entrada e Saida 3.2 Software Entrada e Saida

Transparencias do silberschatz capitulo 13. http://codex.cs.yale.edu/avi/os-book/OS9/slide-dir/PPT-dir/ch13.ppt

até Block and Character Devices - 13.20.

1.16 <2017-06-30> ) 3.2 Software Entrada e Saida

Transparencias do silberschatz capitulo 13. http://codex.cs.yale.edu/avi/os-book/OS7/os7c/slide-dir/ch13.ppt do slide 13.17 até o final. pula a parte de streams.

  • discutir como implementei um driver para a porta paralela.
  • discutir como poderia ser implementado a syscall getchar e como funciona o mecanismo de interrupcao do teclado.

1.17 <2017-07-03> ) 3.3 impasses

transparencias: Chapter-03.ppt (mos2-ppt.zip)

1.18 <2017-07-07> ) => Projetos 3.4 visão geral de E/S no minix (fase 3)

equipes ímpares

1.19 <2017-07-10> ) => Projetos 3.4 visão geral de E/S no minix (fase 3)

equipes pares

1.20 <2017-07-14> ) 4.1 gerenciamento básico de memória 4.2 troca (swap)

transparecias - chapter 4; 1-11 (mos2-ppt.zip)

-> Como gerenciar memória no evaluator 7t que nao possui MMU?

  • para deixar a aula mais interessante deveria comentar como funcionamento o gerenciamento de memoria no minix sem usar a memoria virtual.

-> dar a aula rapidamente e depois comentar o que eh cada exercicio da fase 4 no final da aula; enfatizando principalmente os exercicios que envolvem o minix.

1.21 <2017-07-17> ) 4.3 memória virtual, 4.4 algoritmos de substituição de página.

transparencias - chapter 04 (mos2-ppt.zip); 12-20 (troca otimo), 32 (comparar FIFO com otimo). Inverted page tables http://www.cs.nmsu.edu/~pfeiffer/classes/573/notes/ipt.html geralmente a tabela de páginas é uma por processo, mas no caso da inverted page table, não. Nesse caso, a memória RAM está dividida em páginas sendo algumas para um processo, outras para outro processo, etc. A inverted page table mapea essa RAM atribuida a vários processos. Funciona graças aa TLB que armazena as entradas da tabela de paginas. https://en.wikipedia.org/wiki/Page_table#Inverted_page_table discute o problema de alocar memoria continua usando tabelas de pagina invertidas.

No maximo ateh algoritmo de troca otimo.

Eh possivel dar a anomalia de Belady usando o algoritmo otimo? Fazer uma simulacao.

1.22 <2017-07-21> ) 4.4, 4.5 questões para sistemas de paginação.

termina algoritmos de troca tanenbaum transparencias vitural memory (2) 21-31 exercicio 4.12 pg 442

Comentar sobre o algorimto worst e como ele pode ser usado para avaliar outros algoritmos pois dah uma piso minimo.

1.23 <2017-07-24> ) 4.6 segmentação

  • De final de working set ateh segmentacao.
  • memória Linux.

http://www.youtube.com/watch?v=NtKAG46_3Vg - memoria linux http://kerneltrap.org/node/2450/ memoria linux http://www.youtube.com/watch?v=L2SED6sewRw - desenvolvimento do kernel Item 21.6.2 do Silberschatz

Fazer um grande desenho procurando resumir tudo o que foi ensinado ateh agora em SO.

  • colocar um mapa geral de um SO - hw e sw.

– hw - MMU, TBL, e page fault . – sw. - interrupcoes em geral, mas acrescentando com as page faults, colocar a transparencia da interrupcao de page fault e relacionar na figura com os algoritmos de troca de paginas.

1.24 <2017-07-28> ) => Projetos 4.7 visão geral do gerenciamento de memória do minix (fase 4)

equipes pares

1.25 <2017-07-31> ) => Projetos 4.7 visão geral do gerenciamento de memória do minix (fase 4)

equipes impares.

1.26 <2017-08-04> ) 5.1 arquivos 5.2 diretórios 5.3 implementação do sistema de arquivos

ateh inodes. transparencias Chapter06 - 1-21 Finalizar com: Qual o tamanho maximo do arquivo? transparencia de i-node no unix.

1.27 <2017-08-07> ) 5.3 implementação do sistema de arquivos

terminar sistemas de arquivos

  • discutir o gerenciador de arquivos no minix. (cap 5 do projeto e implementacao).

equipes impares

equipes pares

1.28 <2017-08-11> ) prova 2

2 Livro texto:

Sistemas Operacionais - Projeto e Implementação ; Tanenbaum A.S. Woodhull A.S.; Bookman terceira edição Obs: Este livro contém o Minix que serviu de base para a criação do Linux, mas a versão atual é a 3.0.

Bons Livros de apoio:

  • Sistemas Operacionais com Java; Silberschatz, Galvin, Gane; Editora Campus

Obs: Este livro apresenta os conceitos de forma mais clara que os livros do Tanenbaum. O titulo "com java" se refere a exemplos em java e nao a um sistema operacional em java (que faz uso de threads do SO, e do gerenciamento de memoria para a criacao de objetos e portanto nao eh adequada para se criar SO). A Editora Campus / Esevier publicou a oitava edicao desse livro.

  • Sistemas Operacionais Modernos 3a. edição; Tanenbaum A.S.; Prentice Hall

Obs: Este livro é muito parecido com "Projeto e Implementação" mas não contém o Minix. Por outro lado é mais didático e contém mais informação que o outro.

Sobre Linux: Robert Love, Linux Kernel Development Understanding the Linux Kernel – Publisher: O'REILLY http://www.google.com/books?q=isbn%3A978-0-596-00565-8 Linux Kernel in a Nutshell – Publisher: O'REILLY: http://www.kroah.com/lkn/ UNIX Internals: The New Frontiers – Author: Uresh Vahalia http://www.google.com/books?q=isbn%3A9780131019089 Design of The Unix Operating system – Author: Maurice J.Bach http://www.google.com/books?q=isbn%3A9780132017992 Professional Linux Kernel Architecture [Paperback] Wolfgang Mauerer (Author)

Cursos http://www.cs.berkeley.edu/~kubitron/courses/cs162-F10/

3 Criterio de Avaliação:

O aluno deve ter mais que media 5 nas provas e nos trabalhos.

Nota final = (3 P1 + 4 P2 + 3 P)/10

Caso nao tenha, a nota a ser lançada eh a menor delas. Exemplo: se o aluno tirar como notas de prova, 3 e 5 entao terah como media de nota de prova (3*3 +4*5)/7 = 4,1 que serah a media a ser lancada como nota final independentemente de ter tirado 10 nos trabalhos.

Nota final = (3 P1 + 4 P2)/7

4 Grupos para os projetos.

5 Criterios de avaliacao.

  • tempo: 20 minutos por equipe, com 5 minutos para perguntas.
  • usar powerpoint para explicar o que foi feito.
  • apresentar o sistema rodando ao vivo (muito importante!!!) (caso contrário 1 ponto a menos no mínimo na nota).
  • entregar um relatorio em pdf no dia da apresentacao. Serah descontado um ponto por dia de atraso na entrega do relatorio.

O relatório e apresentacao em powerpoint devem conter: a. todos os passos para desempenhar a tarefa com referencias caso houver (a sites, livros, etc.). b. print screens da tela - geralmente da maquina virtual. A nota costuma ser dividida entre os alunos que apresentarem o trabalho em pesos iguais; porém os pesos podem ser alterados a critério dos alunos. 8 - bom; o aluno fez o esperado. 10 - melhor que o esperado. cada equipe deve entregar o relatorio no dia da apresentacao via email; cada dia de atraso corresponde a um ponto a menos.

6 Fase 1:

Objetivos gerais: . criar processos de usuários que facam chamadas de sistema e observar como elas se comportam. . system call faz com que o processador passe do modo usuário para o modo kernel. Como isso ocorre? É possível visualizar isso? . dados do kernel sao mais difíceis de serem visualizados por processos comuns. Como o "ps" e "top" visualizam dados do kernel? Através de /proc. . fazer pequenas alteracoes no kernel. Exemplo: fazer o kernel imprimir uma mensagem em um dado momento.

http://balau82.wordpress.com/2010/03/22/compiling-linux-kernel-for-qemu-arm-emulator/

A idéia é criar um programa bem simples rodando como o init (primeiro processo rodando em cima do sistema operacional) em um linux rodando na máquina virtual. Esse processo pode disparar system calls. Cada uma das equipes testará uma system call diferente. O grande objetivo é observar o código do kernel sendo executado logo após a system call.

6.1 1 - Linux, system call: read

Altere o boot do linux apresentado em http://www.pcs.usp.br/~jkinoshi/2012/linux-qemu-gdb.org de forma a se ter um processo (correspondente ao init) executando a system call read. Para isso altere o rootfs e crie um arquivo lá. O boot lerá a primeira linha do arquivo e ficará em loop imprindo-a. Quando a system call read é chamada no linux, a funcao doread é executada dentro do kernel. Explique como isso ocorre, observando o código fonte do linux e o tutorial em http://www.pcs.usp.br/~jkinoshi/2012/linux-qemu-gdb.org . Localize no código do linux onde ocorre o tratamento das system calls. Relacione o endereco dessa primeira instrucao com o vetor de interrupcao. Coloque um breakpoint e observe o valor de R7 que contém o numero da system call. Gere um relatório anexando apenas as partes de código mais relevantes e relacionadas com o SWI, bem como print screens da tela do qemu.

> 8 observar modo do processador, rel ok.

6.2 2 - Linux, system call: fork

Altere o boot do linux apresentado em http://www.pcs.usp.br/~jkinoshi/2012/linux-qemu-gdb.org de forma que: O processo pai (correspondente ao init) fica imprindo "sou processo 1" e o processo filho imprime "filho imprimindo". Quando a system call fork (veja o código que implementa fork) é chamada no linux, a funcao dofork é executada dentro do kernel. Explique como isso ocorre, observando o código fonte do linux e o tutorial em http://www.pcs.usp.br/~jkinoshi/2012/linux-qemu-gdb.org . Localize no código do linux onde ocorre o tratamento das system calls. Relacione o endereco dessa primeira instrucao com o vetor de interrupcao. Coloque um breakpoint e observe o valor de R7 que contém o numero da system call. Gere um relatório anexando apenas as partes de código mais relevantes e relacionadas com o SWI, bem como print screens da tela do qemu.

Localize no código do linux onde ocorre o tratamento das system calls. Relacione o endereco dessa primeira instrucao com o vetor de interrupcao. Coloque um breakpoint e observe o valor de R7 que contém o numero da system call. Gere um relatório anexando apenas as partes de código mais relevantes e relacionadas com o SWI, bem como print screens da tela do qemu.

>8, rel ok.

6.3 3 - Linux, system call: execve (ou exec)

Altere o boot do linux apresentado em http://www.pcs.usp.br/~jkinoshi/2012/linux-qemu-gdb.org de forma que: O processo pai correspondente ao init faz fork e fica imprindo "sou processo 1". O processo filho faz execve e executa o código do filho. O filho imprime "filho imprimindo". O programa fonte correpondente ao processo pai deve estar em pai.c e o correspondente ao filho em filho.c. Eles devem ser compilados para o ARM. Os programas pai e filho devem ser previamente armazenados em rootfs. Quando a system call exec é chamada no linux, a funcao doexec é executada dentro do kernel. Explique como isso ocorre, observando o código fonte do linux e o tutorial em http://www.pcs.usp.br/~jkinoshi/2012/linux-qemu-gdb.org. Localize no código do linux onde ocorre o tratamento das system calls. Relacione o endereco dessa primeira instrucao com o vetor de interrupcao. Coloque um breakpoint e observe o valor de R7 que contém o numero da system call. Gere um relatório anexando apenas as partes de código mais relevantes e relacionadas com o SWI, bem como print screens da tela do qemu.

> 8. Giuliana, Izabel, Leonardo, Lucas. Entregaram relatorio?

6.4 4 - Linux, system call que imprime Hello World

Adaptando os passos de http://www.tldp.org/HOWTO/html_single/Implement-Sys-Call-Linux-2.6-i386/ para o ARM, implemente uma system call que imprima Hello World quando chamada. Altere o boot do linux apresentado em http://www.pcs.usp.br/~jkinoshi/2012/linux-qemu-gdb.org de forma a se ter um processo (correspondente ao init) executando essa system call. O numero da system call foi definido em:

#define _NRmycall 317

e foi usado em long mycall(int i)

{

return syscall(_NRmycall, i);

}

Responda:

  1. mycall roda em modo kernel ou modo usuário?
  2. o código syscall em

return syscall(_NRmycall, i); roda em modo kernel ou modo usuário?

  1. apresente e explique o código syscall.

> 8, rel ok.

6.5 5 - Linux, imprimir a data e hora atual.

Adaptando os passos de http://www.tldp.org/HOWTO/html_single/Implement-Sys-Call-Linux-2.6-i386/ para o ARM, implemente uma system call que imprima um numero relacionado com a data e hora atual. como o numero de segundos a partir de 1 de Janeiro de 1970 (o objetivo eh apenas externar algo que o kernel conhece). Altere o boot do linux apresentado em http://www.pcs.usp.br/~jkinoshi/2012/linux-qemu-gdb.org de forma a se ter um processo (correspondente ao init) executando essa system call. O numero da system call foi definido em:

#define _NRmycall 317

e foi usado em long mycall(int i)

{

return syscall(_NRmycall, i);

}

Responda:

  1. mycall roda em modo kernel ou modo usuário?
  2. o código syscall em

return syscall(_NRmycall, i); roda em modo kernel ou modo usuário?

  1. apresente e explique o código syscall.

> Daniel 8.5, Joao Victor 7.5, Lucas 8, Luis, Gustavo 8.5, Victor Franca 8, rel ok.

6.6 6 - Linux, system call que inicializa, soma, subtrai um numero.

Adaptando os passos de http://www.tldp.org/HOWTO/html_single/Implement-Sys-Call-Linux-2.6-i386/ para o ARM, 3 system calls:

  1. inic(Numero)

coloca Numero em alguma variavel interna.

  1. inc()

incrementa a variavel interna, retorna o seu valor apos o incremento.

  1. dec()

decrementa a variavel interna, retorna o seu valor apos o decremento. Crie 2 processos: um que fica em um loop incrementando a variavel interna, imprimindo o seu pid e o valor da variavel e outro que fica em um loop decrementando a variavel, imprimindo o seu pid e o valor da variavel.

que recebe um numero como parametro, e retorna o numero somado de 10. Altere o boot do linux apresentado em http://www.pcs.usp.br/~jkinoshi/2012/linux-qemu-gdb.org de forma a se ter um processo (correspondente ao init) executando essa system call. Gere um log grande (500Mbytes). Crie um script para conferir se houve alguma falha na sequencia de inc's e dec's.

> 9, rel ok

6.7 7 - Linux, fila no kernel.

Veja: http://www.roman10.net/2011/07/28/linux-kernel-programminglinked-list/

Altere o boot do linux apresentado em http://www.pcs.usp.br/~jkinoshi/2012/linux-qemu-gdb.org de forma a se ter dois processos (usando fork) onde um fica continuamente colocando numeros numa fila e outro fica continuamente extraindo numeros de uma fila. A fila corresponde a uma lista ligada no kernel. Vamos criar: insere(numero) que coloca um numero na fila dentro do kernel e numero = remove() que remove um numero na fila dentro do kernel. Adaptando os passos de http://www.tldp.org/HOWTO/html_single/Implement-Sys-Call-Linux-2.6-i386/ para o ARM, implemente inere(numero) e remove().

> Adilson 8, Bianca 7.5, Gustavo 8, Jhonata 8, Luis Henrique 8.5, rel ok.

6.8 8 - Linux, pilha no kernel

Veja: http://www.roman10.net/2011/07/28/linux-kernel-programminglinked-list/

Altere o boot do linux apresentado em http://www.pcs.usp.br/~jkinoshi/2012/linux-qemu-gdb.org de forma a se ter dois processos (usando fork) onde um fica continuamente colocando numeros numa pilha e outro fica continuamente extraindo numeros de uma pilha. A pilha corresponde a uma lista ligada no kernel. Vamos criar: insere(numero) que coloca um numero na pilha dentro do kernel e numero = remove() que remove um numero na pilha dentro do kernel. Adaptando os passos de http://www.tldp.org/HOWTO/html_single/Implement-Sys-Call-Linux-2.6-i386/ para o ARM, implemente inere(numero) e remove().

> 10, rel ok.

6.9 9 - Linux, fila no kernel com um pequeno tratamento de erro.

Veja: http://www.roman10.net/2011/07/28/linux-kernel-programminglinked-list/

Altere o boot do linux apresentado em http://www.pcs.usp.br/~jkinoshi/2012/linux-qemu-gdb.org de forma a se ter dois processos (usando fork) onde um fica continuamente colocando numeros numa fila e outro fica continuamente extraindo numeros de uma fila. A fila corresponde a uma lista ligada no kernel. Vamos criar: insere(numero) que coloca um numero na fila dentro do kernel e numero = remove() que remove um numero na fila dentro do kernel. Adaptando os passos de http://www.tldp.org/HOWTO/html_single/Implement-Sys-Call-Linux-2.6-i386/ para o ARM, implemente inere(numero) e remove().

Em relacao ao grupo 7, faca de diferente:

  • se a lista ultrapassar de 100 numeros, insere(numero) deve retornar erro.
  • se remove() nao tiver o que remover, deve retornar erro.

A chamada fica: nerro = remove(); onde nerro eh o numero do erro. Se retornar zero, estah ok. Se retornar algo diferente de zero, entao o processo de usuario deve imprimir uma mensagem na tela.

> 8, rel ok.

6.10 10 - Linux/raspberry, system call: fork

Os exercicios de 1 a 8 foram feitos com base na placa Versatile emulada pelo qemu. Este exercicio consiste em repetir o exercicio 1, mas na placa Raspberry emulada pelo qemu. Os alunos deverao procurar na internet como se pode emular a placa Raspberry no qemu. O processo pai (correspondente ao init) fica imprindo "sou processo 1" e o processo filho imprime "filho imprimindo". Quando a system call fork (veja o código que implementa fork) é chamada no linux, a funcao dofork é executada dentro do kernel. Explique como isso ocorre, observando o código fonte do linux e inspire-se tutorial em http://www.pcs.usp.br/~jkinoshi/2012/linux-qemu-gdb.org . Nao eh preciso fazer com que o qemu se comunique com o gdb.

> 8, problema comunicacao gdb + qemu emulando o raspberry, rel ok.

6.11 10B - Linux, pilha no kernel com um pequeno tratamento de erro.

Veja: http://www.roman10.net/2011/07/28/linux-kernel-programminglinked-list/

Altere o boot do linux apresentado em http://www.pcs.usp.br/~jkinoshi/2012/linux-qemu-gdb.org de forma a se ter dois processos (usando fork) onde um fica continuamente colocando numeros numa pilha e outro fica continuamente extraindo numeros de uma pilha - First In Last Out. A pilha corresponde a uma lista ligada no kernel. Vamos criar: insere(numero) que coloca um numero na pilha dentro do kernel e numero = remove() que remove um numero na pilha dentro do kernel. Adaptando os passos de http://www.tldp.org/HOWTO/html_single/Implement-Sys-Call-Linux-2.6-i386/ para o ARM, implemente inere(numero) e remove().

Em relacao ao grupo 7, faca de diferente:

  • se a lista ultrapassar de 100 numeros, insere(numero) deve retornar erro.
  • se remove() nao tiver o que remover, deve retornar erro.

A chamada fica: nerro = remove(); onde nerro eh o numero do erro. Se retornar zero, estah ok. Se retornar algo diferente de zero, entao o processo de usuario deve imprimir uma mensagem na tela.

7 Fase 2

7.1 1 signal

Entenda o seguinte código:

#include<stdio.h>
#include<signal.h>
void bypass_sigint(int sig_no)
{
  printf("dividi por zero\n");
}
int main()
{
  int a,b,c;
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = &bypass_sigint;
    sigaction(SIGFPE, &sa,NULL);
    while (1) {
      sleep(1);
        printf("do nothing \n ");
    }
    return 0;
}

Esse código ativa a funcao sigint toda vez que houver uma divisão por zero. Mas um outro processo pode enviar um signal, dizendo que houve uma divisão por zero. Experimente em uma outra shell fazer: kill -8 #pidprocesso

onde -8 se refere a SIGPFE, divisão por zero. Para você realmente observar que houve uma divisão por zero, experimente colocar dentro do código, após sigaction:

a = 1; b= 0; c = a/b;

e veja que a rotina imprime "dividi por zero".

Experimente em uma outra shell fazer: kill -8 #pidprocesso

Como o linux trata a divisão por zero? Explique o código. É de se esperar que o linux envie um signal para o processo que fez a divisão por zero. Faça um programa executável que faz a divisão por zero no linux rodando no qemu. Rode o programa e capture o signal imprimindo na tela uma mensagem toda vez que for feita a divisão por zero. O kernel contém uma estrutura de dados guarda o signal handler do processo. Observem a estrutura de dados dentro do kernel que mostra a que sinais estao associados quais handlers.

Estude o código que trata sigaction(SIGFPE, &sa,NULL); e observe qual é essa estrutura de dados. Quando ocorrer a divisão por zero, essa estrutura de dados será usada para ativar o signal handler ( bypasssigint) adequado. Faça um print screen do qemu logo ao entrar na rotina que faz o tratamento da divisão por zero (observando qual é o endereco da rotina a ser executada dada pelo vetor de interrupcao do ARM - pesqui sobre isso). Realmente eh possivel que um processo A envie um signal a um outro processo B (através do kill), fazendo com que B ache que houve uma divisão por zero dentro do linux? O que acontece desde a interrupcao gerada pela divisao por zero ateh a chamada da rotina bypasssigint (signal handler)? Como o SO fica sabendo qual é o signal handler que deve ser chamado?

Observe o seguinte: quando existe a divisao por zero no programa, ou seja, quando o codigo a = 1; b= 0; c = a/b; eh executado, o signal handler eh executado mas retorna para antes da divisao ser feita. Isso faz com que c = a/b seja executado infinitamente pois a instrucao a/b eh sempre colocada novamente para rodar após o signal handler ser executado. Uma forma de resolver isso eh criar um signal handler que retorna para a instrucao posterior no caso de SIGFPE acessando a pilha em assembly (Ver 'man 2 signal').

> 7 para o grupo, mas Andre 6; rel ok. faltou observar o que acontece no kernel. Ex: O que acontece desde a interrupcao gerada pela divisao por zero ateh a chamada da rotina bypasssigint (signal handler)? Como o SO fica sabendo qual é o signal handler que deve ser chamado?

7.2 2 hierarquia de processos.

Em init crie um processo filho FILHO e faça com que o filho crie outro processo NETO. O processo INIT e NETO ficam em loops continuos imprimindo alguma mensagem, mas o processo FILHO apenas impreme uma mensagem e termina. O que acontece com NETO? Crie a sistema call pidpai() que quando chamada retorna o pid do pai (veja a taskstruct). Faça com que NETO fique continuamente chamando pidpai e imprimindo o pid do pai. Explique o que acontece relacionando com o codigo do kernel.

> 8, rel ok

7.3 3 system call forkexecve

Crie a system call forkexec que faz o fork e em seguida o execve como (ver man execve):

#include <unistd.h>
int forkexecve(const char *filename, char *const argv[], char *const envp[]);

forkexecve deve primeiro fazer o fork e depois executar execve no novo processo.

> 7.5, rel ok. - nao foi possivel fazer o filho dar o fork e executar o exec, mas foi possivel que o pai fizesse isso. Faltou discutir os problemas que deram na implementacao como por exemplo: as chamadas de tratamento de fork e exec dentro do kernel implicavam em se voltar ao modo usuario? Poderiam ter observado melhor o que acontece com o código usando o gdb.

7.4 4 estados de um processo.

Veja a figura 3-3 do livro: Linux kernel Development do Robert Love que contém os estados em que um processo pode estar (Veja a taskstruct). Crie a system call mostraEstado(pid) que quando chamada mostra o estado em que se encontra o processo com certo pid. Faça com que o init dispare um processo filho que continuamente:

  • imprime 10 vezes alguma mensagem
  • executa getchar() esperando um dado do teclado (e ficando bloqueado).

O processo init, pai deve: ficar em um loop infinito imprindo o estado do filho através de mostraEstado(pidFilho) O objetivo eh observar o processo filho entrando no estado de bloqueado quando chama getchar().

> 8 ok.

7.5 5 chaveamento dos processos.

Usando qemu no linux compilado para o Versatile, faca com que o linux rode apenas um processo: o processo que continuamente le caracteres do teclado (usando getchar() e os imprime na tela. Coloque um breakpoint na interrupção de teclado atkbdinterrupt (o breakpoint soh aparece apos inicializar o kernel). Faça um print screen do qemu mostrando a primeira instrução logo ao entrar no tratamento de interrupção do teclado. Relacione o valor do endereço que você vê, com o manual do ARM7 (consulte na internet como o ARM trata interrupcoes de hardware; veja tambem a apostila usada no laboratorio de microprocessadores). Onde (em qual arquivo fonte do linux) o estado do processo é armazenado? Relacione isso com o código do linux e explique. Ao sair da rotina de interrupção, um outro processo foi escalonado para rodar? Qual processo? Apresente um print screen dos registradores antes de sair da interrupção. Como ao sair da interrupção, o novo processo passa a rodar? Com que Program Counter? Explique. Após a syscall getchar, o processo é bloqueado enquanto nada é teclado. Mostre como o processo é bloqueado (retirado da fila de execucao e colocado em uma outra fila para esperar o caracter). Após o caracter ser teclado, ocorre a SWI, e o processo é então desbloqueado. Mostre como isso ocorre. Retire os printscreens mostrando isso ocorrendo e anexe no relatório.

> 7-1=6 Nao prepararam a apresentacao (powerpoint). Falta orgaizacao nas ideias. Relatorio bem melhor apresentado.

7.6 6 escalonador Round Robin

A política default no Linux é o Completely Fair Scheduler. Crie 100 processos:

  1. 99 que continuamente fazem contas. Ex: gera um numero aleatorio e soma com um total.
  2. 1 que continuamente faz entrada e saida: le um caracter do teclado e imprime o caracter lido na tela.

Observe o tempo de resposta do segundo processo contando o numero de caracteres que ele imprime por segundo mantendo uma tecla apertada. Troque a politica do escalonador usando a system call schedsetscheduler para Round Robin. Repita a experiencia para observar o tempo de resposta usando o Round Robin. Houve diferencas? Explique.

> 9 (Felipe G. doente) rel ok; poderiam ter feito o getchar sem depender do ENTER. Deu para perceber bem que o CFS prioriza bem melhor os processos interativos.

7.7 7 solucao de Peterson.

Vamos criar duas system calls: valor = leia(); escreva(valor);

onde: escreva(valor) guarda um certo valor dentro de uma posicao de memoria no kernel e leia() le e retorna o valor lido.

Crie 2 processos que continuamente chamam leia e escreve da seguinte forma:

while (1) { x = leia(); x = x+1; escreva(x); }

Dessa forma eh bem provavel que exista um time out entre o leia e o escreva, gerando uma condicao de corrida. Anexe um printscreen de quando essa situacao ocorre, mostrando qual o valor que se repetiu. Para verificarmos a condicao de corrida, podemos verificar se toda a vez que a system call eh chamada, o valor eh incrementado de um. Use a solucao de Peterson para evitar a condicao de corrida.

O escalonador eh chamado quando ocorre o estouro do quantum. Altere o kernel de forma que o escalonador nao seja mais chamado quando ocorre o estouro do quantum, mas permita que o escalonador seja chamado quando corre a system call leia() e escreva().

Apos alterar os momentos da chamada do escalonador verifique novamente ambos os processos rodando, com e sem a solucao de Peterson.

> 8-1(atraso) = 7. ok

7.8 8 system call bloqueia, desbloqueia.

Crie 2 system calls: bloqueia(pid) bloqueia o processo especificado pelo pid, colocando-o numa fila de processos bloqueados. erro = desbloqueia() desbloqueia o primeiro processo que estah na fila de processos bloqueados com erro = 0 ou apenas continua com erro = 1.

Crie um processo que pai monitora o processo filho da seguinte forma: O processo filho continuamente imprime "A". O processo pai cria o filho recebendo o pidA do filho e observa o teclado. Se o usuario teclar "b", ele faz bloqueia(pidA). Se o usuario teclar "d", ele faz desbloqueia().

Espera-se que o qemu/versatile imprima "A" de acordo com as teclas "b" e "d".

> 9.5 rel ok; boa apresentacao.

7.9 9 CFS Completely Fair Scheduler, a patir de 2.6.23

Estude e explique tanto na apresentacao quanto no relatorio: http://www.ibm.com/developerworks/library/l-completely-fair-scheduler/ Crie a system call cfs() que retorna uma string contendo pares de pid:virtualRuntime de forma ordenada. Do processo com o menor virtual runtime ateh o processo com o maior virtual runtime. Para testar, crie um init que faz chamada de alguns processos, alguns que usam muito a cpu fazendo calculos e outros que usam pouco a cpu lendo dados do teclado.

> 9, rel ok. -> houve problema em criar a system call cfs() por que nao dava para exportar a raiz da red black tree; porem usando printk imprimiram os processos de acordo.

7.10 10 semáforo.

Em http://www.linuxdevcenter.com/lpt/a/7029 temos a apresentacao de threads em modo usuario usando semaforos; porem versoes de semaforos para threads sem fazer chamadas de sistema. Em http://www.cis.upenn.edu/~lee/07cis505/Lec/SemaphoreOperations.pdf temos o uso de semaforos fazendo chamadas de sistema - semop.

Altere o init para fazer algo como:

if (fork() ) {
   while (1) {
      print "1"
      down(S) 
      print 2
      up(S)
      print 3
   }


} else {
  while (1) {
      print "A"
      down(S)
      print X 
      print B
      up(S)
      print C
   }
}

trocando up e down pelo semop. O valor do semáforo é gerenciado pelo kernel porque duas ou mais threads podem estar alterando o seu valor e o kernel deve evitar condicoes de corrida nessas alteracoes. Coloque um breakpoint para observar como o kernel altera o valor do semáforo e retire print screens. Vamos supor que uma thread A fique bloqueada aguardando o incremento do semáforo por outra thread B. No momento em que a outra thread B pedir ao kernel para incrementar o semáforo, o kernel deve desbloquear a thread A. Analise o código do kernel do linux e descubra onde isso ocorre. Coloque um breakpoint nessa posicao, rode o gdb até essa posicao, retire um printscreen. Analise a fila de execucao dos processos. Para isso será necessário estudar http://isis.poly.edu/kulesh/stuff/src/klist/ para entender como o kernel do linux gerencia listas. Motre o processo bloqueado no down e sendo desbloqueado pelo up. Verifique que no "up", o processo bloqueado é retirado da fila do semáforo e vai para a fila dos processos prontos. Ver o codigo do spin lock no kernel no up e no down. Encontre o código onde o processo desbloqueado é colocado na fila do escalonador.

Encontre no código fonte a fila de processos associado ao semáforo. Crie e teste a sistema call esperasem(semaforo) que retorna o pid do processo que estah na fila associado ao semaforo. Teste essa system call em seu codigo.

> 10 rel ok; colocaram e visualizar a fila de processos no semaforo

8 Fase 3

Todas as turmas: apresentem rodando ao vivo.

8.1 1 systemtap - threads esperando I/O.

O systemtap é uma linguagem onde se escreve scripts que rodam em modo kernel, permitindo extrair diversos dados do sistema operacional. Veja: https://sourceware.org/systemtap/SystemTap_Beginners_Guide/

Exemplos de uso: https://sourceware.org/systemtap/examples/#process/cycle_thief.stp Um exemplo é: https://www.sourceware.org/systemtap/SystemTap_Beginners_Guide/inodewatchsect.html#inodewatch

Rode esse script (melhor no centos do que no ubuntu por causa do systemtap) que monitora as operacoes sobre arquivos.

Monitore o arquivo referente a um filme - existe alguma frequencia com que ele é acessado?

Entenda e explique o script. O systemtap roda melhor no centos.

8.2 2 systemtap - uso de um driver.

O systemtap é uma linguagem onde se escreve scripts que rodam em modo kernel, permitindo extrair diversos dados do sistema operacional. Veja: https://sourceware.org/systemtap/SystemTap_Beginners_Guide/

Veja como o systemtap pode ser usado para monitorar como um dispositivo de entrada/saida está sendo usado:

https://sourceware.org/systemtap/SystemTap_Beginners_Guide/traceio2sect.html

Rode esse exemplo com diversos dispositivos. Entenda e explique o script. O systemtap roda melhor no centos.

8.3 3 systemtap - tempo em modo usuario e em modo kernel.

O systemtap é uma linguagem onde se escreve scripts que rodam em modo kernel, permitindo extrair diversos dados do sistema operacional. Veja: https://sourceware.org/systemtap/SystemTap_Beginners_Guide/

Rode o exemplo https://sourceware.org/systemtap/SystemTap_Beginners_Guide/threadtimessect.html

Explique como funciona o script. Faça testes criando dois processos, um que faça muitas contas - e portanto fica muito tempo rodando em modo usuário e outro que faça mais I/O e portanto fica mais tempo rodando em modo kernel. Faca testes atribuindo uma ou duas cpus aa maquina virtual. Rode no centos.

8.4 4 Linux - teclado

No centos (melhor que ubuntu para isso) usando systemtap, crie um script que imprima os processos que ficam bloqueados aguardando que o usuário tecle algo. Crie um init que crie 3 processos e cada processo faz um getchar. Os 3 processos ficam bloqueados esperando com que o usuario tecle algo. Rode o seus script e observe os processos bloqueados aguardando o usuário teclar algo.

8.5 5 Linux - construir um file em /proc.

Na experiencia passada, a equipe 10 implementou uma system call que apresenta os processos na fila de um semáforo. O filesystem /proc externaliza informação do kernel. É possível construir um file em /proc de tal forma a apresentar o número do semáforo e os processos bloqueados nele. O tutorial http://www.tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN128 apresenta como construir um file em /proc. O objetivo é construir o file /proc/waitsem que apresenta para cada semáforo os processos que estao bloqueados nele ao se fazer, por exemplo: more /proc/waitsem

8.6 6 Rode o seguinte programa como init:


#include <stdio.h>

void main() { int c; printf("Hello World!\n"); while(1) { c = getchar(); printf ("teclou %d ", c); }; }


A função getchar chamará o sysread no kernel que esperará o usuário teclar algo seguido de ENTER. sysread chamará indiretamente a função de leitura do driver da tty (drivers/tty/ttyio.c). Onde isso ocorre? Para se ler da tty, o driver chamará schedule pedindo para se escalonar algum outro processo enquanto o usuário não teclar nada. Onde isso ocorre? Antes da chamada de schedule() imprima quais processos estão prontos para ganhar a CPU? Qual ganhará a CPU? Provavelmente serah a task idle que é escalonada quando não se tem nada a fazer. Discuta o que faz essa task.

8.7 7 Linux - construir o driver padrao no arm linux.

A partir de: http://www.pcs.usp.br/~jkinoshi/2008/Exp8_revisada_13_08_07.doc: 1 - crie um driver simples no linux normal (ex: ubuntu). 2 - crie o driver padrao e teste a leitura e escrita no driver usando "echo" na maquina virtual. O passo 1 é muito simples, porém existem diversas dificuldades para fazer o mesmo na maquina virtual/ARM:

  • como criar uma entrada no rootfs para o driver padrao? Deve ser através de system calls para se fazer o mknod. Assim, crie um init que somente irá criar uma entrada em /dev em rootfs para o driver da entrada padrao.
  • a compilacao do driver padrao para o ARM pode apresentar dificuldades. Existem duas formas de se fazer o driver padrao para o ARM - como um modulo a ser carregado ou já compilado no kernel. Experimentem recompilar o kernel com o driver padrao jah inserido no kernel. Observem algumas system calls a serem chamadas pelo init como makedev e mknod. Alterarem o Makefile em /driver para criar o driver no kernel.

8.8 8 Linux - construir o driver padrao no arm linux com interacao de I/O simulando interrupcao via system call.

A partir de: http://www2.pcs.usp.br/~jkinoshi/2008/Exp8_revisada_13_08_07.doc: 1 - crie um driver simples no linux normal (ex: ubuntu). Observe como driver funciona para leitura. Teste o comando cat /dev/driver ter declarado o driver. 2 - crie o driver padrao e teste a leitura e escrita no driver usando "echo" na maquina virtual. O passo 1 é muito simples, porém existem diversas dificuldades para fazer o mesmo na maquina virtual/ARM:

  • como criar uma entrada no rootfs para o driver padrao? Deve ser através de system calls para se fazer o mknod. Assim, crie um init que somente irá criar uma entrada em /dev em rootfs para o driver da entrada padrao.
  • a compilacao do driver padrao para o ARM pode apresentar dificuldades. Existem duas formas de se fazer o driver padrao para o ARM - como um modulo a ser carregado ou já compilado no kernel. Experimentem recompilar o kernel com o driver padrao jah inserido no kernel. Observem algumas system calls a serem chamadas pelo init como makedev e mknod. Alterarem o Makefile em /driver para criar o driver no kernel.

O driver deverah fazer: leitura, como se estivesse lendo algo do teclado, mas passaremos o que estah sendo lido pela system call escreva, a ser implementada.

A idéia é:

  1. Ao fazer o comando:

cat /dev/driver a rotina de leitura do driver serah acionada.

  1. O driver deverah bloquear o processo que fez a leitura caso nao tenha recebido nada pela system call "escreva" na fila "esperadriver" a ser declarada no kernel.
  2. A system call escreva apenas obterm um "char" como parametro e escreve na fila circular "carcateresrecebidos". Se houver algum processo esperando na "esperadriver", ele eh acordado e recebe o caracter. Ou seja, estamos apenas simulando uma rotina de interrupcao que acorda o processo bloqueado esperando por dado de entrada.

Crie 2 processos de usuário. Um que continuamente chama a system call "escreva" quando o usuário teclar "e". Um que continuamente faz a leitura de dados de /dev/driver via system call read e imprima algo assim que conseguir ler. Voce terah que fazer open no device antes para usar o file descriptor.

Espera-se que: O processo que leia continuamente de /dev/driver fique travado e imprima algo apenas quando o usuário teclar "e".

8.9 9 Rode o seguinte programa como init:


#include <stdio.h>

void main() { int c; printf("Hello World!\n"); while(1) { c = getchar(); printf ("teclou %d ", c); }; }


A função getchar chamará o sysread no kernel que esperará o usuário teclar algo seguido de ENTER. sysread chamará indiretamente a função de leitura do driver da tty. Onde isso ocorre? Se o usuário não tiver teclado nada, o driver chamará schedule pedindo para se escalonar algum outro processo. Onde isso ocorre? Quando o usuário teclar algo, a função _wakeup() em kernel/sched.c serah chamada, pois o kernel avisará o processo de usuário (no caso init) de que algo foi teclado. Coloque um breakpoint em _wakeup e veja o caminho (usando bt no gdb) entre a interrupção e o wakeup. Fazendo isso, talvez voce obtenha:

(gdb) bt #0 _wakeup (q=0xc02128fc, mode=1, nrexclusive=1, key=0x0) at kernel/sched.c:4338 #1 0xc01302e8 in creditentropybits (r=<value optimized out>, nbits=<value optimized out>) at drivers/char/random.c:556 #2 0xc0130b80 in addtimerrandomness (state=0xc0231e08, num=<value optimized out>) at drivers/char/random.c:676 #3 0xc014c1a8 in inputevent (dev=0xc71c3c00, type=4, code=3, value=28) at drivers/input/input.c:355 #4 0xc0151278 in atkbdinterrupt (serio=0xc71abe00, data=<value optimized out>, flags=0) at drivers/input/keyboard/atkbd.c:401 #5 0xc0149c88 in seriointerrupt (serio=<value optimized out>, data=<value optimized out>, dfl=<value optimized out>) at drivers/input/serio/serio.c:996 #6 0xc0149de8 in ambakmiint (irq=<value optimized out>, devid=0xc71a13e0) at drivers/input/serio/ambakmi.c:47 #7 0xc0061e30 in handleirqeventpercpu (desc=0xc02097c8, action=0xc7169c60) at kernel/irq/handle.c:126 #8 0xc0061fb8 in handleirqevent (desc=0xc02097c8) at kernel/irq/handle.c:182 #9 0xc00639b4 in handlelevelirq (irq=<value optimized out>, desc=0xc02097c8) at kernel/irq/chip.c:344 #10 0xc003582c in generichandleirqdesc (irq=<value optimized out>, desc=<value optimized out>) at include/linux/irqdesc.h:109 #11 generichandleirq (irq=<value optimized out>, desc=<value optimized out>) at include/linux/irqdesc.h:114 #12 fpgairqhandle (irq=<value optimized out>, desc=<value optimized out>) at arch/arm/plat-versatile/fpga-irq.c:45 #13 0xc0022070 in generichandleirqdesc (irq=31, regs=<value optimized out>) at include/linux/irqdesc.h:109 #14 generichandleirq (irq=31, regs=<value optimized out>) at include/linux/irqdesc.h:114 #15 asmdoIRQ (irq=31, regs=<value optimized out>) at arch/arm/kernel/irq.c:90 #16 0xc002bb34 in _irqsvc () at arch/arm/kernel/entry-armv.S:42

Caso nao tenha obtido o trace acima, basta colocar breakpoints nas rotinas intermediárias. Toda rotina de interrupcao associada a um driver deve ser registrada. Temos uma sequencia de drivers usando outros drivers, mas a primeira interrupcao do primeiro driver foi ambakmiint (subindo da interrupcao de baixo para cima). Fazendo uma busca em sua declaracao, ~/Downloads/linux-2.6.39/drivers$ grep -r ambakmiint * input/serio/ambakmi.c:static irqreturnt ambakmiint(int irq, void *devid) input/serio/ambakmi.c: ret = requestirq(kmi->irq, ambakmiint, 0, "kmi-pl050", kmi);

O registro dessa interrupcao, eh feito por ambakmiopen. Para ver sobre amba kmi: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0447j/Cfhhieif.html

Quando ocorre a interrupcao de hardware, eh necessário saber quem gerou a interrupcao: teclado, timer, mouse, etc. Localize isso no código. Uma vez localizado o hardware, eh necessário passar o tratamento da interrupçao para o driver adequado. Ver ambakmiint. Localize isso no código. O caracter (ou caracteres) teclado é lido de algum port. Na verdade, se lê a posição da tecla. Localize isso no código. O que faz readb(KMIDATA)? O código lido deve ser guardado em um buffer enquanto o usuario nao tecla ENTER. Localize isso no código. A função _wakeup acorda o processo que lia da tty (dentro do kernel). Localize isso no código. Explique melhor o que faz _wakeup. Localize isso no código.

Quando o usuário tecla ENTER, o processamento é diferente: os dados devem ser transferidos para o buffer de usuário. Localize isso no código.

8.10 10 Linux - escalonador de I/O

Rode o seguinte programa: #include <stdio.h>

void main() { int c; int pid;

printf("Hello World!\n"); fork(); fork(); fork();

pid = getpid(); printf("rodando com pid %d \n", pid);

while(1) { pid = getpid(); printf("pid %d \n", pid); c = getchar(); printf ("teclou %d \n", c); };

}

No versatile emulado, crie um init que rode o código acima. Os processos ficam bloqueados esperando com que o usuario tecle algo. Eles sao colocados numa fila. Localize isso no código. O que acontece quando o usuário tecla algo seguido de ENTER? Um processo passa a rodar ou todos passam a rodar? Localize isso no código. Experimente em um linux normal e também na placa versatile emulada. No meu caso, no linux normal, apenas um processo aleatoriamente recebe os caracteres. Coloque um breakpoint quando o processo sai da fila de espera do teclado e é acordado (_wakeup). Modifique o kernel para que imprima essa fila de espera pelo teclado toda vez que o processo é adicionado na wait queue (addwaitqueue) que espera caracteres teclados. É possível se prever qual processo será acordado?

9 Fase 4

9.1 1 linux/ubuntu,centos - page fault.

Existem formas de se ver processos gerando page faults no linux/ubuntu. Exemplo: http://www.ewhathow.com/2013/09/how-to-identify-page-faults-on-linux/ Crie um programa em C que gere muitas page faults em um linux normal (idéia: que esteja continuamente alocando muito memória para si). Monitore esse programa para observar se de fato tem gerado muitas page faults. (http://www.linuxjournal.com/article/8178)

Rode o linux/ubuntu e observe a invasao de memoria.

Veja em: https://sourceware.org/systemtap/examples/keyword-index.html memory/pfaults.stp - Generate Log of Major and Minor Page Faults keywords: MEMORY The pfaults.stp script generates a simple log for each major and minor page fault that occurs on the system. Each line contains a timestamp (in microseconds) when the page fault servicing was completed, the pid of the process, the address of the page fault, the type of access (read or write), the type of fault (major or minor), and the elapsed time for page fault. This log can be examined to determine where the page faults are occurring.

Estude e explique como o kernel lida com o page fault. No ano passado, os alunos observaram apenas minor page faults. Tentem gerar major page faults.

9.2 2. LINUX/ARM - memória compartilhada.

Em um linux normal (ex: ubuntu), crie uma area de memoria compartilhada por dois processos diferentes no linux (veja mmap) e transfira dados usando essa área de memória. O endereco virtual onde estah essa area compartilhada eh o mesmo para os dois processos? Estude como voce pode verificar isso no linux. Usando ferramentas do linux, visualize essa área de memória compartilhada (veja /proc). Faca testes para verificar qual o maximo de área de memória possível compartilhada entre ambos os processos.

No Linux/Versatile faca com que o init crie dois processos com área de memória compartilhada. Coloque um breakpoint na entrada dessa system call, bem como em outras posicoes. Retire uns printscreens do bt (backtrace); isto é, para descobrir que funçoes do kernel sao chamadas para executar essa system call. Busque referencias na internet e livros para explicar como o kernel do linux faz a memória compartilhada.

9.3 3. LINUX/ubuntus,centos DLL

Crie uma funcao que apenas soma dois numeros quando chamada e coloque essa funcao numa Dynamically Linked "Shared Object" Libraries: (.so). Crie dois processos que utilizam essa mesma funcao. Descubra uma ferramenta no linux que permite visualizar quais sao as DLLs carregadas no linux. Ative os dois processos e observe se a DLL está carregada. Voce pode rodar cada programa em uma shell diferente. Descubra em que parte da memória foi carregada a DLL (dica: veja /proc). Esses enderecos virtuais de memoria onde a DLL foi carregada sao os mesmos para os dois processos que compartilham a DLL? Agora altere a funcao para que ela tenha um estado interno; ou seja, ao inves de somar dois numeros; faca com que a funcao apenas incremente alguma variavel interna a ela. Rode os dois processos fazendo com que um numero seja incrementado a cada "enter" do usuário. Isso funciona? É possivel que a DLL guarde valores proprios? Talvez não seja possível, procure comprovar isso. Observe que existem dois tipos de bibliotecas : dinamicas e carregáveis (as dinamicas precisam do comando ldd para carregar primeiro a biblioteca e depois executar o codigo). As loadble verificam se estah na memoria, se não estiver jah sai carregando. Experimente usar os dois tipos de biblioteca. Nao eh necessario colocar no arm+qemu pois eh muito mais facil fazer testes direto no ubuntu.

9.4 4. LINUX slab/slub allocator

Procure na internet e livros sobre o alocador slab/slub; uma referência é: http://www.secretmango.com/jimb/Whitepapers/slabs/slab.html Entenda e explique no relatório para que serve esse alocador, como a memória é alocada e desalocada para uso do kernel. Quando um arquivo é aberto, o kernel aloca memória para o seu inode (uma estrutura de dados contendo ponteiros para blocos, data da criação, permissões, etc.). Crie um programa bem simples (o correspondente ao init) para rodar no Linux/Versatile para observarmos como isso funciona. O programa deve abrir um arquivo, escrever algo nesse arquivo e fechar o arquivo. Quando o arquivo é aberto, o kernel aloca memória para o inode. Quando o arquivo é fechado, a área para o inode deve ser desalocada. Usando o gdb rode até que a system call execve ative este programa (para garantir que as estruturas do kernel já estão prontas). Coloque breakpoints quando a área de memória para o inode é criada e liberada. Coloque os printscreens da tela no relatório. Apresente ao vivo para a classe. Rode no linux/arm no qemu. Verifique que memória eh alocada para o inode quando o open eh feito pela primeira vez. Jah na segunda vez, a memoria eh reutilizada.

9.5 5 Linux/ubuntu,centos - estouro de pilha.

Estouro de pilha (stack overflow): monitorar quando ocorre estouro de pilha. Você pode criar a rotina recursiva "imprime" que chama ela mesma indefinidamente no linux. Ela deve passar como parametro i+1 e imprimir esse valor; de forma que podemos identificar o numero maximo de chamadas recursivas que foi possivel antes de se ter o estouro de pilha. Rode o linux e observe o estouro de pilha.

Veja em: https://sourceware.org/systemtap/examples/keyword-index.html Rode algum scritp systemtap para logar esse tipo de falha. Talvez o script o script overcommit.stp detecte essa falha.

memory/overcommit.stp - Log Failed Process Memory Allocation Due to Overcommit Limits keywords: MEMORY LIMITS The overcommit.stp script prints a line each time the kernel refuses a memory allocation request from a process because of /proc/sys/vm/overcommit* limits.

Coloque o printscreen no relatório. Eh possivel limitar o tamanho da pilha usando a system call setrlimit ou ulimit. Verifique que o numero de recursoes diminui caso a pilha seja menor. O numero de recursoes varia ou eh sempre o mesmo a cada vez que o programa eh executado? Misteriosamente o numero de recursoes varia, mas isso nao eh esperado jah que a memoria virtual sempre deveria ser a mesma para cada ativacao do processo. Tente rodar o programa ativando outros processos pesados (que consumam muita memoria) e outras vezes sem esses processos pesados. Quando a memoria estah mais livre, a pilha eh maior? Procure encontrar uma explicacao para a pilha estar variando de tamanho (isto eh, o numero maximo de recursoes estar variando).

9.6 6 LINUX/ARM alocacao e desalocacao de memória

Mostrar através de um log como a memória foi alocada e desalocada a processos no linux. Toda vez que um processo executar um fork, exec, exit afeta a alocação de memória. Apresente isso num log (imprima usando printk). No log contém informações como: system call (fork) - processo (/usr/bin/init +) quantidadedebytesalocada pgmemoriafisca.

onde:

  • : significa que memória está sendo alocada ao processo
  • : significa que memória está sendo desalocada e devolvida para a área livre.

Faça um programa que fique em loop executando o fork e veja o que ocorre no log. O processo deverá fazer algo como: while (1) { fork(); } Esse tipo de processo vai travar o sistema porque vai consumir toda a memória; ou vai acabar com todas as entradas na tabela de processos. O que acontece no linux? Crie uma forma de monitorar o número de processos que rodam na máquina. Tire printscreens da tela enquanto o processo que gera processos roda.

9.7 7 Linux/ubuntu,centos invasao de memoria

Como o linux protege a área do kernel? Se algum processo tentar invadir a área do kernel ele é realmente barrado? Crie um processo que tenta invadir uma área a que nao tem acesso. Uma forma de fazer isso é criar um ponteiro que varre a memória, lendo e escrevendo a partir da posicao zero ateh o maximo. Ao fazer isso no linux que erro você observa? Localize o tratamento desse erro no código fonte do linux. Apresente uma mensagem diferente quando ocorrer esse erro. Qual a participacao do pentium nessa excessão? Como o pentium é informado da área de memória do processo? Localize isso no código do linux.

Rode o linux/ubuntu e observe a invasao de memoria.

Veja em: https://sourceware.org/systemtap/examples/keyword-index.html Rode algum scritp systemtap para logar esse tipo de falha. Talvez o script o script overcommit.stp detecte essa falha.

memory/overcommit.stp - Log Failed Process Memory Allocation Due to Overcommit Limits keywords: MEMORY LIMITS The overcommit.stp script prints a line each time the kernel refuses a memory allocation request from a process because of /proc/sys/vm/overcommit* limits.

Estude e explique como o kernel o acesso indevido.

9.8 8 Linux/qemu

Aparentemente é facil gerar major page faults. Basta criar um programa que aloque muita memória (criando um grande vetor ou fazendo malloc) e depois escreva e leia em diversas posicoes. Na pratica, nao conseguimos criar nenhum programa que crie major page faults atraves de um simples programa (page faults que necessitam de escrever no disco). Procurei na internet e encontrei o seguinte:

  1. https://stackoverflow.com/questions/29850001/how-to-write-a-simple-page-fault-generator
  2. https://unix.stackexchange.com/questions/188170/generate-major-page-faults
  3. https://github.com/mrecachinas/Page-Faults

Eu pessoalmente testei os programas 1 e 2. Ambos nao geraram major fault (num ubuntu 14.4, 64 bits). Eles geraram o sinal SIGSEGV - segmentation fault. O terceiro caso rodava num mac. O programa 1 funciona para vetores pequenos, mas gera segmentation fault para vetores grandes. Teste no qemu/versatile:

  • o programa 2 rodando como init. Verifique que ele funciona para vetores pequenos.
  • para qual tamanho de vetor ele deixa de funcionar?

No meu ubuntu, o programa é morto porque recebe o sinal SIGSEGV. Em "man 7 signal": SIGSEGV 11 Core Invalid memory reference Observe o que acontece no qemu/versatile. Ao aumentar a memória podemos ter "Invalid memory reference" ou major fault. Num enderecamento invalido, a instrucao quer acessar uma posicao dentro do kernel. Num major page fault, o enderecamento eh valido, mas a instrucao (ou valor referenciado) estah no disco e nao na memoria. Num minor page fault, nao eh necessario acessar o disco. Em qualquer um dos casos, a MMU gera essa excessao (page fault ou referencia invalida). Coloque um breakpoint ao rodar o kernel, o mais perto possivel da excessao sendo gerada. Estude e explique o que o codigo faz. Experimente declarar um signal handler que captura o SIGSEGV. Se funcionar, entao todo acesso a uma posicao invalida poderah ser ignorada. Desafio: criem algum aplicativo que gere um major fault no ubuntu (ou qualquer outra distribuicao), mas principalmente no qemu/versatile.

9.9 9 Linux/ubuntu,centos, arm - tabela de paginas.

No ubuntu, imprima a tabela de paginas de um processo especifico como o firefox. Identifique as areas de codigo, dados, pilha, bem como, codigo compartilhado de bibliotecas e a area que fica no kernel. No qemu/versatile crie uma system call que mostre que identifiue as areas de codigo, dados, pilhas de um processo rodando (ver mmstruct). Passe o pid do processo para a system call.

9.10 10 Linux/qemu

Aparentemente é facil gerar major page faults. Basta criar um programa que aloque muita memória (criando um grande vetor ou fazendo malloc) e depois escreva e leia em diversas posicoes. Na pratica, nao conseguimos criar nenhum programa que crie major page faults atraves de um simples programa (page faults que necessitam de escrever no disco). Procurei na internet e encontrei o seguinte:

  1. https://stackoverflow.com/questions/29850001/how-to-write-a-simple-page-fault-generator
  2. https://unix.stackexchange.com/questions/188170/generate-major-page-faults
  3. https://github.com/mrecachinas/Page-Faults

Eu pessoalmente testei os programas 1 e 2. Ambos nao geraram major fault (num ubuntu 14.4, 64 bits). Eles geraram o sinal SIGSEGV - segmentation fault. O terceiro caso rodava num mac. O programa 1 funciona para vetores pequenos, mas gera segmentation fault para vetores grandes. Teste no qemu/versatile:

  • o programa 1 rodando como init. Verifique que ele funciona para vetores pequenos.
  • para qual tamanho de vetor ele deixa de funcionar?

No meu ubuntu, o programa é morto porque recebe o sinal SIGSEGV. Em "man 7 signal": SIGSEGV 11 Core Invalid memory reference Observe o que acontece no qemu/versatile. Ao aumentar a memória podemos ter "Invalid memory reference" ou major fault. Num enderecamento invalido, a instrucao quer acessar uma posicao dentro do kernel. Num major page fault, o enderecamento eh valido, mas a instrucao (ou valor referenciado) estah no disco e nao na memoria. Num minor page fault, nao eh necessario acessar o disco. Em qualquer um dos casos, a MMU gera essa excessao (page fault ou referencia invalida). Coloque um breakpoint ao rodar o kernel, o mais perto possivel da excessao sendo gerada. Estude e explique o que o codigo faz. Experimente declarar um signal handler que captura o SIGSEGV. Se funcionar, entao todo acesso a uma posicao invalida poderah ser ignorada.

Author: jk

Created: 2017-07-10 Seg 17:16

Emacs 24.3.1 (Org mode 8.2.4)

Validate