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

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, and rephrase a few more things 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
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
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()`
154 that returns a `Person` object given their name:
155
156 ```mojom
157 module example;
158
159 [ServiceName="example::EmployeeRegistry"]
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 needs to be constructed. An interface request message for
viettrungluu 2016/08/11 22:02:42 s/needs to/must/
vardhan 2016/08/12 00:15:14 Done.
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.
viettrungluu 2016/08/11 22:02:41 nit: 80 cols
vardhan 2016/08/12 00:15:14 oops, these are tabs instead of spaces.
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 message (request or response),
208 the message header must first be validated using
209 ```
210 MojomValidationResult MojomMessage_ValidateHeader(const void* in_buf,
211 uint32_t in_buf_size);
212 ```
213 If valid, it is safe to look at the `request_id` in `struct MojomMessage`, and
214 the `ordinal` describing the message. By checking if it's any of
viettrungluu 2016/08/11 22:02:41 The sentence "By checking ..." seems a bit strange
vardhan 2016/08/12 00:15:14 Done. I think there need to be more things genera
215 `example_EmployeeRegistry_*__Ordinal`, you can further validate that it is a
216 request or expects a response. See `bindings/message.h` for more functions that
217 help validate message headers. Once the message header is fully validated, you
218 must also validate the request or response mojom struct following the message
219 header using the generated `*_Validate(..)` function.
220
221 Note that validation is run on encoded messages and structs on the wire --
222 decoding a struct without validating it first is dangerous.
223
224 ## Enums and Constants
225
226 Example mojom code:
227 ``` mojom
228 module example;
229
230 enum MyEnum { Zero, One, Four = 4, Five };
231 const uint64 kMyConst = 34;
232 ```
233
234 Generated C code:
235 ``` C
236 typedef uint32_t example_MyEnum;
237 enum example_MyEnum_Enum {
238 examples_MyEnum_Zero = 0,
239 examples_MyEnum_One = 1,
240 examples_MyEnum_Four = 4,
241 examples_MyEnum_Five = 5,
242 };
243
244 #define example_kMyConst ((uint64_t)34)
245 ```
246
247 ## Tagged Unions
248
249 Example mojom code:
250 ``` mojom
251 module example;
252
253 union MyUnion {
254 int8 f0;
255 string f1;
256 MyUnion f2;
257 };
258
259 struct StructWithUnion {
260 MyUnion u;
261 }
262 ```
263 Generated C code:
264 ```C
265 // Generated code for the Tags enum for |MyUnion|.
266 typedef uint32_t example_MyUnion_Tag;
267 enum example_MyUnion_Tag_Enum {
268 example_MyUnion_Tag_f0 = 0,
269 example_MyUnion_Tag_f1 = 1,
270 example_MyUnion_Tag_f2 = 2,
271 example_MyUnion_Tag__UNKNOWN__ = 0xFFFFFFFF,
272 };
273
274 // Generated code for |MyUnion|.
275 union example_MyUnionPtr {
276 struct example_MyUnion* ptr;
277 uint64_t offset;
278 };
279 struct example_MyUnion {
280 uint32_t size;
281 example_MyUnion_Tag tag;
282 union {
283 int8_t f_f0;
284 union MojomStringHeaderPtr f_f1;
285 union example_MyUnionPtr f_f2;
286 uint64_t unknown;
287 } data;
288 };
289
290 // Snippet of generated code for |StructWithUnion|.
291 struct example_StructWithUnion {
292 struct MojomStructHeader header_;
293 struct example_MyUnion u;
294 };
295 ```
296
297 Note that the `MyUnion` inside the `MyUnion` is a pointer object, whereas the
298 `MyUnion` inside `StructWithUnion` is inlined. The only case when unions are
299 pointer objects are when they are inside another union, otherwise they are
300 inlined. Unions are initialized by setting their size and their tag. The size is
301 always 16 bytes if the union is not null (4 for the size field, 4 for the tag,
302 and 8 for the data). The tag must be set to one defined in the generated enum of
303 tags. The unknown tag isn't meant to be encoded over the wire, and exists as an
viettrungluu 2016/08/11 22:02:42 We really should rename "unknown" to "unset" (not
vardhan 2016/08/12 00:15:14 Acknowledged.
304 initial value for a union's tag, but the tag should be set to something else
viettrungluu 2016/08/11 22:02:41 "should be" -> "must be" "something else" is prob
vardhan 2016/08/12 00:15:14 I think it should be "should be" because the valid
viettrungluu 2016/08/12 16:47:21 As discussed, those tests are trying to test for s
305 before being written to wire. A union whose size is 0 is considered null. There
306 are no functions generated for unions like they are for structs, since unions
viettrungluu 2016/08/11 22:02:42 "like they are for" -> "unlike for"
307 aren't ever encoded as a top-level data type that the programmer should have to
viettrungluu 2016/08/11 22:02:42 "aren't ever" -> "are never" Also, "that the prog
vardhan 2016/08/12 00:15:14 I changed it to "never encoded as a top level obje
308 write to wire.
309
310 ## Arrays and Strings
311
312 Arrays and strings (which are just arrays of characters) are not top-level data
313 types; they can only be defined within a struct, union or interface method.
314 Arrays inside structs are pointers to an array object. The array object's byte
315 layout is as follow:
316 1. `struct MojomArrayHeader`. This contains:
317 - Number of bytes in the array (this includes the header and the data
318 following the array header; see `2.`)
319 - Number of elements in the array.
320 - (see `bindings/array.h` for more details)
321 2. The contents of the array (the size of this is accounted for in the number
322 of bytes specified in the array header).
323
324 Note that if the array contains pointer objects (structs, arrays, maps), the
325 array contains only the 8-byte pointers (or offsets in its encoded form) -- the
326 objects' data follow the array contents, and their size is not accounted for in
327 the array header.
328
329 Example of how to allocate and initialize a new array of 5 int32s, and set each
330 one:
331 ```C
332 ...
333 struct MojomArrayHeader* int32_array = MojomArray_New(&buf, 5, sizeof(int32_t));
334 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 0) = 10;
335 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 1) = 20;
336 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 2) = 30;
337 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 3) = 40;
338 *MOJOM_ARRAY_INDEX(int32_array, int32_t, 4) = 50;
339 ```
340
341 Here, `MojomArray_New(..)` allocates space for the buffer and initializes the
342 header, while the `MOJOM_ARRAY_INDEX(.., i)` macro returns the address of the
343 `i`th element.
344
345 TODO(vardhan): Explain how to make an array of bools.
346
347 Since a mojom string is an array of UTF-8 encoded characters, you can use
348 `MojomArray_New(&buf, NUM_CHARACTERS, sizeof(uint8_t))` if they are ASCII
349 characters. Otherwise, since UTF-8 characters may be variable-sized, you must be
350 careful to set the number of characters appropriately, as it may not be the same
351 as the number of bytes (minus the header). By convention, mojom strings are not
352 null-terminated.
353
354 ## Maps
355
356 Maps on the wire are mojom structs with two arrays; one for the keys, and one
357 for the values. The `i`th element in the keys array corresponds to the `i`th
358 element in the values array. As such, both arrays must have the same number
359 of elements, and neither arrays can be null.
viettrungluu 2016/08/11 22:02:41 s/arrays/array/ (or just write it as "neither may
vardhan 2016/08/12 00:15:14 Done.
360
361 # Numbers on generated bindings.
362
363 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