| Register | FAQ | Calendar | Search | Today's Posts | Mark Forums Read |
|
#1
| |||
| |||
| Hi there, implementing the feature of commit one transaction per http request in a Seaside application exposed a problem regarding Dolphin Continuations. Crhis Uppal in Nov 10, 2005 exposed this piece of code: c := nil. block := [Continuation currentDo:[:cc | c := cc. c value: 'Aha!!']]. sem := Semaphore new. value := nil. [ [value := block value] ensure: [sem signal. Transcript show: 'ooerr...'; cr.] ] fork. sem wait. (in this post: http://groups.google.com/group/comp....ProcessMonitor) It is very interesting because it reveals Dolphin printing in transcript 3 times "ooer..." Caution: with Continuations I learned one rule: don't try to think them, experiment them. Use #halt and debugger because that way is healthier for the brain ![]() I've then compared VisualWorks and Squeak behavior with this very same script. They print in transcript just once. Always. I'm not sure if asking why is a good idea because I think this particular point leaves open if this is about a bug or a feature, so I'll limit myself to ask if someone knows a way to achieve the same behavior as Squeak or VisualWorks on a case like this. To be able to execute the #ensure: block only once is mandatory for Seaside applications which want to use the good practice of wrapping the http request with a transaction. When you get more than one execution of that block you get weird things like mutex protected blocks look like getting violated or transactions trying to get committed twice. I've tried the Crhis hack in: Continuation>>continue: aProcess with: anObject Processor activeProcess exceptionEnvironment: nil. aProcess continueWith: anObject which was discouraged with reservations by Blair. This hack only compensates 1 of the 3 evaluations. I ask if someone knows how to compensate the other so Squeak/ VisualWorks behavior gets emulated. Better will be to understand its origin so ideas of a fix arise. Unless, of course, this behavior gets defined as bug and a proper patch is made about Continuations. cheers, Sebstian |
|
#2
| |||
| |||
| This tests will illustrate the behavior: Note: I've tested with the semaphore in a temp like here and also as instVar. Same results. TEST for Squeak and VisualWorks both green ContinuationTest>>testBlockEnsure | action sem | tmp2 := 0. action := [self callcc: [:cc | tmp := cc. true]]. sem := Semaphore new. [[action value] ensure:[ sem signal. tmp2 := tmp2 +1. self deny: tmp2 > 1]] fork. sem wait. tmp := nil. TEST for Dolphin will also show green but then shows the assertion failed ContinuationTest>>testBlockEnsure | action sem | tmp2 := 0. action := [[:cc | tmp := cc. true] callCC]. sem := Semaphore new. [[action value] ensure:[ tmp2 := tmp2 +1. self deny: tmp2 > 1. sem signal]] fork. sem wait. tmp := nil. Due to continuations the #deny: has to be inside the ensured block otherwise it will assert but the ensured block will actually be executed more than once (as you can check by printing in Transcript like in the Chris script). cheers, Sebastian PD1: for Seaside this has dramatic consequences because code of the app which uses #ensure: (as usual meant to run once) will also be ran more than once. PD2: maybe we can say the continuation to finish the process in a "special" way to compensate this? any pointer about how? |
|
#3
| |||
| |||
| The problem is that the continuation stores a copy of the process, and processes are registered on the finalization queue. Therefore, when the process stored in the continuation is GCed, its finalizer runs. The finalizer terminates the process and that causes its unwind blocks to run. I believe you can fix this by adding "stack beUnfinalizable" to the end of the #stack: method in Continuation. Here was the test case that I used: Object>>runCC | count | count := Array with: 0. [[:c | ] callCC] ensure: [count at: 1 put: count first + 1]. ^count with a test script of: | count | count := nil runCC. MemoryManager current collectGarbage; administerLastRites. Transcript print: count; cr; flush Without the #beUnfinalizable call, it prints an array with 2. However, with the call, it prints an array with 1. John Brant |
|
#4
| |||
| |||
| On Aug 24, 1:21*pm, John Brant <br...@refactoryworkers.com> wrote: > The problem is that the continuation stores a copy of the process, and > processes are registered on the finalization queue. Therefore, when the > process stored in the continuation is GCed, its finalizer runs. The > finalizer terminates the process and that causes its unwind blocks to > run. I believe you can fix this by adding "stack beUnfinalizable" to the > *end of the #stack: method in Continuation. > > Here was the test case that I used: > > Object>>runCC > * * * * | count | > * * * * count := Array with: 0. > * * * * [[:c | ] callCC] ensure: [count at: 1 put: count first + 1]. > * * * * ^count > > with a test script of: > > | count | > count := nil runCC. > MemoryManager current collectGarbage; administerLastRites. > Transcript print: count; cr; flush > > Without the #beUnfinalizable call, it prints an array with 2. However, > with the call, it prints an array with 1. > > John Brant That made the test go green (and remain green ![]() Only experience will say if undesirable secondary consequences arises from that or not. I'm optimistic about this one and for now that was definitively most helpful. I'm now solving other subtleties which emerged once that is working as expected. They are regarding to Seaside itself and to achieve my original goal. Thank you very very much Jhon, Sebastian |
|
#5
| |||
| |||
| Hi, an update: Jhon's patch made that test go green but is not enough. I was moving forward in my goal and found some problems again related to #ensure: and #ifCurtailed: So I've checked again the Chris test: c := nil. block := [[:cc | c := cc. c value: 'Aha!!'] callCC]. sem := Semaphore new. value := nil. [ [value := block value] ensure: [Transcript display: 'ooerr...'; cr. sem signal] ] fork. sem wait. And even with this patch wont get better. The test which fails assertion is: testCallContinuationInsideAndBlockEnsure | action sem | tmp2 := 0. action := [[:cc | tmp := cc. tmp value: 'Aha!'] callCC]. sem := Semaphore new. [[action value] ensure:[ Transcript cr; show: 'opa'. tmp2 := tmp2 +1. self deny: tmp2 > 1. sem signal]] fork. sem wait. tmp := nil. I've checked VisualWorks and Squeak they both do green on that. All Seasiders will appreciate a fix on this. Any clue? cheers, Sebastian |
|
#6
| |||
| |||
| I'm testing both, Chris and Jhon's patches. Sebastian |
|
#7
| |||
| |||
| Sebastian wrote: > I've checked VisualWorks and Squeak they both do green on that. > > All Seasiders will appreciate a fix on this. Any clue? It appears that VW doesn't run the unwind blocks when it creates a continuation and terminates the current process (see Continuation>>terminate: in VW). However, in Dolphin, they are just using the standard #terminate method (Process>>continueWith and thatruns the unwind blocks. I believe you could change the "Processor terminateActive" to be "Processor activeProcess kill" in the Process>>continueWith: method. John Brant |
|
#8
| |||
| |||
| On Aug 25, 8:26*pm, John Brant <br...@refactoryworkers.com> wrote: > Sebastian wrote: > > I've checked VisualWorks and Squeak they both do green on that. > > > All Seasiders will appreciate a fix on this. Any clue? > > It appears that VW doesn't run the unwind blocks when it creates a > continuation and terminates the current process (see > Continuation>>terminate: in VW). However, in Dolphin, they are just > using the standard #terminate method (Process>>continueWith and that> runs the unwind blocks. I believe you could change the "Processor > terminateActive" to be "Processor activeProcess kill" in the > Process>>continueWith: method. > > John Brant Exactly what I though! I was about to propose a special termination for continuations. Let me check how your patch performs... Sebastian |
|
#9
| |||
| |||
| > Exactly what I though! I was about to propose a special termination > for continuations. Let me check how your patch performs... > Sebastian It is working. I'm more comfortable with the idea of killing the process instead of setting nil in the environment. I'll be using both of your patches. Thank you so much John! Sebastian PD: Andy/Blair do you see any problem in integrating John patches? |
|
#10
| |||
| |||
| SebastiaN, >> Exactly what I though! I was about to propose a special termination >> for continuations. Let me check how your patch performs... >> Sebastian > > It is working. I'm more comfortable with the idea of killing the > process instead of setting nil in the environment. > I'll be using both of your patches. > Thank you so much John! > Sebastian > PD: Andy/Blair do you see any problem in integrating John patches? Could you (or someone) provide a summary of the Continuation patches (a fileIn perhaps) and some SUnit tests that demonstrate them working. If so, then I'm happy to integrate the changes into the next image. Best regards Andy Bower |
![]() |
| Thread Tools | |
| Display Modes | |
In an effort to better serve ads to our visitors, cookies are used on objectmix.com. For more information, check out our Privacy Policy.