# Copyright 2002 Combex, Inc. under the terms of the MIT X license # found at http://www.opensource.org/licenses/mit-license.html ............... pragma.syntax("0.9") def makeValueThunk :DeepFrozen := def makeFlexMap :DeepFrozen := def VatID :DeepFrozen := def makeVine :DeepFrozen := def Vine :DeepFrozen := makeVine.asType() def Throwable :DeepFrozen := /** * Rendezvous point for 3-vat live Granovetter introductions of Unresolved * remote references (RemotePromises). *

* Where we normally speak of Alice giving Bob a reference to Carol, we here * speak of the Donor (VatA) giving to the Recipient (VatB) a reference to the * Gift (Carol) residing on the Host (VatC). There is one PromiseGiftTable in * the Host per Donor. The Donor associates the gift with a Nonce and the * Recipient's ID, and she tells the Nonce to the Recipient. The Recipient asks * the Host "What gift has Donor (identified by DonorID) deposited for me at * this Nonce?". *

* A Nonce is a use once unique number. It only needs to be "impossible" to * collide under benevolent assumptions; it doesn't need to be unguessable, so * we just use a 64 bit 'long'. *

* Two interesting complexities: 1) The Recipient's lookup request may arrive * at the Host before the Donors donation request does. 2) A partition could * prevent the operation from completing, in which case the Recipient cannot be * left hanging, and the association must be cleaned up. *

* For 3-vat live Granovetter introductions of Resolved remote references * (FarRefs), see the NearGiftTable. * * @param nonceLocatorPromise A RemotePromise for the Donor's NonceLocator. * The ignore(vine) message is sent to it, so * that it can ignore it. * * @author Mark S. Miller. */ def makePromiseGiftTable(whenGarbage, nonceLocatorPromise) implements DeepFrozen { # Maps from [recipID, Nonce] to [referent, optResolver] var myStuff := makeFlexMap.fromTypes(Tuple[any, int], Tuple[any, any]) def promiseGiftTable { /** * Smash all untaken promises for undonated gifts, and then disable this * table. */ to smash(problem :Throwable) :void { for box in myStuff.getValues() { def [optResolver] := box if (null != optResolver) { optResolver.smash(problem); } } myStuff := null; } /** * Make the gift available to the recipient so long as the Vine is held * onto (isn't garbage). */ to provideFor(gift :any, recipID :VatID, nonce :int) :Vine { def keyPair := [recipID, nonce] def optValuePair := myStuff.fetch(keyPair, makeValueThunk.getNULL_THUNK()); def result := makeVine(null) if (null == optValuePair) { #donation happened first. def valuePair := [gift, null]; myStuff.put(keyPair, valuePair); whenGarbage(result, fn { promiseGiftTable.drop(keyPair) }) } else { #resolve the promise for a gift already looked up. Done. def resolver := optValuePair[1]; resolver.resolve(gift); myStuff.removeKey(keyPair); } return result; } /** * Lookup the gift.

*

* If absent, return a promise for what will be given, and sends an * ignore(vine) to the nonceLocatorPromise. The promise is good as long as * the vine is held.

*

* Note that this message is named "acceptFor" whereas the corresponding * NonceLocator message is named "acceptFrom". In acceptFor, the recipient * is explicit and the donor implicit. In acceptFrom, the donor is explicit * and the recipient implicit. * * @param recipID The vatID of the vat (Bob, the gift recipient) that the * gift is being picked up for. * @param nonce Identifies (together with the recipID) the gift. */ to acceptFor(recipID :VatID, nonce :int) :any { def keyPair := [recipID, nonce]; var optValuePair := myStuff.fetch(keyPair, makeValueThunk.getNULL_THUNK()) if (null == optValuePair) { #lookup happened first, promise a gift to be donated. optValuePair := Ref.promise(); myStuff.put(keyPair, optValuePair); def vine := makeVine(null); whenGarbage(vine, fn { promiseGiftTable.drop(keyPair) }) E.sendOnly(nonceLocatorPromise, "ignore", [vine]) } else { #Done. myStuff.removeKey(keyPair); } return optValuePair[0]; } /** * Automagically called when the vine is dropped.

The Donor is able to * call this as well, which isn't appropriate, but isn't dangerous, so what * the hell. * * XXX E translation note: we can and therefore should now make this private */ to drop(keyPair :List[VatID, int]) :void { def [recipID, nonce] := keyPair def optValuePair := myStuff.fetch(keyPair, makeValueThunk.getNULL_THUNK()); if (null == optValuePair) { return; } def optResolver := optValuePair[1]; if (null != optResolver) { optResolver.smash(E.asRTE("The vine was dropped: " + nonce)); } myStuff.removeKey(keyPair); } } return promiseGiftTable }