Размер стека, используемый при разработке ядра

Я разрабатываю операционную систему, и вместо того, чтобы программировать ядро, я проектирую ядро. Эта операционная система ориентирована на архитектуру x86, а моя цель — на современные компьютеры. Расчетное количество требуемой оперативной памяти составляет 256 МБ или более.

Каков хороший размер стека для каждого потока, работающего в системе? Должен ли я попытаться спроектировать систему таким образом, чтобы стек мог автоматически расширяться при достижении максимальной длины?

Я думаю, если я правильно помню, что страница в оперативной памяти составляет 4 КБ или 4096 байт, и мне это не кажется большим. Я определенно вижу моменты, особенно при использовании большого количества рекурсий, когда я хотел бы иметь более 1000 целых чисел в ОЗУ одновременно. Теперь реальным решением было бы, чтобы программа делала это с помощью malloc и управляла своими собственными ресурсами памяти, но на самом деле я хотел бы узнать мнение пользователей по этому поводу.

Достаточно ли 4k для стека с современными компьютерными программами? Должен ли стек быть больше? Должен ли стек автоматически расширяться для размещения любых типов размеров? Меня это интересует как с практической точки зрения разработчика, так и с точки зрения безопасности.

4k слишком много для стека? Рассматривая обычное выполнение программы, особенно с точки зрения классов в C++, я заметил, что хороший исходный код имеет тенденцию malloc/new использовать данные, которые ему нужны, когда создаются классы, чтобы свести к минимуму количество данных, перебрасываемых при вызове функции.

Чего я даже не касался, так это размера кэш-памяти процессора. В идеале я думаю, что стек должен находиться в кеше, чтобы ускорить работу, и я не уверен, нужно ли мне этого добиваться, и сможет ли процессор справиться с этим за меня. Я просто планировал использовать обычную скучную старую оперативную память для тестирования. Я не могу решить. Какие есть варианты?


person Nicholas Flynt    schedule 13.10.2008    source источник


Ответы (5)


Размер стека зависит от того, что делают ваши потоки. Мой совет:

  • сделайте размер стека параметром во время создания потока (разные потоки будут делать разные вещи и, следовательно, потребуются разные размеры стека)
  • предоставить разумное значение по умолчанию для тех, кто не хочет заморачиваться с указанием размера стека (4K привлекает во мне помешанного на контроле, так как это приведет к тому, что стек-расточительство, э-э, получит сигнал довольно быстро)
  • подумайте, как вы будете обнаруживать и справляться с переполнением стека. Обнаружение может быть сложным. Вы можете поместить защитные страницы — пустые — в конце стека, и это, как правило, будет работать. Но вы полагаетесь на поведение Плохой Нити, чтобы не перепрыгнуть через этот ров и не начать загрязнять то, что лежит за ним. Как правило, этого не происходит... но именно это и делает действительно крутых жуков крутыми. Герметичный механизм включает в себя взлом вашего компилятора для генерации кода проверки стека. Что касается борьбы с переполнением стека, вам понадобится выделенный стек где-то еще, на котором будет работать поток-нарушитель (или его ангел-хранитель, кого бы вы ни выбрали — в конце концов, вы разработчик ОС).
  • Я бы настоятельно рекомендовал пометить концы вашего стека характерным шаблоном, чтобы, когда ваши потоки выходят за концы (а они всегда так и делают), вы могли, по крайней мере, пройти вскрытие и увидеть, что что-то на самом деле вышло из своего состояния. куча. Удобна страница 0xDEADBEEF или что-то в этом роде.

Кстати, размеры страницы x86 обычно 4k, но это не обязательно. Вы можете выбрать размер 64k или даже больше. Обычная причина больших страниц — избежать промахов TLB. Опять же, я бы сделал это конфигурацией ядра или параметром времени выполнения.

person bog    schedule 13.10.2008
comment
Я никогда не думал о том, чтобы что-то настроить во время компиляции. Мне также, кажется, нравится 4k, помешанный на управлении говорит мне, что если вам действительно нужно использовать больше памяти, чем это, вы должны делать это с помощью malloc. ^_^ Тем не менее, есть сумасшедшие программисты ИИ, которые любят свою рекурсию. - person Nicholas Flynt; 13.10.2008
comment
если вы снова и снова выделяете много объектов одного и того же размера, вам следует рассмотреть распределитель с фиксированным блоком. Это может быть намного эффективнее, чем malloc общего назначения. - person bog; 13.10.2008
comment
Размеры страниц x86 ограничены и зависят от множества факторов (включая режимы процессора и т. д.). Но могут существовать размеры страниц: 4 КБ, 2 МБ, 4 МБ и 1 ГБ. Ни в одной из существующих конфигураций x86/x86-64 нет страницы размером 64 КБ. - person Michael Petch; 28.08.2019

Найдите KERNEL_STACK_SIZE в исходном коде ядра Linux, и вы обнаружите, что он очень сильно зависит от архитектуры — PAGE_SIZE или 2*PAGE_SIZE и т. д. (ниже приведены лишь некоторые результаты — многие промежуточные выходные данные удалены).

./arch/cris/include/asm/processor.h:
#define KERNEL_STACK_SIZE PAGE_SIZE

./arch/ia64/include/asm/ptrace.h:
# define KERNEL_STACK_SIZE_ORDER        3
# define KERNEL_STACK_SIZE_ORDER        2
# define KERNEL_STACK_SIZE_ORDER        1
# define KERNEL_STACK_SIZE_ORDER        0
#define IA64_STK_OFFSET         ((1 << KERNEL_STACK_SIZE_ORDER)*PAGE_SIZE)
#define KERNEL_STACK_SIZE       IA64_STK_OFFSET

./arch/ia64/include/asm/mca.h:
    u64 mca_stack[KERNEL_STACK_SIZE/8];
    u64 init_stack[KERNEL_STACK_SIZE/8];

./arch/ia64/include/asm/thread_info.h:
#define THREAD_SIZE         KERNEL_STACK_SIZE

./arch/ia64/include/asm/mca_asm.h:
#define MCA_PT_REGS_OFFSET      ALIGN16(KERNEL_STACK_SIZE-IA64_PT_REGS_SIZE)

./arch/parisc/include/asm/processor.h:
#define KERNEL_STACK_SIZE   (4*PAGE_SIZE)

./arch/xtensa/include/asm/ptrace.h:
#define KERNEL_STACK_SIZE (2 * PAGE_SIZE)

./arch/microblaze/include/asm/processor.h:
# define KERNEL_STACK_SIZE  0x2000
person Peter Teoh    schedule 14.05.2011

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

  • Я не уверен, каким будет «типичный» размер стека. Я бы предположил, что может быть 8 КБ на поток, и если поток превышает этот объем, просто создайте исключение. Однако, согласно этому, Windows имеет зарезервированный размер стека по умолчанию 1 МБ на поток, но он не фиксируется сразу (страницы фиксируются по мере необходимости). Кроме того, вы можете запросить другой размер стека для данного EXE-файла во время компиляции с помощью директивы компилятора. Не уверен, что делает Linux, но я видел ссылки на стеки по 4 КБ (хотя я думаю, что это можно изменить при компиляции ядра, и я не уверен, каков размер стека по умолчанию...)

  • Это связано с первым пунктом. Вероятно, вам нужен фиксированный лимит на количество стека, которое может получить каждый поток. Таким образом, вы, вероятно, не хотите автоматически выделять больше пространства стека каждый раз, когда поток превышает свое текущее пространство стека, потому что программа с ошибками, которая застревает в бесконечной рекурсии, съест всю доступную память.

person Mike Spross    schedule 13.10.2008

Если вы используете виртуальную память, вы хотите сделать стек расширяемым. Принудительное статическое распределение размера стека, как это часто бывает в потоках на уровне пользователя, таких как Qthreads и Windows Fibers, — это беспорядок. Трудно использовать, легко разбить. Все современные ОС динамически увеличивают стек, я думаю, обычно за счет наличия одной или двух защищенных от записи защитной страницы ниже текущего указателя стека. Записывает туда, а затем сообщает ОС, что стек стал ниже выделенного пространства, и вы выделяете новую защитную страницу ниже этого и делаете страницу, на которую попали, доступной для записи. Пока ни одна функция не выделяет больше страницы данных, это работает нормально. Или вы можете использовать две или четыре защитных страницы, чтобы разрешить кадры стека большего размера.

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

person jakobengblom2    schedule 13.10.2008
comment
Я вижу здесь два недостатка. Основная из них — позволить системе самостоятельно переполнять стек. Если я сделаю это, все, что потребуется, — это один рекурсивный бесконечный цикл и бламо, стек для 1 процесса внезапно поглотит весь компьютер ... Что касается однократной сделки, это многозадачная ОС, поэтому там нет бобов. - person Nicholas Flynt; 13.10.2008

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

Существует множество способов настроить это.

Существует рекомендация, в которой указано «0, 1 или n», что означает, что вы должны разрешить ноль, один или любое количество (ограниченное другими ограничениями, такими как память) объекта — это также относится к размерам объектов.

person paxdiablo    schedule 13.10.2008