OberonCore
https://forum.oberoncore.ru/

E11: Спец. тип в Kernel для областей с особой маркировкой GC
https://forum.oberoncore.ru/viewtopic.php?f=116&t=6070
Страница 1 из 1

Автор:  Илья Ермаков [ Понедельник, 19 Июнь, 2017 20:31 ]
Заголовок сообщения:  E11: Спец. тип в Kernel для областей с особой маркировкой GC

Сегодня Евгений Эдуардович выложил сборку ББ OberonCore с некоторыми обновлениями:
viewtopic.php?p=101136#p101136

Одно из изменений ядра - из нашей платформы приложений, для поддержки кооперативной многозадачности (которую пока что не публикуем).
При переключении задач сохраняются их стеки - и сборщик мусора должен маркировать структуру, где сохранён стек неактивной задачи.

Собственно, с этим же столкнулись коллеги, у которых есть аналогичная многозадачность, режим сопрограмм:
viewtopic.php?f=31&t=5219

Как это решено у нас - и как вошло в сборку OberonCore:
- введён специальный абстрактный базовый тип SpecialArea
Код:
      SpecialArea* = POINTER TO ABSTRACT RECORD
         opts*: SET
      END;


Любой тип, в области данных которого хранятся адреса, должен быть расширен от SpecialArea.
Это, например, страница списков, где сохраняются стеки.
Типа: Page = POINTER TO RECORD (Kernel.Special) next: Page; data: ARRAY 512 OF BYTE END.
При наличии в opts флага Kernel.conservMark сборщик будет выполнять консервативную маркировку тела записи.

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

Для такого режима маркировки свой тип данных также расширяется от Page - и добавляется следующий заголовок:
Код:
Page = POINTER TO RECORD (Kernel.Special)
  prev, next: Page;
  dataLen: INTEGER;
  map: ARRAY 32 OF SET;
  data: ARRAY 4096 OF BYTE
END;

Все понимают, что соотношение между размером map-а и размером data должно быть:
LEN(map) = LEN(data) DIV 4 DIV 32.

Далее вы выставляете правильный dataLen, а в opts выставляете флаг Kernel.markByMap.

Правила картографии:
- когда записываете в данные data какой-нибудь RECORD с указателями, то, как и в ОЗУ, сначала записываете тег Kernel.Type.
- в битовой карте бит для слова с тегом НЕ ПОМЕЧАЕТСЯ, он 0.
- далее записываете RECORD, кратно 4 байт, все слова в карте помечаете как 1.
(таким образом, когда идёт один RECORD за другим, в битовой карте начало каждого RECORD-а однозначно определяется по фронту 0->1).

Доп. фишка: ваши странички могут быть связаны в список по prev и next - и тогда RECORD вообще может записываться разрывно (часть на одной странице, часть - на следующей или нескольких следующих), маркировка его будет выполняться корректно.

Страница 1 из 1 Часовой пояс: UTC + 3 часа
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/