HTTPS SSH

PyDispatcher Shell

Um simples gerenciador de processos escrito na linguagem Python.

Descrição

Este código é a resolução do trabalho de Sistemas Operacionais, matéria que ministrei quando fazia estágio docência em 2011. Esse código pretende ser didático e serve para exemplificar a utilização de diversos recursos relacionados com o conteúdo ministrado na matéria, tais como comunicação de processos, filas de prioridade, etc.

Build

Como o código do gerente de processos, escrito em Python, atua sobre processos reais, é necessário um programa definido como processo a ser gerenciado. No caso, o arquivo proc.cpp. Simplesmente compile esse programa

g++ proc.cpp proc

Utilização

Para testar o gerente de processo de acordo com diferentes contextos, basta todar o arquivo Main.py, passando a lista de processos a serem inicializados. Por exemplo, para executar o arquivo fcfs.txt (First Come First Served), execute

python Main.py test/fcfs.txt

Descrição do Trabalho Proposto

Despachador e Gerente de Processos

Neste trabalho você tem como objetivo desenvolver um sistema multiprogramado que agrupe os processos em quatro níveis de prioridades, escalonando-os e administrando os recursos disponíveis.

Estrutura das Filas

O programa deve ter duas filas de prioridades distintas: a fila de processos de tempo real e a fila de processos de usuários.

Processos de tempo real entram para a fila de maior prioridade, sendo gerenciados pela política FCFS (First Come First Served sem preempção).

Processos de usuário devem utilizar múltiplas filas de prioridades com realimentação. Para isto, deve-se manter três filas com prioridades distintas. Para evitar starvation, o sistema operacional deve modificar a prioridade dos processos executados mais frequentemente ou/e utilizar uma técnica de envelhecimento (aging). Processos de usuário podem ser preemptados e o quantum deve ser definido de 1 segundo.

As filas devem suportar no máaximo 1000 jobs. Portanto, recomenda-se utilizar uma fila “global”, que permita avaliar os recursos disponiveis antes da execução ao e que facilite classificar o tipo de processo.

Estrutura de Memória

A alocação de memória deve ser implementada como um conjunto de blocos contíguos, onde cada bloco equivale a uma palavra da memoria real.

Cada processo deve alocar um segmento contiguo de memória, que permanecerão alocados durante toda execução. Deve-se notar que não é necessário a implementaçãoo de memória virtual, swap, nem sistema de paginação. Portanto, não é necessário gerenciar a memória, apenas verificar a disponibilidade de recursos antes de iniciar um processo.

Utilize um tamanho fixo de memória de 1024 blocos. Desta quantidade, 64 blocos devem ser reservados para jobs de tempo real e os 960 blocos restantes são compartilhados entre os jobs de usuário.

Recursos Disponíveis

O SO deve, além de escalonar o processo no compartilhamento da CPU, gerenciar os seguintes recursos

  • 1 scanner
  • 2 impressoras
  • 1 modem
  • 2 dispositivos SATA

Modulos do Programa

Espera-se que o programa seja dividido em pelo menos quatro grandes módulos: processos, memória, filas e recursos. Submódulos ou pacotes são obviamente permitidos, desde que facilite a organização e busca de informações no código fonte.

  • Modulo de Processos: Classes e estruturas de dados relativas ao processo. Basicamente, mantem informações específicas do processo.

  • Modulo de Filas: Mantém as interfaces e funções que operam sobre os processos.

  • Módulo de Memória: Provê uma interface de abstração de memória RAM.

  • Modulo de Recursos: Trata a alocação e liberação dos recursos de E/S para os processos.

Entrada do Programa

O programa deve ler um arquivo contendo as informações dos processos. Neste arquivo, cada linha contem as informações de um processo. Portanto, um arquivo com 2 linhas disparará 2 processos, outro arquivo com 5 linhas fará com que o programa dispare 5 processos e assim por diante. Cada processo -- portanto, cada linha –- deve conter os seguintes dados:

  • tempo de inicializacao
  • prioridade
  • tempo de processador
  • blocos em memória
  • código da impressora requisitada
  • requisição do scanner
  • requisição do modem
  • código do(s) disco(s) utilizados

Obs: verifique os arquivos de exemplo na pasta test.

Saida do Programa

O processo principal é o “despachante”. Este é o primeiro processo criado na execuçãoo do programa e deve ser o responsável pela criação de qualquer processo. Na criação do processo, o despachante deve exibir uma mensagem de identificação contendo as seguintes informações:

  • PID (int);
  • Prioridade do processo (int);
  • Offset da memória (int);
  • Quantidade de blocos alocados (int);
  • Utilização de Impressora (bool);
  • Utilização do Scanner (bool);
  • Utilização de Drivers (bool).

O processo pode exibir alguma mensagem que indique sua execução. Contudo, isso não é obrigatório.

Exemplo de Execução

Por exemplo, um arquivo processes.txt que contém dois processos:

2, 0, 3, 64, 0, 0, 0, 0
8, 0, 2, 64, 0, 0, 0, 0

Deve mostrar algo como

dispatcher =>
    PID: 1
    offset: 0
    blocks: 64
    priority: 0
    time: 3
    printers: 0
    scanners: 0
    modems: 0
    drives: 0
process 1 =>
    P1 STARTED
    P1 instruction 1
    P1 instruction 2
    P1 instruction 3
    P1 return SIGINT
dispatcher =>
    PID: 2
    offset: 65
    blocks: 64
    priority: 0
    time: 2
    printers: 0
    scanners: 0
    modems: 0
    drives: 0
process 2 =>
    P2 STARTED
    P2 instruction 1
    P2 instruction 2
    P2 return SIGINT

onde dispatcher => indica o momento em que o processo despachante (SO) leu as informações do processo a ser executado, imprimiu e que cedeu tempo de CPU para os outros processos. P1 e P2 são processos que executam, exibindo as informações do que cada um está fazendo.

Referências

  1. Stallings, W. 2009, Operating Systems Internals and Design Principles, Pearson Education, New Jersey.

  2. Martin, R.C. 2008. Clean Code. A Handbook of Agile Software Craftsmanship, Prentice Hall, New York.