diff options
-rw-r--r-- | firmware/buflib.c | 45 | ||||
-rw-r--r-- | firmware/core_alloc.c | 15 | ||||
-rw-r--r-- | firmware/include/buflib.h | 20 | ||||
-rw-r--r-- | firmware/include/core_alloc.h | 3 |
4 files changed, 79 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] */ |
123 | enum { | 125 | enum { |
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 | ||
140 | struct buflib_callbacks buflib_ops_locked = { | 143 | struct 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 | ||
1057 | void 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 | |||
1066 | void 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 | |||
1081 | unsigned 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 | |||
1053 | const char* buflib_get_name(struct buflib_context *ctx, int handle) | 1090 | const 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); |
diff --git a/firmware/core_alloc.c b/firmware/core_alloc.c index bf2f8e8298..0374c801c1 100644 --- a/firmware/core_alloc.c +++ b/firmware/core_alloc.c | |||
@@ -104,6 +104,21 @@ bool core_shrink(int handle, void* new_start, size_t new_size) | |||
104 | return buflib_shrink(&core_ctx, handle, new_start, new_size); | 104 | return buflib_shrink(&core_ctx, handle, new_start, new_size); |
105 | } | 105 | } |
106 | 106 | ||
107 | void core_pin(int handle) | ||
108 | { | ||
109 | buflib_pin(&core_ctx, handle); | ||
110 | } | ||
111 | |||
112 | void core_unpin(int handle) | ||
113 | { | ||
114 | buflib_unpin(&core_ctx, handle); | ||
115 | } | ||
116 | |||
117 | unsigned core_pin_count(int handle) | ||
118 | { | ||
119 | return buflib_pin_count(&core_ctx, handle); | ||
120 | } | ||
121 | |||
107 | const char* core_get_name(int handle) | 122 | const char* core_get_name(int handle) |
108 | { | 123 | { |
109 | const char *name = buflib_get_name(&core_ctx, handle); | 124 | const char *name = buflib_get_name(&core_ctx, handle); |
diff --git a/firmware/include/buflib.h b/firmware/include/buflib.h index 45446c3b86..d2231ab79d 100644 --- a/firmware/include/buflib.h +++ b/firmware/include/buflib.h | |||
@@ -38,6 +38,7 @@ union buflib_data | |||
38 | intptr_t val; /* length of the block in n*sizeof(union buflib_data). | 38 | intptr_t val; /* length of the block in n*sizeof(union buflib_data). |
39 | Includes buflib metadata overhead. A negative value | 39 | Includes buflib metadata overhead. A negative value |
40 | indicates block is unallocated */ | 40 | indicates block is unallocated */ |
41 | volatile unsigned pincount; /* number of pins */ | ||
41 | struct buflib_callbacks* ops; /* callback functions for move and shrink. Can be NULL */ | 42 | struct buflib_callbacks* ops; /* callback functions for move and shrink. Can be NULL */ |
42 | char* alloc; /* start of allocated memory area */ | 43 | char* alloc; /* start of allocated memory area */ |
43 | union buflib_data *handle; /* pointer to entry in the handle table. | 44 | union buflib_data *handle; /* pointer to entry in the handle table. |
@@ -292,6 +293,25 @@ static inline void* buflib_get_data(struct buflib_context *ctx, int handle) | |||
292 | bool buflib_shrink(struct buflib_context *ctx, int handle, void* newstart, size_t new_size); | 293 | bool buflib_shrink(struct buflib_context *ctx, int handle, void* newstart, size_t new_size); |
293 | 294 | ||
294 | /** | 295 | /** |
296 | * Increment the pin count for a handle. When pinned the handle will not | ||
297 | * be moved and move callbacks will not be triggered, allowing a pointer | ||
298 | * to the buffer to be kept across yields or used for I/O. | ||
299 | * | ||
300 | * Note that shrink callbacks can still be invoked for pinned handles. | ||
301 | */ | ||
302 | void buflib_pin(struct buflib_context *ctx, int handle); | ||
303 | |||
304 | /** | ||
305 | * Decrement the pin count for a handle. | ||
306 | */ | ||
307 | void buflib_unpin(struct buflib_context *ctx, int handle); | ||
308 | |||
309 | /** | ||
310 | * Get the current pin count of a handle. Zero means the handle is not pinned. | ||
311 | */ | ||
312 | unsigned buflib_pin_count(struct buflib_context *ctx, int handle); | ||
313 | |||
314 | /** | ||
295 | * Frees memory associated with the given handle | 315 | * Frees memory associated with the given handle |
296 | * | 316 | * |
297 | * Returns: 0 (to invalidate handles in one line, 0 is not a valid handle) | 317 | * Returns: 0 (to invalidate handles in one line, 0 is not a valid handle) |
diff --git a/firmware/include/core_alloc.h b/firmware/include/core_alloc.h index f535fc1f6e..87246bcbd6 100644 --- a/firmware/include/core_alloc.h +++ b/firmware/include/core_alloc.h | |||
@@ -14,6 +14,9 @@ int core_alloc(const char* name, size_t size); | |||
14 | int core_alloc_ex(const char* name, size_t size, struct buflib_callbacks *ops); | 14 | int core_alloc_ex(const char* name, size_t size, struct buflib_callbacks *ops); |
15 | int core_alloc_maximum(const char* name, size_t *size, struct buflib_callbacks *ops); | 15 | int core_alloc_maximum(const char* name, size_t *size, struct buflib_callbacks *ops); |
16 | bool core_shrink(int handle, void* new_start, size_t new_size); | 16 | bool core_shrink(int handle, void* new_start, size_t new_size); |
17 | void core_pin(int handle); | ||
18 | void core_unpin(int handle); | ||
19 | unsigned core_pin_count(int handle); | ||
17 | int core_free(int handle); | 20 | int core_free(int handle); |
18 | size_t core_available(void); | 21 | size_t core_available(void); |
19 | size_t core_allocatable(void); | 22 | size_t core_allocatable(void); |