On 9 October 2012 13:21, Henrik Sperre Johansen <[email protected]> wrote: > On 09.10.2012 04:30, Igor Stasenko wrote: >> >> On 8 October 2012 17:12, Henrik Sperre Johansen >> <[email protected]> wrote: >>> >>> On 08.10.2012 16:35, Igor Stasenko wrote: >>> >>> On 8 October 2012 13:41, Henrik Sperre Johansen >>> <[email protected]> wrote: >>> >>> On 08.10.2012 13:25, Igor Stasenko wrote: >>> >>> On 8 October 2012 13:06, Henrik Sperre Johansen >>> <[email protected]> wrote: >>> >>> On 08.10.2012 13:03, Henrik Sperre Johansen wrote: >>> >>> >>> IMO, lazily checking whether the image has been restarted whenever you >>> want to do something stinks. >>> Registering to be notified when image starts/stops is a lot better. >>> >>> Not to mention, less error-prone. >>> Miss one session check that the current session is the right one >>> somewhere... and everything might blow up if that is the first piece of >>> functionality used. >>> >>> True. >>> I did not said that my method should replace old. Sometimes lazy >>> initialization is not what you want. >>> But having no way to perform lazy initialization is even worse. >>> >>> Ah, I just objected to the notion that startup lists inherently stinks, >>> and >>> took the diametrical view for the sake of argument :) >>> Yes, lazy initialization has its uses too, but some guidelines/advice* on >>> when to what those uses are, and when you'd use startUp: registration >>> instead, is needed I think. >>> >>> Notice; in most cases where such cleanup at startup is needed (sockets, >>> window handles, etc.), additional cleanup is needed when the object goes >>> out >>> of scope during regular use, and so a registry usually exist. >>> >> I will put some more reasons for the sake of discussion & learning. >> >> 1. during startup, you have to be very careful about dependencies >> between services, >> the errors like using uninitialized service(s) makes image >> unrecoverable (because VM crashing). >> For example , putting 'Transcript show: ' before freetype initialized >> may kill an image, >> beyond the point of recovery. > > WTF? > Dependencies amongst services is one thing, but process interaction during > startup/shutdown should *not* be a source of problems. > (I assume show: triggers an invalidateRect:, which pokes the UI thread to do > an update. Otherwise, show: somehow triggers a UI update directly, which is > a bug) > I mean, if the snapshot isn't the sole running process/ running at highest > priority, all manner of strange things could potentially happen, both > during/after shutdown and before/during startup. >
Remember lately people was reporting problems because they were doing image snapshot in background process? I guess we should use fork during snapshot to ensure there's no chance for scheduler to interfere. But this is just one thing.. The problem is that the bugs like that will keep popping out over and over again, which will require fixes over and over again. While i would prefer having code which is resilient to such stupid bugs, and don't needs to be modified that often. >> The hardest part in it, that since >> everything is late bound, it sometimes really hard to put >> initialization in right order. And loading any new code in image will >> also contribute to chaos >> of interdependencies, unless all developers know that they should not >> use facility A before facility B is properly initialized. And the only >> way to do it is to add own checks and one more #startup method, >> which 'enabling' your service after all dependencies initialized. >> But the problem is that the longer chain of initialization gets, the >> more chances that something will go wrong (as well as getting lost in >> order of dependencies). > > > When it comes to inter-dependent services; there's rarely dependencies > between those dealing with cleanup of external resources. > Startup services dependent on these, and eachother, sure. > Again, is startUp: and the startup list the right/best abstractions? Perhaps > not. Perhaps a DSL to declare dependencies would be nice, but then you're > quickly moving into metacello-style complexity instead. > and that's why i use session-change detection in my code. Then dependents of my service don't needs to be hard-coupled with it, and can use it at any moment. >> >> 2. garbage collection. Yes, you can walk over weak registry to >> invalidate all handles before they having >> any chance to be used. Unless during startup, you losing sole >> reference to object in registry and then VM triggers GC _before_ >> entering your startup code. As result , finalization code will attempt >> to free non-existing resources.. Which in most cases also leads to VM >> crash. >> >> So, i would not agree that using lazy-initialization & check before >> use is more error prone than startup :) > > How would this ever happen in normal uses? > Does the snapshot primitive not run a GC before saving the image state? it does, but that doesn't matters. I talking about what happens at boot time, during startup phase: some code runs _before_ reaching your startup code, which invalidates all external handles. And that code may: - lose the last reference to your object(s) - trigger GC unless you make your invalidation code to run first, things like that could happen. (but then someone else would also like to run his own code first, and we start over again ;) ). > In which case, you'd have to explicitly dereference things that is supposed > to be cleaned up as a later part of startup, and then trigger a GC... > Maybe it's just me, but I'd characterize that as an edge case that can be > classified under PEBKAC rather than the process itself being error-prone. > What is PEBKAC? That's the problem: exactly because it is an edge case. Because since everyone assumes that "this cannot normally happen", when it happens, you are helpless, because you would never think that problem in that place and will look into something unrelated, means that bugs of such kinds will be very hard to reproduce and fix. Answering your question, how this could happen.. a simplest example which comes into my mind is semaphores: imagine that you have process which waits on semaphore. And it could happen that process stack will hold a sole reference to your object, which represents an external resource. Now, it could also happen that semaphore which blocking process belongs to service which will be initialized first during image startup phase. And initialization of this service can simply drop the reference to that semaphore in order to replace it with fresh one.. (and this is not extremely rare , if you look into image, many services doing like that). And then GC triggers, and the old semaphore and the process which was waiting on it will be collected, and as result, losing last strong reference to the object which represents your external resource, registered in weak registry. The next thing which happens is running finalization process which will try to finalize non-existing external resource. > Cheers, > Henry -- Best regards, Igor Stasenko.
