стек ядра и стек пользовательского пространства

<p>в чем разница между стеком ядра и пользовательским стеком? почему используется стек ядра? если в isr объявлена локальная переменная, где она будет храниться? у каждого процесса есть свой собственный стек ядра? тогда как процесс координирует между этими двумя стеками?</p>

<blockquote> <ol> <li><em>в чем разница между стеком ядра и пользовательским стеком?</em></li> </ol> </blockquote><p>короче говоря, ничего - кроме использования другого местоположения в памяти (и, следовательно, другого значения для регистра стека указателя), и, как правило, других средств защиты доступа к памяти. то есть при выполнении в пользовательском режиме память ядра (частью которой является стек ядра) не будет доступна, даже если отображается. и наоборот, без явного запроса кода ядра (в linux через такие функции, как <code>copy\_from\_user()</code>) пользовательская память (включая пользовательский стек) обычно не доступна напрямую.</p><blockquote> <ol start="2"> <li><em>почему используется [отдельный] стек ядра?</em></li> </ol> </blockquote><p>разделение привилегий и безопасности. с одной стороны, программы пользовательского пространства могут создавать свой стек (указатель) как угодно, и, как правило, нет архитектурного требования, чтобы даже иметь действительный. поэтому ядро не может <em>доверять</em> указатель стека в пользовательском пространстве, чтобы быть действительным или пригодным для использования, и, следовательно, потребует один набор под своим собственным контролем. различные архитектуры цп реализуют это по-разному; процессоры x86 автоматически переключают стековые указатели, когда происходит переключение режима привилегий, и значения, которые будут использоваться для разных уровней привилегий, настраиваются с помощью кода с привилегиями (то есть только ядра).</p><blockquote> <ol start="3"> <li><em>если в isr объявлена локальная переменная, где она будет храниться?</em></li> </ol> </blockquote><p>на стеке ядра. ядро (то есть ядро linux) --- <em>не</em> подключает isr непосредственно к архитектуре x86 <em>шлюзы прерывания</em>, но вместо этого делегирует диспетчеризацию прерывания общему механизму входа/выхода прерывания ядра, который сохраняет состояние регистра перед прерыванием перед вызовом зарегистрированного обработчика (обработчиков). сам цп при отправке прерывания может выполнить привилегию и/или переключение стека, и это используется/устанавливается ядром, так что общий код записи прерывания уже может полагаться на наличие стека ядра.<br> тем не менее, прерывания, возникающие во время выполнения кода ядра, будут просто (продолжать) использовать стек ядра, установленный в этот момент. это может, если обработчики прерываний имеют глубоко вложенные пути вызовов, привести к переполнению стека (если глубокий путь вызова ядра прерывается и обработчик вызывает другой глубокий путь; в linux код raid файловой системы/программного обеспечения прерывается сетевым кодом с активным iptables. известно, что это происходит в ненастроенных старых ядрах ... решение заключается в увеличении размеров стека ядра для таких рабочих нагрузок).</p><blockquote> <ol start="4"> <li><em>у каждого процесса есть свой собственный стек ядра?</em></li> </ol> </blockquote><p>не только каждый процесс - каждый <em>поток</em> имеет свой собственный стек ядра (и, фактически, также свой собственный стек пользователя). помните, что единственное различие между процессами и потоками (для linux) заключается в том, что несколько потоков могут совместно использовать адресное пространство (формируя процесс).</p><blockquote> <ol start="5"> <li><em>как процесс координирует между этими двумя стеками?</em></li> </ol> </blockquote><p>вовсе нет - это не нужно. планирование (как/когда выполняются разные потоки, как их состояние сохраняется и восстанавливается) является задачей операционной системы, и процессам не нужно заботиться об этом. поскольку потоки создаются (и каждый процесс должен иметь хотя бы один поток), ядро создает для них стеки ядра, в то время как стеки в пользовательском пространстве либо создаются явно, либо обеспечиваются тем механизмом, который используется для создания потока (такие функции, как <code>makecontext()</code> или <code>pthread\_create()</code>, позволяют вызывающая программа задает область памяти, которая будет использоваться для стека "дочернего" потока) или наследуется (путем клонирования памяти при доступе, обычно называемого "копировать при записи"/cow при создании нового процесса).<br> тем не менее, процесс <em>может</em> влияет на планирование своих потоков и/или влияет на <em>контекст</em> (состояние, среди которых указатель стека потока). для этого есть несколько способов: сигналы unix, <code>setcontext()</code>, <code>pthread\_yield()</code>/<code>pthread\_cancel()</code>, ... - но это немного противоречит первоначальному вопросу.</p>

<p>мой ответ собран из других so вопросов с моими материалами.</p><pre><code>what's the difference between kernel stack and user stack? </code></pre><p>как программист ядра, вы знаете, что ядро должно быть защищено от ошибочных пользовательских программ. предположим, вы сохраняете одинаковый стек как для ядра, так и для пользовательского пространства, тогда простой segfault в пользовательском приложении приводит к сбою ядра и требует перезагрузки.</p><p>существует один "стек ядра" на процессор, такой как стек isr, и один "стек ядра" на процесс. для каждого процесса существует один "пользовательский стек", хотя каждый поток имеет свой собственный стек, включая потоки как пользователя, так и ядра.</p><p> <a href="http://linux.derkeiler.com/mailing-lists/kernel/2004-10/3194.html">http://linux.derkeiler.com/mailing-lists/kernel/2004-10/3194.html</a> </p><pre><code>why kernel stack is used? </code></pre><p>поэтому, когда мы находимся в режиме ядра, для работы с вызовами функций необходим механизм стекового типа, локальные переменные аналогичны пользовательскому пространству.</p><p> <a href="http://www.kernel.org/doc/documentation/x86/kernel-stacks">http://www.kernel.org/doc/documentation/x86/kernel-stacks</a> </p><pre><code>if a local variable is declared in an isr, where it will be stored? </code></pre><p>он будет храниться в стеке isr (irqstacksize). isr работает в отдельном стеке прерываний, только если оборудование его поддерживает. в противном случае кадры стека isr помещаются в стек прерванного потока.</p><p>пространство пользователя не знает и, честно говоря, не заботится о том, подается ли прерывание в стеке ядра текущего процесса или в отдельном стеке isr. поскольку прерывания поступают на процессор, следовательно, стек isr должен быть на процессор.</p><pre><code> does each process has its own kernel stack ? </code></pre><p>да. каждый процесс имеет свой собственный стек ядра.</p><pre><code> then how the process coordinates between both these stacks? </code></pre><p>@ откровение frankh мне кажется великолепным.</p>

<blockquote> <ol> <li>в чем разница между стеком ядра и пользовательским стеком</li> </ol> </blockquote><p>если взять ссылку из linux kernel development роберта лава, то основным отличием является размер:</p><blockquote> <p>пространство пользователя может избежать статического размещения множества переменных в стеке, включая огромные структуры и массивы из тысячи элементов.<br> такое поведение допустимо, поскольку в пространстве пользователя имеется большой стек, который может динамически расти.<br> стек ядра не является ни большим, ни динамическим; это маленький и фиксированный размер.<br> точный размер стека ядра зависит от архитектуры.<br> в x86 размер стека настраивается во время компиляции и может составлять 4 кб или 8 кб.<br> исторически, стек ядра состоит из двух страниц, что обычно подразумевает, что он равен 8 кб для 32-разрядных архитектур и 16 кб для 64-разрядных архитектур - этот размер является фиксированным и абсолютным.<br> каждый процесс получает свой собственный стек.</p> </blockquote><p>также стек ядра содержит указатель на структуру thread\_info, содержащую информацию о потоке.</p>