Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(59)

Side by Side Diff: mojo/public/c/docs/bindings/TUTORIAL.md

Issue 2234823005: Initial docs on using the C bindings. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: address comments Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # C bindings guide
2
3 The Mojo C bindings are a way to talk the Mojom protocol, the canonical protocol
4 for communication between Mojo programs. The library under `bindings/` provides
5 functionality for encoding, decoding and other computation, so it needs to be
6 linked together with C code generated from .mojom files. These C bindings are
7 lower-level than the C++ bindings (or any other language, for that matter),
8 are more error-prone, and require some knowledge of the C Mojo API and the
9 mojom encoding format. This document assumes the reader knows about (or knows
10 how to look up) this relevant information. Consequently, C bindings can also
11 be faster; generated bindings are smaller than the C++ equivalent, while
12 encoding and decoding is faster. The intention is to use them only when you
13 require speed and flexibility.
14
15 ## Structs
16
17 Let's look at what the generated code looks like for the following struct:
18
19 ``` mojom
20 module example;
21
22 enum Gender { MALE, FEMALE };
23 struct Person {
24 uint32 age;
25 string name;
26 Gender gender;
27 };
28 ```
29
30 A small snippet of the generated C code for the struct and enum:
31
32 ```C
33 // Generated code for mojom enum 'example.Gender'.
34 typedef uint32_t example_Gender;
35 enum example_Gender_Enum {
36 examples_Gender_MALE = 0,
37 examples_Gender_MALE = 1,
38 };
39
40 // Generated code for mojom struct 'example.Person'.
41 union example_PersonPtr {
42 struct example_Person* ptr;
43 uint64_t offset;
44 };
45 struct example_Person {
46 struct MojomStructHeader header_;
47 uint32_t age;
48 example_Gender gender;
49 union MojomStringHeaderPtr name;
50 };
51 ```
52
53 The mojom wire format of a struct is comparable to the C memory model of a
54 struct, with some restrictions; in the example above, we see that the order of
55 the fields is different between the mojom and C structs, since the generated C
56 structs are in packing order, not ordinal order. Although not applicable in this
57 example, there may be additional fields inserted in the generated C struct for
58 padding purposes -- since 4-byte data types need to be 4-byte aligned, the
59 generated C bindings may include some fields not explicitly present in the
60 mojom. Since it's not immediately obvious where padding fields could be
61 inserted, it helps to examine the generated C struct to make sure what the
62 fields are, and if possible, set them using field initializers. The
63 `example_PersonPtr` union is used to represent an offset in the encoded form, or
64 a pointer in the unencoded form.
65
66 Since mojom objects appear in depth-first order relative to their parent object,
67 we can use a `struct MojomBuffer` and calls to `MojomBuffer_Allocate(..)` to
68 linearly allocate space. The struct needs to be constructed and provided by the
69 user, and it contains 3 fields: A pointer to the buffer, size of the buffer in
70 bytes, and the byte-position of the next allocation, typically set to 0.
71
72 For instance, to allocate space for the `name` parameter of an `example_Person`,
73 we can do so this way:
74 ```C
75 char byte_buffer[512] = {0};
76 struct MojomBuffer buf = {byte_buffer, sizeof(byte_buffer), 0};
77
78 // First allocate space for the example_Person struct:
79 struct example_Person* person =
80 (struct example_Person*)MojomBuffer_Allocate(&buf, sizeof(struct example_Pers on));
81
82 // Allocate enough space for a 10 character string.
83 person->name.ptr = (struct MojomStringHeader*)MojomBuffer_Allocate(
84 &buf,
85 sizeof(struct MojomStringHeader) + 10);
86 ```
87
88 We can extract how much buffer space was used by reading `buf.num_byes_used`.
89
90 Along with the C struct, there are some functions generated that help encode and
91 decode mojom structs, amongst other things. For the `example.Person` mojom
92 struct, the following functions are generated:
93
94 ```c
95 struct example_Person* example_Person_DeepCopy(
96 struct MojomBuffer* in_buffer,
97 struct example_Person* in_data);
98
99 void example_Person_EncodePointersAndHandles(
100 struct example_Person* inout_struct, uint32_t in_struct_size,
101 struct MojomHandleBuffer* inout_handle_buffer);
102
103 void example_Person_DecodePointersAndHandles(
104 struct example_Person* inout_struct, uint32_t in_struct_size,
105 MojomHandle inout_handles[], uin32_t in_num_handles);
106
107 MojomValidationResult example_Person_Validate(
108 const struct example_Person* in_struct, uint32_t in_struct_size,
109 uint32_t in_num_handles);
110 ```
111
112 The generated `example_Person_DeepCopy(..)` function is used to copy over the
113 `in_data` into another buffer, specified by `MojomBuffer`. The primary purpose
114 of this function is "linearize" a given `struct example_Person` and its
115 referenced objects into the new buffer. This essentially recursively copies all
116 objects in encoding order. The returned copy can then be encoded.
117
118 Example usage copying a struct example_Person `person`:
119 ```c
120 ...
121 char byte_buffer[512] = {0};
122 struct MojomBuffer buf = {byte_buffer, sizeof(byte_buffer), 0};
123 struct example_Person* new_person = example_Person_DeepCopy(&buf, person);
124 assert(new_person != NULL);
125 ...
126 ```
127
128 The generated `example_Person_EncodePointersAndHandles(..)` is used to encode
129 a given C struct so that it's in wire-format, ready to send over a message pipe.
130 This encoding process involves translating pointers into relative offsets, and
131 extracting handles out of the struct into a separate handle array (and replacing
132 the handle values in the struct with references into the handle array). The
133 supplied `struct MojomHandleBuffer` needs to be constructed and provided by the
134 user and contains 3 fields: pointer to a handles array, the size of the array
135 (number of elements), and the starting offset into the array where handles can
136 be moved into (typically set to 0).
137
138 The generated `example_Person_DecodePointersAndHandles(..)` does the inverse --
139 it translates relative offsets into pointers, and moves handles out of the
140 handle array and into the struct (based on the encoded offset into the array).
141 In practice, before decoding a mojom struct into a usable C struct, it should be
142 first validated; this function may crash on invalid encoded data.
143
144 The generated `example_Person_Validate(..)` validates an encoded `struct
145 example_Person`. If valid, returns `MOJOM_VALIDATION_ERROR_NONE`, and can be
viettrungluu 2016/08/12 16:47:21 "If valid ..." is not a sentence: it's missing a s
vardhan 2016/08/12 20:33:36 Done.
146 decoded. See `bindings/validation.h` for more error codes.
147
148 ## Interfaces
149
150 It isn't enough to talk to other mojo applications by encoding structs and
151 referenced objects alone; communication happens via interface calls, so we need
viettrungluu 2016/08/12 16:47:21 Maybe clarify that "interface calls" really means
vardhan 2016/08/12 20:33:36 Done.
152 to frame our structs this way. The following example describes what's generated
153 for interfaces. Consider an interface `Population` with a method `GetPerson()`
viettrungluu 2016/08/12 16:47:21 s/method/message/ (or at least clarify that callin
vardhan 2016/08/12 20:33:36 Done.
154 that returns a `Person` object given their name:
155
156 ```mojom
157 module example;
158
159 [ServiceName="example::EmployeeRegistry"]
viettrungluu 2016/08/12 16:47:21 We really should stop using "::" in service names,
vardhan 2016/08/12 20:33:36 I'll change it there to '.' and make a bug to chan
160 interface EmployeeRegistry {
161 GetPerson(string name) => (Person person);
162 };
163 ```
164
165 The generated code:
166 ```C
167 #define example_EmployeeRegistry__ServiceName \
168 ((const char*)"example::EmployeeRegistry")
169 #define example_EmployeeRegistry__CurrentVersion ((uint32_t)0)
170
171 // For message GetPerson:
172 #define example_EmployeeRegistry_GetPerson__Ordinal ((uint32_t)0)
173 #define example_EmployeeRegistry_GetPerson__MinVersion ((uint32_t)0)
174
175 // Request struct for GetPerson():
176 struct example_EmployeeRegistry_GetPerson_Request {
177 struct MojomStructHeader header_;
178 struct MojomStringHeaderPtr name;
179 };
180
181 // Response struct for GetPerson():
182 struct example_EmployeeRegistry_GetPerson_Response {
183 struct MojomStructHeader header_;
184 struct example_PersonPtr person;
185 };
186 ```
187
188 We see that the parameters (and return value) of the `GetPerson(..)` message are
189 contained within mojom structs. To send a `GetPerson(..)` request, an interface
190 request message must be constructed. An interface request message for
191 `GetPerson(..)` consists of the following data in the following order:
192
193 1. `struct MojomMessageWithRequestId`. This contains:
194 - the message ordinal (generated above) which represents which message it is.
195 - flags that say if it's a request or response.
196 - a request ID, since this message is expecting a response.
197 - (see `bindings/message.h`)
198 2. `struct examples_EmployeeRegistry_GetPerson_Request`. This contains the
199 actual parameters for GetPerson().
200
201 Since the request parameters are just a mojom struct, all relevant functions for
202 structs are also generated (see above), e.g, ` void
203 examples_EmployeeRegistry_GetPerson_Request_EncodePointersAndHandles()`. Once
204 the request struct has been encoded, the buffer containing the above two structs
205 can be written to a message pipe.
206
207 On the other hand, when reading an incoming message, the message header must
208 first be validated using
209 ```
210 MojomValidationResult MojomMessage_ValidateHeader(const void* in_buf,
211 uint32_t in_buf_size);
212 ```
213 - If the message arrives on the client side:
214 1. It must be validated as a response message.
215 2. You must check that the message ordinal is known and expects a response
216 message.
217 - If the message arrives on the server side:
218 1. It must be validated as a request message, and that it's a known ordinal.
219 2. If the message's ordinal is known to expect a response, the request message
220 must be validated as expecting a response.
221
222 If valid, it is safe to look at the `request_id` in `struct MojomMessage`, and
223 the `ordinal` describing the message. By checking if it's any of
224 `example_EmployeeRegistry_*__Ordinal`, you can further validate that it is a
225 request or expects a response. See `bindings/message.h` for more functions that
226 help validate message headers. Once the message header is fully validated, you
227 must also validate the request or response mojom struct following the message
228 header using the generated `*_Validate(..)` function.
229
230 Note that validation is run on encoded messages and structs on the wire --
231 decoding a struct without validating it first is dangerous.
232
233 ## Enums and Constants
234
235 Example mojom code:
236 ``` mojom
237 module example;
238
239 enum MyEnum { Zero, One, Four = 4, Five };
240 const uint64 kMyConst = 34;
241 ```
242
243 Generated C code:
244 ``` C
245 typedef uint32_t example_MyEnum;
246 enum example_MyEnum_Enum {
247 examples_MyEnum_Zero = 0,
248 examples_MyEnum_One = 1,
249 examples_MyEnum_Four = 4,
250 examples_MyEnum_Five = 5,
251 };
252
253 #define example_kMyConst ((uint64_t)34)
254 ```
255
256 ## Tagged Unions
257
258 Example mojom code:
259 ``` mojom
260 module example;
261
262 union MyUnion {
263 int8 f0;
264 string f1;
265 MyUnion f2;
266 };
267
268 struct StructWithUnion {
269 MyUnion u;
270 }
271 ```
272 Generated C code:
273 ```C
274 // Generated code for the Tags enum for |MyUnion|.
275 typedef uint32_t example_MyUnion_Tag;
276 enum example_MyUnion_Tag_Enum {
277 example_MyUnion_Tag_f0 = 0,
278 example_MyUnion_Tag_f1 = 1,
279 example_MyUnion_Tag_f2 = 2,
280 example_MyUnion_Tag__UNKNOWN__ = 0xFFFFFFFF,
281 };
282
283 // Generated code for |MyUnion|.
284 union example_MyUnionPtr {
285 struct example_MyUnion* ptr;
286 uint64_t offset;
287 };
288 struct example_MyUnion {
289 uint32_t size;
290 example_MyUnion_Tag tag;
291 union {
292 int8_t f_f0;
293 union MojomStringHeaderPtr f_f1;
294 union example_MyUnionPtr f_f2;
295 uint64_t unknown;
296 } data;
297 };
298
299 // Snippet of generated code for |StructWithUnion|.
300 struct example_StructWithUnion {
301 struct MojomStructHeader header_;
302 struct example_MyUnion u;
303 };
304 ```
305
306 Note that the `MyUnion` inside the `MyUnion` is a pointer object, whereas the
307 `MyUnion` inside `StructWithUnion` is inlined. The only case when unions are
308 pointer objects are when they are inside another union, otherwise they are
309 inlined. Unions are initialized by setting their size and their tag. The size is
310 always 16 bytes if the union is not null (4 for the size field, 4 for the tag,
311 and 8 for the data). The tag must be set to one defined in the generated enum of
312 tags. The unknown tag isn't meant to be encoded over the wire, and exists as an
313 initial value for a union's tag, but the tag should be set to a valid tag
314 before being written to wire. A union whose size is 0 is considered null. Unlike
315 for structs, there are no functions generated for unions, since unions are never
316 encoded as a top-level object type on the wire.
317
318 ## Arrays and Strings
319
320 Arrays and strings (which are just arrays of characters) are not top-level data
321 types; they can only be defined within a struct, union or interface method.
322 Arrays inside structs are pointers to an array object. The array object's byte
323 layout is as follow:
324 1. `struct MojomArrayHeader`. This contains:
325 - Number of bytes in the array (this includes the header and the data
326 following the array header; see `2.`)
327 - Number of elements in the array.
328 - (see `bindings/array.h` for more details)
329 2. The contents of the array (the size of this is accounted for in the number
330 of bytes specified in the array header).
331
332 Note that if the array contains pointer objects (structs, arrays, maps), the
333 array contains only the 8-byte pointers (or offsets in its encoded form) -- the
334 objects' data follow the array contents, and their size is not accounted for in
335 the array header.
336
337 Example of how to allocate and initialize a new array of 5 int32s, and set each
338 one:
339 ```C
340 ...
341 struct MojomArrayHeader* int32_array = MojomArray_New(&buf, 5, sizeof(int32_t));
342 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 0) = 10;
343 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 1) = 20;
344 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 2) = 30;
345 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 3) = 40;
346 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 4) = 50;
347 ```
348
349 Here, `MojomArray_New(..)` allocates space for the buffer and initializes the
350 header, while the `MOJOM_ARRAY_INDEX(.., i)` macro returns the address of the
351 `i`th element.
352
353 TODO(vardhan): Explain how to make an array of bools.
354
355 Since a mojom string is an array of UTF-8 encoded characters, you can use
356 `MojomArray_New(&buf, NUM_CHARACTERS, sizeof(uint8_t))` if they are ASCII
357 characters. Otherwise, since UTF-8 characters may be variable-sized, you must be
358 careful to set the number of characters appropriately, as it may not be the same
359 as the number of bytes (minus the header). By convention, mojom strings are not
360 null-terminated.
361
362 ## Maps
363
364 Maps on the wire are mojom structs with two arrays; one for the keys, and one
365 for the values. The `i`th element in the keys array corresponds to the `i`th
366 element in the values array. As such, both arrays must have the same number
367 of elements, and neither may be null.
368
369 # Numbers on generated bindings.
370
371 TODO(vardhan): Probably as a separate doc?
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698