1 = Servers = 2 3 Server code is code that provides components in the form described by those 4 components' interfaces, employing interprocess communications mechanisms. 5 6 <<TableOfContents(2)>> 7 8 == Introduction == 9 10 The following example interface, resident in a file called `calc.idl`, will be 11 used to illustrate the mechanisms described in this document: 12 13 {{{ 14 interface Calc 15 { 16 void add(in int left, in int right, out int result); 17 void subtract(in int left, in int right, out int result); 18 void multiply(in int left, in int right, out int result); 19 void divide(in int numerator, in int denominator, out int result); 20 }; 21 }}} 22 23 To expose this interface to other programs, a server program would do the 24 following: 25 26 * Obtain appropriate program types to reference the interface 27 28 * Initialise values or objects that reference the component implementation 29 30 * Interact with interprocess communication mechanisms and request the 31 invocation of the component's operations 32 33 The sections below describe how this is done in the different supported 34 programming languages. 35 36 Note that the mechanism by which interface descriptions are processed for use 37 in programs is described in the [[L4Re Support]] document. The `idl` manual 38 page provides details for developers wishing to use the tool directly. 39 40 == Server Header Files == 41 42 Given the existence of generated files for the interface, a program would 43 include the server header file: 44 45 {{{ 46 #include "calc_server.h" 47 }}} 48 49 To expose components as servers, a `libipc` header file is also needed: 50 51 {{{ 52 #include <ipc/server.h> 53 }}} 54 55 == C Language Servers == 56 57 An object representing a server will have the `Calc` type. This encapsulates 58 a reference to the object state and a reference to the interface details. 59 60 Since the aim in implementing a server is to provide access to state 61 information held within a process, the object state reference will refer to a 62 location holding such information via a pointer member. 63 64 {{{ 65 ref_Calc ref = {.ptr=0}; 66 }}} 67 68 Here, a value of `0` is used because the interface operations are stateless 69 (they act like plain functions): 70 71 The `Calc` object is initialised using the chosen reference value and a 72 reference to interface information: 73 74 {{{ 75 Calc obj = {.ref=ref, .iface=&server_iface_Calc}; 76 }}} 77 78 Unlike in the client initialisation where a predefined interface already 79 exists, it is up to the component implementer to define the functions that 80 support the exposed interface. For example: 81 82 {{{ 83 iface_Calc server_iface_Calc = { 84 .add=calc_add, 85 .subtract=calc_subtract, 86 .multiply=calc_multiply, 87 .divide=calc_divide, 88 .pow=calc_pow 89 }; 90 }}} 91 92 The `Calc` object is then associated with a server capability and invoked when 93 incoming messages are directed towards it. 94 95 === Compound Interfaces === 96 97 When supporting multiple interfaces, the general initialisation resembles that 98 shown above. Firstly, the object state reference is defined, as in this 99 example involving a reference suitable for a `CalcCounter` object: 100 101 {{{ 102 ref_CalcCounter ref = {.ptr=&counter}; 103 }}} 104 105 Here, the pointer member employs the address of a counter. This is accessed in 106 the appropriate operation function. 107 108 The object itself is populated in the same way as shown above: 109 110 {{{ 111 CalcCounter obj = {.ref=ref, .iface=&server_iface_CalcCounter}; 112 }}} 113 114 The principal difference involves the interface details. Since a compound 115 interface is exposed, there must be a way to address the individual 116 interfaces, and this is done using members employing a specific naming 117 convention: 118 119 {{{ 120 iface_CalcCounter server_iface_CalcCounter = { 121 .to_Calc=&server_iface_Calc, 122 .to_Counter=&server_iface_Counter 123 }; 124 }}} 125 126 Here, the `to_Calc` member provides a reference to suitable details for the 127 `Calc` interface, and the `to_Counter` member provides the corresponding 128 reference for the `Counter` interface. 129 130 === Operation Implementations === 131 132 Implementations of operations employ a signature where the first parameter is 133 the object state reference value. This permits access to the state information 134 and allows functions to update the state of several objects independently: 135 136 {{{ 137 long counter_increment(ref_Counter _self, int *result) 138 { 139 int *counter = (int *) (_self.ptr); 140 141 *counter = *counter + 1; 142 *result = *counter; 143 return L4_EOK; 144 } 145 }}} 146 147 Here, the pointer member is used to access the information referenced when the 148 object was initialised. 149 150 == C++ Language Servers == 151 152 An object representing the component will have the `Calc` type. An object 153 providing a specific implementation of the component might have a type called 154 `server_Calc` and be initialised as follows: 155 156 {{{ 157 server_Calc obj; 158 }}} 159 160 Such an object type would need to be a subtype of `Calc` and would resemble 161 the following: 162 163 {{{ 164 class server_Calc : public Calc 165 { 166 public: 167 long add(int left, int right, int *result); 168 long subtract(int left, int right, int *result); 169 long multiply(int left, int right, int *result); 170 long divide(int numerator, int denominator, int *result); 171 }; 172 }}} 173 174 The `server_Calc` object is then associated with a server capability and 175 invoked when incoming messages are directed towards it. 176 177 === Compound Interfaces === 178 179 When supporting multiple interfaces, the general initialisation resembles that 180 shown above, as in this example involving a specific object type derived from 181 the `CalcCounter` type: 182 183 {{{ 184 server_CalcCounter obj; 185 }}} 186 187 Similarly, a definition of this type is required supporting the range of 188 operations associated with all of the individual interfaces: 189 190 {{{ 191 class server_CalcCounter : public CalcCounter 192 { 193 int counter = 0; 194 195 public: 196 long add(int left, int right, int *result); 197 long subtract(int left, int right, int *result); 198 long multiply(int left, int right, int *result); 199 long divide(int numerator, int denominator, int *result); 200 long increment(int *result); 201 }; 202 }}} 203 204 === Operation Implementations === 205 206 Since C++ manages access to object state transparently, the way of accessing 207 such state is more straightforward: 208 209 {{{ 210 long server_CalcCounter::increment(int *result) 211 { 212 counter = counter + 1; 213 *result = counter; 214 return L4_EOK; 215 } 216 }}} 217 218 == Exposing Objects as Servers == 219 220 In L4Re, component objects can be made available to other programs by 221 associating them with interprocess communication (IPC) "gate" capabilities and 222 then waiting for incoming messages. 223 224 Given an existing capability accessible via the program environment, a 225 component can be exposed to other programs as follows: 226 227 {{{ 228 ipc_server_bind("server", (l4_umword_t) &obj, &server); 229 }}} 230 231 Here, the `server` variable is of type `l4_cap_idx_t` (indicating a 232 capability). The named capability is obtained and assigned to the variable, 233 with the object itself presented to label incoming messages, indicating which 234 IPC gate was involved in delivering the message. 235 236 The details of waiting for messages, testing the label, and directing requests 237 to the component are dealt with by another convenience function: 238 239 {{{ 240 ipc_server_loop(Calc_expected_items, &obj, (ipc_server_handler_type) handle_Calc); 241 }}} 242 243 Here, the following parameters are specified: 244 245 * The predefined number of items expected for the `Calc` interface, generated 246 automatically and provided by `Calc_expected_items` 247 248 * The object address which is used to check message labels 249 250 * A handler function for directing requests to the component, this being 251 provided by the generated `handle_Calc` function which must be cast to an 252 acceptable type as indicated 253 254 == Example Code == 255 256 The `pkg/idl4re-examples` directory contains some example packages for L4Re 257 that feature some of the above code and demonstrate the techniques involved. 258 The `idl4re-examples` directory can be copied into the L4Re distribution's 259 `pkg` directory and built as follows: 260 261 {{{ 262 make O=mybuild S=pkg/idl4re-examples 263 }}} 264 265 The `mybuild` directory name should be adjusted to match your own choice of 266 build output directory.