Oz and Mozart Users Mailing List

_Extremely_ strange behaviour. Help!


From: Robin Lee Powell (rlpowell@digitalkingdom.org)
Date: Sat Aug 25 2001 - 23:39:35 CEST


I'm observing behaviour that I'm almost certain is a bug in Oz, but
every time I've thought that in the past I've been wrong. 8)

I know this is long, but you needn't read the code the first time through; just
read the text. I think you'll be intrigued enough to go back and read the
code.

Here's a code fragment:

- --------------------

local GCObj1 GCObj1Cap in
    {StorageObj
        {StorageObj StorageGetCapabilities getCapabilities($)}.createObject
        createObject( 'T0004a' GCObj1 {NewName} GCObj1Cap )
    }
    {System.showInfo "Test9."}
    {System.show {GCObj1 GCObj1Cap getCapabilities($)}}
    {System.showInfo "Test9.1"}
    {StorageObj StorageCapabilities.info info( Storage Storage) }
    {System.showInfo "Test9.2"}
end

{System.gcDo}
{Delay 5000}
{System.showInfo "Test10."}

- ---------------

All object in this system are wrapped in a procedure wrapper that takes 2
arguments: the capability for the method in question, and a normal method
record. When createObject is called, Storage, among other things, stores
GCObj1 in a weak dictionary with the {NewName} show above as a key, and stores
GCObj1Cap in a non-weak dictionary named @ozNameToCapabilities with the same
key.

This is the finalization thread for the weak dictionary:

- ----------------------------

thread
    Name
in
    {ForAll @ozNameObjFinalize
        proc {$ FinalizeKey#FinalizeObj}
            {@system.showInfo "Finalize stream."}
            {@system.show FinalizeKey}
            {@system.showInfo "Finalize stream.1"}
            {@system.show FinalizeObj}
            {@system.showInfo "Finalize stream.2"}
            {ForAll
                {Dictionary.entries @ozNameToCapabilities}
                proc {$ Name1#Name2}
                    {@system.show Name1==FinalizeKey}
                    {@system.show
                        {Dictionary.condGet
                            @ozNameFile
                            Name1
                            nil
                            $
                        }
                    }
                    {@system.show
                        {Dictionary.condGet
                            @ozNameFile
                            FinalizeKey
                            nil
                            $
                        }
                    }
                    {@system.show Name2==FinalizeKey}
                    {@system.show
                        {Dictionary.condGet
                            @ozNameFile
                            Name2
                            nil
                            $
                        }
                    }
                end
            }
            {@system.showInfo "Finalize stream.3"}
            {@system.show
                    {Dictionary.get
                        @ozNameToCapabilities
                        FinalizeKey
                        $
                    }
            }
            {self saveObject( FinalizeObj FinalizeKey
                    {Dictionary.get
                        @ozNameToCapabilities
                        FinalizeKey
                    }
                    )
            }
            {@system.showInfo "Finalize stream.n"}
        end
    }
end

- -----------------------------

Note that most of that is debugging output.

As the code stands, that thread is never used; gcDo has no perceptible effect,
at least on the weak dictionary in question.

If
    {StorageObj StorageCapabilities.info info( Storage Storage) }
is commented out, the finalization is reached. Note that info() currently
contains only 'skip'!!

It doesn't actually work, though, and the output of the finalization thread is:

- ---------------------------------

Finalize stream.
<N: Name>
Finalize stream.1
<P/2 StatP>
Finalize stream.2
false
2
nil
false
nil
Finalize stream.3

%************************ Error: Dictionary *********************
%**
%** Key not found
%**
%** Dictionary: <Dictionary>
%** Key found: <N: Name>
%** Legal keys: [<N>]
%** In statement: {<P/3 Dictionary.get> <Dictionary> <N: Name> _}
%**
%** Call Stack:
%** procedure in line 101, column 2, PC = 136481280
%**--------------------------------------------------------------

- ---------------------------------

As you can see, the FinalizeKey is not a key in @ozNameToCapabilities, which,
if FinalizeKey is actually the name that it was set to, is impossible.

But wait, it gets better!

If
    {System.show {GCObj1 GCObj1Cap getCapabilities($)}}
is commented out, regardless of whether
    {StorageObj StorageCapabilities.info info( Storage Storage) }
is commented out or not, it works!

With that GCObj1 call commented out, FinalizeKey is, in fact, a key in
@ozNameToCapablities.

Here's the code that handles the port that GCObj1 uses, stolen straight from
the tutorials, with some mods:

- ---------------------------------

% Client side:
proc {StatP Name M}
    R in
        % Note that this send causes R to be bound to
        % whatever the server thread puts after the # in its
        % processing. This will either be N or an error.
        {Send P M#Name#R}

        if R==N then
            skip
        else
            raise R end
        end
end

% Server side:
thread
    {ForAll S
        proc {$ Method#Name#R}
            NewObj OrigRecord
        in

            % First we make sure the caller has the right
            % capability.
            if Name \=
                    {Dictionary.get CapabilityDict {Label Method} }
            then
                R = mozError( permission_denied(
                    'That capability does not exist!' ) )
            end

            % Here we handle those 'methods' that require
            % intervention at the wrapper level.

            case {Label Method}

            % toRecord: takes a variable as its sole
            % argument, which it assigns to the persistent
            % record associated with the object.
            of 'toRecord' then
 
[*********SNIP************]

            % getCapabilities: takes a single variable as
            % its sole argument, which it binds to a record
            % containing bindings of method names to
            % capability Oz names.
            [] 'getCapabilities' then
                % Here we return the set of capabilities as
                % a record.
                Method.1 =
                {List.toRecord 'capabilities'
                        % Here we get a tuple list from the
                        % dictionary in name#method order.
                        {Record.toListInd
                            {Dictionary.toRecord
                                'capabilities'
                                CapabilityDict
                            }
                        $}
                $ }

                R=N

[*********SNIP************]

- ---------------------------------

As you can see, no writing of any dictionaries is done here. In fact, the
Storage object, and hence @ozNameToCapablities, is never gone anywhere _near_
by this code. But if this code gets run, the finalization stream no longer works.

Clearly, this behaviour makes no sense whatsoever.

Help, please!!

-Robin

-- 
http://www.digitalkingdom.org/~rlpowell/ 	BTW, I'm male, honest.
le datni cu djica le nu zifre .iku'i .oi le so'e datni cu to'e te pilno
je xlali -- RLP 				http://www.lojban.org/
-
Please send submissions to users@mozart-oz.org
and administriva mail to users-request@mozart-oz.org.
The Mozart Oz web site is at http://www.mozart-oz.org/.



This archive was generated by hypermail 2b29.