@@ -188,11 +188,12 @@ All common system call operations should have asynchronous versions.
188
188
189
189
These asynchronous APIs must not use or include any internal/global state.
190
190
191
- | Characteristic | Value |
192
- | ------------------| -------------------------------|
193
- | Location | ` libtock/[category] ` |
194
- | Source File Name | ` libtock/[category]/[name].c ` |
195
- | Header File Name | ` libtock/[category]/[name].h ` |
191
+ | Characteristic | Value |
192
+ | -----------------------------------| -------------------------------------|
193
+ | Location | ` libtock/[category] ` |
194
+ | Source File Name | ` libtock/[category]/[name].c ` |
195
+ | Header File Name | ` libtock/[category]/[name].h ` |
196
+ | Types Header File Name (Optional) | ` libtock/[category]/[name]_types.h ` |
196
197
197
198
### Header Files
198
199
@@ -293,6 +294,13 @@ returncode_t libtock_sensor_read(libtock_sensor_callback_reading cb) {
293
294
}
294
295
```
295
296
297
+ ### Types Header
298
+
299
+ If there are any additional types, beyond the callback signature, that are
300
+ exposed in the public API of the driver they must be included in the
301
+ `libtock/[category]/[name]_types.h` file. This makes it possible to include
302
+ these types from `libtock-sync` implementations.
303
+
296
304
## Synchronous APIs
297
305
298
306
Most system call interfaces will want to provide a synchronous API as well. This
@@ -429,3 +437,50 @@ returncode_t libtocksync_sensor_read(int* val) {
429
437
return ret;
430
438
}
431
439
```
440
+
441
+ ### More Complicated Example:
442
+
443
+ Drivers that use allow buffers must un-allow the buffers after the operation
444
+ finishes. To ease authoring of cleanup code, Tock provides a macro-based
445
+ implementation of the `defer {}` feature that will be included with a future
446
+ version of `C`.
447
+
448
+ ```c
449
+ #include <libtock/defer.h>
450
+
451
+ #include "digest.h"
452
+ #include "syscalls/digest_syscalls.h"
453
+
454
+ returncode_t libtocksync_digest_compute(uint8_t* input_buffer,
455
+ uint32_t input_buffer_len,
456
+ uint8_t* output_buffer,
457
+ uint32_t output_buffer_len) {
458
+ returncode_t ret;
459
+
460
+ // First allow for input. If it fails, return.
461
+ ret = libtock_digest_set_readonly_allow(input_buffer, input_buffer_len);
462
+ if (ret != RETURNCODE_SUCCESS) return ret;
463
+ // Now that this buffer has been allowed, set up a `defer` block to
464
+ // ensure that it will be unallowed before this function returns
465
+ // (regardless of exit location out of the function).
466
+ //
467
+ // Note the return value of this "un-allow" operation is ignored in favor
468
+ // of returning the disposition of the library function (i.e., `ret`).
469
+ defer { libtock_digest_set_readonly_allow(NULL, 0); }
470
+
471
+ // Second allow for output.
472
+ ret = libtock_digest_set_readwrite_allow(output_buffer, output_buffer_len);
473
+ if (ret != RETURNCODE_SUCCESS) return ret;
474
+ // Set up the output unallow.
475
+ defer { libtock_digest_set_readwrite_allow(NULL, 0); }
476
+
477
+ // Attempt the command. If it fails, unallow both buffers.
478
+ ret = libtock_digest_command_compute_digest();
479
+ if (err != RETURNCODE_SUCCESS) return ret;
480
+
481
+ // Wait for the digest to compute.
482
+ ret = libtock_digest_yield_wait_for(val);
483
+
484
+ return ret;
485
+ }
486
+ ```
0 commit comments