Sistemas Operacionais: Estrutura do Sistema Operacional
Pode-se dizer que o sistema operacional é formado por “um conjunto de rotinas que oferece serviços aos usuários e às suas aplicações. Esse conjunto de rotinas é denominado núcleo do sistema, ou kernel.” (Machado e Maia, 2014, p. 72). Para acompanhar este kernel, a maioria dos sistemas operacionais é acompanhada de programas utilitários e linguagem de comandos, conforme a Figura 1.

Fonte: Machado e Maia (2014, p. 73).
Percebe-se pela Figura 1 que a comunicação dos usuários com o kernel ocorre de três formas: através de chamadas explícitas a rotinas do sistema (realizadas pelas aplicações), por meio de utilitários ou utilizando a linguagem de comandos. Portanto, estes programas oferecem ferramentas de apoio ao usuário, porém não consideradas parte do núcleo do sistema.
Quanto ao núcleo, a organização interna e o inter-relacionamento dos componentes do código podem variar conforme a concepção do projeto e a arquitetura escolhida para o SO. Este detalhamento será feito no decorrer deste artigo.
Funções do núcleo (kernel)
O núcleo do sistema operacional é responsável por funções essenciais que garantem o funcionamento eficiente e seguro do ambiente multiprogramável. Sua execução não é linear como muitas aplicações costumam ser, de forma que sua construção não é simples de entender.
As principais funções do núcleo são:
- Tratamento de interrupções e exceções.
- Criação e eliminação de processos e threads.
- Sincronização e comunicação entre processos e threads.
- Escalonamento e controle dos processos e threads.
- Gerência de memória.
- Gerência do sistema de arquivos.
Devido ao ambiente multiprogramável, “é natural que surjam problemas relativos à segurança no inter-relacionamento dos diversos subsistemas existentes” (Machado e Maia, 2014, p. 74). Logo, o SO deve implementar mecanismos de proteção para controlar o acesso concorrente aos recursos do sistema, garantindo a integridade e confidencialidade dos dados. Uma das principais implementações de segurança que um sistema operacional utiliza é um mecanismo presente no hardware dos processadores, conhecido como modo de acesso.
Modo de acesso
Os processadores possuem em sua construção física a possibilidade de setar (configurar) dois modos de acesso: o modo usuário e o modo kernel. Quando a CPU trabalha no modo usuário, uma aplicação só pode executar instruções conhecidas como não privilegiadas, tendo acesso a um número reduzido de instruções. Por outro lado, no modo kernel a aplicação pode ter acesso ao conjunto total de instruções do processador (instruções privilegiadas). Geralmente, o modo de operação da CPU é determinado por um conjunto de bits, localizado no registrador de status do processador, que indica o modo de acesso corrente.
Cabe ressaltar que as instruções privilegiadas oferecem risco à segurança e integridade do sistema, pois podem acessar dispositivos ou funções diretas do sistema. Por exemplo, operações diretas de acesso a disco só podem ser executadas quando o processador está em modo kernel – e com acesso às instruções privilegiadas. Assim, o modo de acesso é um mecanismo que impede que uma aplicação de usuário acesse qualquer área do disco sem autorização.
Rotinas do sistema operacional e System Calls
Com as restrições do modo de acesso, a aplicação do usuário não pode especificar diretamente instruções privilegiadas. A utilização de recursos compartilhados deve ser gerenciada unicamente pelo sistema operacional, criando a necessidade de comunicação entre a aplicação e o kernel para solicitar serviços privilegiados. Essa comunicação se dá por meio de chamadas a rotinas do sistema.
O controle de execução de rotinas do sistema operacional é realizado por um mecanismo conhecido como system call. Toda vez que uma aplicação deseja chamar uma rotina do sistema operacional, o mecanismo de system call é ativado, conforme apresentado no exemplo da Figura 2.

Fonte: Machado e Maia (2014, p. 76).
Chamada a rotinas do Sistema Operacional
“As rotinas do sistema e o mecanismo de system call podem ser entendidos como uma porta de entrada para o núcleo do sistema operacional e a seus serviços.” (Machado e Maia, 2014, p. 76). Toda vez que uma aplicação precisar de algum serviço do sistema, ela deve realizar uma chamada a uma das rotinas do SO através de uma system call, conforme o exemplo da Figura 3.
Existem duas formas distintas de se chamar uma rotina do sistema operacional: a primeira é a chamada explícita, onde o código do programa contém uma função que explicita a chamada à rotina do sistema com a passagem de parâmetros; a segunda é a chamada implícita, na qual a chamada é feita por meio de um comando da própria linguagem de programação, que é convertido em uma chamada de função de nível mais baixo durante a tradução.

Fonte: Machado e Maia (2014, p. 77).
As rotinas do sistema são geralmente divididas por grupos de função, descritas na Tabela 1.
| Funções | System Calls |
| Gerência de processos e threads | Criação e eliminação de processos e threads Alteração das características de processos e threads Sincronização e comunicação entre processos e threads Obtenção de informações sobre processos e threads |
| Gerência de memória | Alocação e desalocação de memória |
| Gerência do sistema de arquivos | Criação e eliminação de arquivos e diretórios Alteração das características de arquivos e diretórios Abertura e fechamento de arquivos Leitura e gravação em arquivos Obtenção de informações sobre arquivos e diretórios |
| Gerência de dispositivos | Alocação e desalocação de dispositivos Operações de entrada/saída em dispositivos Obtenção de informações sobre dispositivos |
Fonte: Machado e Maia (2014, p. 78).
Cada sistema operacional possui seu próprio conjunto de rotinas, com nomes, parâmetros e formas de ativação específicos. Devido à especificidade das rotinas em cada sistema operacional, a portabilidade de aplicações é complexa, exigindo correções no código-fonte.
O padrão Portable Operating System Interface for Unix (POSIX), elaborado pelos institutos ISO e IEEE, tentou padronizar uma biblioteca de chamadas para unificar as várias versões do Unix e facilitar a portabilidade para outros sistemas modernos, como o MS Windows e SUN-Solaris. Contudo, o projeto não alcançou seu objetivo integralmente, de forma que o termo system call é comumente utilizado em sistemas Unix. Em outros sistemas, este conceito pode ser conhecido como system services, OpenVMS, ou Application Program Interface (API), no MS Windows.
Apesar de não funcionar integralmente, o padrão POSIX facilitou bastante a portabilidade de algumas chamadas pelas aplicações entre os inúmeros SOs disponíveis atualmente no mercado.
Linguagem de Comandos
A linguagem de comandos (ou linguagem de controle) é a interface que permite ao usuário interagir diretamente com o sistema operacional de forma simples. Ela capacita o usuário a executar tarefas específicas do sistema, como criar ou eliminar arquivos, consultar diretórios ou verificar a data/hora. São exemplos de linguagens de comando o DCL (OpenVMS), o JCL (MVS da IBM) e os comandos do shell (Unix). A Tabela 2 apresenta alguns comandos e suas descrições.
| Comando | Descrição |
| dir | Lista o conteúdo de um diretório |
| cd | Altera o diretório default |
| type | Exibe o conteúdo de um arquivo |
| del | Elimina arquivos |
| mkdir | Cria um diretório |
Fonte: Machado e Maia (2014, p. 79).
Cada comando digitado é interpretado pelo shell ou interpretador de comandos, que verifica a sintaxe, realiza as chamadas às rotinas do sistema e apresenta um resultado. O interpretador de comandos, em geral, não faz parte do núcleo do sistema operacional, o que permite flexibilidade na criação de diferentes linguagens de controle para um mesmo sistema (Bourne Shell, C Shell, Korn Shell no Unix). Interfaces gráficas, como as primeras versões do Microsoft Windows são, muitas vezes, apenas um nível adicional de abstração. O uso de arquivos de comandos (scripts) também possibilita a automação de tarefas de gerência do sistema.
Ativação e Desativação do SO
A princípio, quando um computador é ligado, não há sistema operacional carregado na memória da máquina. Ele fica armazenado em algum dispositivo de memória secundária e é carregado para a memória principal (memória RAM). Esse processo de carregamento é conhecido como ativação (boot).
O processo de ativação (boot) se inicia com a execução do programa boot loader, que está em uma memória ROM. Em seguida, é executado o POST (Power-On Self Test) para identificar problemas de hardware. Após encontrar um dispositivo com um sistema operacional residente, um conjunto de instruções é carregado a partir do setor de boot (boot sector). Finalmente, o sistema operacional é carregado para a memória principal, e arquivos de inicialização são executados para customização e configuração. A Figura 4 exemplifica por meio de imagens este processo.

Fonte: Machado e Maia (2014, p. 80).
O processo de desativação (shutdown) faz exatamente o contrário do boot, permitindo que as aplicações e componentes do SO sejam desativados de maneira ordenada, garantindo sua integridade e a persistência dos dados.
Arquitetura do núcleo
O projeto de sistemas operacionais modernos tende a utilizar técnicas de programação modular e linguagens como C/C++ e Rust para facilitar o desenvolvimento, a manutenção e a portabilidade. A utilização de técnicas de orientação a objetos proporciona benefícios como melhor organização, redução do tempo de desenvolvimento, maior facilidade de manutenção e implementação facilitada do modelo de computação distribuída.
As principais arquiteturas de núcleo são: monolítica, em camadas, máquina virtual e microkernel.
Monolítica
Nesse esquema, o sistema é construído como um único programa executável, formado por módulos que são compilados separadamente e depois linkados. Neste modelo, os módulos podem interagir livremente, igual demonstrado na Figura 5.
Foi adotada nos primeiros sistemas operacionais, como o MS-DOS e o Unix inicial, devido à sua simplicidade e bom desempenho. No entanto, apresentava grande dificuldade no desenvolvimento e, principalmente, na manutenção.

Fonte: Machado e Maia (2014, p. 82).
Em camadas
O sistema é estruturado em níveis sobrepostos, onde cada camada oferece um conjunto de funções que podem ser utilizadas apenas pelas camadas superiores. A Figura 6 demonstra bem o conceito das camadas.
Suas principais vantagens são o isolamento das funções, facilitando a manutenção e a depuração, e a criação de uma hierarquia de níveis de modos de acesso, protegendo as camadas mais internas. Contudo, há perda de desempenho, pois cada transição de camada implica uma mudança no modo de acesso, configurando uma desvantagem.

Fonte: Machado e Maia (2014, p. 83).
O sistema THE (1968) foi o primeiro a utilizar essa abordagem. Atualmente, a maioria dos sistemas comerciais atuais (como Unix e MS Windows) utiliza um modelo simplificado de duas camadas (usuário e kernel).
Máquina virtual
O modelo de Máquina Virtual (em inglês, Virtual Machine – VM) insere um nível intermediário entre o hardware e o sistema operacional, chamado gerência de máquinas virtuais. Este nível cria diversas VMs independentes, cada uma oferecendo uma cópia virtual do hardware, incluindo modos de acesso e interrupções.
Na Figura 7 podemos ver que existem várias (n) VMs acima da camada de gerência de máquinas virtuais que faz a gestão dos recursos de hardware, interrupções e demais funções do SO. Este modelo garante o isolamento total entre cada VM, oferecendo grande segurança.

Fonte: Machado e Maia (2014, p. 84).
As principais aplicações das VMs são a portabilidade de código, pois programas podem ser desenvolvidos em uma linguagem intermediária (bytecode na JVM – Java Virtual Machine) e traduzidos pela VM para qualquer plataforma; e o aumento da disponibilidade dos recursos, pois uma VM pode ser facilmente copiada e restaurada.
Microkernel
Esta arquitetura visa manter o núcleo do sistema operacional o mais simples e menor possível. Os serviços do sistema, como gerência de arquivos e escalonamento, são disponibilizados por processos servidores, conforme pode ser visto na Figura 8.

Fonte: Machado e Maia (2014, p. 85).
Uma aplicação (cliente) solicita um serviço enviando uma mensagem para o processo servidor correspondente, que responde com outra mensagem. A principal função do núcleo (microkernel) é gerenciar a comunicação (troca de mensagens) entre clientes e servidores.
A principal vantagem desse modelo é que os processos servidores podem executar em modo usuário; assim, se um servidor falhar, o sistema não fica inteiramente comprometido, aumentando a disponibilidade. Além disso, acaba-se ganhando facilidade de manutenção, flexibilidade e portabilidade do código. Entretanto, novamente há problemas de desempenho devido à necessidade de mudança de modo de acesso a cada comunicação cliente-servidor, tornando-se uma desvantagem considerável para o modelo de construção.
Considerações finais
A estrutura de um sistema operacional (SO) é composta por diversos componentes interdependentes que trabalham em conjunto para gerenciar os recursos do computador e fornecer uma interface entre o hardware e os programas de usuário.
O núcleo (kernel) é a parte central, responsável por gerenciar a memória, os processos, o controle de entrada e saída, e a comunicação entre o hardware e o software. Acima do núcleo, existem camadas adicionais, como o gerenciador de processos, o gerenciador de arquivos, e a interface de usuário, que oferecem serviços e abstrações para que o usuário interaja com o sistema de maneira mais simples e eficiente. Além disso, o SO pode incluir ferramentas de rede, segurança, e sistemas de arquivos, que são essenciais para a operação e a proteção do sistema como um todo.
A arquitetura do sistema operacional pode variar, mas, independentemente de como ela seja construída, a finalidade sempre é otimizar o uso dos recursos de hardware, além de garantir a estabilidade e a segurança do sistema.
Obrigado pela leitura e bons estudos.
Referências
MACHADO, Francis Berenger; MAIA, Luiz Paulo. Arquitetura de sistemas operacionais. 5ª ed. Rio de Janeiro: LTC, 2014.


