From e0d40f0141f70c9c668b1acb7e236df60e1b1fe6 Mon Sep 17 00:00:00 2001 From: Brad Campbell Date: Wed, 16 Jul 2025 10:14:54 -0700 Subject: [PATCH 1/3] doc: guide: include sync unallow example --- doc/guide.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/doc/guide.md b/doc/guide.md index 69fe5c02a..a724432ec 100644 --- a/doc/guide.md +++ b/doc/guide.md @@ -410,3 +410,47 @@ 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. + +```c +#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; + + // Second allow for output. If it fails, unallow first buffer then return. + ret = libtock_digest_set_readwrite_allow(output_buffer, output_buffer_len); + if (ret != RETURNCODE_SUCCESS) goto exit1; + + // Attempt the command. If it fails, unallow both buffers. + ret = libtock_digest_command_compute_digest(); + if (err != RETURNCODE_SUCCESS) goto exit2; + + // Wait for the digest to compute. + ret = libtock_digest_yield_wait_for(val); + +exit2: + // Do the input unallow. We have to ignore the return value to 1) return the + // correct error of the actual failing operation if something happened, and + // 2) do the second unallow unconditionally. + libtock_digest_set_readonly_allow(NULL, 0); + +exit1: + // Do the output unallow. + libtock_digest_set_readonly_allow(NULL, 0); + + return ret; +} +``` From 2c7f874a53d13dfc532ad66db4048f6697fe106f Mon Sep 17 00:00:00 2001 From: Brad Campbell Date: Wed, 16 Jul 2025 10:15:05 -0700 Subject: [PATCH 2/3] doc: guide: document types file --- doc/guide.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/doc/guide.md b/doc/guide.md index a724432ec..afb5ba67e 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 From e8a56a2690feb116445041ee6787c102d80f4d83 Mon Sep 17 00:00:00 2001 From: Pat Pannuto Date: Fri, 8 Aug 2025 10:47:17 -0700 Subject: [PATCH 3/3] doc: update guide to use `defer` block for un-allows --- doc/guide.md | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/doc/guide.md b/doc/guide.md index afb5ba67e..72cf91fce 100644 --- a/doc/guide.md +++ b/doc/guide.md @@ -422,9 +422,13 @@ returncode_t libtocksync_sensor_read(int* val) { ### More Complicated Example: Drivers that use allow buffers must un-allow the buffers after the operation -finishes. +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" @@ -437,28 +441,27 @@ returncode_t libtocksync_digest_compute(uint8_t* input_buffer, // 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; - - // Second allow for output. If it fails, unallow first buffer then return. + // 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) goto exit1; + 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) goto exit2; + if (err != RETURNCODE_SUCCESS) return ret; // Wait for the digest to compute. ret = libtock_digest_yield_wait_for(val); -exit2: - // Do the input unallow. We have to ignore the return value to 1) return the - // correct error of the actual failing operation if something happened, and - // 2) do the second unallow unconditionally. - libtock_digest_set_readonly_allow(NULL, 0); - -exit1: - // Do the output unallow. - libtock_digest_set_readonly_allow(NULL, 0); - return ret; } ```