summaryrefslogtreecommitdiff
path: root/firmware/buflib.c
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2022-04-03 10:48:14 +0100
committerAidan MacDonald <amachronic@protonmail.com>2022-09-19 15:09:51 -0400
commitf47aa584a8b447d8225fc5b09afb2d1fe6764c1d (patch)
tree8d767aa62d2415e555f49b3217f876afed39c310 /firmware/buflib.c
parentecfec3e9bf9178299cb0fe64bd530a81e10b1142 (diff)
downloadrockbox-f47aa584a8b447d8225fc5b09afb2d1fe6764c1d.tar.gz
rockbox-f47aa584a8b447d8225fc5b09afb2d1fe6764c1d.zip
buflib: add pin/unpin operation
An allocation is pinned by calling buflib_pin() to up its pin count. The pin count is like a reference count: when above 0, buflib won't move the allocation and won't call its move callbacks. This makes it safe to hold the pointer returned by buflib_get_data() across yields or allocations. Note that pinned allocations can still shrink because there are some use cases where this would be valid, if buffer users coordinate with the shrink callback. Change-Id: I0d0c2a8ac7d891d3ad6b3d0eb80c5b5a1b4b9a9d
Diffstat (limited to 'firmware/buflib.c')
-rw-r--r--firmware/buflib.c45
1 files changed, 41 insertions, 4 deletions
diff --git a/firmware/buflib.c b/firmware/buflib.c
index 2a4b4b4f14..7263f1b95d 100644
--- a/firmware/buflib.c
+++ b/firmware/buflib.c
@@ -102,10 +102,12 @@
102#define PARANOIA_CHECK_HANDLE (1 << 1) 102#define PARANOIA_CHECK_HANDLE (1 << 1)
103#define PARANOIA_CHECK_BLOCK_HANDLE (1 << 2) 103#define PARANOIA_CHECK_BLOCK_HANDLE (1 << 2)
104#define PARANOIA_CHECK_CRC (1 << 3) 104#define PARANOIA_CHECK_CRC (1 << 3)
105#define PARANOIA_CHECK_PINNING (1 << 4)
105/* Bitmask of enabled paranoia checks */ 106/* Bitmask of enabled paranoia checks */
106#define BUFLIB_PARANOIA \ 107#define BUFLIB_PARANOIA \
107 (PARANOIA_CHECK_LENGTH | PARANOIA_CHECK_HANDLE | \ 108 (PARANOIA_CHECK_LENGTH | PARANOIA_CHECK_HANDLE | \
108 PARANOIA_CHECK_BLOCK_HANDLE | PARANOIA_CHECK_CRC) 109 PARANOIA_CHECK_BLOCK_HANDLE | PARANOIA_CHECK_CRC | \
110 PARANOIA_CHECK_PINNING)
109 111
110#if BUFLIB_PARANOIA & PARANOIA_CHECK_CRC 112#if BUFLIB_PARANOIA & PARANOIA_CHECK_CRC
111# define BUFLIB_HAS_CRC 113# define BUFLIB_HAS_CRC
@@ -122,6 +124,7 @@ enum {
122/* Backward indices, used to index a block end pointer as block[-bidx_XXX] */ 124/* Backward indices, used to index a block end pointer as block[-bidx_XXX] */
123enum { 125enum {
124 bidx_USER, /* dummy to get below fields to be 1-based */ 126 bidx_USER, /* dummy to get below fields to be 1-based */
127 bidx_PIN, /* pin count */
125#ifdef BUFLIB_HAS_CRC 128#ifdef BUFLIB_HAS_CRC
126 bidx_CRC, /* CRC, protects all metadata behind it */ 129 bidx_CRC, /* CRC, protects all metadata behind it */
127#endif 130#endif
@@ -132,9 +135,9 @@ enum {
132 * accounted for using the BSIZE field. Note that bidx_USER is not an 135 * accounted for using the BSIZE field. Note that bidx_USER is not an
133 * actual field so it is not included in the count. */ 136 * actual field so it is not included in the count. */
134#ifdef BUFLIB_HAS_CRC 137#ifdef BUFLIB_HAS_CRC
135# define BUFLIB_NUM_FIELDS 5 138# define BUFLIB_NUM_FIELDS 6
136#else 139#else
137# define BUFLIB_NUM_FIELDS 4 140# define BUFLIB_NUM_FIELDS 5
138#endif 141#endif
139 142
140struct buflib_callbacks buflib_ops_locked = { 143struct buflib_callbacks buflib_ops_locked = {
@@ -394,7 +397,7 @@ move_block(struct buflib_context* ctx, union buflib_data* block, int shift)
394 union buflib_data *block_end = h_entry_to_block_end(ctx, h_entry); 397 union buflib_data *block_end = h_entry_to_block_end(ctx, h_entry);
395 check_block_crc(ctx, block, block_end); 398 check_block_crc(ctx, block, block_end);
396 399
397 if (!IS_MOVABLE(block)) 400 if (!IS_MOVABLE(block) || block_end[-bidx_PIN].pincount > 0)
398 return false; 401 return false;
399 402
400 int handle = ctx->handle_table - h_entry; 403 int handle = ctx->handle_table - h_entry;
@@ -751,6 +754,7 @@ buffer_alloc:
751 754
752 size_t bsize = BUFLIB_NUM_FIELDS + name_len/sizeof(union buflib_data); 755 size_t bsize = BUFLIB_NUM_FIELDS + name_len/sizeof(union buflib_data);
753 union buflib_data *block_end = block + bsize; 756 union buflib_data *block_end = block + bsize;
757 block_end[-bidx_PIN].pincount = 0;
754 block_end[-bidx_BSIZE].val = bsize; 758 block_end[-bidx_BSIZE].val = bsize;
755 update_block_crc(ctx, block, block_end); 759 update_block_crc(ctx, block, block_end);
756 760
@@ -1050,6 +1054,39 @@ buflib_shrink(struct buflib_context* ctx, int handle, void* new_start, size_t ne
1050 return true; 1054 return true;
1051} 1055}
1052 1056
1057void buflib_pin(struct buflib_context *ctx, int handle)
1058{
1059 if ((BUFLIB_PARANOIA & PARANOIA_CHECK_PINNING) && handle <= 0)
1060 buflib_panic(ctx, "invalid handle pin: %d", handle);
1061
1062 union buflib_data *data = handle_to_block_end(ctx, handle);
1063 data[-bidx_PIN].pincount++;
1064}
1065
1066void buflib_unpin(struct buflib_context *ctx, int handle)
1067{
1068 if ((BUFLIB_PARANOIA & PARANOIA_CHECK_PINNING) && handle <= 0)
1069 buflib_panic(ctx, "invalid handle unpin: %d", handle);
1070
1071 union buflib_data *data = handle_to_block_end(ctx, handle);
1072 if (BUFLIB_PARANOIA & PARANOIA_CHECK_PINNING)
1073 {
1074 if (data[-bidx_PIN].pincount == 0)
1075 buflib_panic(ctx, "handle pin underflow: %d", handle);
1076 }
1077
1078 data[-bidx_PIN].pincount--;
1079}
1080
1081unsigned buflib_pin_count(struct buflib_context *ctx, int handle)
1082{
1083 if ((BUFLIB_PARANOIA & PARANOIA_CHECK_PINNING) && handle <= 0)
1084 buflib_panic(ctx, "invalid handle: %d", handle);
1085
1086 union buflib_data *data = handle_to_block_end(ctx, handle);
1087 return data[-bidx_PIN].pincount;
1088}
1089
1053const char* buflib_get_name(struct buflib_context *ctx, int handle) 1090const char* buflib_get_name(struct buflib_context *ctx, int handle)
1054{ 1091{
1055 union buflib_data *data = handle_to_block_end(ctx, handle); 1092 union buflib_data *data = handle_to_block_end(ctx, handle);