Из книги "Project Oberon":
Цитата:
When a module is no longer needed, it should be possible to unload it; and when it is to be replaced by a new, perhaps corrected version, it must be unloaded. Obviously, in a hierarchy of modules, no module must be removed before its clients are removed. A procedure for unloading must therefore ensure that no clients exist.
For this purpose, each module descriptor is given a reference count. The field refcnt is initialized to zero when a module is loaded, and incremented each time the module is imported by a newly loaded client. Procedure Free checks whether or not this count is zero. Its parameter all indicates whether only the specified module is to be unloaded, or the process is to be transitive, i.e. applied to all its imports, too. Hence Free, or rather the local procedure unload, is recursive. We emphasize that unloading is never automatic, but must be explicitly requested by the system's user. The global variable res records the result of unloading:
0: unloading completed
1: module is not loaded
2: cannot be unloaded, because clients exist
Unloading a module is a tricky operation. One must make sure that no references to the unloaded module exist in the remaining modules and data structures. Unfortunately, this is not at all easy and is not guaranteed in the Oberon System. The violating culprits are procedure variables. If a procedure of a module A is assigned to a variable of a module B, and if A is unloaded, the procedure variable holds a dangling reference to the unloaded module's code block. In systems with virtual addressing (Ceres-1 and Ceres-2), the problem is solved by never reusing code addresses, i.e. by strictly sequential allocation in virtual address space. A dangling reference then points to a not allocated page, causing an address (NIL) trap when used. The situation is unsatisfactory, however, when code space is reused (Ceres-3).
Какие другие пути решения этой проблемы существуют, кроме как инвалидировать адрес процедуры (the problem is solved by never reusing code addresses)?
Думаю, что можно сделать так, чтобы выгрузка модуля не производилась, пока существуют такие указатели на процедуры из этого модуля. А для этого надо сделать подсчет ссылок на каждую из процедур модуля. Это можно реализовать изменив компилятор, чтобы при присваивании значения процедурной переменной производился подсчет ссылок. Но указатели на процедуры могут быть и в динамической памяти, а в динамической памяти они могут быть мусором, который висит, пока не будет собран мусор. Получается, что надо сначала посмотреть счетчики на процедуры, если все нули, то можно выгружать, если не нули, то надо попробовать сделать сборку мусора и снова проверить счетчики. Но еще же может быть и многопоточный код, когда что-то происходит с этими указателями на процедуры в разных потоках, значит должно быть взаимное исключение к этим счетчикам, чтобы там было корректное значение. Таким образом можно будет не выгружать модуль, пока остались ссылки на процедуры. Но стоит ли игра свеч? Возможно, есть еще какие-то решения?