Системный вызов против вызова функции - PullRequest
29 голосов
/ 19 апреля 2010

В чем разница между системным вызовом и вызовом функции? Является ли fopen () системным или функциональным вызовом?

Ответы [ 10 ]

31 голосов
/ 19 апреля 2010

Системный вызов - это вызов кода ядра, обычно выполняемый путем выполнения прерывания. Прерывание заставляет ядро ​​вступить во владение и выполнить запрошенное действие, а затем передает управление обратно приложению. Это переключение режимов является причиной того, что системные вызовы выполняются медленнее, чем эквивалентная функция прикладного уровня.

fopen - это функция из библиотеки C, которая внутренне выполняет один или несколько системных вызовов. Как правило, программисту на C редко требуется использовать системные вызовы, потому что библиотека C оборачивает их за вас.

9 голосов
/ 19 апреля 2010

fopen - это вызов функции.

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

В * nix системах fopen открывает обертки, что делает системный вызов (open - это обертка C для системного вызова). То же самое происходит с fread / read, fwrite / write и т. Д.

Здесь есть хорошее описание задач, выполняемых системным вызовом Unix.

6 голосов
/ 22 октября 2012

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

  • Из представления выполнения потока, чтобы увидеть системный вызов:

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

  • Параметры системного вызова:

    Параметр системного вызова (номер системного вызова, параметры ...). Значение и формат параметров зависит от номера системного вызова.

  • Из представления библиотеки syscall, предоставленной пользовательской программе:

    Программа пользовательского режима обычно вызывает библиотеку glibc для вызова системного вызова. Например, функция open () в glibc:

    1. поместить системный вызов SYS_OPEN в регистр eax
    2. запрос системного вызова путем вызова программного прерывания или инструкции sys_enter
3 голосов
/ 19 апреля 2010

Если вы используете Linux, вы можете отслеживать системные вызовы, выполняемые приложением:

strace appname ...

Его вывод может дать вам хорошее представление о том, что происходит в libc, и какие функции фактически являются системными вызовами.

2 голосов
/ 30 апреля 2018

На вопрос уже есть отличные ответы, но я думаю, что могу что-то добавить (один сегмент из ostep , которого нет в других ответах

Иногда системный вызов и вызов функции имеют одну и ту же подпись, например, open():

open() -системный вызов

--- ~/Documents » man open(2)

OPEN(2)                 Linux Programmer's Manual           OPEN(2)

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
...

open() -функция вызова

$ man open(3)

--- ~/Documents » 
OPEN(3P)                        POSIX Programmer's Manual          OPEN(3P)
...

int open(const char *path, int oflag, ...);

...

Форма цитирования OSTEP

Вас может удивить, почему вызов системного вызова , такого как open() или read(), выглядит точно так же, как обычный вызов процедуры в C; то есть, если он выглядит как вызов процедуры , как система узнает, что это системный вызов , и делает все правильно? Простая причина: это вызов процедуры , но скрытый внутри этого вызова процедуры является знаменитой инструкцией прерывания . Более конкретно, когда вы вызываете open() (например), вы выполняете вызов процедуры в библиотеке C. При этом, будь то для open() или для любых других системных вызовов , библиотека использует согласованное соглашение о вызовах с ядром для размещения аргументов для открытия в известных местах (например, на стек , или в определенных регистрах ), помещает номер системного вызова в хорошо известное место (опять же, в стек *) 1050 * или регистр ), а затем выполняет вышеупомянутую команду прерывания . Код в библиотеке после trap распаковывает возвращаемые значения и возвращает управление программе, которая выполнила системный вызов . Таким образом, части библиотеки C, которые выполняют системные вызовы , кодируются в сборке вручную, так как они должны тщательно следовать соглашению, чтобы правильно обрабатывать аргументы и возвращать значения, а также выполнять аппаратно-зависимые инструкция ловушки . И теперь вы знаете, почему лично вам не нужно писать ассемблерный код для trap в ОС; кто-то уже написал эту сборку для вас.

2 голосов
/ 19 апреля 2010

Точка зрения, которую следует добавить к этому обсуждению, состоит в том, что вызов функции, как правило, в наиболее оптимистичном случае имеет издержки в виде нескольких 8-битных инструкций (в среднем 4-10) в x86.

Системный вызов имеет следующие свойства.

  1. Выполняет гораздо больше инструкций, он должен заморозить процесс, а не просто состояние стека.
  2. Время проведения в основном недетерминированное.
  3. Часто это место планирования, и планировщик может выбрать перепланирование.

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

Помните, что программное обеспечение построено как перевернутая пирамида. Системные звонки на базе.

2 голосов
/ 19 апреля 2010

Системный вызов фактически вызывает API, выполняемый пространством ядра. Со всеми связанными затратами это предполагает (см. Wiki или эту ссылку для деталей)

Вызов функции - это вызов фрагмента кода в пространстве пользователя.

Тем не менее, обратите внимание, что вызов функции МОЖЕТ быть функцией, которая в процессе своего выполнения выполняет системные вызовы - "fopen" является одним из таких примеров. Поэтому, хотя сам вызов fopen является вызовом функции, это не означает, что системный вызов не будет обрабатывать фактический ввод-вывод.

1 голос
/ 19 апреля 2010

Просто для завершения изображения, представленного другими, fopen - это , обычно реализуемый в качестве оболочки вокруг open, что также является функцией, доступной для пользователя. fopen в некотором смысле более высокий уровень, чем open, поскольку возвращаемая им структура FILE* инкапсулирует данные для пользователя. Некоторые пользователи используют open напрямую для особых нужд. Поэтому было бы неправильно называть fopen системным вызовом. Он также не выполняет системные вызовы напрямую , поскольку open также является функцией, вызываемой пользователем.

1 голос
/ 19 апреля 2010

fopen - это вызов функции, но иногда он может называться системным вызовом, поскольку в конечном итоге он обрабатывается «системой» (ОС). fopen встроен в библиотеку времени выполнения C .

0 голосов
/ 26 июня 2017

Системный вызов выполняется на уровне кернета, а не на уровне пользователя, потому что для доступа к оборудованию ему требуются некоторые привилегии.

Поэтому при программировании в пользовательском пространстве и выполнении некоторого обычного вызова функции, например fopen на языке C, libc обычно переносит эту функцию в определенный код, где генерируется прерывание для переключения из пространства пользователя в пространство ядра, а затем в пространство ядра требуемый системный вызов для выполнения функциональности вызова функции на аппаратном уровне будет выполняться в пространстве ядра.

...