diff --git a/doc/architecture.txt b/doc/architecture.txt index 4786138a3..8dbfb3499 100644 --- a/doc/architecture.txt +++ b/doc/architecture.txt @@ -787,251 +787,3 @@ contains its RM session and RAM session. ; supplying the parent capability to the new process -Framework infrastructure -######################## - -Apart from the very fundamental mechanisms implemented by core, all -higher-level services have to be implemented as part of the process tree on top -of core. -There are a number of frameworks at hand that provide convenient interfaces to -be used by such components. -In this section, we outline the most important frameworks. - - -Communication -============= - -The basic mode of operation of our RPC framework is based on C++ streams. -It uses four different stream classes: 'Ipc_ostream' for sending messages, -'Ipc_istream' for receiving messages, 'Ipc_client' for performing RPC calls, -and 'Ipc_server' for dispatching RPC calls. In the following, we use -illustrative examples. - -:Sending a message: - - !Ipc_ostream sender(dst, &snd_buf); - !sender << a << b << IPC_SEND; - The object 'sender' is an output stream that is initialized with a - communication endpoint ('dst') and a message buffer ('snd_buf'). - For sending the message, we sequentially insert both arguments into the stream - to transform the arguments to a message and finally invoke the IPC mechanism of - the kernel by inserting the special object 'IPC_SEND'. - -:Receiving a message: - - !int a, b; - !Ipc_istream receiver(&rcv_buf); - !receiver >> IPC_WAIT >> a >> b; - For creating the 'receiver' input stream object, we specify a receive message - buffer as argument that can hold one incoming message. - By extracting the special object 'IPC_WAIT' from the receiver, we block for - a new message to be stored into 'rcv_buf'. - After returning from the blocking receive operation, we use the extraction - operator to _unmarshal_ the message argument by argument. - -:Performing a RPC call: - - !Ipc_client client(dst, &snd_buf, &rcv_buf); - !int result; - !client << OPCODE_FUNC1 << 1 << 2 - ! << IPC_CALL >> result; - The first argument is a constant that references one among - many server functions. - It is followed by the actual server-function arguments. - All arguments are marshalled into the 'snd_buf'. - When inserting the special object 'IPC_CALL' into the 'client' - stream, the client blocks for the result of the RPC. - After receiving the result message in 'rcv_buf', the RPC - results can be sequentially unmarshalled via the extraction - operator. Note that 'rcv_buf' and 'snd_buf' may use the - same backing store as both buffers are used interleaved. - -:Dispatching a RPC call: - - !Ipc_server server(&snd_buf, &rcv_buf); - !while (1) { - ! int opcode; - ! server >> IPC_REPLY_WAIT >> opcode; - ! switch (opcode) { - ! case OPCODE_FUNC1: - ! { - ! int a, b, ret; - ! server >> a >> b; - ! server << func1(a, b); - ! break; - ! } - ! .. - ! } - !} - The special object 'IPC_REPLY_WAIT' replies to the request of the previous - server-loop iteration with the message stored in 'snd_buf' (ignored for the - first iteration) and then waits for an incoming RPC request to be received - in 'rcv_buf'. - By convention, the first message argument contains the opcode to identify - the server function to handle the request. - After extracting the opcode from the 'server' stream, we branch into - a server-function-specific wrapper that reads the function arguments, calls the - actual server function, and inserts the function result into the 'server' stream. - The result message is to be delivered at the beginning of the next server-loop - iteration. - The two-stage argument-message parsing (the opcode to select the server function, - reading the server-function arguments) is simply done by subsequent extraction - operations. - - -Server framework -================ - -[image server_framework] - Relationships between the classes of the server object framework - -Each component that makes local objects remotely accessible to other components -has to provide means to dispatch RPC requests that refer to different objects. -This procedure highly depends on the mechanisms provided by the -underlying kernel. -The primary motivation of the server framework is to hide actual kernel -paradigms for communication, control flow, and the implementation of -local names (capabilities) behind a generic interface. -The server framework unifies the control flow of RPC dispatching and the mapping -between capabilities and local objects using the classes depicted in Figure [server_framework]. - -:'Object_pool': is an associative array that maps capabilities from/to local objects. - Because capabilities are protected kernel objects, the object pool's functionality - is supported by the kernel. - -*Note:* _On L4v2 and Linux, capabilities are not protected by the kernel but are_ -_implemented as unique IDs. On these base platforms, the object pool performs_ -_the simple mapping of such unique IDs to object pointers in the local_ -_address space._ - -:'Server_object': is an object-pool entry that contains a dispatch function. - To make a local object type available to remote components, the local - object type must inherit from 'Server_object' and provide the implementation - of the dispatch function as described in Section [Communication]. - -:'Server_entrypoint': is an object pool that acts as a logical communication entrypoint. - It can manage any number of server objects. When registering a server object to be - managed by a server entrypoint ('manage' method), a capability for this object - gets created. This capability can be communicated to other processes, - which can then use the server object's RPC interface. - -:'Server_activation': is the stack (or thread) to be used for handling RPC requests - of an entrypoint. - -*Note:* _On L4v2 and Linux, exactly one server activation must be attached to_ -_a server entrypoint. This implicates that RPC requests are handled in a_ -_strictly serialized manner and one blocking server function delays all_ -_other pending RPC requests referring the same server entrypoint. Concurrent handling_ -_of RPC requests should be realized with multiple (completely independent)_ -_server entrypoints._ - - -Process environment -=================== - -As described in Section [Interfaces and Mechanisms], a newly created process -can only communicate to its immediate parent via its parent capability. -This parent capability gets created "magically" dependent on the actual -platform. - -| For example, on the L4v2 platform, the parent writes the information about -| the parent capability to a defined position of the new process' address space -| after decoding the ELF image. On the Linux platform, the parent -| uses environment variables to communicate the parent capability to the -| child. - -Before entering the 'main' function of the new process, the process' startup -code 'crt0' is executed and initializes the _environment_ framework. -The environment contains RPC communication stubs for communicating with the -parent and the process' RM session, CPU session, PD session, and RAM -session. -Furthermore, the environment contains a heap that uses the process' RAM -session as backing store. -The environment can be used from the actual program by dereferencing the pointer -returned by the global function: -! Env *env(); - - -Child management -================ - -The class 'Child' provides a generic and extensible abstraction to unify the -creation of child processes, serve parent-interface requests, and to perform the -book keeping of open sessions. -Different access-control and resource-trading policies can be realized by -inheriting from this class and supplementing suitable parent-interface server -functions. - -A child process can be created by instantiating a 'Child' object: -!Child(const char *name, -! Dataspace_capability elf_ds_cap, -! Ram_session_capability ram_session_cap, -! Cpu_session_capability cpu_session_cap, -! Cap_session *cap_session, -! char *args[]) - -*NOTE:* _The 'name' parameter is only used for debugging._ -_The 'args' parameter is not yet supported._ - -;The 'Child' serves the parent interface for the new process by a distinct thread. - - -Heap partitioning -================= - -In Section [Goals and Challenges] where we introduced the different types of -components composing our system, we highlighted _resource multiplexers_ as -being critical for maintaining the isolation and independence of applications from -each other. -If a flawed resource multiplexer serves multiple clients at a time, information -may leak from one client to another (corrupting isolation) or different clients -may interfere in sharing limited physical resources (corrupting independence). -One particular limited resource that is typically shared among all -clients is the heap of the server. -If the server performs heap allocations on behalf of one client, this resource -may exhaust and renders the service unavailable to all other clients (denial of -service). -The resource-trading concept as presented in Section [Quota] enables clients to -donate memory quota to a server during the use of a session. -If the server's parent closes the session on request of the client, the donated -resources must be released by the server. -In order to comply with the request to avoid intervention by its parent, the -server must store the state of each session on dedicated dataspaces that can be -released independently from other sessions. -Instead of using one heap to hold anonymous memory allocations, the server -creates a _heap partition_ for each client and performs client-specific -allocations exclusively on the corresponding heap partition. -There exist two different classes to assist developers in partitioning the heap: -:'Heap': is an allocator that allocates chunks of memory as dataspaces from a - RAM session. Each chunk may hold multiple allocations. This kind of heap - corresponds loosely to a classical heap and can be used to allocate a high - number of small memory objects. The used backing store gets released on the - destruction of the heap. -:'Sliced_heap': is an allocator that uses a dedicated dataspace for each - allocation. Therefore, each allocated block can be released independently - from all other allocations. -The 'Sliced_heap' must be used to obtain the actual session objects and store -them in independent dataspaces. -Dynamic memory allocations during the lifetime of a session must be performed by -a 'Heap' as member of the session object. -When closing a session, the session object including the heap partition gets -destroyed and all backing-store dataspaces can be released without interfering -other clients. - - -Limitations and Outlook -####################### - -In its current incarnation, the design is subject to a number of limitations. -As a prime example for managing resources, we focused our work on physical -memory and ignored other prominent resource types such as processing time, bus -bandwidth, and network bandwidth. -We intend to apply the same methodology that we developed for physical memory to -other resource types analogously in later design revisions. -We do not cover features such as virtual-memory or transparent -copy-on-write support, which we regard as non-essential at the current stage. -At this point, we also do not provide specifics about the device-driver -infrastructure and legacy-software containers. -Note that the presented design does not fundamentally prevent the support -of these features. -