Hello all,
I used to work with Parkplace Smalltalk for a few months about ten years ago, but even after all this abstinence I had a "relapse" ;) and recently bought the Dolphin Value Edition 5.1 to work on some personal projects. :) One of the first classes I wrote was a "DirectoryChangeWatcher", whose instances monitor for a given directory (and optionally its subdirs) all changes that occur. I implemented this by forking a process and performint an overlapped external call to ReadDirectoryChangesW. Most of the time of course that forked process blocks on the external call. This works fine, but what I am wondering about is how to deal with an image save and restart of Smalltalk. (So far I haven't tried to save an image when an instance of DirectoryChangeWatcher was still around). Will the image save properly (even with a process blocked on an overlapped external call) and if so, what state will the image be when I restart Smalltalk? Will that forked process be still alive or do I need to terminate it and start a new one? If I need to start a new one (or perform some action before and after the image save), what is the protocol to adhere to)? After browsing the SessionManager class hiearchy, it seems that I need to register with "SessionManager current" for the events #sessionStarted, #imageSaveStarting and #imageSaveCompleted. Is that the recommended way or is there another protocol to handle this? Last but not least on what "level" of the application should I handle this? I.e. should every low-level class be able to reinstate their former state after the restart of an image? In that case I would have expected some coding in the File class to "OnStartup" reopen any file. Or should those things rather be handled on a higher application level, i.e. the main application has to invalid and reinstantiate all lower level objects (i.e. instances of File)? Thank you very much for any insights into the matter, Bernhard |
"Bernhard Kohlhaas" <[hidden email]> wrote in message
news:[hidden email]... > ... > One of the first classes I wrote was a "DirectoryChangeWatcher", whose > instances monitor for a given directory (and optionally its subdirs) all > changes that occur. I implemented this by forking a process and > performint an overlapped external call to ReadDirectoryChangesW. > Most of the time of course that forked process blocks on the external call. > > This works fine, but what I am wondering about is how to deal with an > image save and restart of Smalltalk. (So far I haven't tried to save > an image when an instance of DirectoryChangeWatcher was still around). > Will the image save properly (even with a process blocked on an > overlapped external call) and if so, what state will the image be when > I restart Smalltalk? Will that forked process be still alive or do I > need to terminate it and start a new one? The image will certainly save properly, but since the state of the overlapped call cannot be known (in general) when the image is saved, it isn't possible to "restore" it on correctly on restart. We did consider re-initiating the overlapped call on image restart, but reasoned that the times when this would work did not justify the risk of it carrying out some undesired action. Also because external calls are frequently used in conjunction with external resources, it seemed quite likely that the arguments to the call itself would be invalid on image restart. Therefore the call has to be re-initiated (if required) from a higher level. So what you will find is that the Process will be there blocked on the same Semaphore that it was when the image was saved. This is the overlapped call completion Semaphore, which will never get signalled unless explicitly from the "application". In D5 the Semaphore is referenced from the 'overlappedCalls' instance variable of the Processor global, and is the single Semaphore used to block pending overlapped calls. However this is an implementation detail that should not be relied upon because it has been changed for D6. In D5 the single Semaphore is replaced with a new one on image restart (see ProcessorScheduler>>onStartup:), and so unless the process' blocked upon it are referenced from elsewhere, or the Semaphore itself is referenced from elsewhere, then it and the blocked process' will probably be GC'd shortly after image startup. > If I need to start a new one (or perform some action before and after > the image save), what is the protocol to adhere to)? > After browsing the SessionManager class hiearchy, it seems that I need > to register with "SessionManager current" for the events > #sessionStarted, #imageSaveStarting and #imageSaveCompleted. Is that the > recommended way or is there another protocol to handle this? > You probably want to observe #sessionStarted and #sessionStopped. The image save events are less useful than they might at first appear, because one generally doesn't want to upset the state of the image on image save as it has to keep running exactly as before afterwards. > > Last but not least on what "level" of the application should I handle > this? I.e. should every low-level class be able to reinstate their > former state after the restart of an image? In that case I would have > expected some coding in the File class to "OnStartup" reopen any file. Well that is a design decision as to which there is no one right answer. In fact you may decide not to bother reinstating the state of certain objects at all because the convenience does not justify the effort in doing so, or perhaps because the "world" may not be the same when the image is restarted, and so it does not make sense, or is not safe, to restore everything as it was. We do not make any attempt to restore Files. In general though we do try and preserve the illusion that the image will start up everything as it was before, and quite often this is done by observing the SessionManager events. However we typically try and restore external resources lazily - this avoids both unecessarily lengthening startup times, and also consuming external resources that are not actually needed in the new session. We found it such a common pattern that one should have an object that held an ExternalHandle for some external resource, and that we had startup processing to go through and nil these out so that they could be lazily recreated later, that we modified the VM's image loading code such that it automatically nulls out all instances of ExternalHandle (i.e. it sets the value of the instances to zero, rather than nilling out references to external handles). I think this change was made in D4, and the result is that many classes wrapping external resources no longer need special session startup code as long as they protect access to the resource handle with an accessor method that lazily creates the class based on an #isNull test against the handle. > > Or should those things rather be handled on a higher application level, > i.e. the main application has to invalid and reinstantiate all lower > level objects (i.e. instances of File)? > As to the level at which you should restore the state, well my preference is to do this at the lowest level at which you have all the information available to be able to do it. Typically the object which owns an external resource should be responsible for restoring in on image reload. However if that object is a private implementation detail that is not part of the public interface of the higher-level class, it would be reasonable to discard it and create a new one in the higher level object. Another reason to do the state restoral in higher layers would be where on needs to deal with possible changes in the world outside the image since it was last running. Regards Blair |
Blair McGlashan wrote:
[...] > The image will certainly save properly, but since the state of the > overlapped call cannot be known (in general) when the image is saved, it > isn't possible to "restore" it on correctly on restart. We did consider > re-initiating the overlapped call on image restart, but reasoned that the > times when this would work did not justify the risk of it carrying out some > undesired action. Also because external calls are frequently used in > conjunction with external resources, it seemed quite likely that the > arguments to the call itself would be invalid on image restart. Therefore > the call has to be re-initiated (if required) from a higher level. That makes certainly sense, since in my case a valid file handle is needed for the call. [Observing SessionManager events...] > You probably want to observe #sessionStarted and #sessionStopped. The image > save events are less useful than they might at first appear, because one > generally doesn't want to upset the state of the image on image save as it > has to keep running exactly as before afterwards. What would be the benefit of observing #sessionStopped ? Usually I'd close all external resources in the #finalize method. Or is finalization not invoked during image shutdown? In that case I'd of course have to close all external resources that Windows doesn't close automatically (or to my liking) when a program terminates. [...] Thanks so much, Blair for your explanations of Dolphin's behavior and the reflections on the best programming practices. It's not only the level of expertise, but also the level of helpfulness, that makes this newsgroup so impresssive. :) Best Regards, Bernhard |
Free forum by Nabble | Edit this page |