@@ -422,9 +422,13 @@ returncode_t libtocksync_sensor_read(int* val) {
422
422
### More Complicated Example:
423
423
424
424
Drivers that use allow buffers must un-allow the buffers after the operation
425
- finishes.
425
+ finishes. To ease authoring of cleanup code, Tock provides a macro-based
426
+ implementation of the `defer {}` feature that will be included with a future
427
+ version of `C`.
426
428
427
429
```c
430
+ #include <libtock/defer.h>
431
+
428
432
#include "digest.h"
429
433
#include "syscalls/digest_syscalls.h"
430
434
@@ -437,28 +441,27 @@ returncode_t libtocksync_digest_compute(uint8_t* input_buffer,
437
441
// First allow for input. If it fails, return.
438
442
ret = libtock_digest_set_readonly_allow(input_buffer, input_buffer_len);
439
443
if (ret != RETURNCODE_SUCCESS) return ret;
440
-
441
- // Second allow for output. If it fails, unallow first buffer then return.
444
+ // Now that this buffer has been allowed, set up a `defer` block to
445
+ // ensure that it will be unallowed before this function returns
446
+ // (regardless of exit location out of the function).
447
+ //
448
+ // Note the return value of this "un-allow" operation is ignored in favor
449
+ // of returning the disposition of the library funciton (i.e., `ret`).
450
+ defer { libtock_digest_set_readonly_allow(NULL, 0); }
451
+
452
+ // Second allow for output.
442
453
ret = libtock_digest_set_readwrite_allow(output_buffer, output_buffer_len);
443
- if (ret != RETURNCODE_SUCCESS) goto exit1;
454
+ if (ret != RETURNCODE_SUCCESS) return ret;
455
+ // Set up the output unallow.
456
+ defer { libtock_digest_set_readwrite_allow(NULL, 0); }
444
457
445
458
// Attempt the command. If it fails, unallow both buffers.
446
459
ret = libtock_digest_command_compute_digest();
447
- if (err != RETURNCODE_SUCCESS) goto exit2 ;
460
+ if (err != RETURNCODE_SUCCESS) return ret ;
448
461
449
462
// Wait for the digest to compute.
450
463
ret = libtock_digest_yield_wait_for(val);
451
464
452
- exit2:
453
- // Do the input unallow. We have to ignore the return value to 1) return the
454
- // correct error of the actual failing operation if something happened, and
455
- // 2) do the second unallow unconditionally.
456
- libtock_digest_set_readonly_allow(NULL, 0);
457
-
458
- exit1:
459
- // Do the output unallow.
460
- libtock_digest_set_readonly_allow(NULL, 0);
461
-
462
465
return ret;
463
466
}
464
467
```
0 commit comments