Подсистема виртуальной памяти

Адресное пространство Фантома выглядит так:

Зелёная область имеет фиксированный размер и содержит "подземелье". Синяя - надземелье. Размер её может меняться.

В синей области живут объекты. Она разделена на страницы с точки зрения VM. Страницы и объекты пересекаются произвольным образом. Объект может занимать несколько страниц, несколько объектов могут занимать страницу, "дыр" специальным образом не делается - выделение памяти под объекты с началом страницы не увязывается.

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

Область, отмеченная как "данные" используется специфическим образом. Содержимое её не сохраняется при останове машины и, соответственно, в ней не может храниться ничего существенного для продолжения работы. Фактически, основная потребность в ней существует в момент загрузки системы. Эта область используется для работы механизма восстановления состояния виртуальной памяти. По всей видимости, к моменту, когда работа ОС началась этот фрагмент памяти можно освободить.

Область, помеченая как "код" загружается, собственно, кодом микроядра - подземелья. Существенная её часть также необходима только на момент запуска системы и может быть освобождена впоследствии.

Загрузка системы

При загрузке системы ядро должно получить от загрузчика информацию о том, где располагается системный диск. Шаги:

1. Проверка целостности и восстановление структур данных системного диска. К концу шага диск должен содержать полноценный срез состояния системы. Если этого достичь нельзя - система не запускается.

2. Если существуют другие диски (информация об этом - на системном диске) - аналогичная операция производится для них, по возможности - параллельно.

3. Загрузка карты памяти, включение системы виртуализации.

К концу шагов 1-3 адресное пространство сформировано полностью - синяя зона сформирована и содержит состояние системы на момент последней его фиксации.

4. Предпринимаются действия, необходимые для сигнализации объектам системы о том, что происходил рестарт. По всей видимости, они заключаются в посылке нитям exception-а соответствующего типа. Вероятно, путём формирования в стеках нитей кадра вызова подпрограммы и переключения их кода на специальную точку, которая выполняет throw соответствующего типа.

5. Начало синей зоны содержит адрес объекта, содержащего состояние диспетчера нитей. Им инициализируется интерпретатор, инициируется переключение контекста на готовую к исполнению нить, зона "данные" и часть зоны "код" освобождаются, интерпретатор запускается.

Система работает.

Структура диска

Суперблок, зона загрузки, зона настройки, список свободных. Списков занятых и т.п. на уровне отдельного диска не ведётся.

Зона загрузки - список блоков с микроядром. Зона настройки - блок параметров загрузчика. В том числе - список дисков.

Срез - последовательный список номеров блоков диска, составляющих записанное состояние системы.

Структура карты памяти

Страница адресного пространства

struct vm_page {
daddr_t actual; // адрес блока диска, где лежит копия
bool changed; // 0 - страница RO, копия - в срезе, при попытке
// записи - выделить новую копию, писать в неё.
// 1 - страница изменилась

vm_page *disk_queue; // для очереди запросов к диску

void pagein_done();
void pageout_done();

vm_page *next; // для увязывания в пулы - классическая vm...

bool in_ram; // под нами есть физическая память
caddr_t phys_addr; // Вот она

bool locked; // Нельзя отбирать память - I/O идёт

void assign_ram (caddr_t); // выдать память
void revoke_ram(); // отобрать. если locked - NOP

};

Страница физической памяти

struct vm_ram_page {

caddr_t phys_addr;
vm_ram_page *next; // для списка свободных

};

 

 

Формирование среза

На этот момент имеется:

1. Предыдущий срез, который включает в себя список всех страниц, соответствующих состоянию системы на момент его формирования. Размер So среза в страницах.

2. Множество страниц, изменившихся с момента формирования предыдущего среза. Размер Sn актуального адресного пространства в страницах. Все эти страницы имеют рабочую копию на диске или, по крайней мере, им назначено дисковое пространство - это нужно, чтобы не случилось нехватки диска на момент формирования среза.

3. Список свободных блоков диска.

4. Зарезервированный для подсистемы виртуальной памяти объём дисковой памяти, необходимый для формирования среза.

Процесс.

1. Создаём новый список блоков среза. Размер - сообразно So.

2. Все изменившиеся страницы сбрасываем на диск, блокируем скинутое от изменений. С этого момента при попытке изменить страницу ей будет выделяться новый, третий блок на диске. Если это невозможно, нить будет блокироваться до конца формирования среза. Если и после этого не обнаружится свободное пространство - нить получит exception. Это - штатный способ сообщить от нехватке памяти.

3. Заполняем список блоков среза. При этом если страница изменилась - включается изменившаяся копия, а адрес блока диска, где лежит прошлая копия запоминается для последующего освобождения.

4. Как только список заполнен - срез готов. Ссылку на него записываем в суперблок (тут возможны более замысловатые сценарии, не описываю для простоты).

5. Резервируется объём дисковой памяти, необходимый для формирования следующего среза. Надо отметить, что VM в процессе работы может корректировать размер резерва сообразно размеру актуального адресного пространства.

6. Все блоки из запомненных в п. 3 кроме попавших в резерв возвращаются в список свободных.

 

Пейджинг

В промежутках между формированиями срезов функционирует обычная система виртуальной памяти с полным резервированием пейджингового пространства.

 

Интерфейс

NB!!

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

class phantom_vm {

phantom_object* malloc( size_t size );
void free( phantom_object* ); // только если refcount == 0

void run_gc(); // выполнить сборку мусора

void cut_off(); // сделать срез :-)

void page_fault( caddr_t page, bool write );
// вызывается при ошибке доступа к странице

caddr_t virt_to_phys( caddr_t );
void lock( caddr_t ); // lock for i/o
void unlock( caddr_t ); // release lock

};

 

// Интерфейс к подсистеме виртуальной памяти процессора

class cpu_vm_control {

size_t page_size() const; // bytes per page
size_t page_count() const; // size of RAM

void set_read( caddr_t page, bool ); // enable/disable read access
void set_write( caddr_t page, bool); // enable/disable write access

void map( caddr_t page, caddr_t ram_address );
void unmap( caddr_t page );

};

 

// Интерфейс к дисковой подсистеме

class vm_page_device {

int n_pagers() const; // Число дисков в системе
// Смещение начала данного диска от
// начала дискового пространства
daddr_t offset( int pager );

// prio - приоритет операции. Определяет место в очереди.
void page_in_sync( vm_page *, int prio);
void page_in_async( vm_page *, int prio );
page_out_sync( vm_page *, int prio );
page_out_async( vm_page *, int prio );

};

// версии async по окончании работы вызывают методы
// pagein_done/pageout_done объекта

 

Потенциальные проблемы

Фрагментация. Метод борьбы тривиален - арены. Объекты разного размера выделяются из разных арен.

Удвоение потребности в дисковой памяти при активной работе. Если буквально все объекты задумают менять состояние между двумя срезами, то второй срез включит в себя 100% адресного пространства. Если хватит диска. Если не хватит - будет отказ. В то же время, если участить формирование срезов, то этого можно избежать - конечно, ценой снижения производительности, но можно. Вероятно, это значит, что отказ в выделении памяти необходимо откладывать (блокируя нить) до конца формирования среза, как минимум. В то же время, такое откладывание должно подталкивать систему к тому, чтобы формировать срез раньше, чем обычно. Плюс к тому, отказы или откладывания выделения памяти должны учитываться и на основании этих данных система должна рекомендовать пользователю прикупить дисков. :-)

Stripe set? Это будет означать неотключаемолсть диска в будущем, но прирост эффективности должен быть заметный...

 

 

 

Используются технологии uCoz