Что происходит (подробно), когда поток делает системный вызов путем повышения прерывания 80? Какую работу Linux делает к стопке потока и другому состоянию? Какие изменения сделаны к процессору для помещения его в привилегированный режим? После выполнения обработчика прерываний, как управление восстанавливается назад обработке вызовов?
Что, если системный вызов не может быть завершен быстро: например, чтение от диска. Как обработчик прерываний оставляет управление так, чтобы процессор мог сделать другой материал, в то время как данные загружаются и как это тогда получает управление снова?
Хорошие вопросы! (Вопросы для интервью?)
Операция int $ 80 отдаленно похожа на вызов функции. ЦП «принимает ловушку» и перезапускается по известному адресу в режиме ядра, обычно также с другим режимом MMU. Ядро сохранит многие из регистров, хотя ему не нужно сохранять регистры, которые программа не ожидала бы сохранить при обычном вызове функции.
Обычно ОС сохраняет регистры, которые ABI обещает не изменять во время вызовов процедур. Стек останется прежним; ядро будет работать в стеке ядра для каждого потока, а не в пользовательском стеке для каждого потока. Естественно, какое-то состояние изменится, иначе не было бы причин для выполнения системного вызова.
Обычно это происходит полностью автоматически. В общем случае ЦП имеет инструкцию программного прерывания, которая немного похожа на операцию функционального вызова. Это вызовет переключение в режим ядра в контролируемых условиях.Обычно ЦП меняет какой-то бит защиты PSW, сохраняет старые PSW и PC, начинает работу с хорошо известного адреса вектора прерывания, а также может переключиться на другую защиту управления памятью и схему сопоставления.
Будет какая-то инструкция «возврата из прерывания» или «возврата из прерывания» , как правило, это немного похоже на сложную инструкцию возврата функции. Некоторые процессоры RISC делали очень мало автоматически и требовали определенного кода для возврата, а некоторые процессоры CISC, такие как x86, имеют (никогда не используемые) инструкции, которые будут выполнять десятки операций, задокументированных на страницах ручного псевдокода для настройки возможностей.
Само ядро многопоточно, как и многопоточная пользовательская программа. Он просто переключает стеки (потоки) и какое-то время работает над чужим процессом.
Чтобы ответить на последнюю часть вопроса - что делает ядро, если системному вызову нужно заснуть -
После системного вызова ядро все еще логически работает в контексте той же задачи, которая сделала системный вызов - просто в режиме ядра, а не в режиме пользователя - это НЕ отдельный поток, и большинство системных вызовов не вызывают логику из другой задачи/потока. Происходит так: системный вызов вызывает wait_event, или wait_event_timeout, или другую функцию ожидания, которая добавляет задачу в список задач, ожидающих чего-то, затем переводит задачу в спящий режим, что изменяет ее состояние, и вызывает schedule(), чтобы освободить текущий процессор.
После этого задача не может быть запущена снова, пока не будет разбужена, обычно другой задачей (задачей ядра и т.д.) или обработчиком прерывания, вызывающим функцию wake*, которая разбудит спящие задачи, ожидающие этого конкретного события, что означает, что планировщик скоро снова составит для них расписание.
Стоит отметить, что задачи пользовательского пространства (т.е. потоки) - это только один тип задач, и есть еще несколько внутренних задач ядра, которые также могут выполнять работу - это потоки ядра и обработчики нижней половины / tasklets / task queues и т.д.. Работа, которая не принадлежит какому-либо конкретному процессу пользовательского пространства (например, обработка сети, например, ответ на пинги), выполняется в них. В отличие от прерываний (которые не должны вызывать планировщик), этим задачам разрешено засыпать
.