OberonCore https://forum.oberoncore.ru/ |
|
Обнаружение факта выгруженности модуля дин. объекта https://forum.oberoncore.ru/viewtopic.php?f=2&t=4133 |
Страница 1 из 1 |
Автор: | Илья Ермаков [ Четверг, 25 Октябрь, 2012 23:01 ] |
Заголовок сообщения: | Обнаружение факта выгруженности модуля дин. объекта |
Известно, что в ББ можно словить трэп illegal execution, если выгрузить модуль, динамические объекты типов которого используются. Например, в качестве дин. разъёмов в других модулях, обработчиков. Чтобы отследить факт выгрузки модуля, можно использовать такой предикат: Код: PROCEDURE ValidModuleOf* (obj: ANYPTR): BOOLEAN; VAR it: Meta.Item; BEGIN Meta.GetItem(obj, it); RETURN it.Valid() END ValidModuleOf; Неплохо было бы найти нужные места в графич. каркасе, работающие с вьюшками, и добавить туда такие охраны, чтобы при выгрузке модулей вьюшек не шли трепы, а факт выгрузки корректно обнаруживался и вьюшка сразу "засерялась" |
Автор: | Пётр Кушнир [ Пятница, 26 Октябрь, 2012 00:25 ] |
Заголовок сообщения: | Re: Обнаружение факта выгруженности модуля дин. объекта |
Вот, кстати, сам запилил такое, в модуле динамических агентов-экшнов. Они у меня вроде как, нигде не хранятся, только сцеплены с Services.Action, а значит, может получиться так, что от модуля-реализации агента ничего не зависит, выгружается он спокойно и в любой момент. И при следующем вызове Services.Action.Do происходит подобная фигня. Пришлось реализовать финализатор-самоликвидатор. |
Автор: | Info21 [ Пятница, 26 Октябрь, 2012 09:09 ] |
Заголовок сообщения: | Re: Обнаружение факта выгруженности модуля дин. объекта |
Илья Ермаков писал(а): Неплохо было бы найти нужные места в графич. каркасе, работающие с вьюшками, и добавить туда такие охраны, чтобы при выгрузке модулей вьюшек не шли трепы, а факт выгрузки корректно обнаруживался и вьюшка сразу "засерялась" Хорошая идея, спасибо, с вьюшками есть такая маленькая занозка.
|
Автор: | Пётр Кушнир [ Пятница, 26 Октябрь, 2012 14:54 ] |
Заголовок сообщения: | Re: Обнаружение факта выгруженности модуля дин. объекта |
А факт выгрузки модуля всегда совпадает со срабатыванием метода FINALIZE у объекта? |
Автор: | Илья Ермаков [ Пятница, 26 Октябрь, 2012 15:46 ] |
Заголовок сообщения: | Re: Обнаружение факта выгруженности модуля дин. объекта |
Нет! При выгрузке модуля с объектами ничего не делается. Они продолжают лежать в памяти. Их тег типа указывает на мета-секцию выгруженного модуля (она остаётся в памяти навсегда, т.е. идентифицировать объекты даже выгруженных модулей можно). А виртуальная таблица типов модуля... Факт не помню. По логике, нужно её занулять. Что, видимо, и делается. И для FINALIZE в том числе. Финализации для объекта уже не произойдёт никогда. UPDATE: Подумал... У Вас, Пётр, FINALIZE вызывается, видимо, в силу того, что при выгрузке модуля проводится сборка мусора - и на ваши объекты нет якорей... Но в ситуации, когда Вы выгружаете модуль X, а Y, имеющий указатели на объекты из X, остаётся жить в памяти, эти объекты тоже продолжат жить как ни в чём не бывало. До первого вызова их методов. |
Автор: | Пётр Кушнир [ Пятница, 26 Октябрь, 2012 16:30 ] |
Заголовок сообщения: | Re: Обнаружение факта выгруженности модуля дин. объекта |
Влияет ли на выполнение финализатора после выгрузки модуля-реализации то, что сам финализатор реализован для абстрактного базового типа, который расположен в другом модуле? То есть, понятно, что проверка на валидность спасёт от трэпов, но в памяти останется незачищеный элемент списка, в котором лежит идентификатор сущности, которая после выгрузки модуля уже не выполнит финализатор. |
Автор: | Пётр Кушнир [ Пятница, 26 Октябрь, 2012 16:39 ] |
Заголовок сообщения: | Re: Обнаружение факта выгруженности модуля дин. объекта |
Провёл эксперимент, действительно, не удаляет. Проверку на валидность не проходит, и всё, остаётся неявное предположение, что финализатор сам за собой почистит. А он не чистит, такой вот сюрприз. То есть, он бы почистил, если бы модуль не выгружался, а так - нифига. |
Автор: | Александр Ильин [ Пятница, 26 Октябрь, 2012 18:06 ] |
Заголовок сообщения: | Re: Обнаружение факта выгруженности модуля дин. объекта |
Я эту проблему решал так: сохранял в модуле, порождающем объекты Services.Action, список созданных объектов. При выгрузке модуля в разделе CLOSE вызывал финализацию для всего списка. |
Автор: | Илья Ермаков [ Пятница, 26 Октябрь, 2012 20:12 ] |
Заголовок сообщения: | Re: Обнаружение факта выгруженности модуля дин. объекта |
Иногда уже не выкрутиться явным списком: можно нарваться на замкнутый круг: объект никому не нужен, но ещё висит в списке, и никогда не будет определено, что он уже не нужен (потому что в списке-то он есть!) Тут уже приходим к нужности "мягких ссылок" (weak pointers): которая указывает на объект, но не является якорем. Т.е. становится невалидной, когда объект соберёт сборщик. Такие ссылки сделать несложно, но нужна интеграция со сборщиком мусера. Это было сделано в Active BlackBox... |
Автор: | Александр Ильин [ Пятница, 26 Октябрь, 2012 20:49 ] |
Заголовок сообщения: | Re: Обнаружение факта выгруженности модуля дин. объекта |
Илья Ермаков писал(а): Иногда уже не выкрутиться явным списком: можно нарваться на замкнутый круг: объект никому не нужен, но ещё висит в списке, и никогда не будет определено, что он уже не нужен (потому что в списке-то он есть!) Илья, поправьте меня, если я не прав, но мне кажется, что без особого типа указателей вполне себе можно обойтись. Просто с нашим особым типом объектов нужно обращаться как с любым другим глобальным ресурсом. Например, файловые хэндлы Windows мы закрываем либо явно вызовом Close для файла, либо при сборке мусора. Так вот, наши "глобальные" объекты точно так же нужно явным вызовом удалять из глобального списка. Как правило, этим будет заниматься тот, кто изначально создал себе этот объект, при своей финализации.Тут уже приходим к нужности "мягких ссылок" (weak pointers): которая указывает на объект, но не является якорем. Т.е. становится невалидной, когда объект соберёт сборщик. Такие ссылки сделать несложно, но нужна интеграция со сборщиком мусера. Это было сделано в Active BlackBox... Info21, вам это понравится: композиция объектов вместо языковой фичи. Решение в общем виде такое: делаем объект-посредник, а ссылку на глобальный объект прячем внутри. Все клиенты используют только посредника. Когда посредник становится ненужным и собирается сборщиком мусора, его финализация удаляет соответствующий глобальный объект из глобального списка и, возможно, выполняет дополнительные действия по освобождению ресурсов. Таким образом, замкнутый круг разрывается, и модули выгружаются без ошибок. При желании не сложно также сделать так, чтобы при выгрузке модуля и уничтожении глобальных объектов последние оповещали своих посредников. Таким образом, клиенты посредников в случае выгрузки модуля могут поиметь нечто более осмысленное, чем трап: возвращаемый статус ошибки, вывод в лог или просто игнорирование вызываемых методов. Кстати, сам модуль, реализующий сервис изначально, и хранящий в себе глобальный список объектов, может просто-напросто всегда возвращать клиентам уже созданных посредников. Они даже могут и не подозревать, что им представляется посредник. То есть, с точки зрения клиента нет абсолютно никакой добавочной сложности. Если немного подумать, то посредник - это только название такое. На самом деле вместо посредника может наружу выставляться реальный объект, просто у него внутри будет скрытая ссылка на объект-якорь, который уже в свою очередь и вбит накрепко в глобальную очередь. |
Автор: | Илья Ермаков [ Пятница, 26 Октябрь, 2012 21:01 ] |
Заголовок сообщения: | Re: Обнаружение факта выгруженности модуля дин. объекта |
Было у меня такое в хозяйстве... В экспериментальном... В последнюю переработанную реинкарнацию не перекочевало пока. (Возможно, потому, что в ненастольных вещах всё больше придерживаюсь стратегии явного управления ресурсами, по возможности). Там недостаток в том, что базовый тип для указуемой сущности должен быть наш. Т.е. в случае другого базового типа будет три динамических объекта: ссылка, формальная цель ссылки, реальная цель ссылки. Код: Про XxTypes.Object можете считать, что это всего лишь заложенный HandleMsg.
MODULE XxReferences; IMPORT SYSTEM; TYPE Ref* = POINTER TO ABSTRACT RECORD (XxTypes.Object) END; AboutCloseMsg* = RECORD ref*: Ref END; WeakRef = POINTER TO RECORD (Ref) handler: XxTypes.Object; target: INTEGER END; RefItem = POINTER TO RECORD next: RefItem; ref: INTEGER END; WeakTarget* = POINTER TO ABSTRACT RECORD (XxTypes.Object) refs: RefItem END; PROCEDURE (ref: Ref) Deref* (): ANYPTR, NEW, ABSTRACT; PROCEDURE (ref: Ref) SetHandler* (obj: XxTypes.Object), NEW, ABSTRACT; PROCEDURE (ref: Ref) Close*, NEW, ABSTRACT; PROCEDURE AddRef (tg: WeakTarget; ref: WeakRef); VAR it: RefItem; BEGIN ASSERT(ref.target = SYSTEM.ADR(tg^), 20); NEW(it); it.ref := SYSTEM.ADR(ref^); it.next := tg.refs; tg.refs := it END AddRef; PROCEDURE RemoveRef (tg: WeakTarget; ref: WeakRef); VAR prev, r: RefItem; BEGIN r := tg.refs; WHILE r.ref # SYSTEM.ADR(ref^) DO prev := r; r := r.next END; IF prev # NIL THEN prev.next := r.next ELSE tg.refs := r.next END END RemoveRef; PROCEDURE NewWeakRef* (target: WeakTarget): Ref; VAR r: WeakRef; BEGIN ASSERT(target # NIL, 20); NEW(r); r.target := SYSTEM.ADR(target^); AddRef(target, r); RETURN r END NewWeakRef; PROCEDURE IsWeakRef* (ref: Ref): BOOLEAN; BEGIN RETURN ref IS WeakRef END IsWeakRef; PROCEDURE BeforeClose (ref: WeakRef); VAR msg: AboutCloseMsg; BEGIN IF ref.handler # NIL THEN msg.ref := ref; ref.handler.HandleMsg(msg) END END BeforeClose; PROCEDURE (ref: WeakRef) Deref (): WeakTarget; BEGIN RETURN SYSTEM.VAL(WeakTarget, ref.target) END Deref; PROCEDURE (ref: WeakRef) SetHandler (obj: XxTypes.Object); BEGIN ref.handler := obj END SetHandler; PROCEDURE (ref: WeakRef) Close; BEGIN IF ref.target # 0 THEN BeforeClose(ref); RemoveRef(SYSTEM.VAL(WeakTarget, ref.target), ref); ref.target := 0 END END Close; PROCEDURE (ref: WeakRef) FINALIZE; BEGIN ref.Close END FINALIZE; PROCEDURE (t: WeakTarget) FINALIZE2-, NEW, EMPTY; PROCEDURE (t: WeakTarget) FINALIZE-; VAR it: RefItem; ref: WeakRef; BEGIN t.FINALIZE2; it := t.refs; t.refs := NIL; WHILE it # NIL DO ref := SYSTEM.VAL(WeakRef, it.ref); BeforeClose(ref); ref.target := 0; it := it.next END END FINALIZE; END XxReferences. |
Автор: | Илья Ермаков [ Пятница, 26 Октябрь, 2012 21:03 ] |
Заголовок сообщения: | Re: Обнаружение факта выгруженности модуля дин. объекта |
Александр Ильин писал(а): Info21, вам это понравится: композиция объектов вместо языковой фичи. Реализация на уровне рантайма тоже не меняла язык. Библиотечное средство, про которое "знает" сборщик мусора. На самом деле достаточно сборщику сообщать о факте сборки заинтересованным обработчикам, а они сами могут быть за пределами рантайма. |
Автор: | Александр Ильин [ Пятница, 26 Октябрь, 2012 21:08 ] |
Заголовок сообщения: | Re: Обнаружение факта выгруженности модуля дин. объекта |
Илья Ермаков писал(а): Там недостаток в том, что базовый тип для указуемой сущности должен быть наш. Да, чужой сервис не исправить. По сути, это реализация поддержки выгружаемости модуля. Если мы проектируем сервис так, чтобы его можно было выгружать, то мы это реализуем, если нет, то будет трап, что логично: по умолчанию модули не поддерживают выгрузку.Но вот тот факт, что можно проверить выгруженность модуля любого объекта, это вы отлично нашли, Илья! |
Автор: | Илья Ермаков [ Пятница, 26 Октябрь, 2012 21:15 ] |
Заголовок сообщения: | Re: Обнаружение факта выгруженности модуля дин. объекта |
Да, собсьно, Services так же проверяет валидность акшнов... (только через Kernel). Мне просто недавно понадобилась эта штука, потому вспомнил и опубликовал. Даже с Kernel на Meta переписал ради такого дела (У меня есть свой уровень типа Meta, так шо не нужно кидать в меня ничего, у меня Kernel локализован в самом низу, но так, как нужно мне). |
Автор: | Александр Ильин [ Пятница, 26 Октябрь, 2012 21:27 ] |
Заголовок сообщения: | Re: Обнаружение факта выгруженности модуля дин. объекта |
Ну, не знаю... у меня акшны трапали только шум стоял. |
Автор: | Илья Ермаков [ Пятница, 26 Октябрь, 2012 22:22 ] |
Заголовок сообщения: | Re: Обнаружение факта выгруженности модуля дин. объекта |
illegal execution никогда не видел от Actions! Там стоит проверка модуля.... |
Автор: | Пётр Кушнир [ Пятница, 26 Октябрь, 2012 22:49 ] |
Заголовок сообщения: | Re: Обнаружение факта выгруженности модуля дин. объекта |
Кстати, касаемо объектов-посредников, изначально мои агенты не хранились в списке, они скрепляли себя с реализацией Action, и могли существовать вообще без единого якоря со стороны прикладных подсистем, так как экшны уже где-то там хранятся, они держат в себе агента, и всё в порядке. Но потом мне в голову пришла идея прикрутить к агентам хендлер сообщений, потому что при описаной схеме, агенту приходилось для общения с внешним миром заводить себе владельца, хуки всякие и тд, так или иначе. А когда я уже вот-вот почти прикрутил широковещание сообщений, оказалось, что в Services список экшнов скрыт, и значит, придётся всё равно хранить агентов в своём глобальном списке. Не получилось сделать красиво. А раз такой агент лежит в списке, значит и финализатор у него не сработает. Но если он не будет лежать в списке (ну или в каскаде элементов списка, который лежит в списке), то доступа к нему не получить, и он будет собран, потому что якорей у него нет. А вот была бы в Services шина сообщений |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |