Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Continuations behavior of Dolphin and Squeak/VisualWorks

7 views
Skip to first unread message

Sebastian

unread,
Aug 22, 2008, 9:18:24 PM8/22/08
to
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.lang.smalltalk.dolphin/browse_thread/thread/eef5f8b8f5299947/44f04d0252c5142b?lnk=gst&q=WAProcessMonitor)

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

Sebastian

unread,
Aug 24, 2008, 10:36:55 AM8/24/08
to
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?

John Brant

unread,
Aug 24, 2008, 12:21:03 PM8/24/08
to Sebastian
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

Sebastian

unread,
Aug 24, 2008, 3:18:05 PM8/24/08
to

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

Sebastian

unread,
Aug 25, 2008, 11:24:31 AM8/25/08
to
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

Sebastian

unread,
Aug 25, 2008, 3:07:46 PM8/25/08
to
I'm testing both, Chris and Jhon's patches.
Sebastian

John Brant

unread,
Aug 25, 2008, 7:26:36 PM8/25/08
to
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

Sebastian

unread,
Aug 26, 2008, 10:09:09 AM8/26/08
to

Exactly what I though! I was about to propose a special termination
for continuations. Let me check how your patch performs...
Sebastian

Sebastian

unread,
Aug 26, 2008, 10:22:46 AM8/26/08
to
> 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?

Andy Bower

unread,
Sep 22, 2008, 3:10:47 PM9/22/08
to
SebastiaN,

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

0 new messages