Главная страница
Навигация по странице:

  • Планировщик ввода-вывода nоор

  • Выбор планировщика ввода-вывода

  • Таблица 13.2.

  • Значение Тип планировщика

  • Адресное пространство процесса

  • Второе издание


    Скачать 3.09 Mb.
    НазваниеВторое издание
    Дата08.09.2019
    Размер3.09 Mb.
    Формат файлаpdf
    Имя файлаLav_Robert_Razrabotka_yadra_Linux_Litmir.net_264560_original_254.pdf
    ТипДокументы
    #86226
    страница39 из 53
    1   ...   35   36   37   38   39   40   41   42   ...   53
    Рис. 13.3. Три очереди планировщика ввода-вывода с лимитом по времени
    Следует заметить, что deadline-плаиировщик ввода-вывода не дает строгой га- рантии времени задержки запроса. Однако он, в общем, позволяет отправлять на обработку запросы до или вскоре после того, как истек их период ожидания. Это позволяет предотвратить ситуацию недостатка обслуживания запросов. Так как для запросов чтения максимальное время ожидания значительно больше, чем для запро- сов записи, то планировщик с лимитом по времени также позполяет гарантировать,
    что обслуживание запросов записи не приведет к недостатку обслуживания запросов чтения. Больший приоритет запросов чтения позволяет минимизировать время за- держки при операциях чтения.

    Код планировщика ввода-вывода с лимитом по времени находится в файле drivers/block/deadline-iosched.с.
    Прогнозирующий планировщик ввода-вывода
    Хотя планировщик с лимитом по времени ввода-вывода и выполняет работу по минимизации задержек чтения, это делается ценой уменьшения глобального бы- стродействия. Рассмотрим систему с большой активностью записи. Каждый раз, ког- да приходит запрос на чтение, планировщик сразу же начинает его выполнять. Это приводит к тому, что сразу же запускается операция поиска того места на диске, где будет выполнено чтение и сразу после выполнения чтения снова осуществляется по- иск того места, где будет выполнена запись, и так повторяется при каждом запросе чтения. Большой приоритет запросов чтения вещь хорошая, но две операции поис- ка на каждый запрос чтения (перемещение в точку чтения и обратно в точку записи)
    очень плохо сказываются на общей дисковой производительности. Цель прогнози- рующего планировщика ввода-вывода (anticipatory I/O scheduler) — обеспечение хо- роших характеристик по задержкам чтения и в то же время обеспечение отличной общей производительности.
    Прогнозирующий планировщик построен на базе планировщика ввода-вывода с лимитом но времени. Поэтому он не особо отличается. В прогнозирующем плани- ровщике реализованы три очереди (плюс очередь диспетчеризации) и обработка времени ожидания для каждого запроса, так же как и В случае deadline-планировщи- ка. Главное отличие состоит в наличии дополнительного эвристического прогнозирова-
    ния (anticipation heuristic).
    Прогнозирующий планировщик ввода-вывода пытается минимизировать "шторм операций поиска", который следует за каждым запросом чтения во время выполне- ния других дисковых операций. Когда поступает запрос на чтение, он обрабатывает- ся в рамках своего времени ожидания как обычно. После того как запрос отправлен жесткому диску, прогнозирующий планировщик сразу не возвращается к выполне- нию предыдущих запросов и не запускает операцию поиска сразу же. Он абсолютно ничего не делает в течение нескольких миллисекунд (значение этого периода време- ни можно настраивать, а по умолчанию оно равно 6 миллисекунд). Существует боль- шой шанс, что за эти несколько миллисекунд приложение отправит еще один запрос на чтение. Все запросы к соседним секторам диска выполняются немедленно. После
    .того как время ожидания истекает, прогнозирующий планировщик возвращается к выполнению ранее оставленных запросов и выполняет поиск соответствующего ме- ста на диске.
    Важно обратить внимание, что те несколько миллисекунд, в течение которых планировщик ожидает на новые запросы (т.е. время, которое планировщик тратит в предвещании нового запроса), полностью окупаются, даже если это позволяет ми- нимизировать всего лишь небольшой процент операций поиска при выполнении запросов чтения в случае большого количества других запросов. Если во время ожи- дания приходит запрос к соседней области диска, то это позволяет избежать двух операций поиска. Чем больше за это время приходит запросов к соседним областям диска, тем большего количества операций поиска можно избежать.
    Конечно, если в течение периода ожидания не было никакой активности, то про- гнозирующий планировщик зря потратит эти несколько миллисекунд.
    Уровень блочного ввода-вывода

    Ключевой момент для получения максимальной производительности от прогно- зирующего планировщика — правильно предсказать действия приложений и файло- вых систем. Это выполняется на основе эвристических алгоритмов и сбора статики.
    Прогнозирующий планировщик ведет статистику операций блочного ввода-вывода по каждому процессу в надежде предсказать действия приложений. При достаточно высоком проценте точных предсказаний прогнозирующий планировщик способен значительно снизить затраты на поиск при выполнении операций чтения и в то же время уделить внимание тем запросам, которые критичны для производительности системы. Это позволяет прогнозирующему планировщику минимизировать задержки чтения и в то же время уменьшить количество и продолжительность операций по- иска, что в свою очередь проявляется в уменьшении времени реакции системы и в увеличении ее производительности.
    Код прогнозирующего планировщика находится в файле d r i v e r s / b l o c k /
    a s - i o s c h e d . с дерева исходных кодов ядра.
    Этот планировщик используется в ядре Linux по умолчанию и хорошо работает для большинства типов нагрузки на систему. Он идеальный для серверов, однако ра- ботает очень плохо в случае определенных типов загрузки, которые встречаются не очень часто, как, например, в случае баз данных, рассчитанных на большое количе- ство операций поиска но диску.
    Планировщик ввода-вывода с полностью равноправными очередями
    Планировщик ввода-вывода с полностью равноправными очередями (Complete
    Fair Queuing, CFQ) был разработан для определенного типа нагрузок на систему, по на практике он позволяет получить хорошую производительность для широкого диа- пазона типов нагрузки. Он фундаментальным образом отличается от всех ранее рас- смотренных планировщиков ввода-вывода.
    Планировщик CFQ распределяет все приходящие запросы ввода-вывода по определенным очередям на основании того, какой процесс прислал этот запрос.
    Например, запросы от процесса foo идут в очередь foo, запросы от процесса bar — в очередь bar. В пределах каждой очереди запросы объединяются со смежными и со- ртируются. Таким образом очереди поддерживаются в отсортированном состоянии,
    так же как и в случае других планировщиков ввода-вывода. Отличие планировщика
    CFQ состоит в том, что он поддерживает отдельную очередь для каждого процесса,
    который выполняет операции ввода-вывода.
    После этого планировщик CFQ выполняет запросы из разных очередей по круго- вому алгоритму, выполняя конфигурируемое количество запросов (по умолчанию 4)
    из каждой очереди, перед тем как перейти к следующей. Это позволяет получить равномерное распределение пропускной способности диска для каждого процесса в системе. Предполагаемое использование такого планировщика— мультимедийные приложения, для которых он позволяет гарантировать, что, например, аудиопро- игрыватель всегда будет успевать вовремя заполнять аудиобуферы с диска. Тем не менее планировщик CFQ на практике хорошо работает для многих сценариев загру- женности системы.
    308 Глава 13

    Код CFQ планировщика находится в файле d r i v e r s / b l o c k / c f q - i o s c h e d . с .
    Этот планировщик рекомендуется для офисных компьютеров, хотя хорошо работает практически для всех типов нагрузок, за исключением, может быть, уж очень экстре- мальных типов загруженности.
    Планировщик ввода-вывода nоор
    Четвертый, и последний, тип планировщика ввода-вывода— это планировщик noop (no operation, с отсутствием операций). Он назван так потому, что практиче- ски ничего не делает. Этот планировщик не выполняет никакой сортировки или других операций для предотвращения поиска по устройству. Ему нет необходимости выполнять ничего, включая алгоритмы, которые минимизируют задержки и были рассмотрены для предыдущих планировщиков.
    Планировщик ввода-вывода nоор выполняет только объединение приходящих за- просов со смежными, которые находятся в очереди. Кроме этого, больше никаких функций у данного планировщика нет. Он просто обслуживает очередь запросов, ко- торые передаются драйверу блочного устройства, в режиме FIFO.
    Планировщик nоор не является полностью бесполезным. В том, что он ничего не делает, есть большой смысл. Он рассчитан на блочные устройства, которые позво- ляют выполнять истинно произвольный доступ, такие как платы флеш-памяти. Если для блочного устройства нет накладных затрат, связанных с поиском по устройству,
    то нет и необходимости выполнять сортировку и вставку вновь приходящих запро- сов, и планировщик nоор — идеальный вариант.
    Код планировщика nоор находится в файле drivers/block/noop-iosched.с.
    Он предназначен только для устройств с произвольным доступом.
    Выбор планировщика ввода-вывода
    В ядрах серии 2.6 есть четыре планировщика ввода-вывода. Каждый из этих пла- нировщиков может быть активизирован. По умолчанию все блочные устройства используют прогнозирующий планировщик ввода-вывода. Планировщик можно из- менить, указав параметр ядра elevator=<плaниpoвщик> в командной строке при загрузке системы, где <планировщик> — это один из поддерживаемых типов плани- ровщика, которые показаны в табл. 13.2.
    Таблица 13.2. Возможные значения параметра e l e v a t o r
    Например, указание параметра elevator=cfq в командной строке ядра при за- грузке системы означает, что для всех блочных устройств будет использоваться пла- нировщик с полностью равноправными очередями.
    Уровень блочного ввода-вывода 309
    Значение Тип планировщика
    as
    cfq deadline noop
    Прогнозирующий
    С полностью равноправными очередями
    С лимитом по времени
    С отсутствием операций (nоор)

    Резюме
    В этой главе были рассмотрены основы работы устройств блочного ввода-вывода,
    а также структуры данных, используемые для работы уровня ввода-вывода блоками:
    структура bio, которая представляет выполняемую операцию ввода-вывода; структу- ра buffer_head, которая представляет отображение блоков на страницы памяти;
    структура r e q u e s t , которая представляет собой отдельный запрос ввода-вывода.
    После рассмотрения запросов ввода-вывода был описан их короткий, но важный путь, кульминацией которого является прохождение через планировщик ввода-вы- вода. Были рассмотрены дилеммы, возникающие при планировании операций вво- да-вывода, и четыре типа планировщика, которые на данный момент существуют в ядре Linux, а также планировщик ввода вывода из ядра 2.4 — лифтовой алгоритм
    Линуса.
    Далее мы рассмотрим адресное пространство процесса.
    310
    Глава 13

    Адресное
    пространство процесса
    В
    главе 11, "Управление памятью", было рассказано о том, как ядро управляет физической намятью. В дополнение к тому, что ядро должно управлять своей памятью, оно также должно, управлять и адресным пространством процессов— тем,
    как память видится для каждого процесса в системе. Операционная система Linux —
    это операционная система с виртуальной памятью (virtual memory operating system),
    т.е. для всех процессов выполняется виртуализация ресурсов памяти. Для каждого процесса создается иллюзия того, что он один использует всю физическую память в системе. Еще более важно, что адресное пространство процессов может быть даже значительно больше объема физической памяти. В этой главе рассказывается о том,
    как ядро управляет адресным пространством процесса.
    Адресное пространство процесса состоит из диапазона адресов, которые выде- лены процессу, и, что более важно, в этом диапазоне выделяются адреса, которые процесс может так или иначе использовать. Каждому процессу выделяется "плоское"
    32- или 64-битовое адресное пространство. Термин "плоское" обозначает, что адрес- ное пространство состоит из одного диапазона адресов (например, 32-разрядное адресное пространство занимает диапазон адресов от 0 до 429496729). Некоторые операционные системы предоставляют сегментированное адресное простран- ство — адресное пространство состоит больше чем из одного диапазона адресов, т.е.
    состоит из сегментов. Современные операционные системы обычно предоставляют плоское адресное пространство. Размер адресного пространства зависит от аппарат- ной платформы. Обычно для каждого процесса существует свое адресное простран- ство. Адрес памяти в адресном пространстве одного процесса не имеет никакого от- ношения к такому же адресу памяти в адресном пространстве другого процесса. Тем не менее несколько процессов могут совместно использовать одно общее адресное пространство. Такие процессы называются потоками.
    Значение адреса памяти — это заданное значение из диапазона адресов адресного пространства, как, например, 41021f000. Это значение идентифицирует определен- ный байт в 32-битовом адресном пространстве. Важной частью адресного простран- ства являются интервалы адресов памяти, к которым процесс имеет право доступа,
    как, например, 08048000-0804с000. Такие интервалы разрешенных адресов называ- ются областями памяти (memory area). С помощью ядра процесс может динамически добавлять и удалять области памяти своего адресного пространства.

    Процесс имеет право доступа только к действительным областям памяти. Более того, на область памяти могут быть установлены права только для чтения или запрет на выполнение. Если процесс обращается к адресу памяти, который не находится в действительной области памяти, или доступ к действительной области выполня- ется запрещенным образом, то ядро уничтожает процесс с ужасным сообщением "Segmentation Fault" (ошибка сегментации).
    Области памяти могут содержать следующую нужную информацию.
    • Отображение выполняемого кода из выполняемого файла в область памяти процесса, которая называется сегментом кода (text section).
    Отображение инициализированных переменных из выполняемого файла в об- ласть памяти процесса, которая называется сегментом данных (data section).
    • Отображение страницы памяти, заполненной нулями, в область памяти про- цесса, которая содержит неинициализированные глобальные переменные и называется сегментом bss
    1
    (bss section). Нулевая страница памяти (zero page, стра- ница памяти, заполненная нулями) — это страница памяти, которая полностью заполнена нулевыми значениями и используется, например, для указанной выше цели.
    • Отображение страницы памяти, заполненной нулями, в память процесса, ко- торая используется в качестве стека процесса пространства пользователя (не нужно путать со стеком процесса в пространстве ядра, который является от- дельной структурой данных и управляется и используется ядром).
    • Дополнительные сегменты кода, данных и BSS каждой совместно используемой библиотеки, таких как библиотека libc и динамический компоновщик, которые загружаются в адресное пространство процесса.
    • Все файлы, содержимое которых отображено в память.
    • Все области совместно используемой памяти.
    • Все анонимные отображения в память, как, например, связанные с функцией m a l l o c ( )
    2
    Каждое действительное значение адреса памяти в адресном пространстве про- цесса принадлежит только и только одной области памяти (области памяти не перекрываются). Как будет показано, для каждого отдельного участка памяти в вы- полняющемся процессе существует своя область: стек, объектный код, глобальные переменные, отображенный в память файл и т.д.
    1
    Термин "BSS" сложился исторически и является достаточно старым. Он означает block started
    by symbol (блок, начинающийся с символа). Неинициализированные переменные в выпол- няемом файле не хранятся, поскольку с ними не связано никакого значения. Тем не менее стан- дарт языка С требует, чтобы неинициализированным переменным присваивалось определенное значение по умолчанию (обычно все заполняется нулями). Поэтому ядро загружает переменные
    (без их значений) из выполняемого файла в память и отображает в эту память нулевую страницу,
    тем самым переменным присваивается нулевое значение без необходимости зря тратить место в объектном файле на ненужную инициализацию.
    2
    В более новых версиях библиотеки giibc фушщия m a l l o c ( ) реализована через системный вызов
    ттар(), а не через вызов brk().
    312 Глава 14

    Дескриптор памяти
    Ядро представляет адресное пространство процесса в виде структуры данных, ко- торая называется дескриптором памяти. Эта структура содержит всю информацию,
    которая относится к адресному пространству процесса. Дескриптор памяти пред- ставляется с помощью структуры s t r u c t mm_struct, которая определена в файле
    <1inux/sched.h>
    3
    Рассмотрим эту структуру с комментариями, поясняющими назначение каждого поля.
    struct mm_struct {
    struct vm_area_struct *mmap; /* список областей памяти */
    struct rb_root mm_rb; /* красно-черное дерево областей памяти */
    struct vm_area_struct *mmap_cache; /*последняя использованная область памяти */
    unsigned long free_area_cache; /* первый незанятый участок адресного пространства */
    pgd_t *pgd; /* глобальный каталог страниц */
    atomic_t mm_users; /* счетчик пользователей адресного пространства */
    atomic_t mm_count; /* основной счетчик использования */
    int map_count; /* количество областей памяти */
    struct rw_semaphore mmap_sem; /* семафор для областей памяти */
    spinlock_t page_table_lock; /* спин-блокировка таблиц страниц */
    struct list_head mmlist; /* список всех структур mm_struct */
    unsigned long start_code; /* начальный адрес сегмента кода */
    unsigned long end code; /* конечный адрес сегмента кода */
    unsigned long start_data; /* начальный адрес сегмента данных */
    unsigned long end_data; /* конечный адрес сегмента данных */
    unsigned long start_brk; /* начальный адрес сегмента "кучи" */
    unsigned long brk; /* конечный адрес сегмента "кучи" */
    unsigned long start_stack; /* начало стека процесса */
    unsigned long arg_start; /* начальный адрес области аргументов */
    unsigned long arg_end; /* конечный адрес области аргументов */
    unsigned long env_start; /*начальный адрес области переменных среды */
    unsigned long env_end; /*конечный адрес области переменных среды */
    unsigned long rss; /* количество физических страниц памяти */
    unsigned long total_vm; /* общее количество страниц памяти */
    unsigned long locked_vm; /* количество заблокированных страниц памяти */
    unsigned long def_flags; /* флаги доступа, используемые по умолчанию */
    unsigned long cpu_vm_mask; /*MacKa отложенного переключения буфера TLB */
    unsigned long swap_address; /* последний сканированный адрес */
    unsigned dumpable:l; /* можно ли создавать файл core? */
    int used_hugetlb; /* используются ли гигантские страницы памяти (hugetlb)? */
    3
    Между дескриптором процесса, дескриптором памяти и соответствующими функциями существует тесная связь. Поэтому структура s t r u c t mm_struct и определена в заголовочном файле sched.h.
    Адресное пространство процесса
    313
    mm_context_t context; /* данные, специфичные для аппаратной платформы */
    int core_waiters; /* количество потоков, ожидающих на создание файла core */
    struct completion *core_startup_donc; /* условная переменная начала создания файла core */
    struct completion core_done; /* условная переменная завершения создания файла core */
    rwlock_t ioctx_l.ist_lock; /* блокировка списка асинхронного ввода-вывода (AIO) */
    struct kioctx *ioctx_list; /* список асинхронного ввода-вывода (AIO) V
    struct kioctx default kioctx; /* контекст асинхронного ввода- вывода, используемый по умолчанию */
    };
    Поле mm_users — это количество процессов, которые используют данное адрес- ное пространство. Например, если одно и то же адресное пространство совмест- но используется двумя потоками, то значение поля mm_users равно двум. Поле ram_count — это основной счетчик использования структуры mm_struct. Наличие пользователей структуры, которым соответствует поле mm_users, приводит к уве- личению счетчика mm_count на единицу. В предыдущем примере значение поля mm_count равно единице. Когда значение поля mm_users становится равным нулю
    (т.е. когда два потока завершатся), только тогда значение поля mm_count уменьша- ется на единицу. Когда значение поля mm_count становится равным нулю, то на соответствующую структуру m m _ s t r u c t больше нет ссылок, и она освобождается,
    Поддержка двух счетчиков позволяет ядру отличать главный счетчик использова- ния (mm_count) от количества процессов, которые используют данную структуру
    (mm_users).
    Поля mmap и mm_rb — это два различных контейнера данных, которые содержат одну и ту же информацию: информацию обо всех областях памяти в соответству- ющем адресном пространстве. В первом контейнере эта информация хранится в виде связанного списка, а во втором— в виде красно-черного бинарного дерева.
    Поскольку красно-черное дерево — это разновидность бинарного дерева, то, как и для всех типов бинарного дерева, количество операций поиска заданного элемента в нем равно О(log (n) ). Более детальное рассмотрение красно-черных деревьев най- дете в разделе "Списки и деревья областей памяти".
    Хотя обычно в ядре избегают избыточности, связанной с введением нескольких структур для хранения одних и тех же данных, тем не менее в данном случае эта избыточность очень кстати. Контейнер mmap — это связанный список, который по- зволяет очень быстро проходить по всем элементам. С другой стороны, контейнер mm_rb — это красно-черное дерево, которое очень хорошо подходит для поиска за- данного элемента. Области памяти будут рассмотрены в этой главе несколько ниже,
    Все структуры mm_struct объединены в двухсвязный список с помощью нолей mmlist. Первым элементом этого списка является дескриптор памяти init_mm, ко- торый является дескриптором памяти процесса ink. Этот список защищен от конку- рентного доступа с помощью блокировки mmlist_lock, которая определена в фай- ле k e r n e l / f o r k . с . Общее количество дескрипторов памяти хранится в глобальной целочисленной переменной mmlist_nr, которая определена в том же файле.
    314 Глава 14

    Выделение дескриптора памяти
    Указатель на дескриптор памяти, выделенный для какой-либо задачи, хранится в поле mm дескриптора процесса этой задачи. Следовательно, выражение current->rnm позволяет получить дескриптор памяти текущего процесса. Функция copy_mm() ис- пользуется для копирования дескриптора родительского процесса в дескриптор по- рожденного процесса во время выполнения вызова fоrk ( ) . Структура m m _ s t r u c t выделяется из слябового кэша mm_cachep с помощью макроса allocate_mm (). Это реализовано в файле k e r n e l / f o r k . с . Обычно каждый процесс получает уникаль- ный экземпляр структуры mm_struct и соответственно уникальное адресное про- странство.
    Процесс может использовать одно и то же адресное пространство совместно со своими порожденными процессами, путем указания флага CLONE_VM при выполне- нии вызова c l o n e (). Такие процессы называются потоками. Вспомните из матери- ала главы 3, "Управление процессами", что в операционной системе Linux в этом и состоит единственное существенное отличие между обычными процессами и потока- ми. Ядро Linux больше никаким другим образом их не различает. Потоки с точки зрения ядра— это обычные процессы, которые просто совместно используют неко- торые общие ресурсы.
    В случае, когда указан флаг CLONE_VM, макрос allocate_mm() не вызывается, а в поле mm дескриптора порожденного процесса записывается значение указателя на дескриптор памяти родительского процесса. Это реализовано с. помощью следующе- го оператора ветвления в функции сору_mm ().
    if (clone_flags & CLONE_VM) {
    /*
    * c u r r e n t — это родительский процесс
    * tsk — это процесс, порожденный в вызове fork()
    */
    atomic_inc(¤t->mm->mm_users);
    tsk->mm = current->mm;
    }
    Удаление дескриптора памяти
    Когда процесс, связанный с определенным адресным пространством, завершает- ся, то вызывается функция exit_mm() . Эта функция выполняет некоторые служеб- ные действия и обновляет некоторую статистическую информацию. Далее вызыва- ется функция input() , которая уменьшает на единицу значение счетчика количества пользователей mm_users для дескриптора памяти. Когда значение счетчика коли- чества пользователей становится равным нулю, то вызывается функция m m d r o p ( ) ,
    которая уменьшает значение основного счетчика использования mm_count. Когда и этот счетчик использования наконец достигает нулевого значения, то вызывается функция free_mm(), которая возвращает экземпляр структуры mm_struct в слябо- вый кэш mm_cachep с помощью вызова функции kmem_cache_fгее(), поскольку де-.
    скриптор памяти больше не используется.
    Адресное пространство процесса 315

    Структура mm_struct и потоки пространства ядра
    Потоки пространства ядра не имеют своего адресного пространства процесса и,
    следовательно, связанного с ним дескриптора памяти. Значение поля mm для потока пространства ядра равно NULL. Еще одно определение потока ядра — это процесс, ко- торый не имеет пользовательского контекста.
    Отсутствие адресного пространства— хорошее свойство, поскольку потоки ядра вообще не обращаются к памяти в пространстве пользователя (действительно, к ка- кому адресному пространству им обращаться?). Поскольку потоки ядра не обращают- ся к страницам памяти в пространстве пользователя, им вообще не нужен дескрип- тор памяти и таблицы страниц (таблицы страниц обсуждаются дальше в этой главе).
    Несмотря на это, потокам пространства ядра все же нужны некоторые структуры данных, такие как таблицы страниц, чтобы обращаться к памяти ядра. Чтобы обе- спечить потоки ядра всеми данными без необходимости тратить память на дескрип- тор памяти и таблицы страниц, а также процессорное время на переключение на новое адресное пространство и так далее, каждый поток ядра использует дескрип- тор памяти задания, которое выполнялось перед ним.
    Когда процесс запланирован на выполнение, то загружается адресное простран- ство, на которое указывает поле mm этого процесса. Поле a c t i v e _ m m дескриптора процесса обновляется таким образом, чтобы указывать на новое адресное простран- ство. Потоки ядра не имеют своего адресного пространства, поэтому значение поля mm для них равно NULL. Поэтому, когда поток ядра планируется на выполнение, ядро определяет, что значение ноля mm равно NULL, и оставляет загруженным предыдущее адресное пространство. После этого ядро обновляет поле active_mm дескриптора процесса для потока ядра, чтобы он указывал на дескриптор памяти предыдущего процесса. При необходимости поток ядра может использовать таблицы страниц предыдущего процесса. Так как потоки ядра не обращаются к памяти в пространстве пользователя, то они используют только ту информацию об адресном пространстве ядра, которая связана с памятью ядра и является общей для всех процессов.
    Области памяти
    Области памяти (memory areas) представляются с помощью объектов областей памяти, которые хранятся в структурах типа v m _ a r e a _ s t r u c t . Эта структура опре- делена в файле . Области памяти часто называются областями вирту-
    альной памяти (virtual memory area, или VMA).
    Структура v m _ a r e a _ s t r u c t описывает одну непрерывную область памяти в дан- ном адресном пространстве. Ядро рассматривает каждую область памяти, как уни- кальный объект. Для каждой области памяти определены некоторые общие свой- ства, такие как права доступа и набор соответствующих операций. Таким образом,
    одна структура VMA может представлять различные типы областей памяти, напри- мер файлы, отображаемые в память, или стек пространства пользователя. Это анало- гично объектно-ориентированному подходу, который используется в подсистеме VFS
    (см .главу 12, "Виртуальная файловая система").
    Ниже показана эта структура данных с комментариями, описывающими назначе- ние каждого поля.
    316 Глава 14
    struct vm_area_struct {
    struct mm_struct *vm_mm; /* соответствующая структура mm_struct */
    unsigned long vm_start; /* начало диапазона адресов */
    unsigned long vm_end; /* конец диапазона адресов */
    struct vm_area_struct *vm_next; /* список областей VMA */
    pgprot_t vm_page_prot; /* права доступа */
    unsigned long vm_flags; /* флаги */
    struct rb_node vm_rb; /* узел текущей области VMA */
    union { /* связь с address_space->i_mmap, или i_mmap_nonlinear */
    struct {
    struct list_head list;
    void *parent;
    struct vm_area_struct *head;
    } vm_set;
    struct prio_tree_node prio_tree_node;
    } shared;
    struct list_head anon_vma_node; /* анонимные области */
    struct anon_vma *anon_vma; /* объект анонимной VMA */
    struct vm_operations_struct *vm_ops; /* операции */
    unsigned long vm_pgoff; /* смещение в файле */
    struct file *vm_file; /* отображенный файл (если есть) */
    void *vm_private_data; /* приватные данные */
    };
    Как уже было рассказано, каждый дескриптор памяти связан с уникальным диа- пазоном (интервалом) адресов в адресном пространстве процесса. Поле vm_start —
    это начальный (минимальный) адрес, а поле vm_end— конечный (максимальный)
    адрес данного интервала
    1   ...   35   36   37   38   39   40   41   42   ...   53


    написать администратору сайта