Chamada de sistema - System call

Uma visão geral de alto nível da interface de chamada do sistema do kernel do Linux, que lida com a comunicação entre seus vários componentes e o espaço do usuário

Na computação , uma chamada de sistema (comumente abreviada para syscall ) é a maneira programática pela qual um programa de computador solicita um serviço do kernel do sistema operacional no qual é executado. Isso pode incluir serviços relacionados a hardware (por exemplo, acessar uma unidade de disco rígido ou acessar a câmera do dispositivo), criação e execução de novos processos e comunicação com serviços de kernel integrais , como agendamento de processo . As chamadas do sistema fornecem uma interface essencial entre um processo e o sistema operacional.

Na maioria dos sistemas, as chamadas de sistema só podem ser feitas a partir de processos do espaço do usuário , enquanto em alguns sistemas, OS / 360 e sucessores, por exemplo, o código de sistema privilegiado também emite chamadas de sistema.

Privilégios

A arquitetura da maioria dos processadores modernos, com exceção de alguns sistemas embarcados, envolve um modelo de segurança . Por exemplo, o modelo de anéis especifica vários níveis de privilégio sob os quais o software pode ser executado: um programa é geralmente limitado a seu próprio espaço de endereço para que não possa acessar ou modificar outros programas em execução ou o próprio sistema operacional, e geralmente é impedido de manipular diretamente dispositivos de hardware (por exemplo, o buffer de quadro ou dispositivos de rede ).

No entanto, muitos aplicativos precisam de acesso a esses componentes, de modo que as chamadas do sistema são disponibilizadas pelo sistema operacional para fornecer implementações seguras e bem definidas para tais operações. O sistema operacional é executado no nível de privilégio mais alto e permite que os aplicativos solicitem serviços por meio de chamadas do sistema, que geralmente são iniciadas por meio de interrupções . Uma interrupção coloca automaticamente a CPU em algum nível de privilégio elevado e então passa o controle para o kernel, que determina se o programa de chamada deve receber o serviço solicitado. Se o serviço for concedido, o kernel executa um conjunto específico de instruções sobre as quais o programa de chamada não tem controle direto, retorna o nível de privilégio ao do programa de chamada e, em seguida, retorna o controle ao programa de chamada.

A biblioteca como intermediária

Geralmente, os sistemas fornecem uma biblioteca ou API que fica entre os programas normais e o sistema operacional. Em sistemas do tipo Unix, essa API geralmente faz parte de uma implementação da biblioteca C (libc), como glibc , que fornece funções de empacotador para as chamadas do sistema, geralmente nomeadas da mesma forma que as chamadas do sistema que invocam. No Windows NT , essa API é parte da API nativa , na biblioteca ntdll.dll ; esta é uma API não documentada usada por implementações da API regular do Windows e usada diretamente por alguns programas do sistema no Windows. As funções de invólucro da biblioteca expõem uma convenção de chamada de função comum (uma chamada de sub - rotina no nível de montagem ) para usar a chamada do sistema, além de tornar a chamada do sistema mais modular . Aqui, a função principal do wrapper é colocar todos os argumentos a serem passados ​​para a chamada do sistema nos registros do processador apropriados (e talvez na pilha de chamadas também), e também definir um número de chamada do sistema exclusivo para o kernel chamar . Desta forma, a biblioteca existente entre o SO e a aplicação aumenta a portabilidade .

A chamada para a função de biblioteca em si não causa uma mudança para o modo kernel e geralmente é uma chamada de sub-rotina normal (usando, por exemplo, uma instrução de montagem "CALL" em algumas arquiteturas de conjunto de instruções (ISAs)). A chamada do sistema real transfere o controle para o kernel (e é mais dependente da implementação e da plataforma do que a chamada da biblioteca que o abstrai). Por exemplo, em sistemas do tipo Unix, forke execvesão funções de biblioteca C que, por sua vez, executam instruções que invocam as chamadas de sistema forke exec. Fazer a chamada do sistema diretamente no código do aplicativo é mais complicado e pode exigir o uso do código assembly incorporado (em C e C ++ ), bem como exigir o conhecimento da interface binária de baixo nível para a operação de chamada do sistema, o que pode estar sujeito mudar com o tempo e, portanto, não fazer parte da interface binária do aplicativo ; as funções da biblioteca têm como objetivo abstrair isso.

Em sistemas baseados em exokernel , a biblioteca é especialmente importante como intermediária. Em exokernels, as bibliotecas protegem os aplicativos do usuário da API do kernel de nível muito baixo e fornecem abstrações e gerenciamento de recursos .

O OS / 360 e o DOS / 360 da IBM implementam a maioria das chamadas de sistema por meio de uma biblioteca de macros de linguagem assembly , embora existam alguns serviços com um link de chamada. Isso reflete sua origem em um momento em que a programação em linguagem assembly era mais comum do que o uso de linguagem de alto nível . Portanto, as chamadas do sistema IBM não eram executáveis ​​diretamente por programas de linguagem de alto nível, mas exigiam uma sub-rotina de invólucro de linguagem assembly que pode ser chamada. Desde então, a IBM adicionou muitos serviços que podem ser chamados a partir de linguagens de alto nível em, por exemplo, z / OS e z / VSE .

Exemplos e ferramentas

No Unix , Unix-like e outros POSIX sistemas operacionais-compatível, chamadas de sistema populares são open, read, write, close, wait, exec, fork, exit, e kill. Muitos sistemas operacionais modernos têm centenas de chamadas de sistema. Por exemplo, Linux e OpenBSD têm cada um mais de 300 chamadas diferentes, NetBSD tem cerca de 500, FreeBSD tem mais de 500, Windows tem quase 2000, dividido entre chamadas de sistema win32k (gráfico) e ntdll (núcleo) enquanto o Plan 9 tem 51.

Ferramentas como strace , ftrace e truss permitem que um processo seja executado desde o início e relate todas as chamadas de sistema que o processo invoca, ou pode anexar a um processo já em execução e interceptar qualquer chamada de sistema feita por tal processo se a operação não violar as permissões do usuário. Essa habilidade especial do programa geralmente também é implementada com chamadas de sistema, como ptrace ou chamadas de sistema em arquivos em procfs .

Implementações típicas

A implementação de chamadas de sistema requer uma transferência de controle do espaço do usuário para o espaço do kernel, o que envolve algum tipo de recurso específico da arquitetura. Uma maneira típica de implementar isso é usar uma interrupção ou trap de software . Interrompe a transferência de controle para o kernel do sistema operacional , então o software simplesmente precisa configurar algum registro com o número de chamada do sistema necessário e executar a interrupção do software.

Esta é a única técnica fornecida para muitos processadores RISC , mas as arquiteturas CISC , como x86, oferecem suporte a técnicas adicionais. Por exemplo, o conjunto de instruções x86 contém as instruções SYSCALL/ SYSRETe SYSENTER/ SYSEXIT(esses dois mecanismos foram criados independentemente pela AMD e pela Intel , respectivamente, mas em essência eles fazem a mesma coisa). Essas são instruções de transferência de controle "rápidas" projetadas para transferir rapidamente o controle para o kernel para uma chamada de sistema sem a sobrecarga de uma interrupção. O Linux 2.5 começou a usar isso no x86 , onde disponível; anteriormente, ele usava a INTinstrução, onde o número de chamada do sistema era colocado no EAX registro antes da interrupção 0x80 ser executada.

Um mecanismo mais antigo é o portão de chamada ; originalmente usado no Multics e posteriormente, por exemplo, consulte o call gate no Intel x86 . Ele permite que um programa chame uma função do kernel diretamente usando um mecanismo de transferência de controle seguro, que o sistema operacional configura com antecedência. Esta abordagem tem sido impopular em x86, presumivelmente devido ao requisito de uma chamada distante (uma chamada para um procedimento localizado em um segmento diferente do segmento de código atual) que usa segmentação de memória x86 e a resultante falta de portabilidade que ela causa, e o existência das instruções mais rápidas mencionadas acima.

Para a arquitetura IA-64 , a EPCinstrução (Enter Privileged Code) é usada. Os primeiros oito argumentos de chamada do sistema são passados ​​em registradores e o restante é passado na pilha.

Na família de mainframe IBM System / 360 , e seus sucessores, uma instrução Supervisor Call ( SVC ), com o número na instrução em vez de em um registro, implementa uma chamada de sistema para instalações legadas na maioria dos próprios sistemas operacionais da IBM, e para todas as chamadas de sistema no Linux. Em versões posteriores do MVS, a IBM usa a instrução Program Call (PC) para muitos recursos mais recentes. Em particular, o PC é usado quando o chamador pode estar no modo Service Request Block (SRB).

O minicomputador PDP-11 usava as instruções EMT e IOT , que, semelhantes ao IBM System / 360 SVC e x86 INT , colocam o código na instrução; eles geram interrupções em endereços específicos, transferindo o controle para o sistema operacional. O sucessor VAX de 32 bits da série PDP-11 usava as instruções CHMK , CHME e CHMS para fazer chamadas de sistema para código privilegiado em vários níveis; o código é um argumento para a instrução.

Categorias de chamadas de sistema

As chamadas do sistema podem ser agrupadas aproximadamente em seis categorias principais:

  1. Controle do processo
  2. Gerenciamento de arquivos
    • criar arquivo, excluir arquivo
    • abrir fechar
    • ler, escrever, reposicionar
    • obter / definir atributos de arquivo
  3. Gerenciamento de dispositivo
    • solicitar dispositivo, liberar dispositivo
    • ler, escrever, reposicionar
    • obter / definir atributos do dispositivo
    • conectar ou desconectar dispositivos logicamente
  4. Manutenção de informação
    • obter / definir informações totais do sistema (incluindo hora, data, nome do computador, empresa, etc.)
    • obter / definir o processo, arquivo ou metadados do dispositivo (incluindo autor, abridor, hora e data de criação, etc.)
  5. Comunicação
    • criar, excluir conexão de comunicação
    • enviar, receber mensagens
    • transferência de informações de status
    • anexar ou desconectar dispositivos remotos
  6. Proteção
    • obter / definir permissões de arquivo

Modo de processador e troca de contexto

As chamadas de sistema na maioria dos sistemas semelhantes ao Unix são processadas no modo kernel , o que é realizado alterando o modo de execução do processador para um mais privilegiado, mas nenhuma troca de contexto de processo é necessária - embora uma troca de contexto de privilégio ocorra. O hardware vê o mundo em termos do modo de execução de acordo com o registro de status do processador , e os processos são uma abstração fornecida pelo sistema operacional. Uma chamada de sistema geralmente não requer uma mudança de contexto para outro processo; em vez disso, ele é processado no contexto de qualquer processo que o tenha invocado.

Em um processo multithread , as chamadas do sistema podem ser feitas a partir de vários threads . O tratamento dessas chamadas depende do design do kernel do sistema operacional específico e do ambiente de tempo de execução do aplicativo. A lista a seguir mostra modelos típicos seguidos por sistemas operacionais:

  • Modelo muitos para um : todas as chamadas de sistema de qualquer thread do usuário em um processo são tratadas por um único thread no nível do kernel. Este modelo tem uma séria desvantagem - qualquer bloqueio de chamada do sistema (como aguardar entrada do usuário) pode congelar todos os outros threads. Além disso, como apenas um thread pode acessar o kernel por vez, este modelo não pode utilizar vários núcleos de processadores.
  • Modelo um para um : cada thread do usuário é anexado a um thread distinto no nível do kernel durante uma chamada do sistema. Este modelo resolve o problema acima de bloqueio de chamadas do sistema. Ele é encontrado em todas as principais distribuições de Linux , macOS , iOS , versões recentes do Windows e Solaris .
  • Modelo muitos para muitos : neste modelo, um pool de threads de usuário é mapeado para um pool de threads de kernel. Todas as chamadas do sistema de um pool de thread do usuário são tratadas pelos threads em seu pool de thread do kernel correspondente .
  • Modelo híbrido : este modelo implementa modelos muitos para muitos e um para um, dependendo da escolha feita pelo kernel. Isso é encontrado em versões antigas do IRIX , HP-UX e Solaris .

Veja também

Notas

Referências

links externos