summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/buflib.c45
-rw-r--r--firmware/core_alloc.c15
-rw-r--r--firmware/include/buflib.h20
-rw-r--r--firmware/include/core_alloc.h3
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] */
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);
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
107void core_pin(int handle)
108{
109 buflib_pin(&core_ctx, handle);
110}
111
112void core_unpin(int handle)
113{
114 buflib_unpin(&core_ctx, handle);
115}
116
117unsigned core_pin_count(int handle)
118{
119 return buflib_pin_count(&core_ctx, handle);
120}
121
107const char* core_get_name(int handle) 122const 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)
292bool buflib_shrink(struct buflib_context *ctx, int handle, void* newstart, size_t new_size); 293bool 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 */
302void buflib_pin(struct buflib_context *ctx, int handle);
303
304/**
305 * Decrement the pin count for a handle.
306 */
307void 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 */
312unsigned 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);
14int core_alloc_ex(const char* name, size_t size, struct buflib_callbacks *ops); 14int core_alloc_ex(const char* name, size_t size, struct buflib_callbacks *ops);
15int core_alloc_maximum(const char* name, size_t *size, struct buflib_callbacks *ops); 15int core_alloc_maximum(const char* name, size_t *size, struct buflib_callbacks *ops);
16bool core_shrink(int handle, void* new_start, size_t new_size); 16bool core_shrink(int handle, void* new_start, size_t new_size);
17void core_pin(int handle);
18void core_unpin(int handle);
19unsigned core_pin_count(int handle);
17int core_free(int handle); 20int core_free(int handle);
18size_t core_available(void); 21size_t core_available(void);
19size_t core_allocatable(void); 22size_t core_allocatable(void);