UP
 
EROS Web
 
Developer Documentation
 
Programmer's Guide
 

Capability Support in High-Level Languages

D R A F T


 
 

This note describes the support mechanisms provided to enable C and C++ programs to manipulate capabilities. All of the current EROS libraries are built using these conventions.

1. Introduction

Higher level languages such as C and C++. do not directly support capabilities as a standard datatype. While it is possible to extend these languages, such an extension represents a significant departure from the runtime expectations of existing programs. Instead, the current EROS programming environment has adopted a compromise using a combination of preprocessor facilities and compiler extensions.

1.1 Slot References

The EROS capability support mechanism provides a data type for capability slot references. Every capability resides in a slot, and a slot reference names that slot.

Two capability slot types are provided:

global

A global slot represents an object that is used throughout the program. A global slot can be mentioned by name at any point in the application.

temporary

A temporary slot can be used by a library routine that needs a place to put capabilities that are the interim results of computations. These names of these slots follow the scoping rules of the language, but the slots themselves remain allocated until the procedure exits.

Both types of slot references can be passed as arguments to library routines, but procedures are not permitted to return them as results or to copy one slot reference to another.

1.2 The Key Cache Library

The key cache library provides an optional tool for managing large numbers of capabilities. EROS processes have 31 effective capability registers (capability register zero cannot be modified). For many applications this is ample.

Other applications must support a larger number of capabilities. The Key Cache Library transparently multiplexes this larger number of capability slots onto the available capability registers, allowing the application to be written as though a large number of capabilities were directly available.

Because the EROS runtime libraries are written using the capability slot data type, they transparently take advantage of the key cache if it is present.

2. C and C++ Interface

The C/C++ interface for capability slots involves three declarations and three new procedure calls.

2.1 Slot Declarations

The declarations are:

DEF_SLOT(name)
DEF_SLOT(name, regno)

Defines a new slot, and a reference to that slot called name. If the optional register number is provided, the capability can initially be found in register regno.

This declaration can only be used at file scope.

DECL_SLOT(name)

Provides an external declaration for a slot that has been defined elsewhere in the application. This is similar to an extern declaration, and allows a single slot reference to be used in multiple files. It is an error to define two slots with the same name in the same application; slots do not conform to the usual rules about the C and C++ ``common'' areas.

TEMP_SLOT(name)

Declares a slot that is local to the declaring procedure. A currently unused slot number is allocated and bound to name. The identifier name remains in scope according to the usual C/C++ scoping rules. The actual slot is not released until the procedure returns.

    The peculiarity of the slot release timing is an artifact of the implementation of TEMP_SLOT. The runtime mechanism records the stack pointer of the procedure that allocated the slot. It later compares this recorded stack pointer to the current stack pointer to determine of the slot has been freed. Optimizing compilers go to some lenghts to avoid frequent adjustments to the stack pointer, so the scope of the allocation is not quite the same as the scope of the label.

The TEMP_SLOT mechanism provides a ``holding slot'' for interim results. As an example, a routine that creates a new process and returns a start capability to it must briefly hold both the start capability and the process capability to that process. This means that it requires a place to store the process capability that will not clobber a capability that is actively in use. The temp_slot declaration is intended for this purpose.

2.2 Procedures

The three new procedures are KCALL, KRETURN, and KSEND. Where the CALL, RETURN, and SEND procedures use a low-level message format, the KCALL, KRETURN, and KSEND procedures provide the binding layer between slot references and the capability registers in order for the invocation to succeed. KCALL, KSEND, and KRETURN resolve the slots to registers and then invoke the lower-level primitives.

3. Typical Usage

C and C++ code that wishes to use this interface should first include

    #include <domain/keyslot.h>

For native EROS applications, some of the key registers will initially contain values placed there by the constructor. Most applications will therefore wish to include the following declarations in the main source code file:

    DEF_SLOT(constituents, 1);   /* process constituents node */
    DEF_SLOT(self, 2);           /* domain key to this process */
    DEF_SLOT(proccre, 3);        /* our process creator */
    DEF_SLOT(mybank, 4);         /* our space bank */
    DEF_SLOT(mysched, 5);        /* our schedule capability */
    DEF_SLOT(caller, 31);        /* resume key to our caller */
    	      

Applications that wish to accept capability arguments as part of their invocations may also wish to declare:

    DEF_SLOT(arg1);              /* process constituents node */
    DEF_SLOT(arg2);              /* domain key to this process */
    DEF_SLOT(arg3);              /* our process creator */
    	      

As an example of TEMP_SLOT, consider the lwp_start library routine, which releases a new lightweight process to run:

    uint32_t lwp_start(KeySlot lwp /* a domain key */)
    {
      uint32_t result;
      TEMP_SLOT(lwp_fault);
      KMessage km;
    
      result = process_make_waiting(lwp, lwp_fault /* OUT */);
      if (result != RC_OK)
        return result;
    
      km.snd_len = 0;
      km.snd_slot0 = KR_ZERO;
      km.snd_slot1 = KR_ZERO;
      km.snd_slot2 = KR_ZERO;
      km.snd_slot3 = KR_ZERO;
      km.snd_code = RC_OK;
      km.snd_invSlot = lwp_fault;
    
      KSEND(&km);
      return RC_OK;
    }
    	      

4. Special Situations

A special situation arises in the case where a program is converting itself into another program by replacing its address space. The recipient program usually will have embedded assumptions about which of its initial capabilities are in what registers. These assumptions must be satisfied by the original program before invoking the target program.

This can be accomplished by means of the BIND_SLOT call:

BIND_SLOT(name, regno)

Given a slot named by name, cause the corresponding capability to be moved to regno if it is not already there. If the register regno is currently bound to some other slot name name2, this is accomplished by swapping both the capabilities and the slots of the two capabilities. Thus, if name1 is currently bound to reg1, and name2 is currently bound to reg2, and the call BIND_SLOT(name1, reg2) is made, the effect is to exchange the two registers, rebind name1 to reg2 and rebind name2 to reg1.

This is a long-winded way of saying the values are swapped.

It is therefore possible to achieve explicit placement of capabilities in desired registers by appropriate calls to BIND_SLOT.

Caution!

Any subsequent call to KCALL, KRETURN, or KSEND is entitled to rearrange the capability registers, so the slot bindings do not remain in effect across such calls.


Copyright 1998 by Jonathan Shapiro. All rights reserved. For terms of redistribution, see the EROS License Agreement