Rockbox open source high quality audio player as a Music Player Daemon
mpris rockbox mpd libadwaita audio rust zig deno
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

buflib: clean up and refactor to improve maintainability

Buflib is written with a lot of hardcoded offsets to header fields,
arbitrary pointer arithmetic, and similar but not quite duplicated
code, making maintenance a nightmare.

Most of the pointer arithmetic involving header fields is replaced
by indexing from two well-defined pointers, the block start and end
pointers. The start pointer points to the first header field, and
he end pointer is one past the end of the header.

Hardcoded field indices are replaced by two enums. Forward indices
(fidx_XXX) are used to access fields from a block start pointer and
negated backward indices (-bidx_XXX) are used to index from a block
end pointer. There is no overlap between the indices because of the
variable length name field in the middle of the header. The length
of the fixed fields in the block header is now a #define'd constant
rather than being open coded.

There is now a function to acquire the block end pointer from the
user data pointer (ie. the pointer stored in the handle table). The
old code was not consistent in this; some functions would handle a
non-aligned user pointer, which may occur as a result of shrinking,
while other uses just assumed the user pointer was aligned.

Block CRC calculations have also been factored out to a function
that accepts block start and end pointers.

Change-Id: I6a7e8a8c58aec6c6eaf0e5021400032d8e5f841e

+133 -105
+133 -105
firmware/buflib.c
··· 97 97 98 98 #define BPANICF panicf 99 99 100 + /* Forward indices, used to index a block start pointer as block[fidx_XXX] */ 101 + enum { 102 + fidx_LEN, /* length of the block, must come first */ 103 + fidx_HANDLE, /* pointer to entry in the handle table */ 104 + fidx_OPS, /* pointer to an ops struct */ 105 + fidx_NAME, /* name, optional and variable length, must come last */ 106 + }; 107 + 108 + /* Backward indices, used to index a block end pointer as block[-bidx_XXX] */ 109 + enum { 110 + bidx_USER, /* dummy to get below fields to be 1-based */ 111 + bidx_CRC, /* CRC, protects all metadata behind it */ 112 + bidx_BSIZE, /* total size of the block header */ 113 + }; 114 + 115 + /* Number of fields in the block header, excluding the name, which is 116 + * accounted for using the BSIZE field. Note that bidx_USER is not an 117 + * actual field so it is not included in the count. */ 118 + #define BUFLIB_NUM_FIELDS 5 119 + 100 120 struct buflib_callbacks buflib_ops_locked = { 101 121 .move_callback = NULL, 102 122 .shrink_callback = NULL, 103 123 .sync_callback = NULL, 104 124 }; 105 125 106 - #define IS_MOVABLE(a) (!a[2].ops || a[2].ops->move_callback) 126 + #define IS_MOVABLE(a) (!a[fidx_OPS].ops || a[fidx_OPS].ops->move_callback) 127 + 107 128 static union buflib_data* find_first_free(struct buflib_context *ctx); 108 129 static union buflib_data* find_block_before(struct buflib_context *ctx, 109 130 union buflib_data* block, ··· 241 262 if (!data) 242 263 return NULL; 243 264 244 - return data - data[-2].val; 265 + return data - data[-bidx_BSIZE].val; 245 266 } 246 267 247 268 /* Shrink the handle table, returning true if its size was reduced, false if ··· 263 284 return handle != old_last; 264 285 } 265 286 287 + static inline 288 + union buflib_data* userpointer_to_block_end(void *userpointer) 289 + { 290 + union buflib_data *data = ALIGN_DOWN(userpointer, sizeof(*data)); 291 + return data; 292 + } 293 + 294 + static uint32_t calc_block_crc(union buflib_data *block, 295 + union buflib_data *block_end) 296 + { 297 + union buflib_data *crc_slot = &block_end[-bidx_CRC]; 298 + const size_t size = (crc_slot - block) * sizeof(*block); 299 + return crc_32(block, size, 0xffffffff); 300 + } 266 301 267 302 /* If shift is non-zero, it represents the number of places to move 268 303 * blocks in memory. Calculate the new address for this block, ··· 275 310 move_block(struct buflib_context* ctx, union buflib_data* block, int shift) 276 311 { 277 312 char* new_start; 313 + union buflib_data *new_block; 278 314 279 315 if (block < ctx->buf_start || block > ctx->alloc_end) 280 316 buflib_panic(ctx, "buflib data corrupted %p", block); 281 317 282 - union buflib_data *new_block, *tmp = block[1].handle, *crc_slot; 283 - struct buflib_callbacks *ops = block[2].ops; 284 - crc_slot = (union buflib_data*)tmp->alloc - 1; 285 - if (crc_slot < ctx->buf_start || crc_slot > ctx->alloc_end) 286 - buflib_panic(ctx, "buflib metadata corrupted %p", crc_slot); 318 + union buflib_data *h_entry = block[fidx_HANDLE].handle; 319 + union buflib_data *block_end = userpointer_to_block_end(h_entry->alloc); 287 320 288 - const int metadata_size = (crc_slot - block)*sizeof(union buflib_data); 289 - uint32_t crc = crc_32((void *)block, metadata_size, 0xffffffff); 290 - 291 - /* check for metadata validity */ 292 - if (crc != crc_slot->crc) 321 + uint32_t crc = calc_block_crc(block, block_end); 322 + if (crc != block_end[-bidx_CRC].crc) 293 323 buflib_panic(ctx, "buflib metadata corrupted, crc: 0x%08x, expected: 0x%08x", 294 - (unsigned int)crc, (unsigned int)crc_slot->crc); 324 + (unsigned int)crc, (unsigned int)block_end[-bidx_CRC].crc); 295 325 296 326 if (!IS_MOVABLE(block)) 297 327 return false; 298 328 299 - int handle = ctx->handle_table - tmp; 300 - BDEBUGF("%s(): moving \"%s\"(id=%d) by %d(%d)\n", __func__, block[3].name, 301 - handle, shift, shift*(int)sizeof(union buflib_data)); 329 + int handle = ctx->handle_table - h_entry; 330 + BDEBUGF("%s(): moving \"%s\"(id=%d) by %d(%d)\n", __func__, 331 + block[fidx_NAME].name, handle, shift, shift*(int)sizeof(union buflib_data)); 302 332 new_block = block + shift; 303 - new_start = tmp->alloc + shift*sizeof(union buflib_data); 333 + new_start = h_entry->alloc + shift*sizeof(union buflib_data); 334 + 335 + struct buflib_callbacks *ops = block[fidx_OPS].ops; 304 336 305 337 /* If move must be synchronized with use, user should have specified a 306 338 callback that handles this */ ··· 308 340 ops->sync_callback(handle, true); 309 341 310 342 bool retval = false; 311 - if (!ops || ops->move_callback(handle, tmp->alloc, new_start) 343 + if (!ops || ops->move_callback(handle, h_entry->alloc, new_start) 312 344 != BUFLIB_CB_CANNOT_MOVE) 313 345 { 314 - tmp->alloc = new_start; /* update handle table */ 346 + h_entry->alloc = new_start; /* update handle table */ 315 347 memmove(new_block, block, block->val * sizeof(union buflib_data)); 316 348 retval = true; 317 349 } ··· 424 456 this < ctx->alloc_end; 425 457 before = this, this += abs(this->val)) 426 458 { 427 - if (this->val > 0 && this[2].ops 428 - && this[2].ops->shrink_callback) 459 + if (this->val <= 0) 460 + continue; 461 + 462 + struct buflib_callbacks *ops = this[fidx_OPS].ops; 463 + if (!ops || !ops->shrink_callback) 464 + continue; 465 + 466 + union buflib_data* h_entry = this[fidx_HANDLE].handle; 467 + int handle = ctx->handle_table - h_entry; 468 + 469 + unsigned pos_hints = shrink_hints & BUFLIB_SHRINK_POS_MASK; 470 + /* adjust what we ask for if there's free space in the front 471 + * this isn't too unlikely assuming this block is 472 + * shrinkable but not movable */ 473 + if (pos_hints == BUFLIB_SHRINK_POS_FRONT && 474 + before != this && before->val < 0) 429 475 { 430 - int ret; 431 - int handle = ctx->handle_table - this[1].handle; 432 - char* data = this[1].handle->alloc; 433 - bool last = (this+this->val) == ctx->alloc_end; 434 - unsigned pos_hints = shrink_hints & BUFLIB_SHRINK_POS_MASK; 435 - /* adjust what we ask for if there's free space in the front 436 - * this isn't too unlikely assuming this block is 437 - * shrinkable but not movable */ 438 - if (pos_hints == BUFLIB_SHRINK_POS_FRONT 439 - && before != this && before->val < 0) 440 - { 441 - size_t free_space = (-before->val) * sizeof(union buflib_data); 442 - size_t wanted = shrink_hints & BUFLIB_SHRINK_SIZE_MASK; 443 - if (wanted < free_space) /* no shrink needed? */ 444 - continue; 445 - wanted -= free_space; 446 - shrink_hints = pos_hints | wanted; 447 - } 448 - ret = this[2].ops->shrink_callback(handle, shrink_hints, 449 - data, (char*)(this+this->val)-data); 450 - result |= (ret == BUFLIB_CB_OK); 451 - /* 'this' might have changed in the callback (if it shrinked 452 - * from the top or even freed the handle), get it again */ 453 - this = handle_to_block(ctx, handle); 454 - /* The handle was possibly be freed in the callback, 455 - * re-run the loop with the handle before */ 456 - if (!this) 457 - this = before; 458 - /* could also change with shrinking from back */ 459 - else if (last) 460 - ctx->alloc_end = this + this->val; 476 + size_t free_space = (-before->val) * sizeof(union buflib_data); 477 + size_t wanted = shrink_hints & BUFLIB_SHRINK_SIZE_MASK; 478 + if (wanted < free_space) /* no shrink needed? */ 479 + continue; 480 + wanted -= free_space; 481 + shrink_hints = pos_hints | wanted; 461 482 } 483 + 484 + char* data = h_entry->alloc; 485 + char* data_end = (char*)(this + this->val); 486 + bool last = (data_end == (char*)ctx->alloc_end); 487 + 488 + int ret = ops->shrink_callback(handle, shrink_hints, 489 + data, data_end - data); 490 + result |= (ret == BUFLIB_CB_OK); 491 + 492 + /* 'this' might have changed in the callback (if it shrinked 493 + * from the top or even freed the handle), get it again */ 494 + this = handle_to_block(ctx, handle); 495 + 496 + /* The handle was possibly be freed in the callback, 497 + * re-run the loop with the handle before */ 498 + if (!this) 499 + this = before; 500 + /* could also change with shrinking from back */ 501 + else if (last) 502 + ctx->alloc_end = this + this->val; 462 503 } 463 504 /* shrinking was successful at least once, try compaction again */ 464 505 if (result) ··· 547 588 size += name_len; 548 589 size = (size + sizeof(union buflib_data) - 1) / 549 590 sizeof(union buflib_data) 550 - /* add 5 objects for alloc len, pointer to handle table entry and 551 - * name length, the ops pointer and crc */ 552 - + 5; 591 + + BUFLIB_NUM_FIELDS; 553 592 handle_alloc: 554 593 handle = handle_alloc(ctx); 555 594 if (!handle) ··· 559 598 */ 560 599 union buflib_data* last_block = find_block_before(ctx, 561 600 ctx->alloc_end, false); 562 - struct buflib_callbacks* ops = last_block[2].ops; 601 + struct buflib_callbacks* ops = last_block[fidx_OPS].ops; 563 602 unsigned hints = 0; 564 603 if (!ops || !ops->shrink_callback) 565 604 { /* the last one isn't shrinkable ··· 627 666 /* Set up the allocated block, by marking the size allocated, and storing 628 667 * a pointer to the handle. 629 668 */ 630 - union buflib_data *header_size_slot, *crc_slot; 631 - block->val = size; 632 - block[1].handle = handle; 633 - block[2].ops = ops; 669 + block[fidx_LEN].val = size; 670 + block[fidx_HANDLE].handle = handle; 671 + block[fidx_OPS].ops = ops; 634 672 if (name_len > 0) 635 - strcpy(block[3].name, name); 636 - header_size_slot = (union buflib_data*)B_ALIGN_UP(block[3].name + name_len); 637 - header_size_slot->val = 5 + name_len/sizeof(union buflib_data); 638 - crc_slot = (union buflib_data*)(header_size_slot + 1); 639 - crc_slot->crc = crc_32((void *)block, 640 - (crc_slot - block)*sizeof(union buflib_data), 641 - 0xffffffff); 642 - handle->alloc = (char*)(crc_slot + 1); 673 + strcpy(block[fidx_NAME].name, name); 674 + 675 + size_t bsize = BUFLIB_NUM_FIELDS + name_len/sizeof(union buflib_data); 676 + union buflib_data *block_end = block + bsize; 677 + block_end[-bidx_BSIZE].val = bsize; 678 + block_end[-bidx_CRC].crc = calc_block_crc(block, block_end); 679 + 680 + handle->alloc = (char*)&block_end[-bidx_USER]; 643 681 644 682 BDEBUGF("buflib_alloc_ex: size=%d handle=%p clb=%p crc=0x%0x name=\"%s\"\n", 645 683 (unsigned int)size, (void *)handle, (void *)ops, 646 - (unsigned int)crc_slot->crc, name ? block[3].name:""); 684 + (unsigned int)block_end[-bidx_CRC].crc, name ? name : ""); 647 685 648 686 block += size; 649 687 /* alloc_end must be kept current if we're taking the last block. */ ··· 743 781 { 744 782 /* subtract 5 elements for 745 783 * val, handle, meta_len, ops and the handle table entry*/ 746 - ptrdiff_t diff = (ctx->last_handle - ctx->alloc_end - 5); 784 + ptrdiff_t diff = (ctx->last_handle - ctx->alloc_end - BUFLIB_NUM_FIELDS); 747 785 diff -= 16; /* space for future handles */ 748 786 diff *= sizeof(union buflib_data); /* make it bytes */ 749 787 diff -= 16; /* reserve 16 for the name */ ··· 858 896 bool 859 897 buflib_shrink(struct buflib_context* ctx, int handle, void* new_start, size_t new_size) 860 898 { 861 - union buflib_data *crc_slot; 862 - int size_for_crc32; 863 899 char* oldstart = buflib_get_data(ctx, handle); 864 900 char* newstart = new_start; 865 901 char* newend = newstart + new_size; ··· 883 919 metadata_size.val = aligned_oldstart - block; 884 920 /* update val and the handle table entry */ 885 921 new_block = aligned_newstart - metadata_size.val; 886 - block[0].val = new_next_block - new_block; 922 + block[fidx_LEN].val = new_next_block - new_block; 887 923 888 - block[1].handle->alloc = newstart; 924 + block[fidx_HANDLE].handle->alloc = newstart; 889 925 if (block != new_block) 890 926 { 891 927 /* move metadata over, i.e. pointer to handle table entry and name ··· 906 942 } 907 943 908 944 /* update crc of the metadata */ 909 - crc_slot = (union buflib_data*)new_block[1].handle->alloc - 1; 910 - size_for_crc32 = (crc_slot - new_block)*sizeof(union buflib_data); 911 - crc_slot->crc = crc_32((void *)new_block, size_for_crc32, 0xffffffff); 945 + union buflib_data *new_h_entry = new_block[fidx_HANDLE].handle; 946 + union buflib_data *new_block_end = userpointer_to_block_end(new_h_entry->alloc); 947 + new_block_end[-bidx_CRC].crc = calc_block_crc(new_block, new_block_end); 912 948 913 949 /* Now deal with size changes that create free blocks after the allocation */ 914 950 if (old_next_block != new_next_block) ··· 932 968 const char* buflib_get_name(struct buflib_context *ctx, int handle) 933 969 { 934 970 union buflib_data *data = ALIGN_DOWN(buflib_get_data(ctx, handle), sizeof (*data)); 935 - size_t len = data[-2].val; 936 - if (len <= 5) 971 + size_t len = data[-bidx_BSIZE].val; 972 + if (len <= BUFLIB_NUM_FIELDS) 937 973 return NULL; 938 974 939 975 data -= len; 940 - return data[3].name; 976 + return data[fidx_NAME].name; 941 977 } 942 978 943 979 #ifdef DEBUG ··· 952 988 953 989 void buflib_check_valid(struct buflib_context *ctx) 954 990 { 955 - union buflib_data *crc_slot; 956 - int metadata_size; 957 - uint32_t crc; 958 - 959 991 for(union buflib_data* this = ctx->buf_start; 960 992 this < ctx->alloc_end; 961 993 this += abs(this->val)) ··· 963 995 if (this->val < 0) 964 996 continue; 965 997 966 - crc_slot = (union buflib_data*) 967 - ((union buflib_data*)this[1].handle)->alloc - 1; 968 - metadata_size = (crc_slot - this)*sizeof(union buflib_data); 969 - crc = crc_32((void *)this, metadata_size, 0xffffffff); 970 - 971 - if (crc != crc_slot->crc) 998 + union buflib_data *h_entry = this[fidx_HANDLE].handle; 999 + union buflib_data *block_end = userpointer_to_block_end(h_entry->alloc); 1000 + uint32_t crc = calc_block_crc(this, block_end); 1001 + if (crc != block_end[-bidx_CRC].crc) 1002 + { 972 1003 buflib_panic(ctx, "crc mismatch: 0x%08x, expected: 0x%08x", 973 - (unsigned int)crc, (unsigned int)crc_slot->crc); 1004 + (unsigned int)crc, (unsigned int)block_end[-bidx_CRC].crc); 1005 + } 974 1006 } 975 1007 } 976 1008 #endif ··· 985 1017 { 986 1018 if (!this->alloc) continue; 987 1019 988 - int handle_num; 989 - const char *name; 990 - union buflib_data *block_start, *alloc_start; 991 - intptr_t alloc_len; 992 - 993 - handle_num = end - this; 994 - alloc_start = buflib_get_data(ctx, handle_num); 995 - name = buflib_get_name(ctx, handle_num); 996 - block_start = (union buflib_data*)name - 3; 997 - alloc_len = block_start->val * sizeof(union buflib_data); 1020 + int handle_num = end - this; 1021 + void* alloc_start = this->alloc; 1022 + union buflib_data *block_start = handle_to_block(ctx, handle_num); 1023 + const char* name = buflib_get_name(ctx, handle_num); 1024 + intptr_t alloc_len = block_start[fidx_LEN]; 998 1025 999 1026 snprintf(buf, sizeof(buf), 1000 1027 "%s(%d):\t%p\n" ··· 1016 1043 this += abs(this->val)) 1017 1044 { 1018 1045 snprintf(buf, sizeof(buf), "%8p: val: %4ld (%s)", 1019 - this, this->val, 1020 - this->val > 0? this[3].name:"<unallocated>"); 1046 + this, this->val, 1047 + this->val > 0 ? this[fidx_NAME].name : "<unallocated>"); 1021 1048 print(i++, buf); 1022 1049 } 1023 1050 } ··· 1045 1072 this += abs(this->val); 1046 1073 block_num -= 1; 1047 1074 } 1075 + 1048 1076 snprintf(buf, bufsize, "%8p: val: %4ld (%s)", 1049 - this, (long)this->val, 1050 - this->val > 0? this[3].name:"<unallocated>"); 1077 + this, (long)this->val, 1078 + this->val > 0 ? this[fidx_NAME].name : "<unallocated>"); 1051 1079 } 1052 1080 1053 1081 #endif