On Fri, 2013-07-19 at 14:33 -0700, Jonathan S. Shapiro wrote: > On Thu, Jul 18, 2013 at 1:06 PM, Sandro Magi <[email protected]> > wrote: > Since we're establishing terminology, I suggest the following: > > 1. reclamation: return of resources to the pool, eg. memory, > CPU schedule. > 2. finalization: explicit program code that runs before > reclamation can > complete. > 3. disposal: cleanup of non-reclaimable resources, eg. file > handles, > sockets, etc. > > My view of the above is as follows: > > +---------------------------+ > | Reclaimable | > | +-------------------+ | > | |Finalizable | | > | | +------------+ | | > | | | Disposable | | | > +---+---+------------+--+---+ > > That is, all disposable resources ought to have finalizers, > and all > finalizable resources ought to have some reclaimable > representation, > although not all finalizers manage disposable resources. > > > This terminology seems fine. I'm not sure, personally, whether > "reclaimable" is a useful category, since every resource is > reclaimable (we could quibble about CPU time, but never mind). My > guess is that we'll eventually find it more useful to talk about > specific classes of reclaimable objects (e.g. GC'd, RC'd, and so > forth). But by all means let's see as we go. > > > Task-local resources are guaranteed by the type system not to > be shared > beyond the task's environment, so reference counting seems > appropriate > for "prompt" resource reclamation, by which I mean > specifically that the > task should not be marked "Done" until all resources it held > are fully > disposed, finalized and reclaimed. > > > I don't see how this is accounting for the distinction between > voluntary and involuntary exit conditions. For involuntary exit (task > is killed), the only actions that are guaranteed are the lower-layer > dispose actions are taken. By definition, an involuntarily terminated > task must not execute further instructions of any sort after the point > of demise. > > > > For voluntary exit (including I request that your task exits and you > comply), I like the concept you are proposing, but depending on the > implementation of finalization there can be problems. As you know, > there are many hopelessly broken implementations of finalization. In > some (bad) approaches, it is possible for unreachable objects to > become reachable again. In others, it is possible for a finalizer's > execution to cause further objects to become free. This can lead to a > requirement that the "GC then finalize" cycle may need to run multiple > times before it converges. > > > In the finalization design that is generally viewed as sane these > days, finalization is performed by application code upon noticing that > a weak reference in a table somewhere has reached its demise. Running > that code from within the Exit() logic is problematic. But! This is > voluntary exit. And that means we can rely an application to wrap > itself in a catch block from which finalizers are run before the final > Exit() call is made.
Sometimes it is used C signal handlers setup to catch program error signals or termination signals in order to close open files upon application exit or crash. http://www.gnu.org/software/libc/manual/html_node/Program-Error-Signals.html#Program-Error-Signals http://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html#Termination-Signals > > In the end, what I'm really saying here is that the execution of > finalization code during exit raises issues that aren't > straightforward. I think we can achieve the objective you set, but I > think we need to be a bit careful how we go about it. If an > application really wants finalization to happen on exit, then I think > that one of the following two statements must be true for every > finalizer: > > > 1. The finalization in question must be post-finalization, and the > application must establish a catch point at which (1) no objects to be > finalized are still live, and (2) the application explicitly invokes > gc-and-finalize(), or > 2. The finalizer body must be non-escaping and known to terminate. > Such a finalizer can safely be run out-of-band on borrowed stack > space. Note that such a finalizer can safely be run even on > involuntary exit. > > > Speaking generally, I think that the non-escaping rule is a good rule > for both constructors and finalizers. For constructors, the > requirement is that this not escape. For finalizers, it is necessary > that no non-live object escape into the live set. In practice, this > probably means that for finalizers no object references of any sort > can escape. > > > Reference counting achieves this with > no extra effort required, because full reclamation occurs upon > the > task's finalizer completing. This should apply even in the > event a task > is killed, though I'm not sure I've ever seen a satisfactory > safe > semantics for killing tasks. > > > Reference counting for task resources isn't needed. There is single > owning data structure - the task - and after task death no other > reference can be outstanding for exclusively owned resources. > Therefore the reference count must be one under your assumptions. > > > Unfortunately your assumptions are problematic. As an example, > consider a task that passes an opened file descriptor to another task. > When that occurs, the underlying resource is now shared across > multiple tasks and your assumption of exclusive ownership no longer > holds. At that point, yes, reference counting becomes an appropriate > solution. This is why POSIX uses a reference counting solution. > > > > > Jonathan > > > _______________________________________________ > bitc-dev mailing list > [email protected] > http://www.coyotos.org/mailman/listinfo/bitc-dev _______________________________________________ bitc-dev mailing list [email protected] http://www.coyotos.org/mailman/listinfo/bitc-dev
