Sistemas Operacionais - AULA 3
 

Processos - Conceitos Básicos

Não é fácil localizar na história quando surgiu o conceito de processo. Creio eu, que no momento em que houve seperação entre um programa supervisor (ancestral do SO) e o job que executa a tarefa para o qual o computador foi comprado (computador não foi comprado para executar SO!), neste ponto podemos dizer que essa tarefa é uma espécie de ancestral do processo. O conceito moderno de processo está relacionado a um conjunto de instruções numa memória volátil e um estado de processo, aleḿ disso um processo detém memória bem definida, CPU (por alguns instantes), arquivos abertos, contexto, dentre outras características. Como já falamos anteriormente um processo é um programa em execução. Sendo um programa um ou mais arquivos contendo instruções para execução da tarefa.

Multiprogramação

As instruções que executam na CPU devem passar obrigatóriamente pela memória RAM, sendo assim, um processo para ser executado precisa está na RAM. Os primeiros sistemas operacionais eram monoprogramados, isso que dizer que em um dado momento somente um processo ocuparia a memória além do SO. Em um sistema multiprogramado, a memória poderá está ocupada por vários processos, cada um com o seu espaço de endereçamento. A idéia desta abordagem surgiu nos SOs da 3a geração, para resolver o problema de disperdício de tempo de CPU durante uma operação de E/S realizada por uma tarefa, isso ocorre principalmente porquê os dispositivos de E/S são mais lentos que a CPU. Em ambiente multiprogramado a CPU poderá ser chaveada rápidamente entre várias tarefas, desta forma, uma situação onde o programa espera por E/S, a CPU poderá ser entregue a outro processo evitando o disperdício de tempo de CPU.

Pseudo-Paralelismo

Em sala de aula a pergunta que normalmente faço é: O que é um sistema operacional multitarefa? A resposta mais comum é: "Um sistema que executa várias tarefas ao mesmo tempo". Pois bem, essa é de fato a sensação que os usuários experimentam, porém não bem assim que funciona.

Para possibilitar essa "experiência multitarefa", o que ocorre é que a CPU é compatilhada entre os processos que estão na memória aguardando CPU. Funciona da seguinte forma: É escolhido um tempo máximo, conhecido como quantum ou timeslice (fatias de tempo), em que a CPU será entregue a cada processo, por exemplo 20ms , desta forma, em único segundo a CPU, terá sido alocada para vários processos. no exemplo 50 vezes teoricamente. Desta forma, para o usuário parece que os vários processos executam juntos, mas o que houve foi um compatilhamento do tempo de CPU. Essa técnica é conhecida como timesharing e foi implementada a partir dos sistemas da 3a Geração. Para que isso funcione é necessário que exista apoio do hardware, neste caso um gerador de interrupções, conhecido como relógio. A cada intervalo de tempo a CPU terá o fluxo de execução desviado para o Sistema Operacional e neste ponto o SO assumirá o controle do sistema, até entregar novamente a CPU a outro processo.

Mudança de Contexto

Em um sistema de tempo compatilhado, quando um processo é interrompido por alguma razão (interrupção ou chamada de sistema), este deverá retornar a CPU no futuro próximo, quando o processo retornar ele deve continuar do ponto onde parou. Para que isso ocorra é importante que algumas informações sejam salvas antes que a CPU seja utilizada por qualquer outro software (SO ou processo). A essa informação é chamada de contexto do processo e é composta basicamente de registradores da CPU, como por exemplo o PC program counter, Os registradores acumuladores, o registrador de status, dentre outros (existem outras informações que não são registradores, mas essas serão tratadas em um momento oportuno).

Dito isso, podemos dizer que quando um processo deixa a CPU, antes de qualquer coisa o SO precisa realizar o Salvamento do Contexto e antes que o SO passe o controle da CPU para um processo, é preciso que seja restaurado o contexto do processo. A esse evento de saída de um processo da CPU e entrada de outro, chamamos de troca ou mudança de contexto.

Processo X Programa

Já abordamos isso anteriormente. Um processo tem características que são dinâmicas e que mudam ao longo do tempo. Dentre essas características podemos citar variáveis, estado, arquivos abertos, contexto. O programa é o código (instruções) que encontra-se eu uma memória não volátil diferentemente do processo que estará obrigatóriamente na RAM, quando em execução.

OBS.: Sabemos que um processo pode ocupar uma área em disco conhecida como área de troca. Porém é importante lembrar que essa área estende a memória RAM de certo forma, porém um processo para executar (ocupar a CPU) terá que ser movido desta área para a RAM.

Comportamento do Processo (I/O x CPU).

Conhecer o perfil de execução de um processo é importante no momento de escolher (escalonar) um processo que vai usar a CPU, o motivo de tal afirmação será mostrado na aula de escalonamento de processos. Existem 2 perfis de execução de processo. O perfil Orientado a CPU (CPU bound) usa extensivamente a CPU. Esses processos quando ocupam a CPU constumam usar toda a sua fatia de tempo. Por exemplo em calculos matemáticos complexos (fatorial de 80.000). Já no perfil Orientado a Entrada e Sáida (I/O bound) os processos quando ocupam a CPU usam uma pequena fração da sua fatia de tempo e logo acionam o SO para alguma tarefa.

Criação de Processos

Em linhas gerais o Sistema Operacional é o conjunto de aplicações que tornam possível o uso do computador. Para o nosso estudo estamos preocpuados especificamente com o Kernel do SO. O kernel será responsável por prover recursos para que as demais aplicações possam executar suas atividades. Aqui consideramos processos todas aquelas aplicações que NÃO rodam em modo supervisor do processador.

Inicialização do SO

Por mais rápido que seja o computador, existe sempre um tempo entre o momento que se pressiona o botão ligar e o instante em que o sistema estará pronto para uso. Boa parte deste tempo é usado pelo SO para preparar o sistema. Esse preparo consiste basicamente na inicialização de processos que são primordiais para o funcionamento do sistema. O termo usado para esses processos é Daemon (Serviço).

Atraves de um processo

Um processo poderá ser iniciado dentro de um outro processo, usando uma chamada de sistema. No windows a chamada de sistema CreateProcess() poderá ser usada para criar um processo. Nos sistemas POSIX (Linux, AIX, SUnOS, Opensolaris, HPUX, MacOs), A chamada de sistema usada para criar um processo é a fork(). Essa chamada não recebe nenhum parâmetro e o que ela faz é criar um processo filho que é identico ao processo que fez a chamada. Para subistituir esse processo filho por um novo processo é executada a chamada de sistema exec(). Essa técnica é o conhecida como fork-exec e á maneira como esses sistemas disparam novos processos.

Requisição de Usuário

Um usuário pode a qualquer momento solicitar a criação de um processo. Em um sistema operacional gráfico ele fára isso através de um clique de mouse. Já em uma interface de linha de comando (CLI) isso será feito digitando um comando.

Término de Processos

Podemos dizer que um processo foi finalizado quando este não estiver mais presente na tabela de processos. Isso implica que toda a memória alocada e todos os recursos alocados anteriormente para aquele processo agora estarão livres. Esta seção fala das diversas forma de um processo terminar.

Saida Programada Normal e Por Erro

Alguns aplicativos executam por um certo tempo até executar a tarefa e depois são terminados. Um exemplo de aplicação é o comando DIR do Windows. Esse termino é sempre codificado pelo programandor da aplicação. Outra forma de um processo sair é no caso de algum erro detectado pelo programador durante a execução do processo. Por exemplo num sistema onde o usuário entra algum valor inesperado e o programador devia o fluxo para uma instrução de saída. Nestes casos instrução passada pelo programador para o termino da aplicação se traduzirá sempre em uma chamada de sistema que deve ser usada para avisar o SO para tomar as providências para finalizar o processo em questão. No Windows essa chamada de sistema é o ExitProcess(). Nos Sistemas POSIX a chamada de sistema em questão é a exit().

Erro Fatal

O erro fatal ocorre quando o processo executa alguma operação ilegal (por exemplo divisão por zero). Quando ocorre esse tipo de situação é gerada uma interrupção a nível de hardware e o processo atual é interrompido e o controle da CPU volta ao sistema operacional. Nestes casos o comportamento padrão do SO é execluir o processo da lista dos processos em execução e liberar todos os recursos. Algumas liguagens de programação trabalham com o conceito de excessão para impedir que o processo seja terminado, nestes casos a instrução ilegal é capturada (possívelmente por um interpretador ou máquina virtual) antes de ser passada a CPU.

Cancelamento

O cancelamento de um processo é um evento externo ao processo (provocado pelo SO ou outro processo). Quando esse evento ocorre, o processo tem o seu fluxo normal de execução interrompido e é desviado para uma função que vai tratar da finalização do processo. Um exemplo desta situação ocorre quando você pressiona o [X] para fechar o Word. Nesta situação o Word é desviado para um rotina que, dentre outras coisas, vai questionar sobre o salvamento dos documentos não salvos. Em algum casos é possível interromper o processo abruptamente (sem o devido tratamento). Um exemplo deste tipo desta última situação ocorre quando você fecha uma janela que não está mais respodendo.

Hierarquia de Processos

A possibilidade de criar um processo a partir de outro, dá origem a uma ralação do tipo pai-filho entre os processos. Um processo quando criado recebe um identificador (Process ID ou PID) perante o Sistema Operacional. Nos sistemas operacionais que possuem (O Windows não possui) esse relacionamento os processos costumam guardar em seus atributos também o (Parent Process ID ou PPID) que é o PID do processo que o criou. Usando esse atributo dos processo é possível mapaear todos os processo do sistema na forma de uma arvore de processos. Essa relação existente entre os processos dá origem a chamada Hieraquia de Processos A listagem abaixo mostra a arvore de processos para um sistema GNU/Linux distribuição Debian (saida obtida pelo comando pstree -p).

init(1)-+-acpid(1823)
        |-atd(1888)
        |-cron(1908)
        |-dhclient3(1839)
        |-getty(1927)
        |-getty(1929)
        |-getty(1931)
        |-getty(1933)
        |-getty(1935)
        |-login(1925)---bash(1951)---pstree(1961)
        |-named(1863)-+-{named}(1864)
        |             |-{named}(1865)
        |             `-{named}(1866)
        |-portmap(1606)
        |-rpc.statd(1617)
        |-rsyslogd(1809)-+-{rsyslogd}(1811)
        |                `-{rsyslogd}(1812)
        `-udevd(864)

Estados de Processos (Ciclo de Vida dos Processos)

Durante a sua vida, um processo poderá está em um dos três estados a seguir:

Pronto (ready): O processo está pronto para ganhar a CPU, tudo o que ele precisa é ser escolhido, dentre os processos existentes, para ganhar a CPU e continuar processando. Por favor não confundir esse estado com finalizado.

Executando (running): Neste estado o processo estará ocupando a CPU. O número máximo de processos neste estado em um Sistema será igual a quantidade de CPUs disponíveis.

Bloqueado (blocked): Neste estado o processo estará aguardando algo necessário para continuar a sua execução. Em geral o processo solicitou algo ao SO através de uma chamada de sistema blocante.

O diagrama abaixo mostra a transição entre esses estados:

Transição 1: Ocorre quando um processo da fila de prontos é escolhido (escalonado) para ocupar a CPU.

Transição 2: Essa transição ocorre em consequência de uma interrupção de hardware. Um dispositivo requer atenção. Em SOs preemptivos o relógio de hardware gera uma interrupção para indicar que a fatia de tempo destinada ao processo acabou.

Transição 3: Ocorre quando o processo solicita algo ao sistema operacional. Por exemplo Entrada e Saída, Mais memória, etc.

Transição 4: Ocorre quando a solicitação do processo está atendida pelo SO. O processo irá ocupar um posição na fila de prontos.

OBS.: Observe que esta é uma sugestão do Tanenbaum e que é seguida por grande parte dos escritores sobre o tema. O fato é que os SOs da atualidade apresentam, muitas vezes com outra nomeclatura, em seu conjunto de estados, também esses estados sugeridos acima. Por exemplo o Windows apresenta além dos estados acima: Exit (marcado para ser removido da memória), New (Ainda não foi aceito) e Suspended (pausado). Maiores informações sobre estados no Windows por favor consultar aqui. Abaixo uma figura com os estados de processo do Windows tirada desta referência citada. Observe a semelhança do ciclo Ready-Running-Blocked, com o ciclo descrito anteriormente.

Para os estados dos processos no Linux pode-se consultar Aqui. Abaixo uma animação com os estados dos processo para o Linux retirado desta referência.

Leitura recomendada:

Gerencia de Processos - UFRN - Vicente Neto e Roberta Coelho

Interrupções (Prestação 1/3)

O termo interrupção aplica-se a um evento inesperado que provoca um desvio no fluxo de execução atual (o processo que está usando a CPU é interrompido e o fluxo é desviado para o sistema operacional, esse ponto de desvio faz parte do espaço de instruções do SO é conhecido como rotina de tratamento de interrupção ou interrupt handler). Em geral o recurso de interrupção está disponível em qualquer sistema computacional, essa é uma funcionalidade provida pelo hardware em questão.

A interrupção pode ocorrer tanto em nível de hardware (imprevisível) ou Software (Normalmente Previsível). A interrupção de Hardware ocorre por solicitação de algum dispositivo que necessita de atenção imediata, como por exemplo atualização da posição do ponteiro na tela provocada por uma movimentação do mouse. Ja interrupção de Software, é provocada pelo processo e ocorre quando um programa solicita algum serviço do sistema operacional. Anteriormente vimos que para um processo executar uma chamada de sistema é necessário a execução da instrução int 80h, essa instrução provoca o chavemento do controle para o SO. Esse tipo de interrupção é conhecida na literatura como interrupção de software e pelo fato de ser uma instrução dada pelo programador da aplicação, podemos dizer que esse tipo de interrupção é previsível.

Para garantir que o processo que foi interrompido, retorne ao ponto de onde parou, quando esse ocupar novamente a CPU, é necessário que o tratador de interrupção faça o salvamento do contexto do processo que foi interrompido. Abaixo uma lista com todos os procedimentos executados por um rotina de tratamento de interrupção (Tanenbaum):

Implementação de Processo - A fazer