A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 263 lines 6.7 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2023 Aidan MacDonald 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21 22/* 23 * Malloc backed buflib. This is intended for debugging rather than for 24 * serious use - the buffer passed to the context is wasted, and memory 25 * is acquired from malloc() instead. The main point is to make ASAN more 26 * effective by isolating buflib allocations from each other. 27 * 28 * Currently this is a bare-minimum implementation, it doesn't even run 29 * buflib callbacks since it never moves anything. It could later be 30 * extended with stress-testing options, for example by randomly moving 31 * allocations around. 32 */ 33 34#include "buflib.h" 35#include "panic.h" 36#include <stdlib.h> 37 38static struct buflib_malloc_handle *get_free_handle(struct buflib_context *ctx) 39{ 40 struct buflib_malloc_handle *h; 41 for (size_t i = 0; i < ctx->num_allocs; ++i) 42 { 43 h = &ctx->allocs[i]; 44 if (h->size == 0) 45 return h; 46 } 47 48 ctx->num_allocs++; 49 ctx->allocs = realloc(ctx->allocs, ctx->num_allocs * sizeof(*ctx->allocs)); 50 if (!ctx->allocs) 51 panicf("buflib %p handle OOM", ctx); 52 53 h = &ctx->allocs[ctx->num_allocs - 1]; 54 h->size = 0; 55 return h; 56} 57 58static int get_handle_num(struct buflib_context *ctx, 59 struct buflib_malloc_handle *handle) 60{ 61 return (handle - ctx->allocs) + 1; 62} 63 64static struct buflib_malloc_handle *get_handle(struct buflib_context *ctx, 65 int handle) 66{ 67 return &ctx->allocs[handle - 1]; 68} 69 70struct buflib_callbacks buflib_ops_locked = { 71 .move_callback = NULL, 72 .shrink_callback = NULL, 73 .sync_callback = NULL, 74}; 75 76void buflib_init(struct buflib_context *ctx, void *buf, size_t size) 77{ 78 ctx->allocs = NULL; 79 ctx->num_allocs = 0; 80 ctx->buf = buf; 81 ctx->bufsize = size; 82} 83 84size_t buflib_available(struct buflib_context *ctx) 85{ 86 return ctx->bufsize; 87} 88 89size_t buflib_allocatable(struct buflib_context *ctx) 90{ 91 return ctx->bufsize; 92} 93 94bool buflib_context_relocate(struct buflib_context *ctx, void *buf) 95{ 96 ctx->buf = buf; 97 return true; 98} 99 100int buflib_alloc(struct buflib_context *ctx, size_t size) 101{ 102 return buflib_alloc_ex(ctx, size, NULL); 103} 104 105int buflib_alloc_ex(struct buflib_context *ctx, size_t size, 106 struct buflib_callbacks *ops) 107{ 108 struct buflib_malloc_handle *handle = get_free_handle(ctx); 109 110 handle->data = malloc(size); 111 handle->user = handle->data; 112 handle->size = size; 113 handle->pin_count = 0; 114 handle->ops = ops; 115 116 if (!handle->data) 117 panicf("buflib %p data OOM", ctx); 118 119 return get_handle_num(ctx, handle); 120} 121 122int buflib_alloc_maximum(struct buflib_context* ctx, 123 size_t *size, struct buflib_callbacks *ops) 124{ 125 *size = ctx->bufsize; 126 127 return buflib_alloc_ex(ctx, *size, ops); 128} 129 130bool buflib_shrink(struct buflib_context *ctx, int handle, 131 void *newstart, size_t new_size) 132{ 133 struct buflib_malloc_handle *h = get_handle(ctx, handle); 134 if (newstart < h->user || new_size > h->size - (newstart - h->user)) 135 return false; 136 137 /* XXX: this might be allowed, but what would be the point... */ 138 if (new_size == 0) 139 { 140 panicf("weird shrink"); 141 return false; 142 } 143 144 /* due to buflib semantics we must not realloc */ 145 h->user = newstart; 146 h->size = new_size; 147 return true; 148} 149 150void buflib_pin(struct buflib_context *ctx, int handle) 151{ 152 struct buflib_malloc_handle *h = get_handle(ctx, handle); 153 154 h->pin_count++; 155} 156 157void buflib_unpin(struct buflib_context *ctx, int handle) 158{ 159 struct buflib_malloc_handle *h = get_handle(ctx, handle); 160 161 h->pin_count--; 162} 163 164unsigned buflib_pin_count(struct buflib_context *ctx, int handle) 165{ 166 struct buflib_malloc_handle *h = get_handle(ctx, handle); 167 168 return h->pin_count; 169} 170 171void _buflib_malloc_put_data_pinned(struct buflib_context *ctx, void *data) 172{ 173 for (size_t i = 0; i < ctx->num_allocs; ++i) 174 { 175 if (ctx->allocs[i].user == data) 176 { 177 ctx->allocs[i].pin_count--; 178 break; 179 } 180 } 181} 182 183int buflib_free(struct buflib_context *ctx, int handle) 184{ 185 if (handle <= 0) 186 return 0; 187 188 struct buflib_malloc_handle *h = get_handle(ctx, handle); 189 190 free(h->data); 191 h->size = 0; 192 193 return 0; 194} 195 196#ifdef BUFLIB_DEBUG_GET_DATA 197void *buflib_get_data(struct buflib_context *ctx, int handle) 198{ 199 /* kind of silly since it's better for ASAN to catch this but... */ 200 if (handle <= 0 || handle > ctx->num_allocs) 201 panicf("buflib %p: invalid handle %d", ctx, handle); 202 203 struct buflib_malloc_handle *h = get_handle(ctx, handle); 204 if (h->user == NULL) 205 panicf("buflib %p: handle %d use after free", ctx, handle); 206 207 return h->user; 208} 209#endif 210 211void *buflib_buffer_out(struct buflib_context *ctx, size_t *size) 212{ 213 if (*size == 0) 214 *size = ctx->bufsize; 215 216 void *ret = ctx->buf; 217 218 ctx->buf += *size; 219 return ret; 220} 221 222void buflib_buffer_in(struct buflib_context *ctx, int size) 223{ 224 ctx->buf -= size; 225} 226 227#ifdef BUFLIB_DEBUG_PRINT 228int buflib_get_num_blocks(struct buflib_context *ctx) 229{ 230 return ctx->num_allocs; 231} 232 233bool buflib_print_block_at(struct buflib_context *ctx, int block_num, 234 char *buf, size_t bufsize) 235{ 236 if (block_num >= ctx->num_allocs) 237 { 238 if (bufsize > 0) 239 *buf = '\0'; 240 return false; 241 } 242 243 struct buflib_malloc_handle *handle = &ctx->allocs[block_num]; 244 if (handle->data) 245 { 246 snprintf(buf, bufsize, "%03d addr:%8p length:%zu", 247 block_num, handle->data, handle->size); 248 } 249 else 250 { 251 snprintf(buf, bufsize, "%03d (unallocated)", block_num); 252 } 253 254 return true; 255} 256#endif 257 258#ifdef BUFLIB_DEBUG_CHECK_VALID 259void buflib_check_valid(struct buflib_context *ctx) 260{ 261 (void)ctx; 262} 263#endif