PythonBrasil

quinta-feira, junho 19, 2008

Explorando Sistemas Operacionais com Python - Processos

Um processo é a entidade básica ativa na maioria dos sistemas operacionais modernos.

Quando um usuário e criado no Unix/Linux, ele recebe um ID de usuário e um ID de grupo. O sistema utiliza os IDs de usuário e de grupo para buscar as permissões atribuídas a este usuário. O usuário mais privilegiado é o administrador de sistema, que tem o ID 0.

Um processo tem vários IDs de usuário e grupo que resultam em privilégios ao processo. Estes incluem o ID real de usuário, o ID real de grupo, o ID efetivo de usuário e o ID efetivo de grupo. Usualmente, os IDs real e efetivo são os mesmos, mas sob certas circunstâncias o processo pode mudá-los. O processo utiliza os IDs efetivos para determinar permissões de acesso a arquivos. Por exemplo, um programa que roda com privilégios de root pode querer criar um arquivo em nome de um usuário comum. Definindo o ID efetivo de usuário do processo como o do usuário, o processo pode criar arquivos "como se" o usuário os tivesse criado. Na maior parte, assumimos que os IDs real e efetivo de usuário e grupo são os mesmos.

As seguintes funções retornam os IDs de usuário e grupo para um processo. Os gid_t e uid_t são tipos inteiros representando os IDs de grupo e usuário, respectivamente. As funções getgid e getuid retornam os IDs reais, e as funções getegid e geteuid retornam os IDs efetivos.


import
os
uid_t = os.getuid()
euid_t = os.geteuid()
gid_t = os.getgid()
egid_t = os.getegid()



Um processo pode criar outro processo chamando fork. O processo chamador se torna o pai e o processo criado é chamado filho.

A função fork copia a imagem da memória do pai de modo que o novo processo recebe uma cópia do espaço de endereçamento do pai. Ambos os processos continuam sua execução na instrução seguinte à declaração fork (executando em suas imagens de memória respectivas).


import
os
pid_t = os.fork()


A criação de dois processos completamente idênticos não seria muito útil. O valor de retorno da função fork é a característica crítica que permite que pai e filho distinguam-se para executar código diferente. A função fork retorna 0 para o filho e retorna o ID do processo filho para o pai. Quando fork falha, ela retorna -1 e define errno. Se o sistema não tem os recursos necessários para criar o filho ou se os limites sobre o número de processos forem excedidos, fork define errno como EAGAIN. No caso de uma falha, fork não cria o filho.

No exemplo a seguir, após o fork, pai e filho imprimem seus respectivos ID's de processo.


import os,sys

childpid = os.fork()

if childpid == -1:
print 'erro no fork'
sys.exit()
if childpid == 0:
print 'Eu sou o processo filho %ld' % (os.getpid())
else:
print 'Eu sou o processo pai %ld' % (os.getpid())



O programa a seguir cria uma cadeia de n processos chamando fork em um loop. Em cada iteração do loop, o processo pai tem um childpid não zero e interrompe o loop. O processo filho tem um valor zero de childpid e se torna um pai na próxima iteração do loop. No caso de um erro, fork retorna -1 e o processo chamador sai do loop.


import os,sys

if len(sys.argv) != 2:
print >>sys.stderr,"Uso: %s processos\n" % (sys.argv[0])
sys.exit(1)

n = int(sys.argv[1])
i = 1
while i<n:
childpid = os.fork()
if childpid > 0:
break
i+=1

print >>sys.stderr,"i:%d ID do processo: %ld, ID do pai: %ld, \
ID do filho %ld\n" % (i, os.getpid(), os.getppid(), childpid)
sys.exit(0)


Por padrão, o sistema buferiza a saída escrita em stdout, de modo que uma mensagem particular pode não aparecer imediatamente após o retorno de print. Mensagens para stderr não são buferizadas, mas, ao contrário, são imediatamente escritas. Por esta razão, você deve sempre utilizar stderr para as mensagens de depuração.

O programa a seguir cria um ventilador de processos chamando fork em um loop. Em cada iteração, o processo recém criado sai do loop enquanto o processo original continua. Isto é o inverso do que acontece no programa acima.


import os,sys

if len(sys.argv) != 2:
print >>sys.stderr,"Uso: %s processos\n" % (sys.argv[0])
sys.exit(1)

n = int(sys.argv[1])
i = 1
while i<n:
childpid = os.fork()
if childpid <= 0:
break
i += 1

print >>sys.stderr,'i:%d ID do processo %ld, ID do pai %ld, \
ID do filho %ld\n' % (i, os.getpid(), os.getppid(), childpid)
sys.exit(0)


Estes scripts são baseados no livro Unix Systems Programming, de Robbins e Robbins, da Prentice Hall. Por serem scripts pequenos, os códigos são facilmente digitados. Quando houver algum script longo, o código fonte será disponibilizado também.

Continuarei com mais programas para explorar o Sistema Operacional.

Nenhum comentário: