Указатель на дескриптор памяти, выделенный для какой-либо задачи, хранится в поле mm
дескриптора процесса этой задачи. Следовательно, выражение current->mm
позволяет получить дескриптор памяти текущего процесса. Функция copy_mm()
используется для копирования дескриптора родительского процесса в дескриптор порожденного процесса во время выполнения вызова fork()
. Структура mm_struct
выделяется из слябового кэша mm_cachep
с помощью макроса allocate_mm()
. Это реализовано в файле kernel/fork.c
. Обычно каждый процесс получает уникальный экземпляр структуры mm_struct
и соответственно уникальное адресное пространство.
Процесс может использовать одно и то же адресное пространство совместно со своими порожденными процессами, путем указания флага CLONE_VM
при выполнении вызова clone()
. Такие процессы называются потоками. Вспомните из материала главы 3, "Управление процессами", что в операционной системе Linux в этом и состоит
В случае, когда указан флаг CLONE_VM
, макрос allocate_mm()
не вызывается, а в поле mm дескриптора порожденного процесса записывается значение указателя на дескриптор памяти родительского процесса. Это реализовано с. помощью следующего оператора ветвления в функции сору_mm()
.
if (clone_flags & CLONE_VM) {
/*
* current — это родительский процесс
* tsk — это процесс, порожденный в вызове fork()
*/
atomic_inc(¤t->mm->mm_users);
tsk->mm = current->mm;
}
Удаление дескриптора памяти
Когда процесс, связанный с определенным адресным пространством, завершается, то вызывается функция exit_mm()
. Эта функция выполняет некоторые служебные действия и обновляет некоторую статистическую информацию. Далее вызывается функция mput()
, которая уменьшает на единицу значение счетчика количества пользователей mm_users
для дескриптора памяти. Когда значение счетчика количества пользователей становится равным нулю, то вызывается функция mmdrop()
, которая уменьшает значение основного счетчика использования mm_count
. Когда и этот счетчик использования наконец достигает нулевого значения, то вызывается функция free_mm()
, которая возвращает экземпляр структуры mm_struct
в слябовый кэш mm_cachep
с помощью вызова функции kmem_cache_free()
, поскольку дескриптор памяти больше не используется.
Структура mm_struct
и потоки пространства ядра
Потоки пространства ядра не имеют своего адресного пространства процесса и, следовательно, связанного с ним дескриптора памяти. Значение поля mm
для потока пространства ядра равно NULL
. Еще одно
Отсутствие адресного пространства— хорошее свойство, поскольку потоки ядра вообще не обращаются к памяти в пространстве пользователя (действительно, к какому адресному пространству им обращаться?). Поскольку потоки ядра не обращаются к страницам памяти в пространстве пользователя, им вообще не нужен дескриптор памяти и таблицы страниц (таблицы страниц обсуждаются дальше в этой главе). Несмотря на это, потокам пространства ядра все же нужны некоторые структуры данных, такие как таблицы страниц, чтобы обращаться к памяти ядра. Чтобы обеспечить потоки ядра всеми данными без необходимости тратить память на дескриптор памяти и таблицы страниц, а также процессорное время на переключение на новое адресное пространство и так далее, каждый поток ядра использует дескриптор памяти задания, которое выполнялось перед ним.
Когда процесс запланирован на выполнение, то загружается адресное пространство, на которое указывает поле mm
этого процесса. Поле active
_mm дескриптора процесса обновляется таким образом, чтобы указывать на новое адресное пространство. Потоки ядра не имеют своего адресного пространства, поэтому значение поля mm для них равно NULL
. Поэтому, когда поток ядра планируется на выполнение, ядро определяет, что значение ноля mm
равно NULL
, и оставляет загруженным предыдущее адресное пространство. После этого ядро обновляет поле active_mm
дескриптора процесса для потока ядра, чтобы он указывал на дескриптор памяти предыдущего процесса. При необходимости поток ядра может использовать таблицы страниц предыдущего процесса. Так как потоки ядра не обращаются к памяти в пространстве пользователя, то они используют только ту информацию об адресном пространстве ядра, которая связана с памятью ядра и является общей для всех процессов.