Dierone Trab - DEINFO - Universidade Estadual de Ponta

Propaganda
UNIVERSIDADE ESTADUAL DE PONTA GROSSA
SETOR DE CIÊNCIAS AGRÁRIAS E DE TECNOLOGIA
DEPARTAMENTO DE INFORMÁTICA
JUAN CASSIUS CARNEIRO PEREIRA
PEDRO M. M. M. NETO
FUNÇÕES E MECANISMOS DE MANIPULAÇÃO DE PROCESSOS EM
LINUX
PONTA GROSSA
2016
JUAN CASSIUS CARNEIRO PEREIRA
PEDRO M. M. M. NETO
FUNÇÕES E MECANISMOS DE MANIPULAÇÃO DE PROCESSOS EM
LINUX
Trabalho apresentado para obtenção de
nota parcial na disciplina de Sistemas
Operacionais.
Prof. Dr. Dierone Foltran.
PONTA GROSSA
2016
SUMÁRIO
INTRODUÇÃO................................................................................................ 4
REVISÃO BIBLIOGRÁFICA ........................................................................... 5
1.1.
VISUALIZANDO UM PROCESSO .................................................... 6
1.1.1. Identificador do processo ............................................................ 6
1.1.2. Visualizando os processos ativos no Linux ................................. 6
1.1.3. Estado de execução de um processo ......................................... 6
1.2.
CRIANDO UM PROCESSO .............................................................. 8
1.2.1. Utilizando a chama system.......................................................... 8
1.2.2. Utilizando a função fork ............................................................... 8
1.2.3. Utilizando a função exec ............................................................. 8
1.3 ESCALONAMENTO DE PROCESSOS EM LINUX ............................ 10
1.4 SINAIS ................................................................................................ 11
1.5 FINALIZANDO UM PROCESSO NO LINUX ....................................... 12
1.5.1 Utilizando a chamada de sistema wait ......................................... 12
CONCLUSÃO ............................................................................................... 13
INTRODUÇÃO
Com a evolução e o desenvolvimento de novos sistemas operacionais e o
surgimento da multiprogramação, foi essencial a fundamentação do conceito de
processo pois é a base dos sistemas multiprogramados.
Os sistemas operacionais continuaram se desenvolvendo e acabaram se
dividindo em vários tipos. O Linux, que é um sistema multiprogramado, acabou
derivando da família BSD do UNIX.
Este trabalho tem como base a revisão bibliográfica de funções e manipulação
de processos nos sistemas operacionais do tipo Linux.
REVISÃO BIBLIOGRÁFICA
Segundo Oliveira; Carissim e Toscani (2004), o conceito de processo é
fundamental para qualquer sistema operacional multiprogramado, ele é definido como
uma instância de um programa em execução. Processos podem representar tanto
programa do usuário quanto tarefas do sistema operacional.
No Linux, quando o usuário visualiza um terminal aberto, este é um processo
em execução. O terminal pode estar rodando um shell, que é um novo processo.
Quando utilizada uma função do shell, o programa correspondente é executado em
um novo processo.
A maioria das funções de manipulação de processos que serão vistas neste
trabalho, são similares as usadas nos sistemas UNIX. A maioria é declarada no
arquivo header <unistd.h>.
1.1.
VISUALIZANDO UM PROCESSO
O sistema operacional sempre vai ter vários processos rodando,
independente de um usuário estar utilizando o computador ou não. Cada programa
que está sendo executado pode ter um ou mais processos.
1.1.1. Identificador do processo
Cada processo no Linux é identificado por um process ID único. Não existem
duas process IDs do processo com o mesmo valor, algumas vezes é referida como
pid. As process IDs dos processos são números de 16-bits que são atribuídos
sequencialmente pelo próprio Linux quando o processo é criado e é apagado quando
o processo é encerrado. Ao executar o mesmo programa após fechá-lo, o programa
terá um pid diferente do anterior.
Cada processo tem um processo pai, com exceção do init. Os processos no
Linux são organizados como uma árvore, sendo o init como a raiz dela. Cada processo
tem um identificador do processo pai, ou parent process ID, também conhecido como
ppid.
Quando for identificar um process ID em um programa em C ou C++, utilizase o tipo de dado pid_t, que está definido na biblioteca <sys/types.h>. Qualquer
programa pode obter o próprio process ID ou do pai que está sendo executado
utilizando as funções getpid e getppid respectivamente.
1.1.2. Visualizando os processos ativos no Linux
No Linux, para verificar os processos ativos no sistema, utiliza-se o comando
ps ou top no terminal.
O comando ps retorna ao usuário uma foto dos processos que estavam sendo
executados no momento que o comando foi utilizado. Para mostrar todos os
processos do sistema usando a sintaxe padrão, utiliza-se o comando ps -e. Para
mostrar quais informações o ps deve retornar, utiliza-se ps -o, podendo mostrar o pid
e o ppid de cada processo utilizando ps -o pid,ppid.
O comando top retorna ao usuário uma lista que se mantém atualizada de
todos os processos que estão sendo executados no Linux.
1.1.3. Estado de execução de um processo
Segundo de Oliveira; Carissim e Toscani (2004), durante sua fase de
execução, todo processo em Linux passa por diferentes estados.
O estado de task_running é quando o processo está em execução ou
esperando para ser executado.
O task_interruptible é o estado em que o processo está bloqueado, esperando
que determinada condição esteja satisfeita, como operação de entrada e saída ou a
interrupção de um software emitida por outro processo. Retorna ao task_running
quando satisfeito.
O task_uninterruptible é o estado que representa uma condição crítica e não
pode ser alterado até a conclusão. Normalmente ocorre com um evento relacionado
ao hardware.
O task_stoppped é o estado em que o processo recebe um sinal e só retorna
sua execução com outro sinal.
O task_zombie é o estado que um processo filho assume ao terminar sua
execução, enquanto o processo pai não utiliza uma chamada de sistema para o
retorno de sua execução.
1.2.
CRIANDO UM PROCESSO
Existem duas maneiras de se criar um processo no Linux, usando as funções
fork e exec ou utilizando o system. Ambas são chamadas do sistema, ou seja,
chamam o sistema operacional para fazer algo que o usuário não pode.
1.2.1. Utilizando a chama system
Uma das maneiras de se criar um processo é usando a chama de sistema
system. Essa função não é tão eficiente ou segura quanto as funções fork e exec, pois
ela funciona como se o usuário digitasse o comando em um shell, o Bourne shell
padrão (bin/sh), portanto ela está vulnerável a todas as falhas de um shell.
A função passa o comando para o shell executar, caso a função execute
comandos de root, ela terá diferentes resultados em diferentes distribuições do Linux.
Em vários sistemas UNIX, o caminho (bin/sh) é apenas uma conexão
simbólica com outro shell. No Linux, o shell usado é o bash(Bourne-Again Shell), mas
cada distribuição dele usa determinada versão do bash.
1.2.2. Utilizando a função fork
O fork é uma chama do sistema que cria uma cópia exata do programa que a
chamou, com as mesmas variáveis, registros. O programa que chamou a função fork
será o processo pai e o novo programa gerado através da função será o processo
filho.
A partir do momento em que a função fork é chamada e os dois processos
são criados, cada processo segue um rumo diferente do mesmo lugar. Para chamar
a função, não se passa nenhum argumento, o sistema operacional trabalha com o
resto e retorna um pid, caso ocorra um erro, a função retorna um número negativo.
O pid retornado é um número do tipo pid_t e tem um comportamento especial.
Dentro do processo filho, o pid tem valor 0. Dentro do processo pai, o pid tem o valor
do processo filho.
1.2.3. Utilizando a função exec
Exec é um grupo de funções que acabam fazendo o programa filho executar
como outro programa, substituindo a execução do programa anterior. Para se utilizar
a função exec necessitam só da biblioteca <unistd.h>. Existem vários tipos de funções
dentro da família do exec, com diferentes capacidades.
Funções que contém a letra ‘p’ nos nomes aceitam o nome do programa
e procura ele no diretório de execução atual. As que não contém, devem ter o caminho
completo até o programa executado.
As funções que contém a letra ‘v’ nos nomes, aceitam um vetor de
argumentos de string terminados em nulo. Já as terminadas em ‘l’, acabam recebem
argumento por argumento, sendo a principal diferença.
Funções que contém a letra ‘e’ nos nomes, aceitam um argumento
adicional, um vetor de strings que contém variáveis do ambiente, mas ainda deve ser
um vetor terminado em nulo.
O primeiro parâmetro da função, é o caminho que o arquivo deve ser
executado e a função só vai retornar caso ocorra um erro. Como o código que chama
a função acaba sendo destruído, não há sentido em chamá-la sem o uso da função
fork antes.
1.3 ESCALONAMENTO DE PROCESSOS EM LINUX
Em Linux, o escalonamento de processos pais e filhos são feitos de maneira
independente, fazendo com que não se saiba qual ira ser executado primeiro nem sua
duração até que o Linux interrompa o processo.
Existe uma maneira de priorizar processos em Linux, pode-se atribuir um nível
de importância usando o comando nice. O valor inicial de todo processo é 0, esse
valor pode ser alterado sendo que quanto maior, menor a prioridade que o sistema
dará ao processo, podendo também esse valor ser negativo. Uma aplicação desse
comando é quando se necessita executar um processo muito pesado e não desejase sobrecarregar o sistema.
Um processo pode sofrer reajuste de prioridade enquanto está sendo
executado, isso pode ser feito com o comando renice.
1.4 SINAIS
Segundo Mitchell; Samuel e Oldham (2001), sinais são um tipo de
comunicação assíncrona entre processos concorrentes. Assim que um processo
recebe um sinal ele o processa imediatamente.
Um processo pode executar uma de várias alternativas quando recebe um
sinal. Ele pode seguir a rotina padrão, usar tratamento de sinal ou simplesmente
ignorá-lo. Os sinais são identificados simbolicamente pelo prefixo SIG.
Um uso bem comum é o dos sinais SIGKILL e SIGTERM, os dois têm a
mesma função, encerrar o processo que o recebeu, somente diferem quanto ao
tratamento de sinais, que só pode ser feito pelo processo que recebe o sinal
SIGTERM.
Para tratar um sinal que chega ao processo usa-se a função signal() com dois
parâmetros, o primeiro é o nome do sinal, o segundo é o nome do tratador criado
dentro do programa que gerará o processo.
1.5 FINALIZANDO UM PROCESSO NO LINUX
Para finalizar um processo no Linux, basta usar o comando kill no
terminal, informando o sinal e o pid do processo.
O comando kill é usando para mandar um sinal a um processo. Se usado
sem nenhum sinal, ele irá mandar finalizar um processo. É possível ver a lista de sinais
usando o comando kill -l.
O comando killall é usado para matar todos os processos possíveis ou
com determinados nomes.
1.5.1 Utilizando a chamada de sistema wait
Como falado no tópico 1.1.3, alguns processos podem requerir a resposta do
final do processo filho, para isso utiliza-se a chamada wait. Ela trava o processo que
fez o requerimento até que um processo filho termine.
Se necessário a finalização de um filho específico, pode-se utilizar a chamada
waitpid. Existem também as chamadas de sistemas wait3 e wait4 que oferecem
opções a mais sobre o processo que irá morrer.
CONCLUSÃO
Processos são a base dos sistemas operacionais multiprogramados. Uma boa
fundamentação sobre seus conceitos e habilidade de manipulá-los são essenciais
para compreensão do funcionamento dos sistemas e contribuem para o
aprimoramento do usuário como desenvolvedor.
REFERÊNCIAS
MITCHELL, M.;SAMUEL, A.; OLDHAM, J. Advanced Linux Programming. 2001.
de OLIVEIRA, R. S.; CARISSIM, A. da S.; TOSCANI, S. S. Sistemas Operacionais.
2004.
Download