1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/docs/wiki/Clients Sat Apr 25 22:27:39 2020 +0200
1.3 @@ -0,0 +1,122 @@
1.4 += Clients =
1.5 +
1.6 +Client code is code that accesses the facilities of components as described by
1.7 +those components' interfaces, potentially via interprocess communications
1.8 +mechanisms. Given an interface description featuring component operations,
1.9 +code may be written to invoke these operations and to treat the component as
1.10 +if it resides in the same program.
1.11 +
1.12 +<<TableOfContents(2)>>
1.13 +
1.14 +== Introduction ==
1.15 +
1.16 +The following example interface, resident in a file called `calc.idl`, will be
1.17 +used to illustrate the mechanisms described in this document:
1.18 +
1.19 +{{{
1.20 +interface Calc
1.21 +{
1.22 + void add(in int left, in int right, out int result);
1.23 + void subtract(in int left, in int right, out int result);
1.24 + void multiply(in int left, in int right, out int result);
1.25 + void divide(in int numerator, in int denominator, out int result);
1.26 +};
1.27 +}}}
1.28 +
1.29 +To use this interface, a client program would do the following:
1.30 +
1.31 + * Obtain appropriate program types to reference the interface
1.32 +
1.33 + * Initialise values or objects that reference the component providing the
1.34 + interface
1.35 +
1.36 + * Invoke operations provided by the interface, thus interacting with the
1.37 + component
1.38 +
1.39 +The sections below describe how this is done in the different supported
1.40 +programming languages.
1.41 +
1.42 +Note that the mechanism by which interface descriptions are processed for use
1.43 +in programs is described in the [[L4Re Support]] document. The `idl` manual
1.44 +page provides details for developers wishing to use the tool directly.
1.45 +
1.46 +== Client Header Files ==
1.47 +
1.48 +Given the existence of generated files for the interface, a program would
1.49 +include the client header file:
1.50 +
1.51 +{{{
1.52 +#include "calc_client.h"
1.53 +}}}
1.54 +
1.55 +== C Language Clients ==
1.56 +
1.57 +An object representing the component will have the `Calc` type. This
1.58 +encapsulates a reference to the object state and a reference to the interface
1.59 +details.
1.60 +
1.61 +The object state can be populated using a capability in L4Re:
1.62 +
1.63 +{{{
1.64 +ref_Calc ref = {.cap=server};
1.65 +}}}
1.66 +
1.67 +However, the state of a local object would be populated using a pointer:
1.68 +
1.69 +{{{
1.70 +ref_Calc ref = {.ptr=local_state};
1.71 +}}}
1.72 +
1.73 +The `Calc` object is initialised using the chosen reference value and a
1.74 +predefined interface reference:
1.75 +
1.76 +{{{
1.77 +Calc obj = {.ref=ref, .iface=&client_iface_Calc};
1.78 +}}}
1.79 +
1.80 +This predefined interface reference is obtained via the header file.
1.81 +
1.82 +To call interface operations, the functions providing access to them can be
1.83 +called directly:
1.84 +
1.85 +{{{
1.86 +Calc_add(ref, 123, 456, &result);
1.87 +}}}
1.88 +
1.89 +However, this ignores the object type and just employs the reference to the
1.90 +object state. A more object-oriented approach involves using the interface:
1.91 +
1.92 +{{{
1.93 +obj.iface->add(obj.ref, 123, 456, &result);
1.94 +}}}
1.95 +
1.96 +By employing object type values (instances), it becomes possible to treat
1.97 +local and remote components interchangeably.
1.98 +
1.99 +== C++ Language Clients ==
1.100 +
1.101 +An object representing the component will have the `Calc` type. A client
1.102 +object employing a capability in L4Re is a subtype of `Calc` called
1.103 +`client_Calc` and would be initialised as follows:
1.104 +
1.105 +{{{
1.106 +client_Calc obj(server);
1.107 +}}}
1.108 +
1.109 +Meanwhile, an object implemented locally might have a type called `local_Calc`
1.110 +and be initialised as follows:
1.111 +
1.112 +{{{
1.113 +local_Calc obj;
1.114 +}}}
1.115 +
1.116 +Such a local object would also need to be defined as a subtype of `Calc`.
1.117 +
1.118 +These objects can then be used to call interface operations:
1.119 +
1.120 +{{{
1.121 +obj.add(123, 456, &result);
1.122 +}}}
1.123 +
1.124 +Since a common base class is used to declare the interface, local and remote
1.125 +components are interchangeable.
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/docs/wiki/Servers Sat Apr 25 22:27:39 2020 +0200
2.3 @@ -0,0 +1,219 @@
2.4 += Servers =
2.5 +
2.6 +Server code is code that provides components in the form described by those
2.7 +components' interfaces, employing interprocess communications mechanisms.
2.8 +
2.9 +<<TableOfContents(2)>>
2.10 +
2.11 +== Introduction ==
2.12 +
2.13 +The following example interface, resident in a file called `calc.idl`, will be
2.14 +used to illustrate the mechanisms described in this document:
2.15 +
2.16 +{{{
2.17 +interface Calc
2.18 +{
2.19 + void add(in int left, in int right, out int result);
2.20 + void subtract(in int left, in int right, out int result);
2.21 + void multiply(in int left, in int right, out int result);
2.22 + void divide(in int numerator, in int denominator, out int result);
2.23 +};
2.24 +}}}
2.25 +
2.26 +To expose this interface to other programs, a server program would do the
2.27 +following:
2.28 +
2.29 + * Obtain appropriate program types to reference the interface
2.30 +
2.31 + * Initialise values or objects that reference the component implementation
2.32 +
2.33 + * Interact with interprocess communication mechanisms and request the
2.34 + invocation of the component's operations
2.35 +
2.36 +The sections below describe how this is done in the different supported
2.37 +programming languages.
2.38 +
2.39 +Note that the mechanism by which interface descriptions are processed for use
2.40 +in programs is described in the [[L4Re Support]] document. The `idl` manual
2.41 +page provides details for developers wishing to use the tool directly.
2.42 +
2.43 +== Server Header Files ==
2.44 +
2.45 +Given the existence of generated files for the interface, a program would
2.46 +include the server header file:
2.47 +
2.48 +{{{
2.49 +#include "calc_server.h"
2.50 +}}}
2.51 +
2.52 +== C Language Servers ==
2.53 +
2.54 +An object representing a server will have the `Calc` type. This encapsulates
2.55 +a reference to the object state and a reference to the interface details.
2.56 +
2.57 +Since the aim in implementing a server is to provide access to state
2.58 +information held within a process, the object state reference will refer to a
2.59 +location holding such information via a pointer member.
2.60 +
2.61 +{{{
2.62 +ref_Calc ref = {.ptr=0};
2.63 +}}}
2.64 +
2.65 +Here, a value of `0` is used because the interface operations are stateless
2.66 +(they act like plain functions):
2.67 +
2.68 +The `Calc` object is initialised using the chosen reference value and a
2.69 +reference to interface information:
2.70 +
2.71 +{{{
2.72 +Calc obj = {.ref=ref, .iface=&server_iface_Calc};
2.73 +}}}
2.74 +
2.75 +Unlike in the client initialisation where a predefined interface already
2.76 +exists, it is up to the component implementer to define the functions that
2.77 +support the exposed interface. For example:
2.78 +
2.79 +{{{
2.80 +iface_Calc server_iface_Calc = {
2.81 + .add=calc_add,
2.82 + .subtract=calc_subtract,
2.83 + .multiply=calc_multiply,
2.84 + .divide=calc_divide,
2.85 + .pow=calc_pow
2.86 + };
2.87 +}}}
2.88 +
2.89 +The `Calc` object is then associated with a server capability and invoked when
2.90 +incoming messages are directed towards it.
2.91 +
2.92 +=== Compound Interfaces ===
2.93 +
2.94 +When supporting multiple interfaces, the general initialisation resembles that
2.95 +shown above. Firstly, the object state reference is defined, as in this
2.96 +example involving a reference suitable for a `CalcCounter` object:
2.97 +
2.98 +{{{
2.99 +ref_CalcCounter ref = {.ptr=&counter};
2.100 +}}}
2.101 +
2.102 +Here, the pointer member employs the address of a counter. This is accessed in
2.103 +the appropriate operation function.
2.104 +
2.105 +The object itself is populated in the same way as shown above:
2.106 +
2.107 +{{{
2.108 +CalcCounter obj = {.ref=ref, .iface=&server_iface_CalcCounter};
2.109 +}}}
2.110 +
2.111 +The principal difference involves the interface details. Since a compound
2.112 +interface is exposed, there must be a way to address the individual
2.113 +interfaces, and this is done using members employing a specific naming
2.114 +convention:
2.115 +
2.116 +{{{
2.117 +iface_CalcCounter server_iface_CalcCounter = {
2.118 + .to_Calc=&server_iface_Calc,
2.119 + .to_Counter=&server_iface_Counter
2.120 + };
2.121 +}}}
2.122 +
2.123 +Here, the `to_Calc` member provides a reference to suitable details for the
2.124 +`Calc` interface, and the `to_Counter` member provides the corresponding
2.125 +reference for the `Counter` interface.
2.126 +
2.127 +=== Operation Implementations ===
2.128 +
2.129 +Implementations of operations employ a signature where the first parameter is
2.130 +the object state reference value. This permits access to the state information
2.131 +and allows functions to update the state of several objects independently:
2.132 +
2.133 +{{{
2.134 +long counter_increment(ref_Counter _self, int *result)
2.135 +{
2.136 + int *counter = (int *) (_self.ptr);
2.137 +
2.138 + *counter = *counter + 1;
2.139 + *result = *counter;
2.140 + return L4_EOK;
2.141 +}
2.142 +}}}
2.143 +
2.144 +Here, the pointer member is used to access the information referenced when the
2.145 +object was initialised.
2.146 +
2.147 +== C++ Language Servers ==
2.148 +
2.149 +An object representing the component will have the `Calc` type. An object
2.150 +providing a specific implementation of the component might have a type called
2.151 +`server_Calc` and be initialised as follows:
2.152 +
2.153 +{{{
2.154 +server_Calc obj;
2.155 +}}}
2.156 +
2.157 +Such an object type would need to be a subtype of `Calc` and would resemble
2.158 +the following:
2.159 +
2.160 +{{{
2.161 +class server_Calc : public Calc
2.162 +{
2.163 +public:
2.164 + long add(int left, int right, int *result);
2.165 + long subtract(int left, int right, int *result);
2.166 + long multiply(int left, int right, int *result);
2.167 + long divide(int numerator, int denominator, int *result);
2.168 +};
2.169 +}}}
2.170 +
2.171 +The `server_Calc` object is then associated with a server capability and
2.172 +invoked when incoming messages are directed towards it.
2.173 +
2.174 +=== Compound Interfaces ===
2.175 +
2.176 +When supporting multiple interfaces, the general initialisation resembles that
2.177 +shown above, as in this example involving a specific object type derived from
2.178 +the `CalcCounter` type:
2.179 +
2.180 +{{{
2.181 +server_CalcCounter obj;
2.182 +}}}
2.183 +
2.184 +Similarly, a definition of this type is required supporting the range of
2.185 +operations associated with all of the individual interfaces:
2.186 +
2.187 +{{{
2.188 +class server_CalcCounter : public CalcCounter
2.189 +{
2.190 + int counter = 0;
2.191 +
2.192 +public:
2.193 + long add(int left, int right, int *result);
2.194 + long subtract(int left, int right, int *result);
2.195 + long multiply(int left, int right, int *result);
2.196 + long divide(int numerator, int denominator, int *result);
2.197 + long increment(int *result);
2.198 +};
2.199 +}}}
2.200 +
2.201 +=== Operation Implementations ===
2.202 +
2.203 +Since C++ manages access to object state transparently, the way of accessing
2.204 +such state is more straightforward:
2.205 +
2.206 +{{{
2.207 +long server_CalcCounter::increment(int *result)
2.208 +{
2.209 + counter = counter + 1;
2.210 + *result = counter;
2.211 + return L4_EOK;
2.212 +}
2.213 +}}}
2.214 +
2.215 +== Exposing Objects as Servers ==
2.216 +
2.217 +In L4Re, component objects can be made available to other programs by
2.218 +associating them with interprocess communication (IPC) "gate" capabilities and
2.219 +then waiting for incoming messages. Upon receiving a message, the identity of
2.220 +the gate providing the message can be tested, and if it is the gate associated
2.221 +with a component, the message can then be interpreted and directed at the
2.222 +component as an invocation.