@@ -188,11 +188,12 @@ All common system call operations should have asynchronous versions.
188188
189189These asynchronous APIs must not use or include any internal/global state.
190190
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 ` |
196197
197198### Header Files
198199
@@ -293,6 +294,13 @@ returncode_t libtock_sensor_read(libtock_sensor_callback_reading cb) {
293294}
294295```
295296
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+
296304## Synchronous APIs
297305
298306Most system call interfaces will want to provide a synchronous API as well. This
@@ -429,3 +437,50 @@ returncode_t libtocksync_sensor_read(int* val) {
429437 return ret;
430438}
431439```
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