Rescindable and Redirectable Capabilities
The rescindable version of a gate is provided merely by building a front end to the program that passes the parameters thru to the real node. Deleting the front end rescinds access to the program. If the program already has a front end, that front end can serve as the domain to be deleted.
We give here several mechanisms for implementing this mutual exclusion. These mechanisms are not semaphores but they fulfill the most common application for semaphores. See also {(p2,semaphore)} for an impure Gnosis technique that may be useful in converting programs designed for other environments.
Since there can be only one process in a domain, the Gnosis kernel ensures the mutual exclusion.
The domain executes the following Assembler code (see (p3,asmintf)):]
LABEL SLR
1,1]
LOADEXBL 0]
LOADENBL R1,,,,,0]
RETJUMP Here
while unlocked]
SLR 1,1]
KEYCALL 0,,R1,(,,,0) Here
while locked] B LABEL]
The domain is initialized by putting
DK(0) in its general key slot 0 and starting it at LABEL.
The domain will make itself available.
The critical region is implemented as follows. ENTRY is
a slot containing a start key to the domain. EXIT is some
other key slot.]
KEYCALL ENTRY,,,(,,,EXIT)]
critical
region]
KEYCALL EXIT]
LOOSE END Give PL/I version.
There is a domain which executes the same code as in (p3,restsema), but initially the domain is busy, its PSW points to LABEL, and there is a return key to it in some key slot which is shared by all domains which have a critical region. There is a word variable SEMACTR in shared memory, initialized to -1. The critical region is implemented as follows.
The first KEYCALL in (p3,optsema)
need not accept EXIT; it does accept a return code. The
second KEYCALL is replaced by:] LA 1,65 make domain
available]
KEYCALL DOMAIN,,R1 this will put 1 in R1]
DOMAIN is a slot containing a domain key to the domain.
To sleep, a domain executes a return jump to a data key. This makes the domain available.
To wake up a domain, execute a fork jump to a start key designating the domain to be awakened. This will cause the sleeping domain to continue execution after its return jump. The fork jump can pass parameters to the sleeping domain.
Note that the result of a sleep and a wakeup is the same regardless of the order in which they are executed.
{arcane}{nonref}Note also that the technique can be used regardless of whether jump packets are implemented {(p1,stall)}. If a fork jump to a start key can stall, the wakeup operation may stall until the domain to be awakened sleeps (becomes available). By using shared variables, it can be arranged that the wakeup operation stall for a short time at most.
Forks and Joins
Our policy in Gnosis is to use two domains when there are two independent calculations to be done. Suppose in our case that we have a domain D available to execute P2. When our program reaches F we do a fork jump to the D and proceed to P1.
At the end of P1 we call D again (neither passing nor accepting parameters) and proceed to J. At the end of P2 we return to DK(0) (to become available) followed by another return.
If P1 finishes first it will become stalled on trying to enter D. In either case we reach code J only after P1 and P2 both have finished.
Another way to describe the join is to say that domain D sleeps {(p3,sleep)} after executing P2 and the domain executing P1 wakes it up with a call jump, and then D returns.
Another way to do it, if the P1 domain does not otherwise service a start key, would be for the P1 domain to sleep and D to wake it up.
Other problems may arise if the segment or node disappears or otherwise mal-performs while the user is using the object.
1. Advise the client to provide a guarded space bank to the creator. If a zot key is lost, the user must call the guard to reclaim the space. Since space banks are hierarchical, there is always a sufficiently high bank to which not all keys have been lost. Disadvantages of this method: the zots may not be prompt because the space bank can be zapped at any time. Also, zots must be independent - no shared storage.
2. Accept an account and use it to charge rent for the zot. If a zot key is lost, the user can exhaust the account to destroy the zot. Since accounts are hierarchical, there is always a sufficiently high account to which not all keys have been lost. The space bank creator uses this method. Disadvantage: it is awkward or impossible for a client to specify the type of storage to be used for the zot.
3. Place a limit on the lifetime of a zot. A zot is destroyed when its lifetime expires. The user pays to receive a zot creator key good for N zot-seconds. If he loses a zot key, the zot will eventually expire. It may be possible to turn in a zot creator and get a refund. This method is useful when zot-seconds are an artificially scarce resource. The Tymnet adapter uses this method. Disadvantage: a zot does not stay around forever. It must be possible to choose a lifetime which is long enough to be useful and short enough so that paying for the zot over that lifetime (in case zot key is lost) is not terribly expensive.
4. This is a combination of 2 and 3. When a user creates a zot he supplies an account and says what he wants the lifetime of that zot to be. The account pays a one-time charge. There may be a call, using a zot key and an account, to extend the lifetime of the zot. This is like 3 except there is a separate limit for each zot instead of one for all zots created under a given zot creator.
5. Whenever a zot is created, keep a pointer (key) to it (which can be used to destroy it) in something older, like a previously existing zot. When a zot is destroyed, all the zots to which it has pointers are destroyed (recursively). Thus these pointers form a tree. The key to the oldest zot (root of the tree) is kept in a place where it is never lost.
If it uses a space bank, it should use the SBT to verify that the bank is official and prompt.
If necessary, it can act as a front end and create a domain to do any work that might not be prompt. This requires a prompt official space bank and a meter (which need not be verified). One other key can be accepted (in addition to a resume key).
If it needs to accept more than three keys, it can accept a node key containing the extra keys.
Or it can accept a key to a prompt official space bank to which the node is acceptable. After verifying the bank, the service can sever the node. This verifies the officialness of the node without destroying its contents. It incidentally also ensures the privacy of the node.
Returning to an Start Key
Each correspondent of a co-routine is a collection of domains. While they have control, the members of this collection must hold on to the most recent gate key received from the other correspondent. When they give up control they use this gate and pass (usually by a call) a gate to the other correspondent to be used to get back to the first correspondent.
Some instances may be implemented by producing a node which holds all of the particular values {or keys to them} and also a start key to a shared domain that obeys the code that defines the logic of the flavor. This node is formatted as a segment node with the latter entry as the segment keeper and {presumably} 0 initial slots.
A segment key to the new node is produced and this can be used as a key to the instance of the module.
See (one-node-dom) for related ideas.