About CAmkES

Overview

CAmkES (component architectures for microkernel-based embedded systems) is a software development and runtime framework for quickly and reliably building microkernel-based multiserver (operating) systems. It follows a component-based software engineering approach to software design, resulting in a system that is modelled as a set of interacting software components. These software components have explicit interaction interfaces and a system design that explicitly details the connections between the components.

The development framework provides:

  • a language to describe component interfaces, components, and whole component-based systems
  • a tool that processes these descriptions to combine programmer-provided component code with generated scaffolding and glue code to build a complete, bootable, system image
  • full integration in the OKL4 environment and build system

Motivation

A microkernel-based multiserver operating system is designed as a set of protected and separated services that communicate with each other through efficient and secure interprocess communication mechanisms. Since these services are protected from each other by a combination of kernel and hardware protection, the resulting systems have the potential to be highly reliable and secure.

However, the design of such a system becomes increasingly difficult as the number of services and the complexity of their interconnection grows. They become particularly difficult to build and maintain when there is no explicit specification of how the services should and do interoperate By making the interactions between these services explicit a component-based software engineering approach reduces this complexity for the developer and makes the design and implementation of complex microkernel-based systems feasible.

Component-Based Software Engineering

Component-Based Software Engineering (CBSE) is a software development approach that is based on the decomposition of a system into a set of interconnected software components.

A software component is a system element offering a predefined service through well-defined interfaces. Software components are similar to objects in the object-oriented paradigm in that they encapsulate their state so that it is not visible or directly accessible from outside the component. However, components are typically more coarse-grained, and of a higher abstraction level, than objects, and have stricter requirements regarding their interfaces. In particular, besides defining the interfaces they provide, they also define interfaces they use, that is, the interfaces of other components they rely on. A key feature of software components is that they are meant to be reusable and should be designed and implemented such that they can be used in many different systems.

Components are connected to each other using connectors, which are system elements that explicitly connect corresponding interfaces of communicating components. Connectors implement the glue code that binds components together, and they are the only parts of the system that need to explicitly use underlying system mechanisms (such as IPC, capabilities, etc.). A set of components and the connections between them form a system architecture which is commonly referred to as a component system or architecture.

The details of how components, component interfaces, and component architectures are specified are defined by a component model. The features of a component model determine the flexibility and power of a particular CBSE-based approach. A component framework implements a component model, providing tools and support software for building components and component-based systems according to that model. (Note that terminology varies and there is some overlap: in particular what we call a component framework is sometimes called a component architecture or a component system.)

While most models leave out the details of the inter-component connection (i.e., do not allow the explicit specification of connections, or if they do do not include details of how the connectors work), CAmkES treats connectors as first-class entities, bringing them up to the level of software components themselves. This means that system developers may choose which connectors to use when connecting software components and may also define and implement their own connectors. The key benefit of this is that it allows inter-component connections to be highly optimised and tuned to specific components and scenarios, allowing system designers to focus on building systems that combine good software engineering practices with high performance.

See The CAmkES component model for more details about the CAmkES component model.

CAmkES Features

The CAmkES framework provides:

IDL
to define component interfaces. CAmkES uses the same IDL already used by OKL4.
ADL
to define components and system architectures.
ADL/IDL compiler
generates all required scaffolding and glue code. It is extensible, template-based, and based on the Magpie compiler already used for OKL4.
Connectors
provide mechanisms for inter-component communicatin. They are user definable and reusable just like components.
OKL4 build system integration
CAmkES is fully integrated into the OKL4 build system. It takes much of the pain out of dealing with the build system, providing an easy one-step build process. In particular there is no need to modify any parts of the build system when building a CAmkES-based system.

OKL4 Development with CAmkES

A CAmkES-based system is designed as a set of components connected together by connectors. CAmkES components represent the system services and are ultimately implemented as OKL4 protection domains. CAmkES connectors represent the communication channels and are implemented using appropriate OKL4 IPC mechanisms including synchronous IPC, asynchronous notifications, and shared memory sections.

This is most easily explained with a component system diagram.

In this example we have two compontents, Component1 and Component2. Component2 provides an interface called inf, and Component1 uses the inf interface. The two components are connected at their interfaces through a connector. This allows Component1 to invoke operations (as defined in the inf interface) on Component2.

In designing such a system a developer first decides on the components needed. These can either be pre-existing reusable components, or may need to be custom-built for the desired system. Components are usually designed so that they are reusable in different systems, enabling rapid development of systems from libraries of reusable software components.

When designing and building components a developer first defines the interfaces that the components will provide. The interfaces are defined in an interface definition language (IDL). CAmkES provides three different classes of interfaces.

  • RPC (remote procedure call)
  • events (asynchronous messages, carry no data)
  • dataports (shared memory)

The developer then defines the component by specifying the interfaces provided by the component and the interfaces used by the component. This is done using an architecture description language (ADL). The actual functionality of the component is provided as C source code.

Once all the components have been chosen and defined, the developer then defines the system architecture, i.e., how all the components will be connected together. This architecture is described using the ADL and specifies all the components used, the connections between them, and the connectors used for the connections.

The developer then invokes the build system, which analyses the ADL descriptions, generates appropriate runtime and glue code, and compiles and links this together with the component and connector code to produce appropriate OKL4 server images. The build system then then further combines these images with the OKL4 kernel and other standard servers to produce a final bootable system image. Finally, the image can be run on the desired hardware or emulator.

Example

Here is an example of a simple component system and some of the associated IDL, ADL, and C code (see the tutorial for more details):

The ADL:

  import "Hello.idl4"; 
  import "std_connector.camkes";
  
  component HelloComponent {
          provides Hello h;
  }
  
  component HelloClient {
          control;
          uses Hello h;
  }
  
  assembly {
          composition {
                  component HelloComponent hcomp;
                  component HelloClient hclient;
  
                  connection IguanaRPC hello(from hclient.h, to hcomp.h);
          }
  }

The IDL:

  interface Hello {
          void hello(in smallstring msg);
  };

The C code for HelloComponent component:

  #include <stdio.h>
  #include <HelloComponent_h.h> 
  
  void h__init(void) {
  }
  
  void h_hello(char *msg) {
          printf("This is the hello component saying %s\n", msg);
  }

The C code for HelloClient component:

  #include <stdio.h>
  #include <HelloClient_h.h>
  
  void run(void);
  void run(void) {
          printf("Starting the client\n");
          printf("-------------------\n");
          while (1) {
                  h_hello("hello world");
          }
  
          printf("After the client\n");
  }
  

The CAmkES component model

The key features of the CAmkES component model are:

A minimal core model

The core of the CAmkES model provides the minimum functionality required to build static componentised systems. The functionality provided by the core model includes: specification of RPC, event, and dataport interfaces, specification of components, specification of connectors, specification of compositions of components.

Explicit interactions

In a componentised system making commuincation between components explicit is critical in providing reusable components. This means that components interact with the rest of the system only via well-defined interfaces. As such all communication (including communication through shared data) is explicit in a CAmkES system architecture.

Furthermore, In CAmkES we have identified that communication between components is a critical part of a reliable and high performance system. As a result, the connectors that implement communication in our model are first-class entities. This means that connectors can be defined, implemented, and reused by system programmers just like components. We call these user-defined connectors.

Low overhead

The minimal, static, core of CAmkES makes it possible for us to limit the overhead introduced by a component-based design. Our JSS paper describes the low overhead of an early prototype. The flexibility provided by user-defined connectors allows us to further optimise systems based on their specific requirements.

Extensibility of the model and the tools

While the core provides only a static model, the CAmkES framework is extensible, allowing further functionality to be added as needed. To illustrate this we have extended CAmkES to provide dynamic (run-time) component instantiation and binding. The costs (in terms of space, performance and complexity) for such extra functionality are only paid for systems where it is required. This is one of the key motivations behind the CAmkES design: don't pay for what you don't need. Our QoSA paper discusses CAmkES extensibility.

Optimisability

Given that all communication between components is explicit, and that the system developer can influence how that communication takes place, CAmkES provides a lot of space for system-specific optimisations. Such optimisations can range from a reorganisation of the system architecture for improved performance based on known best practices or patterns, to a system specific implementation of connectors and key components that takes advantage of system specific behaviour to optimise performance hot-spots. This is the topic of current and future research.

Platform

CAmkES runs on OKL4 (version 2.1 and 3.0)

Components are written in C. Connectors are written in a combination of C and Python.

CAmkES is supported on any hardware platform that OKL4 supports (for example, ia32, XScale, etc.)

License

CAmkES is licensed under a BSD license (except for parts that are modifications of OKL4 code, in which case they retain their OKL4 license).

People

The core CAmkES team consists of:

  • Ihor Kuz
  • Jenny Liu
  • Nicholas FitzRoy-Dale

Past team members and others that have significantly contributed to the project include:

  • Ted Wong
  • Soeren Kemmann
  • Andri Toggenburger
  • Michael Hills