\Note{Must provide a prtl instance. Implement upcall too!
A portal is a communication endpoint. It can be attached to a handler and
also invoked like an interrupt. Portals are contained in the portal
server, an instance of the PrtlSrv class whose main task is to allocate
portals.
<Off portal server. >=
// A portal server.
//
class off_PrtlSrv : public off_AbsCompResource {
public:
// Allocates a portal.
off_Prtl *alloc(const off_Protection &p,
natural_t n=1, off_prtl_id_t at=OFF_PRTL_NULL);
// Deallocates a portal
void free(off_Prtl *p, natural_t n=1);
// Gets a portal by its number
off_Prtl *operator+(vm_offset_t p) ;
off_Prtl *operator+(off_prtl_id_t p);
<Other public methods of off_PrtlSrv. >
};
Definesoff_PrtlSrv(links are to index).
Portals support both protected control transfers (PCTs) and asynchronous message delivering.
<Other public methods of off_PrtlSrv. >= (<-U)
// Delivers a message to this portal using a PCT.
// (May reset the stack)
err_t pct(off_prtl_id_t p, vm_size_t msz, vm_size_t rsz,
off_Msg *msg, off_Msg *reply, natural_t tmout);
// Pass the PCT to a different portal.
// Reply to the initial PCT will be issued from there. (May reset the stack)
err_t pct_pass(const off_shtl_id_t &sender, off_prtl_id_t p,
vm_size_t msz, vm_size_t rsz,
off_Msg *msg, off_Msg *reply, natural_t tmout );
// Returns from a PCT.
err_t pct_ret(void);
When used for PCTs, the sender shuttle changes its properties on the fly and becomes itself a flow of control in the receiver protection domain. After the handler completes, the shuttle recovers its original state and continues its execution.
Callees may, at any time, delegate the execution of PCTs to other
servers. In this case, one single shuttle can cross several protection
domains and come back directly to its
original site. To delegate a PCT reply to a different server,
pct_pass can be used.
Finally, when no reply is ever expected, deliver should be used
instead. It will simply save (in the callee context) what users are
unable to save safely (like eflags on Intel architectures) and
install a simple activation frame for the handler on the receiver's
shuttle. In this case, the caller will resume execution as soon as the
callee has been notified; the message is sent but may be not delivered
yet.
The handler information present in the portal is basically a program
counter (pc), a pointer to a pool of stack pointers (spp), an
access mode mode, and an (optional) set of properties (props).
Each property value in props will cause the sender's property to
be set to that value during portal invocation. Remaining sender
properties will maintain their original value. As it is most likely
that the address space property (see section
) will be
present, that property is factored out of the property array to gain
some performance. On nodes where the kernel is compiled without support
for multiple protection domains, a null value is used the such
property is ignored. When the props set is not present in the
portal, it will not support PCTs but just asynchronous message
delivering.
That is enough to support PCTs, but for asynchronous message
delivering it is necessary that the portal have a shuttle identifier.
Thus, when deliver is used, the handler (known by the portal
information) will run not on the sender shuttle but on the receiver.
If the receiver shuttle identifier is not specified, the portal will
not support asynchronous delivering.
<Off portal. >=
// A portal.
//
class off_Prtl : public AbsResUnit {
private:
<Other off_Prtl private members. >
public:
// Creates a portal.
off_Prtl(const off_Protection &p,
const off_prtl_id_t &domain,
const off_EventHandler *h,
vm_offset_t stack_pointers_pool,
off_mode_t mode,
natural_t maxmsgsz=0,
const off_ShtlProp *props=NULL,
off_shtl_id_t s=OFF_SHTL_NULL );
// (Re)sets the portal handler.
err_t set_hndlr(vm_offset_t pc, vm_offset_t spp, off_mode_t mode,
off_dtlb_id_t vas, natural_t maxmsgsz=0,
const off_ShtlProp *props=NULL,
off_shtl_id_t s=OFF_SHTL_NULL);
// (Locally) delivers a message to this portal using a PCT.
// (May reset the stack)
err_t pct(off_Shtl *sender, vm_offset_t msz, vm_offset_t rsz,
Msg *msg, Msg *reply, natural_t tmout) const;
// Pass the PCT to a different portal.
// Reply to the initial PCT will be issued from there. (May reset the stack)
err_t pct_pass(off_Shtl &sender, off_prtl_id_t p) const;
// Delivers an event to a portal (one-way PCT).
// (May reset the stack)
err_t deliver(off_Shtl &sender, vm_offset_t msz,
Msg *rq_msg, natural_t tmout) const;
<Other public methods of off_Prtl. >
};
Definesoff_Prtl(links are to index).
There are specialized versions of pct and deliver for use
inside the kernel.
<Other public methods of off_Prtl. >= (<-U)
// (Locally) delivers a message to this portal using a PCT.
// (May reset the stack)
err_t kpct(off_Shtl &sender, vm_offset_t msz, vm_offset_t rsz,
Msg *msg, Msg *reply, natural_t tmout) const;
// Delivers an event to a portal (one-way PCT).
// (May reset the stack)
err_t kdeliver(off_Shtl &sender, vm_offset_t msz,
Msg *rq_msg, natural_t tmout) const;
Portals may be used to enforce object access control. When the handler
is attached to the portal, the permitted access mode through this
portal is specified. The kernel does not enforce it. Instead, the
access mode will be placed in a pre-specified register so that the
user handler can check the validity of the access. For example, a file
object may create a read-only access point using a portal specifying
OFF_OP_R as the only permitted access mode. We could have omitted
this access mode feature from portals, but it does not change the
portal semantics and avoid those calls which will fail to proceed
further.
The stack pool pointer (spp) portal member points to an array of
initial stack pointers provided by the handler. Each incoming
invocation will use, as its own user stack, one of the stacks found
there. The pool of stacks can be of any length, but it is assumed that
the last stack pointer will be invalid and its value will be 1.
Upon portal invocation, the kernel selects one of the non-zero
pointers found in the pool and then resets it to 0. Since a stack
pointer with value 0 will be ignored, this is a safe mechanism to
avoid race conditions during stack selection. To allow the stack to be
reused, the user-level handler must (atomically) write the original
stack pointer value back to the stack pool.
When there are no more free stacks, any further call on the portal blocks.
These blocked shuttles are queued (using shuttle identifiers instead of
pointers, so that the list can span several nodes) using the p_wstack
private member. When a new stack is made available, they are awakened.
<Other off_Prtl private members. >= (<-U)
off_Bureaucrat p_wstack; // No stack available on a PCT portal
\subsection{Portals for plain users}
The portal server has a ``conventional'' wrapper.
<Off portal server for users. >=
ENTRY class off_uPrtlSrv : public off_uAbsCompResource {
public:
off_uPrtl *alloc(const off_Protection &prot,
natural_t n=1, off_prtl_id_t at=OFF_PRTL_NULL);
void free(off_uPrtl *p, natural_t n=1, const off_Rights &r);
off_uPrtl *operator [](off_prtl_id_t id, const off_Rights &r);
};
Definesoff_uPrtlSrv(links are to index).
The portal wrapper is the most special one in the kernel. Only the non-delivering methods are exported to users as usually. Methods used for message delivering and PCT are implemented without wrapper services (because they are used to implement the portal delivering mechanism used by the wrappers).
<Off portal for users. >=
ENTRY class off_uPrtl : public uAbsResUnit {
public:
// (Re)sets the portal handler.
void set_hndlr(vm_offset_t pc, vm_offset_t spp, off_mode_t mode,
off_dtlb_id_t vas, natural_t maxmsgsz=0,
const off_ShtlPSet *props=NULL,
off_shtl_id_t s=OFF_SHTL_NULL,
const off_Rights &prtl_r, const off_Rights &shtl_r,
const off_Rights &dtlb_r);
};
Definesoff_uPrtl(links are to index).
%\Note{Should perform access checking for properties passed in props.