A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

SVCs para Controle de Processos no Unix id, no retorno da chamada, contém, no processo pai, o identificador do processo filho criado; Para o processo filho.

Apresentações semelhantes


Apresentação em tema: "SVCs para Controle de Processos no Unix id, no retorno da chamada, contém, no processo pai, o identificador do processo filho criado; Para o processo filho."— Transcrição da apresentação:

1 SVCs para Controle de Processos no Unix id, no retorno da chamada, contém, no processo pai, o identificador do processo filho criado; Para o processo filho o valor da variável id será zero; Pode-se selecionar o trecho de código que será executado pelos processos com o comando if; Sistemas Operacionais

2 Sistemas Operacionais LPRM/DI/UFES 2 Criação de Processos (1) A maioria dos sistemas operacionais usa um mecanismo de spawn para criar um novo processo a partir de um outro executável.

3 Sistemas Operacionais LPRM/DI/UFES 3 Criação de Processos (2) Exemplo Não é exatamente assim no Unix!

4 Sistemas Operacionais LPRM/DI/UFES 4 Exemplo Grafo de Precedência Criação de Processos (3)

5 Sistemas Operacionais LPRM/DI/UFES 5 Exercício: Desenhar o grafo de precedência Criação de Processos (4)

6 Sistemas Operacionais LPRM/DI/UFES 6 Criação de Processos no UNIX No Unix, são usadas duas funções distintas relacionadas à criação e execução de programas. São elas: fork(): cria processo filho idêntico ao pai, exceto por alguns atributos e recursos. exec(): carrega e executa um novo programa A sincronização entre processo pai e filho(s) é feita através da SVC wait(), que bloqueia o processo pai até que um processo filho termine.

7 Sistemas Operacionais LPRM/DI/UFES 7 A SVC fork() (1) No Unix, a única forma de se criar um novo processo (dito processo filho) é através da invocação da chamada ao sistema fork(). Fork() duplica/clona o processo que executa a chamada. O processo filho é uma cópia fiel do pai, ficando com uma cópia do segmento de dados, heap e stack; no entanto, o segmento de texto (código) é muitas vezes partilhado por ambos. Processos pai e filho continuam a sua execução na instrução seguinte à chamada fork(). Em geral, não se sabe quem continua a executar imediatamente após uma chamada a fork() (se é o pai ou o filho). Depende do algoritmo de escalonamento.

8 Sistemas Operacionais LPRM/DI/UFES 8 A SVC fork() (2) O processo filho herda do pai alguns atributos, tais como: variáveis de ambiente, variáveis locais e globais, privilégios e prioridade de escalonamento. O processo filho tem seu próprio espaço de endereçamento, com cópia de todas as variáveis do processo pai. Essas são independentes em relação às variáveis do processo pai. O processo filho também herda alguns recursos, tais como arquivos abertos e devices. Alguns atributos e recursos, tais como PID, PPDI, sinais pendentes e estatísticas do processo, não são herdados pelo processo filho. A função fork() é invocada uma vez (no processo-pai) mas retorna duas vezes, uma no processo que a invocou e outra num novo processo agora criado, o processo-filho. O retorno da função fork(), no processo pai, é igual ao número do pid do processo filho recém criado (todos os processos em Unix têm um identificador, geralmente designado por pid – process identifier). O retorno da função fork() é igual a 0 (zero) no processo filho.

9 Sistemas Operacionais LPRM/DI/UFES 9 A SVC fork() (3)

10 Sistemas Operacionais LPRM/DI/UFES 10 A SVC fork() (4)

11 Sistemas Operacionais LPRM/DI/UFES 11 Copy-on-Write Como alternativa a significante ineficiência do fork(), no Linux o fork() é implementado usando uma técnica chamada copy-on-write (COW). Essa técnica atrasa ou evita a cópia dos dados. Ao invés de copiar o espaço de endereçamento do processo pai, ambos podem compartilhar uma única cópia somente de leitura. Se uma escrita é feita, uma duplicação é realizada e cada processo recebe uma cópia. Conseqüentemente, a duplicação é feita apenas quando necessário, economizando tempo e espaço. O único overhead inicial do fork() é a duplicação da tabela de páginas do processo pai e a criação de um novo proc Struct (c/ PID para o filho).

12 Sistemas Operacionais LPRM/DI/UFES 12 SVCs para Identificação do Processo no UNIX Como visto, todos os processos em Unix têm um identificador, geralmente designados por pid (process identifier). Os identificadores são números inteiros diferentes para cada processo (ou melhor, do tipo pid_t definido em sys/types.h ). É sempre possível a um processo conhecer o seu próprio identificador e o do seu pai. Os serviços a utilizar para conhecer pids (além do serviço fork() ) são:

13 Sistemas Operacionais LPRM/DI/UFES 13 User ID e Group ID No Unix, cada processo tem de um proprietário, um usuário que seja considerado seu dono. Através das permissões fornecidas pelo dono, o sistema sabe quem pode e não pode executar o processo em questão. Para lidar com os donos, o Unix usa os números UID (User Identifier) e GID (Group Identifier). Os nomes dos usuários e dos grupos servem apenas para facilitar o uso humano do computador. Cada usuário precisa pertencer a um ou mais grupos. Como cada processo (e cada arquivo) pertence a um usuário, logo esse processo pertence ao grupo de seu proprietário. Assim sendo, cada processo está associado a um UID e a um GID. Os números UID e GID variam de 0 a Dependendo do sistema, o valor limite pode ser maior. No caso do usuário root, esses valores são sempre 0 (zero). Assim, para fazer com que um usuário tenha os mesmos privilégios que o root, é necessário que seu GID seja 0. Primitivas: uid_t getuid(void) / uid_t geteuid(void) gid_t getgid(void) / gid_t getegid(void)

14 Sistemas Operacionais LPRM/DI/UFES 14 Exemplo 1: #include int main (void) { printf("I am process %ld\n", (long)getpid()); printf("My parent is %ld\n", (long)getppid()); printf("My real user ID is %5ld\n", (long)getuid()); printf("My effective user ID is %5ld\n", (long)geteuid()); printf("My real group ID is %5ld\n", (long)getgid()); printf("My effective group ID is %5ld\n", (long)getegid()); return 0; }

15 Sistemas Operacionais LPRM/DI/UFES 15 Exemplo 2: simplefork.c #include int main(void) { int x; x = 0; fork(); x = 1; printf("I am process %ld and my x is %d\n", (long)getpid(), x); return 0; }

16 Sistemas Operacionais LPRM/DI/UFES 16 Comando ps COLUNAS (maiores informações: % man ps) S : estado do processo. C: utilização da CPU. Uso muito baixo é reportado como zero. PRI: prioridade do processo. NI: valor do nice. WCHAN: endereço da rotina de kernel onde o processo dorme. Processos em execução são marcados com hífen (-).

17 Sistemas Operacionais LPRM/DI/UFES 17 Estrutura Geral do fork() pid=fork(); if(pid < 0) { /* falha do fork */ } else if (pid > 0) { /* código do pai */ } else { //pid == 0 /* código do filho */ }

18 Sistemas Operacionais LPRM/DI/UFES 18 Exemplo 3: twoprocs.c #include int main(void) { pid_t childpid; childpid = fork(); if (childpid == -1) { //error perror("Failed to fork"); return 1; } if (childpid == 0) /* child code */ printf("I am child %ld\n", (long)getpid()); else /* parent code */ printf("I am parent %ld\n", (long)getpid()); return 0; }

19 Sistemas Operacionais LPRM/DI/UFES 19 Exercício 1: Montar o Grafo de Precedência c2 = 0; c1 = fork(); /* fork number 1 */ if (c1 == 0) c2 = fork(); /* fork number 2 */ fork();/* fork number 3 */ if (c2 > 0) fork(); /* fork number 4 */ exit();

20 Sistemas Operacionais LPRM/DI/UFES 20 Exemplo 5: simplechain.c #include int main (int argc, char *argv[]) { pid_t childpid = 0; int i, n; if (argc != 2){ /* check for valid number of command-line arguments */ fprintf(stderr, "Usage: %s processes\n", argv[0]); return 1; } n = atoi(argv[1]); for (i = 1; i < n; i++) if (childpid = fork()) //only the parent enters break; fprintf(stderr, "i:%d process ID:%ld parent ID:%ld child ID:%ld\n", i, (long)getpid(), (long)getppid(), (long)childpid); return 0; }

21 Sistemas Operacionais LPRM/DI/UFES 21 Exemplo 6: simplefan.c #include int main (int argc, char *argv[]) { pid_t childpid = 0; int i, n; /* check for valid number of command-line arguments */... n = atoi(argv[1]); for (i = 1; i < n; i++) if ((childpid = fork()) <= 0) //only the child (or error) enters break; fprintf(stderr, "i:%d process ID:%ld parent ID:%ld child ID:%ld\n", i, (long)getpid(), (long)getppid(), (long)childpid); return 0; } 4 123

22 Sistemas Operacionais LPRM/DI/UFES 22 Exercício 2 Explique o que acontece quando se altera a linha abaixo no programa simplefan.c (childpid = fork()) <= 0 para (childpid = fork()) == -1

23 Sistemas Operacionais LPRM/DI/UFES 23 Término de Processos no Unix Um processo pode terminar normalmente ou anormalmente nas seguintes condições: Normal: Executa return na função main(), o que é equivalente à chamar exit() ; Invoca diretamente a função exit() da biblioteca C; Invoca diretamente o serviço do sistema _exit(). Anormal: Invoca o função abort() ; Recebe sinais de terminação gerados pelo próprio processo, ou por outro processo, ou ainda pelo Sistema Operacional. A função abort() Destina-se a terminar o processo em condições de erro e pertence à biblioteca padrão do C. Em Unix, a função abort() envia ao próprio processo o sinal SIGABRT, que tem como conseqüência terminar o processo. Esta terminação deve tentar fechar todos os arquivos abertos.

24 Sistemas Operacionais LPRM/DI/UFES 24 A Chamada exit() void exit(code) O argumento code é um número de 0 a 255, escolhido pela aplicação e que será passado para o processo pai na variável status. A chamada exit() termina o processo; portanto, exit() nunca retorna Chama todos os exit handlers que foram registrados na função atexit(). A memória alocada ao segmento físico de dados é liberada. Todos os arquivos abertos são fechados. É enviado um sinal para o pai do processo. Se este estiver bloqueado esperando o filho, ele é acordado. Se o processo que invocou o exit() tiver filhos, esses serão adotados pelo processo init. Faz o escalonador ser invocado.

25 Sistemas Operacionais LPRM/DI/UFES 25 Processo Zombie O que acontece se o processo filho termina antes do pai? No Unix, o processo pai sempre tem que saber o status do término do processo filho. Por isso, sempre que um processo termina, o kernel guarda algumas informações sobre ele, de modo que essas informações estejam disponíveis para o processo pai quando ele executar wait ou waitpid. Na terminologia do Unix, um processo que já terminou (já está morto) mas cujo pai ainda não executou o comando wait ou waitpid é dito um processo zombie. O que acontece se o processo pai termina antes do filho? O processo init (PID 1) torna-se pai de todo e qualquer processo cujo pai termina antes do filho (isto é, processos órfão é adotado pelo processo init). Sempre que um filho do init termina, ele chama wait/waitpid.

26 Sistemas Operacionais LPRM/DI/UFES 26 A SVC wait() do Unix (1) Como processos descobrem se seu filho terminou? Chamada wait() feita pelo pai – retorna o PID do processo filho que terminou execução Normalmente, pai executando wait() é bloqueado até filho terminar Se não existir filhos no estado zombie, esperar que um filho termine waitpid() Para esperar um filho específico Também pode esperar por qualquer filho waitpid(-1,...,...) ~ wait(...) #include pid_t wait(int *stat_loc); pid_t waitpid(pid_t pid, int *stat_loc, int options);

27 Sistemas Operacionais LPRM/DI/UFES 27 A SVC wait() do Unix (2) Em caso de erro retorna -1 Seta a variável global errno ECHILD: não existem filhos para termitar (wait), ou pid não existe (waitpid) EINTR: função foi interrompida por um sinal EINVAL: o parâmetro options do waitpid estava inválido Solução para que um processo pai continue esperando pelo término de um processo filho, mesmo que o pai seja interrompido por um sinal:

28 Sistemas Operacionais LPRM/DI/UFES 28 A SVC wait() do Unix (3) A opção WNOHANG na chamada waitpid permite que um processo pai verifique se um filho terminou, sem que este primeiro bloqueie caso filho ñ tenha terminado Neste caso waitpid retorna 0 pid_t child pid; while (childpid = waitpid(-1, NULL, WNOHANG)) if ((childpid == -1) && (errno != EINTR)) break;

29 Sistemas Operacionais LPRM/DI/UFES 29 Exemplo 7: fanwait.c #include #include "restart.h" int main(int argc, char *argv[]) { pid_t childpid; int i, n;... for (i = 1; i < n; i++) if ((childpid = fork()) <= 0) break; while(r_wait(NULL) > 0) ; /* wait for all of your children */ fprintf(stderr, "i:%d proc.ID:%ld parentID:%ld child ID:%ld\n", i, (long)getpid(), (long)getppid(), (long)childpid); return 0; }

30 Sistemas Operacionais LPRM/DI/UFES 30 Exercício 3 Referente ao programa fanwait.c Explique o que acontece quando coloca o printf antes do while ? Explique o que acontece se substituirmos a chamada r_wait por wait(NULL) simplesmente ?

31 Sistemas Operacionais LPRM/DI/UFES 31 Valores de stat_loc (1) O argumento stat_loc: ponteiro p/a uma variável inteira Um filho sempre retorna seu status ao chamar exit ou ao retornar do main 0: indica EXIT_SUCCESS outro valor: indica EXIT_FAILURE WIFEXITED(status) – permite determinar se o processo filho terminou normalmente WEXITSTATUS(status) – retorna o código de saída do processo filho WIFSIGNALED(status) – permite determinar se o processo filho terminou devido a um sinal WTERMSIG(status) – permite obter o número do sinal que provocou a finalização do processo filho WIFSTOPPED(status) – permite determinar se o processo filho que provocou o retorno se encontra congelado (stopped) WSTOPSIG(status) – permite obter o número do sinal que provocou o congelamento do processo filho MACROS

32 Sistemas Operacionais LPRM/DI/UFES 32 Valores de stat_loc (2) Exemplo

33 Sistemas Operacionais LPRM/DI/UFES 33 A SVC exec() do Unix (1) Quando um processo invoca uma das funções exec, ele é completamente substituído por um novo programa Substitui o processo corrente (os seus segmentos text, data, heap e stack) por um novo programa carregado do disco O novo programa começa a sua execução a partir da função main() O identificador do processo não é alterado De fato, nenhum novo processo é criado Valor de retorno Sucesso - não retorna Erro - retorna o valor -1 e seta a variável errno com o código específico do erro Quando um processo executando um programa A quer executar outro programa B: Primeiramente ele deve criar um novo processo usando fork() Em seguida, o processo recém criado deve substituir todo o seu programa pelo programa B, chamando uma das primitivas da família exec

34 Sistemas Operacionais LPRM/DI/UFES 34 A SVC exec() do Unix (1)

35 Sistemas Operacionais LPRM/DI/UFES 35 Exemplo de Uso: fork() – exec() #incude main( int argc, char *argv[] ) { int pid; /* fork a child process */ pid = fork(); /* check fork() return code */ if ( pid < 0 ) { /* some error occurred */ fprintf( stderr, Fork failed!\n ); exit( -1 ); } else if ( pid == 0 ) { /* this is the child process */ execl( /bin/ls, ls, NULL ); /* morph into ls */ } else { /* this is the parent process. Wait for child to complete */ wait( NULL ); printf( Child completed -- parent now exiting.\n ); exit( 0 ); }

36 Sistemas Operacionais LPRM/DI/UFES 36 O processo que executou a função exec mantém as seguintes informações pid e o ppid user, group, session id Mascara de sinais Alarmes Terminal de controle Diretórios raiz e corrente Informações sobre arquivos abertos Limites de uso de recursos Estatísticas e informações de accounting A SVC exec() do Unix (2)

37 Sistemas Operacionais LPRM/DI/UFES 37 Funções exec (1) int execl(const char *pathname, const char *arg0,...) int execv(const char *pathname, char *const argv[]) int execlp(const char *filename, const char *arg0,...) int execvp(const char *filename, char *const argv[]) int execle(const char *pathname, const char *arg0,..., char *const envp[]) int execve(const char *pathname, char *const argv[], char *const envp[])

38 Sistemas Operacionais LPRM/DI/UFES 38 Funções exec (2) Sufixos l lista de argumentos (terminada com NULL) v argumentos num array de strings (terminado com NULL) e variáveis de ambiente num array de strings (terminado com NULL) p procura executável nos diretórios definidos na variável de ambiente PATH (echo $PATH)

39 Sistemas Operacionais LPRM/DI/UFES 39 Funções exec (3) Relações entre as funções exec

40 Sistemas Operacionais LPRM/DI/UFES 40 Funções exec (4) Se alguma das funções retorna, um erro terá ocorrido Valores possíveis na variável global errno E2BIG Lista de argumentos muito longa EACCES Acesso negado EINVAL Sistema não pode executar o arquivo ENAMETOOLONG Nome de arquivo muito longo ENOENT Arquivo ou diretório não encontrado ENOEXEC Erro no formato de exec ENOTDIR Não é um diretório

41 Sistemas Operacionais LPRM/DI/UFES 41 Funções exec (4) Executar os seguintes comandos ls -l /etc ls -l /etc/s*.conf

42 Sistemas Operacionais LPRM/DI/UFES 42 Funções exec (5) Um programa que cria um processo filho para executar ls -l

43 Sistemas Operacionais LPRM/DI/UFES 43 Funções exec (5) Um programa que cria um processo filho para executar um comando (com ou sem parâmetros) passado como parâmetro... execcmd.c

44 Sistemas Operacionais LPRM/DI/UFES 44 O shell do UNIX (1) Quando o interpretador de comandos UNIX interpreta comandos, ele chama fork e execl... Lê comando para o interpretador de comandos... If (fork()==0) exec...(command, lista_arg...)

45 Sistemas Operacionais LPRM/DI/UFES 45 O shell do UNIX (2) exec

46 Sistemas Operacionais LPRM/DI/UFES 46 O shell do UNIX (3)

47 Sistemas Operacionais LPRM/DI/UFES 47 Processos background e foreground (1) Existem vários tipos de processos no Linux: processos interativos, processos em lote (batch) e Daemons. Processos interativos são iniciados a partir de uma sessão de terminal e por ele controlados. Quando executamos um comando do shell, entrando simplesmente o nome do programa seguido de, estamos rodando um processo em foreground. Um programa em foreground recebe diretamente sua entrada (stdin) do terminal que o controla e, por outro lado, toda a sua saida (stdout e stderr) vai para esse mesmo terminal. Digitando Ctrl-Z, suspendemos esse processo, e recebemos do shell a mensagem Stopped (talvez com mais alguns caracteres dizendo o número do job e a linha de comando). A maioria dos shells tem comandos para controle de jobs, para mudar o estado de um processo parado para background, listar os processos em background, retornar um processo de back para foreground, de modo que o possamos controlar novamente com o terminal. No bash o comando jobs mostra os jobs correntes, o bg restarta um processo suspenso em background e o comando fg o restarta em foreground. Daemons ou processos servidores, mais freqüentemente são iniciados na partida do sistema, rodando continuamente em background enquanto o sistema está no ar, e esperando até que algum outro processo solicite o seu serviço (ex: sendmail).

48 Sistemas Operacionais LPRM/DI/UFES 48 Processos de background e foreground (2) O Comando Jobs Serve para visualizar os processos que estão parados ou executando em segundo plano (background). Quando um processo está nessa condição, significa que a sua execução é feita pelo kernel sem que esteja vinculada a um terminal. Em outras palavras, um processo em segundo plano é aquele que é executado enquanto o usuário faz outra coisa no sistema. Para executar um processo em background usa-se o & (ex: ls –l &). Assim, uma dica para saber se o processo está em background é verificar a existência do caractere & no final da linha. Se o processo estiver parado, geralmente a palavra "stopped" aparece na linha, do contrário, a palavra "running" é exibida. Os comandos fg e bg O fg é um comando que permite a um processo em segundo plano (ou parado) passar para o primeiro plano (foreground), enquanto que o bg passa um processo do primeiro para o segundo plano. Para usar o bg, deve-se paralisar o processo. Isso pode ser feito pressionando-se as teclas Ctrl + Z. Em seguida, digita-se o comando da seguinte forma: bg +número O número mencionado corresponde ao valor de ordem informado no início da linha quando o comando jobs é usado. Quanto ao comando fg, a sintaxe é a mesma : fg +número

49 Sistemas Operacionais LPRM/DI/UFES 49 Sessões e grupos de processos (1) No Unix, além de ter um PID, todo processo também pertence a um grupo. Um process group é é uma coleção de um ou mais processos. Todos os processos dentro de um grupo são tratados como uma única entidade. A função getpgrp() retorna o número do grupo do processo chamador. Cada grupo pode ter um processo líder, que é identificado por ter o seu PID igual ao seu GoupID. É possível ao líder criar novos grupos, criar processos nos grupos e então terminar (o grupo ainda existirá mesmo se o líder terminar; para isso tem que existir pelo menos um processo no grupo - process group lifetime). Uma sessão é um conjunto de grupos de processos. Grupos ou sessões são também herdadas pelos filhos de um processo. Um servidor, por outro lado, deve operar independentemente de outros processos. Como fazer então que um processo servidor atenda a todos os grupos e sessões? A primitiva setsid() obtém um novo grupo para o processo. Ela coloca o processo em um novo grupo e sessão, tornando-o independente do seu terminal de controle ( setpgrp ié uma alternativa para isso). É usada para passar um processo de foreground em background.

50 Sistemas Operacionais LPRM/DI/UFES 50 Sessões e grupos de processos (1) Uma sessão é um conjunto de grupos de processos Cada sessão pode ter um único terminal controlador no máximo 1 grupo de processos de foregroud n grupos de processos de background

51 Sistemas Operacionais LPRM/DI/UFES 51 Colocando um processo em background Uso de setsid para que o processo pertença a uma outra sessão, e a um outro grupo, se tornando de background

52 Sistemas Operacionais LPRM/DI/UFES 52 Resumo SVCs: Processos fork: cria um novo processo que é uma cópia do processo pai. O processo criador e o processo filho continuam em paralelo, e executam a instrução seguinte à chamada de sistema. wait: suspende a execução do processo corrente até que um filho termine. Se um filho terminou antes desta chamada de sistema(estado zombie), os recursos do filho são liberados e o processo não fica bloqueado, retornando imediatamente. exit: termina o processo corrente. Os filhos, se existirem, são herdados pelo processo init e o processo pai é sinalizado. exec: executa um programa, substituindo a imagem do processo corrente pela imagem de um novo processo, identificado pelo nome de um arquivo executável, passado como argumento. kill: usada para enviar um sinal para um processo ou grupo de processos. O sinal pode indicar a morte do processo. sleep: suspende o processo pelo tempo especificado como argumento.

53 Referências Kay A. Robbins, Steven Robbins, UNIX Systems Programming: Communication, Concurrency and Threads, 2 nd Edition Capítulo 3 Sistemas Operacionais LPRM/DI/UFES 53


Carregar ppt "SVCs para Controle de Processos no Unix id, no retorno da chamada, contém, no processo pai, o identificador do processo filho criado; Para o processo filho."

Apresentações semelhantes


Anúncios Google