"Espaço de usuário" refere-se ao ambiente de execução de processos normais (em oposição aos do núcleo). Isso não significa necessariamente que esses processos foram realmente iniciados por usuários, pois um sistema padrão normalmente tem vários processos "daemon" (serviços) (ou em segundo plano) em execução antes mesmo do usuário abrir uma sessão. Processos daemon também são considerados processos no espaço do usuário.
Quando o núcleo passa por sua fase de inicialização, ele inicia o primeiro de todos os processos, o init
. O processo #1 sozinho, raramente é útil por si só, e em sistemas similares ao Unix rodam com muitos processos adicionais.
Em primeiro lugar, um processo pode se clonar (isto é conhecido como fork). O núcleo aloca um novo (mas idêntico) espaço de memória do processo, e um outro processo para usá-lo. Neste momento, a única diferença entre esses dois processos é o pid. O novo processo é normalmente chamado de processo filho, e o processo original cujo pid não muda, é chamado de processo pai.
Às vezes, o processo filho continua a viver de forma independente de seu pai, com os seus próprios dados copiados do processo pai. Em muitos casos, porém, este processo filho executa outro programa. Com poucas exceções, sua memória é simplesmente substituída pela do novo programa, e a execução deste novo programa começa. Esse é o mecanismo usado pelo processo init (com processo número 1) para iniciar serviços adicionais e executar toda a sequência de inicialização. Em algum momento, um dos processos descendentes do
init
inicia uma interface gráfica para os usuários iniciarem sua sessão (a sequência dos eventos é descrita em mais detalhes no
Seção 9.1, “Inicialização do Sistema”).
Quando um processo termina a tarefa para a qual ele foi iniciado, ele termina. O núcleo então recupera a memória designada para este processo, e pára de dar porções de tempo de execução. O processo pai é avisado de que seu processo filho que está sendo encerrado, o que permite que um processo aguarde a conclusão de uma tarefa delegada a um processo filho. Este comportamento é claramente visível nos interpretadores de linha de comando (conhecidos como shells). Quando um comando é digitado em um shell, o prompt só volta quando a execução do comando é concluída. A maioria dos shells permite a execução do comando em segundo plano simplesmente adicionando um &
no final do comando. O prompt volta a ser exibido imediatamente, o que pode ser um problema se o comando deve exibir dados.
Um "daemon" (serviço) é um processo iniciado automaticamente pela sequência de inicialização. Ele continua em execução (em segundo plano) para executar as tarefas de manutenção ou prover serviços a outros processos. Esta "tarefa em segundo plano" é realmente arbitrária e não tem uma importância especial do ponto de vista do sistema. Eles são simplesmente processos, bastante semelhantes a outros processos, que executam quando está em sua porção de tempo. A distinção é apenas na língua humana: dizemos que um processo que é executado sem interação com o usuário (em particular, sem qualquer interface gráfica) está em execução "em segundo plano" ou "como um serviço".
B.5.3. Comunicação Inter Processos
Um processo isolado, seja um daemon ou um aplicativo interativo, raramente é útil por si só, e é por isso que existem vários métodos que permitem a comunicação entre os processos separados, seja para troca de dados ou para controlar um ao outro. O termo genérico que se refere a isso é comunicação entre processos, ou IPC (Inter-Process Communication) para abreviar.
O sistema IPC mais simples é utilizar arquivos. O processo que deseja enviar dados escreve-os em um arquivo (com um nome já conhecido), enquanto o destinatário só precisa abrir o arquivo e ler seu conteúdo.
No caso de você não desejar armazenar dados em disco, você pode usar um pipe (conexão), que é simplesmente um objeto com duas extremidades; bytes escritos em uma extremidade são legíveis na outra. Se as extremidades são controladas por processos separados, ela se converte em um canal de comunicação entre processos simples e conveniente. Pipes podem ser classificados em duas categorias: pipes nomeados e pipes anônimos. Um pipe nomeado é representado por uma entrada no sistema de arquivos (embora os dados transmitidos não são armazenados lá), para que ambos os processos posam abri-lo de forma independente desde que a localização do pipe nomeado seja conhecida antecipadamente. Nos casos em que os processos se comunicando sejam relacionados (por exemplo, um pai e seu processo filho), o processo pai também pode criar um pipe anônimo antes da bifurcação (fork), e o filho o herda. Assim, ambos os processos serão capazes de trocar dados através do pipe sem a necessidade do sistema de arquivos.
No entanto, nem todas as comunicações entre processos são usadas para mover dados. Em muitas situações, a única informação que deve ser transmitida são mensagens de controle tais como "execução em pausa" ou "retomar execução". O Unix (e Linux) fornece um mecanismo conhecido como sinais, através do qual um processo pode simplesmente enviar um sinal específico (escolhido dentro de uma lista pré-definida de sinais) para outro processo. O único requisito é saber o pid do alvo.
Para comunicações mais complexas também existem mecanismos que permitem que um processo abra o acesso, ou compartilhe, parte da memória alocada para outros processos. A memória agora compartilhada entre eles pode ser usada para mover dados entre os processos.
Finalmente, as conexões de rede também podem ajudar a comunicação de processos; esses processos podem até ser executados em diferentes computadores, possivelmente a milhares de quilômetros de distância.
É bastante normal para um típico sistema similar ao Unix fazer uso de todos esses mecanismos em vários graus.
Bibliotecas de funções desempenham um papel crucial em um sistema operacional similar ao Unix. Elas não são programas propriamente ditos, uma vez que não podem ser executadas por si próprias, mas coleções de fragmentos de código que podem ser utilizados pelos programas normais. Entre as bibliotecas comuns, você pode encontrar:
a biblioteca padrão C (glibc), que contém as funções básicas como aquelas para abrir arquivos ou conexões de rede, e outras que facilitam as interações com o kernel;
toolkits gráficos, como Gtk+ e Qt, permitindo que muitos programas reutilizem os objetos gráficos que eles fornecem;
a biblioteca libpng que permite carregar, interpretar e salvar imagens no formato PNG.
Graças a essas bibliotecas, as aplicações podem reutilizar o código existente. O desenvolvimento de aplicações é simplificado já que muitas aplicações podem reutilizar as mesmas funções. Como as bibliotecas são geralmente desenvolvidas por pessoas diferentes, o desenvolvimento global do sistema está mais perto da filosofia histórica do Unix.
Além disso, essas bibliotecas muitas vezes são chamadas de "bibliotecas compartilhadas", já que o núcleo pode carregá-las apenas uma vez para a memória, mesmo se vários processos utilizam a mesma biblioteca ao mesmo tempo. Isso permite economia de memória, quando comparado com a situação oposta (hipotética), onde o código para uma biblioteca seria carregado tantas vezes quantos os processos que a utilizam.