Системный вызов

Материал из Википедии — свободной энциклопедии
Перейти к: навигация, поиск
Ядро Linux: 380 Системный вызов

Систе́мный вы́зов (англ. system call) в программировании и вычислительной технике — обращение прикладной программы к ядру операционной системы для выполнения какой-либо операции.

Современные операционные системы (ОС) предусматривают разделение времени между выполняющимися вычислительными процессами (многозадачность) и разделение полномочий, препятствующее исполняемым программам обращаться к данным других программ и оборудованию. Ядро ОС исполняется в привилегированном режиме работы процессора. Для выполнения межпроцессной операции или операции, требующей доступа к оборудованию, программа обращается к ядру, которое, в зависимости от полномочий вызывающего процесса, исполняет либо отказывает в исполнении такого вызова.

С точки зрения программиста, системный вызов обычно выглядит как вызов подпрограммы или функции из системной библиотеки. Однако системный вызов, как частный случай вызова такой функции или подпрограммы, следует отличать от более общего обращения к системной библиотеке, поскольку последнее может и не требовать выполнения привилегированных операций.

Привилегии[править | править вики-текст]

Архитектура современных процессоров предусматривает использование защищенного режима с несколькими уровнями привилегий: приложения обычно ограничены своим адресным пространством таким образом, что они не могут получить доступ или модифицировать другие приложения, исполняемые в операционной системе, либо саму операционную систему, и обычно не могут напрямую получать доступ к системным ресурсам.

Однако, многим приложениям нужен способ взаимодействовать с системными компонентами, и системные вызовы дают возможность операционной системе обеспечить безопасный доступ для таких операций. Операционная система исполняется с наивысшей степенью привилегий и позволяет приложениям запрашивать сервисы с помощью системных вызовов, которые иногда называются "прерываниями". Прерывания автоматически выводят процессор на некоторый повышенный привилегированный уровень и передают управление ядру, которое определяет давать ли приложению запрашиваемые сервисы. Если сервисы доступны, то ядро выполняет запрошенное действие, затем возвращается на предыдущий уровень привилегий и возвращает управление приложению.

Промежуточная библиотека[править | править вики-текст]

Как правило, система предоставляет библиотеку или API, которые находятся между обычным приложением и ОС. В Windows NT такой API - это часть Native API в библиотеке ntdll.dll; это недокументированный API используемый имплементациями обычного Windows API и напрямую используемый некоторыми системными приложениями Windows. Интерфейсные функции библиотеки предоставляют обычные соглашения о вызове функций для использования системных вызовов и делают системные вызовы более унифицированными. Таким образом, главное назначение интерфейсной функции - размещение всех аргументов, которые передаются системным вызовом, в соответствующие регистры процессора (и, возможно, в стек вызовов) и присвоение уникального номера, чтобы ядро могло его вызвать. В этом случае, библиотека, которая находится между ОС и приложением увеличивает переносимость приложения.

Обращение к функции библиотеки само по себе не вызывает переключения в режим ядра (если только выполнение до этого в этом режиме не находилось) и является обычным вызовом подпрограммы. Реальный системный вызов передает управление ядру (и в большей степени зависит от реализации и платформы, чем вызов библиотеки, абстрагирующей его).

Примеры и инструменты[править | править вики-текст]

В Unix, Unix-like и других POSIX-совместимых операционных системах популярными системными вызовами являются: open, read, write, close, wait, exec, fork, exit и kill. Многие современные ОС имеют сотни системных вызовов. Например, Linux и OpenBSD каждые имеют более 300 разных вызовов,[1][2] NetBSD имеет около 500,[3] FreeBSD имеет более 500,[4] в то время какPlan 9 имеет 51.[5]

Инструменты такие как strace, sysdig и truss наблюдают за исполнением процесса с самого начала и выводят все системные вызовы этого процесса или могут присоединяться к уже работающему процессу и перехватывают все системные вызовы, сделанные этим процессом, если операции не нарушают пользовательские разрешения.

Типичные имплементации[править | править вики-текст]

Имплементация системных вызовов требует передачу управления, которая предполагает некоторые специфические для определенной архитектуры детали. Классический способ имплементации - использование прерываний (interruption, trap). Прерывания передают управление ядру ОС, при этом приложению нужно внести в определенные регистры процессора номер системного вызова и необходимые аргументы и выполнить инструкцию генерации программного прерывания.

Для многих RISC-процессоров это единственный способ, но архитектуры группы CISC (в том числе, широко используемые x86 и x86 64) имеет дополнительные методы. Например, специальные инструкции SYSCALL/SYSRET или SYSENTER/SYSEXIT (эти два механизма были разработаны независимо друг от друга AMD и Intel соответственно, но, по сути, выполняют одинаковые функции). Это инструкции "быстрой" передачи управления, которые разработаны для передачи управления к ОС для системных вызовов без прерываний.

Категории системных вызовов[править | править вики-текст]

Системные вызовы могут быть сгруппированы в пять больших категорий:

  1. Управление процессами
    • load
    • execute
    • end (exit), abort
    • создание процесса (fork в Unix-like, NtCreateProcess в Windows_NT Native API)
    • завершение процесса
    • get/set process attributes
    • wait время, события, signal события
    • allocate, free memory
  2. Работа с файлами
    • create file, delete file
    • open, close
    • read, write, reposition
    • get/set file attributes
  3. Управление устройствами
    • request device, release device
    • read, write, reposition
    • get/set device attributes
    • logically attach or detach devices
  4. Работа с информацией
    • get/set time or date
    • get/set system data
    • get/set process, file, or device attributes
  5. Связь, коммуникация
    • create, delete communication connection
    • send, receive messages
    • transfer status information
    • attach or detach remote devices

Режим процессора и переключение контекста[править | править вики-текст]

Системные вызовы в Unix-подобных системах обрабатываются в режиме ядра, которое завершается повышением режима выполнения процессора в более привилегированный, но изменение контекста процесса не требуется - однако при этом происходит изменение контекста привилегии. Системные ресурсы работают с учетом режима исполнения в соответствии с статусом регистра процессора и процессы - это своего рода абстракция, предоставляемая ОС. Системный вызов обычно не требует изменение контекста на другой процесс, напротив, он выполняется в контексте того процесса, который его вызвал.

В многопотоковых процессах системные вызовы могут исходить из разных потоков. Обработка таких системных вызовов полностью зависит от архитектуры ОС. Ниже приведена типичные модели, которые используются ядрами:

  • Модель многие-к-одному: все системные вызовы от любого пользовательского потока в процессе обрабатываются одним потоком уровня ядра. У этой системы есть один серьезный недостаток - любой блокирующий системный вызов (например, ожидание ввода пользователя) может остановить остальные потоки. Также эта модель не может использовать многоядерные процессоры.
  • Модель один-к-одному: Каждый поток пользователя во время системного вызова присоединяется к своему собственному потоку. Эта модель решает проблему блокирования системных вызовов. она применяется в большинстве дистрибутивов Linux, Windows, Solaris последних версий.
  • Модель многие-к-многим: В этой модели во время системного вызова множество пользовательских потоков увязываются с множеством потоков уровня ядра.
  • Гибридная модель: В этой модели имплементированы модели "многие-к-многим" и "один-к-одному" в зависимости от выбора ядра ОС.

Примечания[править | править вики-текст]

Ссылки[править | править вики-текст]