A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 417 lines 17 kB view raw
1/************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2009 Andrew Mahone 11 * Copyright (C) 2011 Thomas Martitz 12 * Copyright (C) 2023 Aidan MacDonald 13 * 14 * This program is free software; you can redistribute it and/or 15 * modify it under the terms of the GNU General Public License 16 * as published by the Free Software Foundation; either version 2 17 * of the License, or (at your option) any later version. 18 * 19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 20 * KIND, either express or implied. 21 * 22 ****************************************************************************/ 23#ifndef _BUFLIB_H_ 24#define _BUFLIB_H_ 25 26#include "config.h" 27#include <stdint.h> 28#include <stdbool.h> 29#include <string.h> 30 31/* Add extra checks to buflib_get_data to catch bad handles */ 32//#define BUFLIB_DEBUG_GET_DATA 33 34/* Support integrity check */ 35//#define BUFLIB_DEBUG_CHECK_VALID 36 37/* Support debug printing of memory blocks */ 38//#define BUFLIB_DEBUG_PRINT 39 40/* Defined by the backend header. */ 41struct buflib_context; 42 43/* Buflib callback return codes. */ 44#define BUFLIB_CB_OK 0 45#define BUFLIB_CB_CANNOT_MOVE 1 46#define BUFLIB_CB_CANNOT_SHRINK 1 47 48/* Buflib shrink hints. */ 49#define BUFLIB_SHRINK_SIZE_MASK (~BUFLIB_SHRINK_POS_MASK) 50#define BUFLIB_SHRINK_POS_FRONT (1u<<31) 51#define BUFLIB_SHRINK_POS_BACK (1u<<30) 52#define BUFLIB_SHRINK_POS_MASK (BUFLIB_SHRINK_POS_FRONT|BUFLIB_SHRINK_POS_BACK) 53 54/** 55 * Callbacks run by buflib to manage an allocation. 56 */ 57struct buflib_callbacks 58{ 59 /** 60 * \brief Called when buflib wants to move the buffer 61 * \param handle Handle being moved 62 * \param current Current address of the buffer 63 * \param new New address the buffer would have after moving 64 * \return BUFLIB_CB_OK - Allow the buffer to be moved. 65 * \return BUFLIB_CB_CANNOT_MOVE - Do not allow the buffer to be moved. 66 * 67 * This callback allows you to fix up any pointers that might 68 * be pointing to the buffer before it is moved. The task of 69 * actually moving the buffer contents is performed by buflib 70 * after the move callback returns, if movement is allowed. 71 * 72 * Care must be taken to ensure that the buffer is not accessed 73 * from outside the move callback until the move is complete. If 74 * this is a concern, eg. due to multi-threaded access, then you 75 * must implement a sync_callback() and guard any access to the 76 * buffer with a lock. 77 * 78 * If the move callback is NULL then buflib will never move 79 * the allocation, as if you returned BUFLIB_CB_CANNOT_MOVE. 80 */ 81 int (*move_callback)(int handle, void* current, void* new); 82 83 /** 84 * \brief Called when buflib wants to shrink the buffer 85 * \param handle Handle to shrink 86 * \param hints Hints regarding the shrink request 87 * \param start Current address of the buffer 88 * \param size Current size of the buffer as seen by buflib. 89 * This may be rounded up compared to the nominal 90 * allocation size due to alignment requirements. 91 * \return BUFLIB_CB_OK - Was able to shrink the buffer. 92 * \return BUFLIB_CB_CANNOT_SHRINK - Buffer cannot shrink. 93 * 94 * This callback is run by buflib when it runs out of memory 95 * and starts a compaction run. Buflib will not actually try 96 * to shrink or move memory, you must do that yourself and 97 * call buflib_shrink() to report the new start address and 98 * size of the buffer. 99 * 100 * If the shrink callback is NULL then buflib will regard the 101 * buffer as non-shrinkable. 102 */ 103 int (*shrink_callback)(int handle, unsigned hints, 104 void *start, size_t size); 105 106 /** 107 * \brief Called before and after attempting to move the buffer 108 * \param handle Handle being moved 109 * \param lock True to lock, false to unlock 110 * 111 * The purpose of this callback is to block access to the buffer 112 * from other threads while a buffer is being moved, using a lock 113 * such as a mutex. 114 * 115 * It is called with `sync_callback(handle, true)` before running 116 * the move callback and `sync_callback(handle, false)` after the 117 * move is complete, regardless of whether the buffer was actually 118 * moved or not. 119 */ 120 void (*sync_callback)(int handle, bool lock); 121}; 122 123/** 124 * A set of all NULL callbacks for use with allocations that need to stay 125 * locked in RAM and not moved or shrunk. These type of allocations should 126 * be avoided as much as possible to avoid memory fragmentation but it can 127 * suitable for short-lived allocations. 128 * 129 * \note Use of this is discouraged. Prefer to use normal moveable 130 * allocations and pin them. 131 */ 132extern struct buflib_callbacks buflib_ops_locked; 133 134/** 135 * \brief Intialize a buflib context 136 * \param ctx Context to initialize 137 * \param buf Buffer which will be used as the context's memory pool 138 * \param size Size of the buffer 139 */ 140void buflib_init(struct buflib_context *ctx, void *buf, size_t size); 141 142/** 143 * Returns the amount of unallocated bytes. It does not mean this amount 144 * can be actually allocated because they might not be contiguous. 145 */ 146size_t buflib_available(struct buflib_context *ctx); 147 148/** 149 * Returns the size of the largest possible contiguous allocation, given 150 * the current state of the memory pool. A larger allocation may still 151 * succeed if compaction is able to create a larger contiguous area. 152 */ 153size_t buflib_allocatable(struct buflib_context *ctx); 154 155/** 156 * \brief Relocate the buflib memory pool to a new address 157 * \param ctx Context to relocate 158 * \param buf New memory pool address 159 * \return True if relocation should proceed, false if it cannot. 160 * 161 * Updates all pointers inside the buflib context to point to a new pool 162 * address. You must call this function before moving the pool and move 163 * the data manually afterwards only if this function returns true. 164 * 165 * This is intended from a move_callback() in buflib-on-buflib scenarios, 166 * where the memory pool of the "inner" buflib is allocated from an "outer" 167 * buflib. 168 * 169 * \warning This does not run any move callbacks, so it is not safe to 170 * use if any allocations require them. 171 */ 172bool buflib_context_relocate(struct buflib_context *ctx, void *buf); 173 174/** 175 * \brief Allocate memory from buflib 176 * \param ctx Context to allocate from 177 * \param size Allocation size 178 * \return Handle for the allocation (> 0) or a negative value on error 179 * 180 * This is the same as calling buflib_alloc_ex() with a NULL callbacks 181 * struct. The resulting allocation can be moved by buflib; use pinning 182 * if you need to prevent moves. 183 * 184 * Note that zero is not a valid handle, and will never be returned by 185 * this function. However, this may change, and you should treat a zero 186 * or negative return value as an allocation failure. 187 */ 188int buflib_alloc(struct buflib_context *ctx, size_t size); 189 190/** 191 * \brief Allocate memory from buflib with custom buffer ops 192 * \param ctx Context to allocate from 193 * \param size Allocation size 194 * \param ops Pointer to ops struct or NULL if no ops are needed. 195 * \return Handle for the allocation (> 0) or a negative value on error. 196 * 197 * Use this if you need to pass custom callbacks for responding to buflib 198 * move or shrink operations. Passing a NULL ops pointer means the buffer 199 * can be moved by buflib at any time. 200 * 201 * Note that zero is not a valid handle, and will never be returned by 202 * this function. However, this may change, and you should treat a zero 203 * or negative return value as an allocation failure. 204 */ 205int buflib_alloc_ex(struct buflib_context *ctx, size_t size, 206 struct buflib_callbacks *ops); 207 208/** 209 * \brief Attempt a maximum size allocation 210 * \param ctx Context to allocate from 211 * \param size Size of the allocation will be written here on success. 212 * \param ops Pointer to ops struct or NULL if no ops are needed. 213 * \return Handle for the allocation (> 0) or a negative value on error. 214 * 215 * Buflib will attempt to compact and shrink other allocations as much as 216 * possible and then allocate the largest contigous free area. Since this 217 * will consume effectively *all* available memory, future allocations are 218 * likely to fail. 219 * 220 * \note There is rarely any justification to use this with the core_alloc 221 * context due to the impact it has on the entire system. You should 222 * change your code if you think you need this. Of course, if you are 223 * using a private buflib context then this warning does not apply. 224 */ 225int buflib_alloc_maximum(struct buflib_context *ctx, 226 size_t *size, struct buflib_callbacks *ops); 227 228/** 229 * \brief Reduce the size of a buflib allocation 230 * \param ctx Buflib context of the allocation 231 * \param handle Handle identifying the allocation 232 * \param newstart New start address. Must be within the current bounds 233 * of the allocation, as returned by buflib_get_data(). 234 * \param new_size New size of the buffer. 235 * \return True if shrinking was successful; otherwise, returns false and 236 * does not modify the allocation. 237 * 238 * Shrinking always succeeds provided the new allocation is contained 239 * within the current allocation. A failure is always a programming 240 * error, so you need not check for it and in the future the failure 241 * case may be changed to a panic or undefined behavior with no return 242 * code. 243 * 244 * The new start address and size need not have any particular alignment, 245 * however buflib cannot work with unaligned addresses so there is rarely 246 * any purpose to creating unaligned allocations. 247 * 248 * Shrinking is typically done from a shrink_callback(), but can be done 249 * at any time if you want to reduce the size of a buflib allocation. 250 */ 251bool buflib_shrink(struct buflib_context *ctx, int handle, 252 void *newstart, size_t new_size); 253 254/** 255 * \brief Increment an allocation's pin count 256 * \param ctx Buflib context of the allocation 257 * \param handle Handle identifying the allocation 258 * 259 * The pin count acts like a reference count. Buflib will not attempt to 260 * move any buffer with a positive pin count, nor invoke any move or sync 261 * callbacks. Hence, when pinned, it is safe to hold pointers to a buffer 262 * across yields or use them for I/O. 263 * 264 * Note that shrink callbacks can still be invoked for pinned handles. 265 */ 266void buflib_pin(struct buflib_context *ctx, int handle); 267 268/** 269 * \brief Decrement an allocation's pin count 270 * \param ctx Buflib context of the allocation 271 * \param handle Handle identifying the allocation 272 */ 273void buflib_unpin(struct buflib_context *ctx, int handle); 274 275/** 276 * \brief Return the pin count of an allocation 277 * \param ctx Buflib context of the allocation 278 * \param handle Handle identifying the allocation 279 * \return Current pin count; zero means the handle is not pinned. 280 */ 281unsigned buflib_pin_count(struct buflib_context *ctx, int handle); 282 283/** 284 * \brief Free an allocation and return its memory to the pool 285 * \param ctx Buflib context of the allocation 286 * \param handle Handle identifying the allocation 287 * \return Always returns zero (zero is not a valid handle, so this can 288 * be used to invalidate the variable containing the handle). 289 */ 290int buflib_free(struct buflib_context *context, int handle); 291 292/** 293 * \brief Get a pointer to the buffer for an allocation 294 * \param ctx Buflib context of the allocation 295 * \param handle Handle identifying the allocation 296 * \return Pointer to the allocation's memory. 297 * 298 * Note that buflib can move allocations in order to free up space when 299 * making new allocations. For this reason, it's unsafe to hold a pointer 300 * to a buffer across a yield() or any other operation that can cause a 301 * context switch. This includes any function that may block, and even 302 * some functions that might not block -- eg. if a low priority thread 303 * acquires a mutex, calling mutex_unlock() may trigger a context switch 304 * to a higher-priority thread. 305 * 306 * buflib_get_data() is a very cheap operation, however, costing only 307 * a few pointer lookups. Don't hesitate to use it extensively. 308 * 309 * If you need to hold a pointer across a possible context switch, pin 310 * the handle with buflib_pin() to prevent the buffer from being moved. 311 * This is required when doing I/O into buflib allocations, for example. 312 */ 313#ifdef BUFLIB_DEBUG_GET_DATA 314void *buflib_get_data(struct buflib_context *ctx, int handle); 315#else 316static inline void *buflib_get_data(struct buflib_context *ctx, int handle); 317#endif 318 319/** 320 * \brief Get a pinned pointer to a buflib allocation 321 * \param ctx Buflib context of the allocation 322 * \param handle Handle identifying the allocation 323 * \return Pointer to the allocation's memory. 324 * 325 * Functionally equivalent to buflib_pin() followed by buflib_get_data(), 326 * but this call is more efficient and should be preferred over separate 327 * calls. 328 * 329 * To unpin the data, call buflib_put_data_pinned() and pass the pointer 330 * returned by this function. 331 */ 332static inline void *buflib_get_data_pinned(struct buflib_context *ctx, int handle); 333 334/** 335 * \brief Release a pinned pointer to a buflib allocation 336 * \param ctx Buflib context of the allocation 337 * \param data Pointer returned by buflib_get_data() 338 * 339 * Decrements the pin count, allowing the buffer to be moved once the 340 * pin count drops to zero. This is more efficient than buflib_unpin() 341 * and should be preferred when you have a pointer to the buflib data. 342 */ 343static inline void buflib_put_data_pinned(struct buflib_context *ctx, void *data); 344 345/** 346 * \brief Shift allocations up to free space at the start of the pool 347 * \param ctx Context to operate on 348 * \param size Indicates number of bytes to free up, or 0 to free 349 * up as much as possible. On return, the actual number 350 * of bytes freed is written here. 351 * \return Pointer to the start of the free area 352 * 353 * If `*size` is non-zero, the actual amount of space freed up might 354 * be less than `*size`. 355 * 356 * \warning This will move data around in the pool without calling any 357 * move callbacks! 358 * \warning This function is deprecated and will eventually be removed. 359 */ 360void* buflib_buffer_out(struct buflib_context *ctx, size_t *size); 361 362/** 363 * \brief Shift allocations down into free space below the pool 364 * \param ctx Context to operate on 365 * \param size Number of bytes to add to the pool. 366 * 367 * This operation should only be used to return memory that was previously 368 * taken from the pool with buflib_buffer_out(), by passing the same size 369 * that you got from that function. 370 * 371 * \warning This will move data around in the pool without calling any 372 * move callbacks! 373 * \warning This function is deprecated and will eventually be removed. 374 */ 375void buflib_buffer_in(struct buflib_context *ctx, int size); 376 377#ifdef BUFLIB_DEBUG_PRINT 378/** 379 * Return the number of blocks in the buffer, allocated or unallocated. 380 * 381 * Only available if BUFLIB_DEBUG_PRINT is defined. 382 */ 383int buflib_get_num_blocks(struct buflib_context *ctx); 384 385/** 386 * Write a string describing the block at index block_num to the 387 * provided buffer. The buffer will always be null terminated and 388 * there is no provision to detect truncation. (A 40-byte buffer 389 * is enough to contain any returned string.) 390 * 391 * Returns false if the block index is out of bounds, and writes 392 * an empty string. 393 * 394 * Only available if BUFLIB_DEBUG_PRINT is defined. 395 */ 396bool buflib_print_block_at(struct buflib_context *ctx, int block_num, 397 char *buf, size_t bufsize); 398#endif 399 400#ifdef BUFLIB_DEBUG_CHECK_VALID 401/** 402 * Check integrity of given buflib context 403 */ 404void buflib_check_valid(struct buflib_context *ctx); 405#endif 406 407#if CONFIG_BUFLIB_BACKEND == BUFLIB_BACKEND_MEMPOOL 408#include "buflib_mempool.h" 409#elif CONFIG_BUFLIB_BACKEND == BUFLIB_BACKEND_MALLOC 410#include "buflib_malloc.h" 411#endif 412 413#ifndef BUFLIB_ALLOC_OVERHEAD 414# define BUFLIB_ALLOC_OVERHEAD 0 415#endif 416 417#endif /* _BUFLIB_H_ */