netlib.narod.ru< Назад | Оглавление | Далее >

Компоновка процессов памяти

Важным средством обеспечения использования процессом отведенной ему памяти являются следующие три структуры данных: struct vm_area_struct (строка 15113), struct vm_operations_struct (строка 15171) и struct mm_struct (строка 16270). В этом разделе последовательно рассматривается каждая из этих структур данных.

struct vm_area_struct

Ядро следит за областями памяти, используемыми процессом, с помощью набора из одного или нескольких объектов struct vm_area_struct, которые принято сокращенно обозначать как VMA. Каждая структура VMA представляет одну сплошную область адресного пространства процесса. Две области VMA никогда не перекрываются — в каждом конкретном процессе адрес может принадлежать не более, чем к одной области VMA; адрес, к которому процесс не обращался никоим образом, не принадлежит ни к одной области VMA.

Одну область VMA отличают от другой следующие две особенности:

Отметим следующий важный факт: адрес может быть уже охвачен областью VMA, даже несмотря на то, что ядро еще не выделило страницу для его хранения. И действительно, одно из основных назначений областей VMA состоит в поддержке принятия решения о том, как реагировать, когда возникает ситуация отсутствия страницы. Можно считать VMA абстрактным описанием областей памяти, о которых известно процессу, и способов защиты этих областей. Ядро могло бы повторно вычислять большую часть информации, содержащейся в структурах VMA, из таблиц страниц, но это происходило бы гораздо медленнее.

Структуры VMA процесса хранятся в виде отсортированного списка с двойными связями, в котором для управления списком используются указатели в самих структурах VMA. Когда процесс приобретает такое число структур VMA, которое превышает величину AVL_MIN_MAP_COUNT (установлена директивой #define равной 32 в строке 16268), ядро создает также для их хранения дерево AVL, опять-таки с применением указателей в самих структурах VMA для управления этим деревом. Дерево AVL — это информационная структура в виде уравновешенного двоичного дерева, поэтому такой подход обеспечивает значительное повышение эффективности поиска при увеличении числа областей VMA. Однако даже после построения дерева AVL поддерживается и линейный список, чтобы ядро могло последовательно просматривать все структуры VMA процесса легко и без рекурсии.

Двумя наиболее важными элементами объекта struct vm_area_struct являются его члены vm_start и vm_end (соответственно, строки 15115 и 15116), которые определяют начало и конец диапазона адресов, охваченных областью VMA: vm_start — это наименьший адрес в области VMA, a vm_end — на единицу больше наибольшего адреса. В данной главе эти члены будут упоминаться неоднократно.

Обратите внимание, что vm_start и vm_end имеют тип unsigned long, а не void *, как можно было бы ожидать. Отметим, что в ядре тип данных unsigned long применяется вместо void * во всех местах, где должны быть представлены адреса. Это отчасти предусмотрено для предотвращения появления предупреждающих сообщений компилятора при проведении некоторых вычислений, которые ядро должно выполнять над этими адресами (типа поразрядных операций), и, возможно, также отчасти для предотвращения случайной разадресации с их использованием. При обращении к адресу структуры данных, существующей в пространстве ядра, код ядра использует переменную с указателем. При манипуляции адресами в пространстве пользователя он часто использует unsigned long, и действительно, в коде, рассматриваемом в данной главе, применяется почти исключительно только этот тип данных.

Отметим, что это накладывает определенные ограничения на компилятор, который используется для компиляции ядра. Применение в качестве адресов переменных с типом данных unsigned long означает, что компилятор должен использовать для unsigned long тип данных такого же размера, как для void *. Однако на практике эти ограничения не столь существенны. При использовании компилятора gcc на компьютере х86 оба эти типа, естественно, имеют размер 32 бита. В архитектурах с 64-разрядными указателями, таких, как Alpha, тип данных unsigned long компилятора gcc также обычно имеет размер 64 бита. Тем не менее, в будущем в результате переноса компилятора gcc на другую архитектуру тип данных unsigned long может приобрести в нем размер, отличный от void *, и эту возможность должны всегда учитывать те, кто занимаются переносом ядра на другую архитектуру.

Кстати отметим, что изучая возможность применения компиляторов, отличных от gcc, нужно учитывать, что в самом коде ядра уже присутствует значительная часть других особенностей, свойственных gcc. Вполне можно себе представить, что при попытке скомпилировать ядро с использованием какого-то другого компилятора к многочисленному списку полученных ошибок добавится множество сообщений, связанных с различием относительных размеров типов данных unsigned long и void *.

struct vm_operations_struct

Область VMA может представлять обычный участок памяти, типа того, какой возвращает функция malloc. Однако она может также представлять область памяти, которая была установлена в качестве соответствия файлу, участку разделяемой памяти, разделу свопинга или какому-то иному специальному объекту; такое соответствие устанавливается с помощью системного вызова mmap, рассматриваемого далее в этой главе.

Однако вряд ли кто-то захочет засорять код ядра конкретной информацией о каждом из объектов, на который может быть отображена структура VMA, поскольку необходимость снова и снова принимать решение о закрытии файла, отключении от разделяемой памяти и т.д. привела бы к значительному усложнению кода. Вместо этого, в объекте типа struct vm_operations_struct применяется абстрактное представление всех доступных операций, предусмотренных в объекте, на который отображена область памяти VMA: open, close и т.д. Объект struct vm_operations_struct — это просто набор указателей на функции, часть которых может быть установлена в NULL для указания о том, что данная операция не доступна для отображаемого объекта данного типа. Например, поскольку нет смысла синхронизировать страницы объекта разделяемой памяти с диском, если разделяемая память не участвует в отображении, в составе операций с разделяемой памятью в объекте struct vm_operations_struct функция синхронизации будет установлена в NULL.

Все это означает, что если область VMA отображена на какой-либо объект, то член vm_ops структуры VMA — это отличный от NULL указатель на объект struct vm_operations_struct, который представляет операции, поддерживаемые отображаемым объектом. Для объекта каждого типа, на который может быть отображена область VMA, где-то существует единственный статический объект struct vm_operations_struct, на который могут указывать структуры VMA. В качестве примера можно указать строку 21809.

struct mm_struct

Все области VMA, зарезервированные процессом, находятся под управлением объекта struct mm_struct. Указателем на структуру этого типа является член mm структуры struct task_struct. Это именно тот параметр, который применялся в функции goodness (строка 26388) в предыдущей главе для определения того, находились ли две задачи в одной и той же группе потоков. Две задачи, которые имеют один и тот же член mm (как мы теперь знаем), управляют одними и теми же областями глобальной памяти, а это является отличительной особенностью потоков.

Член mmap объекта struct mm_struct (строка 16271) представляет собой связанный список структур VMA, упомянутый ранее, а его член mmap_avl, если он отличен от NULL, представляет собой дерево AVL структур VMA. Как можно убедиться, вкратце ознакомившись с его определением, объект struct mm_struct включает довольно значительное число других членов, часть которых рассматривается в этой главе.


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz