Re: [Pharo-project] Global session object?
Yes, session management is cross-cutting concern, so it makes sense to have it in the system, and not just as a NB feature. Object new, is a cool workaround for the unique ID! Fernando On Mon, Oct 8, 2012 at 8:33 AM, Marcus Denker <marcus.denker@inria.fr> wrote:
Hello,
Yes, this sounds good.
Marcus
On Oct 8, 2012, at 5:11 AM, Igor Stasenko <siguctua@gmail.com> wrote:
I wanna have this:
SmalltalkImage>>snapshot: save andQuit: quit ... resuming ifTrue: [ session := self newSession ]. ...
(where session is additional instance variable of SmalltalkImage).
SmalltalkImage>>newSession "Just answer unique object, which never can be identical to any previous session object, this is all what we need for detecting session change. A session object don't needs to carry any state (we have plenty of other objects in image which can do this for us). it just needs to be unique"
^ Object new.
SmalltalkImage>>session ^ session
then, i can write in own code:
Smalltalk session == mySession ifFalse: [ self initForNewSession. mySession := Smalltalk session ]
So, basically, this little addition allows you to detect whether session changed or not between two different calls to your code (given that you remembered the previous session somewhere). Currently we don't have such feature, and looking how some existing code deals with session management, i see how it can be simplified. If you want to do something similar today, you will need to register in startup list.. which IMO stinks ;)
i don't like using startup lists, since you never know , what is the right order of resource initialization, and what inter-dependencies they may form, and changing dependencies over time will require changing startup order, again and again. Not fun. This technique allows you to lazily re-initialize any of your object(s) due to session change, once the control flow hits your code, but not before. (so you don't have to do all accounting at image startup time, you doing it only when it required/requested, which means shorter image startup time).
The notion of session is highly important for external resource management.
I using it in NativeBoost from very beginning, and wanna propose to use it globally.
-- Best regards, Igor Stasenko.
-- Marcus Denker -- http://marcusdenker.de
Just from the deleted wiki page on our google code project site: Squeak startup and shutdown lists are iterated too often, and startup is ignored by the network classes. = Introduction = == Squeak/Pharo Problems == Squeak's startup and shutdown lists are not used as such. Each snapshot forces a shutdown and then a startup. This is not only inefficient, it is unfair to things like open sockets, database connections, etc. Platform windows will not be well served: imagine shutting down the entire IDE for a snapshot; something needs to be done. == Dolphin's Solution == Dolphin solves the problem through session managers that control the startup and shutdown sequences; they polymorphically adapt to manage deployed GUI applications, the IDE, console applications, etc. Events triggered off of a singleton session manager sub-instance assist in external resource management. Dolphin does not free external resources on a snapshot. Resources are freed on shutdown (by registering for the shutdown events) and pointers/handles are cleared on *startup*. Having worked with it for years, I have gone from considering it strange to believing it is the correct design. == First Steps Toward a Fix == It became clear that my life would be easier given a singleton SessionManager that triggers #sessionStarted and #sessionStopped. The open question was whether Squeak's startup and shutdown lists with the quitting and resuming flags would be enough to reproduce Dolphin's behavior, which is to trigger #sessionStarted and #sessionStopped when *and only when* the image starts and stops, respectively. Somewhat surprisingly, it appears to be. I am left wondering why people have tolerated the need to litter images with #initializeNetwork sends; that should be done once every time the image starts. == Code == See http://code.google.com/p/pharo/issues/detail?id=1200 On 2012-10-08, at 10:41, Fernando Olivero <fernando.olivero@usi.ch> wrote:
Yes, session management is cross-cutting concern, so it makes sense to have it in the system, and not just as a NB feature.
Object new, is a cool workaround for the unique ID!
Fernando
On Mon, Oct 8, 2012 at 8:33 AM, Marcus Denker <marcus.denker@inria.fr> wrote:
Hello,
Yes, this sounds good.
Marcus
On Oct 8, 2012, at 5:11 AM, Igor Stasenko <siguctua@gmail.com> wrote:
I wanna have this:
SmalltalkImage>>snapshot: save andQuit: quit ... resuming ifTrue: [ session := self newSession ]. ...
(where session is additional instance variable of SmalltalkImage).
SmalltalkImage>>newSession "Just answer unique object, which never can be identical to any previous session object, this is all what we need for detecting session change. A session object don't needs to carry any state (we have plenty of other objects in image which can do this for us). it just needs to be unique"
^ Object new.
SmalltalkImage>>session ^ session
then, i can write in own code:
Smalltalk session == mySession ifFalse: [ self initForNewSession. mySession := Smalltalk session ]
So, basically, this little addition allows you to detect whether session changed or not between two different calls to your code (given that you remembered the previous session somewhere). Currently we don't have such feature, and looking how some existing code deals with session management, i see how it can be simplified. If you want to do something similar today, you will need to register in startup list.. which IMO stinks ;)
i don't like using startup lists, since you never know , what is the right order of resource initialization, and what inter-dependencies they may form, and changing dependencies over time will require changing startup order, again and again. Not fun. This technique allows you to lazily re-initialize any of your object(s) due to session change, once the control flow hits your code, but not before. (so you don't have to do all accounting at image startup time, you doing it only when it required/requested, which means shorter image startup time).
The notion of session is highly important for external resource management.
I using it in NativeBoost from very beginning, and wanna propose to use it globally.
-- Best regards, Igor Stasenko.
-- Marcus Denker -- http://marcusdenker.de
On 08.10.2012 11:31, Camillo Bruni wrote:
Just from the deleted wiki page on our google code project site:
Squeak startup and shutdown lists are iterated too often, and startup is ignored by the network classes.
= Introduction = == Squeak/Pharo Problems == Squeak's startup and shutdown lists are not used as such. Each snapshot forces a shutdown and then a startup. This is not only inefficient, it is unfair to things like open sockets, database connections, etc. Platform windows will not be well served: imagine shutting down the entire IDE for a snapshot; something needs to be done. This is false, using startUp:/shutDown: serves exactly this purpose.
Dolphin does not free external resources on a snapshot. Resources are freed on shutdown (by registering for the shutdown events) and pointers/handles are cleared on *startup*. Having worked with it for years, I have gone from considering it strange to believing it is the correct design.
== First Steps Toward a Fix == It became clear that my life would be easier given a singleton SessionManager that triggers #sessionStarted and #sessionStopped. The open question was whether Squeak's startup and shutdown lists with the quitting and resuming flags would be enough to reproduce Dolphin's behavior, which is to trigger #sessionStarted and #sessionStopped when *and only when* the image starts and stops, respectively. Somewhat surprisingly, it appears to be. I am left wondering why people have tolerated the need to litter images with #initializeNetwork sends; that should be done once every time the image starts. And this is true, you can achieve the same using startUp:/shutDown: as you can in Dolphin. Whether that is the best interface, or a manager/announcer would be better is a different question.
Ironically, the session object Igor describes would necessitate the same kind of intrusive checks as #initializeNetwork. 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. Cheers, Henry
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. Cheers, Henry
On 8 October 2012 13:06, Henrik Sperre Johansen <henrik.s.johansen@veloxit.no> 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.
Cheers, Henry
-- Best regards, Igor Stasenko.
On 08.10.2012 13:25, Igor Stasenko wrote:
On 8 October 2012 13:06, Henrik Sperre Johansen <henrik.s.johansen@veloxit.no> 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. Thus, your startup code isn't usually X allInstancesDo: #something but X weakRegistry allEntriesDo: #someting. which stinks a whole lot less. Cheers, Henry *So in my view, to use lazy init over startUp registration, it would need to: - Concern instance data. - Not need weak cleanup. - Be containable to a single accessor
On 8 October 2012 13:41, Henrik Sperre Johansen <henrik.s.johansen@veloxit.no> wrote:
On 08.10.2012 13:25, Igor Stasenko wrote:
On 8 October 2012 13:06, Henrik Sperre Johansen <henrik.s.johansen@veloxit.no> 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.
Yes.
Thus, your startup code isn't usually X allInstancesDo: #something but X weakRegistry allEntriesDo: #someting.
which stinks a whole lot less.
in perfect world, yes :) But world is imperfect.. For example, look here: FT2Handle>>shutDown: quitting "we must not save handles (which are pointers) in the image" self clearRegistry. FreeTypeFace allInstances do:[:i | "destroy any faces that are still being referenced" i isValid ifTrue:[i destroyHandle]]. FT2Handle allSubInstances do: [:h | h beNull]. "if some handle was not registered" because of the above, when i pass freetype faces handles to Cairo, which caching a lot of stuff inside (obviously for performance reasons), when you save an image, and then try to use Cairo after that (like rendering text with same font) an image is crashing. Which means that "we must not save handles (which are pointers) in the image" now blocking me from having nice interoperability with Cairo.. Needless to say that destroying handles will force their recreation after snapshot, since image continues running and will keep using freetype fonts. This is actually the reason why i want to introduce session object(s), so that i can fix freetype code to play more nicely with cairo library.
Cheers, Henry
*So in my view, to use lazy init over startUp registration, it would need to: - Concern instance data. - Not need weak cleanup. - Be containable to a single accessor
-- Best regards, Igor Stasenko.
On 08.10.2012 16:35, Igor Stasenko wrote:
On 8 October 2012 13:41, Henrik Sperre Johansen <henrik.s.johansen@veloxit.no> wrote:
On 08.10.2012 13:25, Igor Stasenko wrote:
On 8 October 2012 13:06, Henrik Sperre Johansen <henrik.s.johansen@veloxit.no> 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. Yes.
Thus, your startup code isn't usually X allInstancesDo: #something but X weakRegistry allEntriesDo: #someting.
which stinks a whole lot less.
in perfect world, yes :)
But world is imperfect.. For example, look here:
FT2Handle>>shutDown: quitting "we must not save handles (which are pointers) in the image" self clearRegistry. FreeTypeFace allInstances do:[:i | "destroy any faces that are still being referenced" i isValid ifTrue:[i destroyHandle]]. FT2Handle allSubInstances do: [:h | h beNull]. "if some handle was not registered"
because of the above, when i pass freetype faces handles to Cairo, which caching a lot of stuff inside (obviously for performance reasons), when you save an image, and then try to use Cairo after that (like rendering text with same font) an image is crashing. Which means that "we must not save handles (which are pointers) in the image" now blocking me from having nice interoperability with Cairo..
Needless to say that destroying handles will force their recreation after snapshot, since image continues running and will keep using freetype fonts.
This is actually the reason why i want to introduce session object(s), so that i can fix freetype code to play more nicely with cairo library.
I agree with this part from the wiki entry: "Dolphin does not free external resources on a snapshot. Resources are freed on shutdown (by registering for the shutdown events) and pointers/handles are cleared on *startup*. Having worked with it for years, I have gone from considering it strange to believing it is the correct design." Rewriting the shutdown to a startUp: method (conditional on the resuming parameter) shouldn't be too much work. A short analysis of the code reveals: 1) FT2Face/FT2MemoryFaceData aren't instatiated. 2) Both FT2Face and FreeTypeExternalMemory instances are both registered in the FT2Handle registry. (if used in a way which instantiates handle) 3) FT2Library recreates a new instance based for each call to current, which may be problematic, but current return values are never kept, just used to check that FT is present. So really, cleaning the entries found in registry is all that's actually needed at startup. Cheers, Henry
On 8 October 2012 17:12, Henrik Sperre Johansen <henrik.s.johansen@veloxit.no> wrote:
On 08.10.2012 16:35, Igor Stasenko wrote:
On 8 October 2012 13:41, Henrik Sperre Johansen <henrik.s.johansen@veloxit.no> wrote:
On 08.10.2012 13:25, Igor Stasenko wrote:
On 8 October 2012 13:06, Henrik Sperre Johansen <henrik.s.johansen@veloxit.no> 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. 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). 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 :)
Yes.
Thus, your startup code isn't usually X allInstancesDo: #something but X weakRegistry allEntriesDo: #someting.
which stinks a whole lot less.
in perfect world, yes :)
But world is imperfect.. For example, look here:
FT2Handle>>shutDown: quitting "we must not save handles (which are pointers) in the image" self clearRegistry. FreeTypeFace allInstances do:[:i | "destroy any faces that are still being referenced" i isValid ifTrue:[i destroyHandle]]. FT2Handle allSubInstances do: [:h | h beNull]. "if some handle was not registered"
because of the above, when i pass freetype faces handles to Cairo, which caching a lot of stuff inside (obviously for performance reasons), when you save an image, and then try to use Cairo after that (like rendering text with same font) an image is crashing. Which means that "we must not save handles (which are pointers) in the image" now blocking me from having nice interoperability with Cairo..
Needless to say that destroying handles will force their recreation after snapshot, since image continues running and will keep using freetype fonts.
This is actually the reason why i want to introduce session object(s), so that i can fix freetype code to play more nicely with cairo library.
I agree with this part from the wiki entry: "Dolphin does not free external resources on a snapshot. Resources are freed on shutdown (by registering for the shutdown events) and pointers/handles are cleared on *startup*. Having worked with it for years, I have gone from considering it strange to believing it is the correct design."
Rewriting the shutdown to a startUp: method (conditional on the resuming parameter) shouldn't be too much work.
A short analysis of the code reveals: 1) FT2Face/FT2MemoryFaceData aren't instatiated. 2) Both FT2Face and FreeTypeExternalMemory instances are both registered in the FT2Handle registry. (if used in a way which instantiates handle) 3) FT2Library recreates a new instance based for each call to current, which may be problematic, but current return values are never kept, just used to check that FT is present.
So really, cleaning the entries found in registry is all that's actually needed at startup.
Cheers, Henry
-- Best regards, Igor Stasenko.
On 09.10.2012 04:30, Igor Stasenko wrote:
On 8 October 2012 17:12, Henrik Sperre Johansen <henrik.s.johansen@veloxit.no> wrote:
On 08.10.2012 16:35, Igor Stasenko wrote:
On 8 October 2012 13:41, Henrik Sperre Johansen <henrik.s.johansen@veloxit.no> wrote:
On 08.10.2012 13:25, Igor Stasenko wrote:
On 8 October 2012 13:06, Henrik Sperre Johansen <henrik.s.johansen@veloxit.no> 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. 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.
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? 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. Cheers, Henry
On 9 October 2012 13:21, Henrik Sperre Johansen <henrik.s.johansen@veloxit.no> wrote:
On 09.10.2012 04:30, Igor Stasenko wrote:
On 8 October 2012 17:12, Henrik Sperre Johansen <henrik.s.johansen@veloxit.no> wrote:
On 08.10.2012 16:35, Igor Stasenko wrote:
On 8 October 2012 13:41, Henrik Sperre Johansen <henrik.s.johansen@veloxit.no> wrote:
On 08.10.2012 13:25, Igor Stasenko wrote:
On 8 October 2012 13:06, Henrik Sperre Johansen <henrik.s.johansen@veloxit.no> 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.
Igor Stasenko wrote
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. 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).
Just shooting from the hip, isn't that the same problem that more or less all unix os-es have on start up, what parts of systems are alive at particular moment and which ones are not. Instead of hard wiring all dependencies, maybe introduce different run levels, and roughly divide registered start up actions based on the run level? ----- http://www.cloud208.com/ -- View this message in context: http://forum.world.st/Global-session-object-tp4650371p4650576.html Sent from the Pharo Smalltalk mailing list archive at Nabble.com.
On 9 October 2012 14:28, drush66 <davorin.rusevljan@gmail.com> wrote:
Igor Stasenko wrote
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. 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).
Just shooting from the hip, isn't that the same problem that more or less all unix os-es have on start up, what parts of systems are alive at particular moment and which ones are not. Instead of hard wiring all dependencies, maybe introduce different run levels, and roughly divide registered start up actions based on the run level?
run levels just adding another dimension into dependency soup. they don't solve the dependency problem.. when you say "i run at level 5, so everything which runs at level 4 will be initialized first" which is equal to saying " Facility A (level 5) should not be used before facility B (level 4) is initialized.
----- http://www.cloud208.com/ -- View this message in context: http://forum.world.st/Global-session-object-tp4650371p4650576.html Sent from the Pharo Smalltalk mailing list archive at Nabble.com.
-- Best regards, Igor Stasenko.
Igor Stasenko wrote
On 9 October 2012 14:28, drush66 <
davorin.rusevljan@
> wrote:
Igor Stasenko wrote run levels just adding another dimension into dependency soup. they don't solve the dependency problem.. when you say "i run at level 5, so everything which runs at level 4 will be initialized first" which is equal to saying " Facility A (level 5) should not be used before facility B (level 4) is initialized.
They do not solve them, but they make i ta bit les fragile, since you do not specify all facilities that have to run before your own, but you say, any facility from some class (run level), should run before mine. So one can write such rule without knowing explicit list of all facilities that need to run before mine. But anyway, I have just posted this as an food for thoughts, if it helps or not you decide. ----- http://www.cloud208.com/ -- View this message in context: http://forum.world.st/Global-session-object-tp4650371p4650580.html Sent from the Pharo Smalltalk mailing list archive at Nabble.com.
On 9 October 2012 14:45, drush66 <davorin.rusevljan@gmail.com> wrote:
Igor Stasenko wrote
On 9 October 2012 14:28, drush66 <
davorin.rusevljan@
> wrote:
Igor Stasenko wrote run levels just adding another dimension into dependency soup. they don't solve the dependency problem.. when you say "i run at level 5, so everything which runs at level 4 will be initialized first" which is equal to saying " Facility A (level 5) should not be used before facility B (level 4) is initialized.
They do not solve them, but they make i ta bit les fragile, since you do not specify all facilities that have to run before your own, but you say, any facility from some class (run level), should run before mine. So one can write such rule without knowing explicit list of all facilities that need to run before mine.
right, it is just grouping.
But anyway, I have just posted this as an food for thoughts, if it helps or not you decide.
imo, it would make sense, if we would have that many services as linux has.
----- http://www.cloud208.com/ -- View this message in context: http://forum.world.st/Global-session-object-tp4650371p4650580.html Sent from the Pharo Smalltalk mailing list archive at Nabble.com.
-- Best regards, Igor Stasenko.
In this case, would it make sense to have a global "external handles registry" so, that during image boot it does: clearExternalObjects and booting ifTrue: [ registry := registry reject: [:each | each invalidate ] ]. (where registry is WeakIdentitySet , and #invalidate should answer true if object wants to remove itself (deregister) after invalidating external handle). and only then doing startup as usual. like that, then we could have better guarantee that nothing will go wrong, and things like FreeType won't require own startup procedure at all. -- Best regards, Igor Stasenko.
On 8 October 2012 13:03, Henrik Sperre Johansen <henrik.s.johansen@veloxit.no> wrote:
On 08.10.2012 11:31, Camillo Bruni wrote:
Just from the deleted wiki page on our google code project site:
Squeak startup and shutdown lists are iterated too often, and startup is ignored by the network classes.
= Introduction = == Squeak/Pharo Problems == Squeak's startup and shutdown lists are not used as such. Each snapshot forces a shutdown and then a startup. This is not only inefficient, it is unfair to things like open sockets, database connections, etc. Platform windows will not be well served: imagine shutting down the entire IDE for a snapshot; something needs to be done.
This is false, using startUp:/shutDown: serves exactly this purpose.
Dolphin does not free external resources on a snapshot. Resources are freed on shutdown (by registering for the shutdown events) and pointers/handles are cleared on *startup*. Having worked with it for years, I have gone from considering it strange to believing it is the correct design.
== First Steps Toward a Fix == It became clear that my life would be easier given a singleton SessionManager that triggers #sessionStarted and #sessionStopped. The open question was whether Squeak's startup and shutdown lists with the quitting and resuming flags would be enough to reproduce Dolphin's behavior, which is to trigger #sessionStarted and #sessionStopped when *and only when* the image starts and stops, respectively. Somewhat surprisingly, it appears to be. I am left wondering why people have tolerated the need to litter images with #initializeNetwork sends; that should be done once every time the image starts.
And this is true, you can achieve the same using startUp:/shutDown: as you can in Dolphin. Whether that is the best interface, or a manager/announcer would be better is a different question.
Ironically, the session object Igor describes would necessitate the same kind of intrusive checks as #initializeNetwork.
Then you should do things once at startup.
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.
I want both. Doing everything at startup time is not necessary , especially when you want faster startup time. And regarding stinks.. how do you think, a following pseudo-code is less stinky: startup MyClassOne allInstancesDo: [:i | i resetExternalHandle ]. MyOtherClass allInstancesDo: [:i | i clearExternalHandle ]. .... YetAnOtherClass allInstancesDo: [:i | i reinitExternalHandles ]. (a tip: allInstances scanning whole heap)
Cheers, Henry
-- Best regards, Igor Stasenko.
participants (5)
-
Camillo Bruni -
drush66 -
Fernando Olivero -
Henrik Sperre Johansen -
Igor Stasenko