diff --git a/doc/guide.md b/doc/guide.md index 69fe5c02a..72cf91fce 100644 --- a/doc/guide.md +++ b/doc/guide.md @@ -188,11 +188,12 @@ All common system call operations should have asynchronous versions. These asynchronous APIs must not use or include any internal/global state. -| Characteristic | Value | -|------------------|-------------------------------| -| Location | `libtock/[category]` | -| Source File Name | `libtock/[category]/[name].c` | -| Header File Name | `libtock/[category]/[name].h` | +| Characteristic | Value | +|-----------------------------------|-------------------------------------| +| Location | `libtock/[category]` | +| Source File Name | `libtock/[category]/[name].c` | +| Header File Name | `libtock/[category]/[name].h` | +| Types Header File Name (Optional) | `libtock/[category]/[name]_types.h` | ### Header Files @@ -275,6 +276,13 @@ returncode_t libtock_sensor_read(libtock_sensor_callback_reading cb) { } ``` +### Types Header + +If there are any additional types, beyond the callback signature, that are +exposed in the public API of the driver they must be included in the +`libtock/[category]/[name]_types.h` file. This makes it possible to include +these types from `libtock-sync` implementations. + ## Synchronous APIs Most system call interfaces will want to provide a synchronous API as well. This @@ -410,3 +418,50 @@ returncode_t libtocksync_sensor_read(int* val) { return err; } ``` + +### More Complicated Example: + +Drivers that use allow buffers must un-allow the buffers after the operation +finishes. To ease authoring of cleanup code, Tock provides a macro-based +implementation of the `defer {}` feature that will be included with a future +version of `C`. + +```c +#include + +#include "digest.h" +#include "syscalls/digest_syscalls.h" + +returncode_t libtocksync_digest_compute(uint8_t* input_buffer, + uint32_t input_buffer_len, + uint8_t* output_buffer, + uint32_t output_buffer_len) { + returncode_t ret; + + // First allow for input. If it fails, return. + ret = libtock_digest_set_readonly_allow(input_buffer, input_buffer_len); + if (ret != RETURNCODE_SUCCESS) return ret; + // Now that this buffer has been allowed, set up a `defer` block to + // ensure that it will be unallowed before this function returns + // (regardless of exit location out of the function). + // + // Note the return value of this "un-allow" operation is ignored in favor + // of returning the disposition of the library function (i.e., `ret`). + defer { libtock_digest_set_readonly_allow(NULL, 0); } + + // Second allow for output. + ret = libtock_digest_set_readwrite_allow(output_buffer, output_buffer_len); + if (ret != RETURNCODE_SUCCESS) return ret; + // Set up the output unallow. + defer { libtock_digest_set_readwrite_allow(NULL, 0); } + + // Attempt the command. If it fails, unallow both buffers. + ret = libtock_digest_command_compute_digest(); + if (err != RETURNCODE_SUCCESS) return ret; + + // Wait for the digest to compute. + ret = libtock_digest_yield_wait_for(val); + + return ret; +} +```