OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Четверг, 28 Март, 2024 13:53

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 17 ] 
Автор Сообщение
СообщениеДобавлено: Четверг, 25 Октябрь, 2012 23:01 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Известно, что в ББ можно словить трэп 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 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
Вот, кстати, сам запилил такое, в модуле динамических агентов-экшнов.
Они у меня вроде как, нигде не хранятся, только сцеплены с Services.Action, а значит, может получиться так, что от модуля-реализации агента ничего не зависит, выгружается он спокойно и в любой момент. И при следующем вызове Services.Action.Do происходит подобная фигня.
Пришлось реализовать финализатор-самоликвидатор.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 26 Октябрь, 2012 09:09 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 12:02
Сообщения: 8500
Откуда: Троицк, Москва
Илья Ермаков писал(а):
Неплохо было бы найти нужные места в графич. каркасе, работающие с вьюшками, и добавить туда такие охраны, чтобы при выгрузке модулей вьюшек не шли трепы, а факт выгрузки корректно обнаруживался и вьюшка сразу "засерялась" :)
Хорошая идея, спасибо, с вьюшками есть такая маленькая занозка.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 26 Октябрь, 2012 14:54 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
А факт выгрузки модуля всегда совпадает со срабатыванием метода FINALIZE у объекта?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 26 Октябрь, 2012 15:46 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Нет! При выгрузке модуля с объектами ничего не делается. Они продолжают лежать в памяти. Их тег типа указывает на мета-секцию выгруженного модуля (она остаётся в памяти навсегда, т.е. идентифицировать объекты даже выгруженных модулей можно). А виртуальная таблица типов модуля... Факт не помню. По логике, нужно её занулять. Что, видимо, и делается. И для FINALIZE в том числе. Финализации для объекта уже не произойдёт никогда.

UPDATE: Подумал... У Вас, Пётр, FINALIZE вызывается, видимо, в силу того, что при выгрузке модуля проводится сборка мусора - и на ваши объекты нет якорей...
Но в ситуации, когда Вы выгружаете модуль X, а Y, имеющий указатели на объекты из X, остаётся жить в памяти, эти объекты тоже продолжат жить как ни в чём не бывало. До первого вызова их методов.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 26 Октябрь, 2012 16:30 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
Влияет ли на выполнение финализатора после выгрузки модуля-реализации то, что сам финализатор реализован для абстрактного базового типа, который расположен в другом модуле?

То есть, понятно, что проверка на валидность спасёт от трэпов, но в памяти останется незачищеный элемент списка, в котором лежит идентификатор сущности, которая после выгрузки модуля уже не выполнит финализатор.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 26 Октябрь, 2012 16:39 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
Провёл эксперимент, действительно, не удаляет.
Проверку на валидность не проходит, и всё, остаётся неявное предположение, что финализатор сам за собой почистит. А он не чистит, такой вот сюрприз. То есть, он бы почистил, если бы модуль не выгружался, а так - нифига.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 26 Октябрь, 2012 18:06 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2449
Откуда: Россия, Томск
Я эту проблему решал так: сохранял в модуле, порождающем объекты Services.Action, список созданных объектов. При выгрузке модуля в разделе CLOSE вызывал финализацию для всего списка.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 26 Октябрь, 2012 20:12 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Иногда уже не выкрутиться явным списком: можно нарваться на замкнутый круг: объект никому не нужен, но ещё висит в списке, и никогда не будет определено, что он уже не нужен (потому что в списке-то он есть!)
Тут уже приходим к нужности "мягких ссылок" (weak pointers): которая указывает на объект, но не является якорем. Т.е. становится невалидной, когда объект соберёт сборщик.
Такие ссылки сделать несложно, но нужна интеграция со сборщиком мусера. Это было сделано в Active BlackBox...


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 26 Октябрь, 2012 20:49 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2449
Откуда: Россия, Томск
Илья Ермаков писал(а):
Иногда уже не выкрутиться явным списком: можно нарваться на замкнутый круг: объект никому не нужен, но ещё висит в списке, и никогда не будет определено, что он уже не нужен (потому что в списке-то он есть!)
Тут уже приходим к нужности "мягких ссылок" (weak pointers): которая указывает на объект, но не является якорем. Т.е. становится невалидной, когда объект соберёт сборщик.
Такие ссылки сделать несложно, но нужна интеграция со сборщиком мусера. Это было сделано в Active BlackBox...
Илья, поправьте меня, если я не прав, но мне кажется, что без особого типа указателей вполне себе можно обойтись. Просто с нашим особым типом объектов нужно обращаться как с любым другим глобальным ресурсом. Например, файловые хэндлы Windows мы закрываем либо явно вызовом Close для файла, либо при сборке мусора. Так вот, наши "глобальные" объекты точно так же нужно явным вызовом удалять из глобального списка. Как правило, этим будет заниматься тот, кто изначально создал себе этот объект, при своей финализации.

Info21, вам это понравится: композиция объектов вместо языковой фичи.

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

Таким образом, замкнутый круг разрывается, и модули выгружаются без ошибок. При желании не сложно также сделать так, чтобы при выгрузке модуля и уничтожении глобальных объектов последние оповещали своих посредников. Таким образом, клиенты посредников в случае выгрузки модуля могут поиметь нечто более осмысленное, чем трап: возвращаемый статус ошибки, вывод в лог или просто игнорирование вызываемых методов.

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

Если немного подумать, то посредник - это только название такое. На самом деле вместо посредника может наружу выставляться реальный объект, просто у него внутри будет скрытая ссылка на объект-якорь, который уже в свою очередь и вбит накрепко в глобальную очередь.


Последний раз редактировалось Александр Ильин Пятница, 26 Октябрь, 2012 21:02, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 26 Октябрь, 2012 21:01 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Было у меня такое в хозяйстве... В экспериментальном... В последнюю переработанную реинкарнацию не перекочевало пока. (Возможно, потому, что в ненастольных вещах всё больше придерживаюсь стратегии явного управления ресурсами, по возможности).

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

Код:
Про 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 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Александр Ильин писал(а):
Info21, вам это понравится: композиция объектов вместо языковой фичи.


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


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 26 Октябрь, 2012 21:08 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2449
Откуда: Россия, Томск
Илья Ермаков писал(а):
Там недостаток в том, что базовый тип для указуемой сущности должен быть наш.
Да, чужой сервис не исправить. По сути, это реализация поддержки выгружаемости модуля. Если мы проектируем сервис так, чтобы его можно было выгружать, то мы это реализуем, если нет, то будет трап, что логично: по умолчанию модули не поддерживают выгрузку.

Но вот тот факт, что можно проверить выгруженность модуля любого объекта, это вы отлично нашли, Илья!


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 26 Октябрь, 2012 21:15 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Да, собсьно, Services так же проверяет валидность акшнов... (только через Kernel).
Мне просто недавно понадобилась эта штука, потому вспомнил и опубликовал.
Даже с Kernel на Meta переписал ради такого дела :)
(У меня есть свой уровень типа Meta, так шо не нужно кидать в меня ничего, у меня Kernel локализован в самом низу, но так, как нужно мне).


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 26 Октябрь, 2012 21:27 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2449
Откуда: Россия, Томск
Ну, не знаю... у меня акшны трапали только шум стоял.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 26 Октябрь, 2012 22:22 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
illegal execution никогда не видел от Actions!
Там стоит проверка модуля....


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 26 Октябрь, 2012 22:49 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
Кстати, касаемо объектов-посредников, изначально мои агенты не хранились в списке, они скрепляли себя с реализацией Action, и могли существовать вообще без единого якоря со стороны прикладных подсистем, так как экшны уже где-то там хранятся, они держат в себе агента, и всё в порядке. Но потом мне в голову пришла идея прикрутить к агентам хендлер сообщений, потому что при описаной схеме, агенту приходилось для общения с внешним миром заводить себе владельца, хуки всякие и тд, так или иначе.
А когда я уже вот-вот почти прикрутил широковещание сообщений, оказалось, что в Services список экшнов скрыт, и значит, придётся всё равно хранить агентов в своём глобальном списке. Не получилось сделать красиво. А раз такой агент лежит в списке, значит и финализатор у него не сработает. Но если он не будет лежать в списке (ну или в каскаде элементов списка, который лежит в списке), то доступа к нему не получить, и он будет собран, потому что якорей у него нет.

А вот была бы в Services шина сообщений


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 17 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2024, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB