В чем разница между стеком ядра и стеке пользователя? Почему используется стек ядра? Если локальная переменная объявлена в ISR, где она будет сохранена? Каждый процесс имеет свой собственный стек ядра? Затем как процесс координирует между этими стеками?
Стек ядра и стек пользовательского пространства
Ответ 1
- В чем разница между стеком ядра и стекю пользователя?
Короче говоря, ничего - кроме использования другого места в памяти (и, следовательно, другого значения для регистра стека), и обычно различных защит доступа к памяти. То есть при выполнении в пользовательском режиме память ядра (часть из которых представляет собой стек ядра) не будет доступна даже при сопоставлении. И наоборот, без явного запроса кода ядра (в Linux с помощью таких функций, как copy_from_user()
), пользовательская память (включая стек пользователя) обычно не доступна напрямую.
- Почему используется [отдельный] стек ядра?
Разделение привилегий и безопасности. Во-первых, программы пользовательского пространства могут сделать свой стек (указатель) тем, что они хотят, и, как правило, нет требований к архитектуре даже для допустимого. Поэтому ядро не может доверять стекному указателю пользовательского пространства, чтобы оно было действительным и непригодным для использования, и поэтому для его управления потребуется один набор. Различные архитектуры ЦП реализуют это по-разному; x86 CPU автоматически переключают стековые указатели при переключении режимов привилегий, а значения, которые будут использоваться для разных уровней привилегий, настраиваются - с помощью привилегированного кода (т.е. только ядра).
- Если локальная переменная объявлена в ISR, где она будет сохранена?
В стеке ядра. Ядро (ядро Linux, то есть) не перехватывает ISR напрямую в ворота прерывания архитектуры x86, а вместо этого делегирует отправку прерываний на механизм ввода/вывода прерывания ядра, который сохраняет состояние регистрации перед прерыванием перед вызовом зарегистрированного обработчика (ов), Сам процессор при отправке прерывания может выполнять переключатель привилегий и/или стека, и это используется/настраивается ядром, так что общий код ввода прерывания может уже полагаться на стек ядра. Тем не менее, прерывания, возникающие во время выполнения кода ядра, будут просто (продолжать) использовать стек ядра на месте в этой точке. Это может быть, если обработчики прерываний имеют глубоко вложенные пути вызова, приводят к переполнениям стека (если прерывается глубокий путь вызова ядра, а обработчик вызывает еще один глубокий путь; в Linux код RAID/файловой системы/программного RAID, прерываемый сетевым кодом с активным iptables, является как известно, запускать такие в неработающих старых ядрах... решение заключается в увеличении размеров стека ядра для таких рабочих нагрузок).
- У каждого процесса есть свой собственный стек ядра?
Не только каждый процесс - каждый поток имеет свой собственный стек ядра (и, фактически, собственный стек пользователя). Помните, что единственная разница между процессами и потоками (для Linux) заключается в том, что несколько потоков могут совместно использовать адресное пространство (формирование процесса).
- Как процесс координирует между этими стеками?
Совсем нет - это не нужно. Планирование (как/когда выполняются разные потоки, как их состояние сохраняется и восстанавливается) является задачей операционной системы, и процессам не нужно беспокоиться об этом. Поскольку потоки создаются (и каждый процесс должен иметь хотя бы один поток), ядро создает для них стеки ядра, в то время как стеки пользовательского пространства либо явно создаются/предоставляются каким-либо механизмом, используемым для создания потока (такие функции, как makecontext()
или pthread_create()
позволяет вызывающему абоненту указать область памяти, которая будет использоваться для "дочернего" потока потоков) или наследуется (при клонировании памяти при доступе, обычно называемом "копирование при записи" /COW, при создании нового процесса). < ш > Тем не менее, этот процесс может влиять на планирование его потоков и/или влиять на контекст (состояние, среди которого есть указатель потока потока). Для этого существует несколько способов: сигналы UNIX, setcontext()
, pthread_yield()
/pthread_cancel()
,... - но это немного нарушает исходный вопрос.
Ответ 2
Мой ответ собран из других вопросов SO с моими материалами.
What the difference between kernel stack and user stack?
Как программист ядра, вы знаете, что ядро должно быть ограничено от ошибочных пользовательских программ. Предположим, что вы храните один и тот же стек как для ядро, так и для пользовательского пространства, тогда простой segfault в пользовательском приложении разбивает ядро и требует перезагрузки.
Существует один "стек ядра" для каждого процессора, такой как ISR Stack и один "стек ядра" для каждого процесса. Для каждого процесса есть один "стек пользователя", хотя каждый поток имеет свой собственный стек, включая потоки пользователей и ядра.
http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-10/3194.html
Why kernel stack is used?
Итак, когда мы находимся в режиме ядра, для работы с вызовами функций необходимы локальные переменные типа, локальные переменные, подобные пользовательскому пространству.
http://www.kernel.org/doc/Documentation/x86/kernel-stacks
If a local variable is declared in an ISR, where it will be stored?
Он будет храниться в стеке ISR (IRQSTACKSIZE). ISR работает в отдельном стеке прерываний только в том случае, если аппаратное обеспечение поддерживает его. В противном случае кадры стека ISR помещаются в стек прерывистого потока.
Пользовательское пространство не знает и, откровенно говоря, не заботится о том, обслуживается ли прерывание в текущем стеке ядра процесса или отдельном стеке ISR. Поскольку прерывания поступают на процессор, поэтому стек ISR должен быть на процессор.
Does each process has its own kernel stack ?
Да. Каждый процесс имеет свой собственный стек ядра.
Then how the process coordinates between both these stacks?
@FrankH ответ выглядит здорово для меня.