Something went wrong. Try again.
A modern, network-enabled music player platform built on Rockbox technology. rockboxd.tsiry-sandratraina.com
rust deno navidrome airplay libadwaita zig mpris snapcast mpd rockbox audio subsonic
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * * Copyright (C) 2002 by Ulf Ralberg * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/#include "kernel-internal.h"#include "system.h"
/* Unless otherwise defined, do nothing */#ifndef YIELD_KERNEL_HOOK#define YIELD_KERNEL_HOOK() false#endif#ifndef SLEEP_KERNEL_HOOK#define SLEEP_KERNEL_HOOK(ticks) false#endif
const char __main_thread_name_str[] = "main";
/* Array indexing is more efficient in inlines if the elements are a native word size (100s of bytes fewer instructions) */
#if NUM_CORES > 1static struct core_entry __core_entries[NUM_CORES] IBSS_ATTR;struct core_entry *__cores[NUM_CORES] IBSS_ATTR;#elsestruct core_entry __cores[NUM_CORES] IBSS_ATTR;#endif
static struct thread_entry __thread_entries[MAXTHREADS] IBSS_ATTR;struct thread_entry *__threads[MAXTHREADS] IBSS_ATTR;
/** Internal functions **/
/*--------------------------------------------------------------------------- * Find an empty thread slot or NULL if none found. The slot returned will * be locked on multicore. *--------------------------------------------------------------------------- */static struct threadalloc{ threadbit_t avail;#if NUM_CORES > 1 struct corelock cl;#endif} threadalloc SHAREDBSS_ATTR;
/*--------------------------------------------------------------------------- * Initialize the thread allocator *--------------------------------------------------------------------------- */void thread_alloc_init(void){ corelock_init(&threadalloc.cl);
for (unsigned int core = 0; core < NUM_CORES; core++) { #if NUM_CORES > 1 struct core_entry *c = &__core_entries[core]; __cores[core] = c; #else struct core_entry *c = &__cores[core]; #endif rtr_queue_init(&c->rtr); corelock_init(&c->rtr_cl); tmo_queue_init(&c->tmo); c->next_tmo_check = current_tick; /* Something not in the past */ }
for (unsigned int slotnum = 0; slotnum < MAXTHREADS; slotnum++) { struct thread_entry *t = &__thread_entries[slotnum]; __threads[slotnum] = t; corelock_init(&t->waiter_cl); corelock_init(&t->slot_cl); t->id = THREAD_ID_INIT(slotnum); threadbit_set_bit(&threadalloc.avail, slotnum); }}
/*--------------------------------------------------------------------------- * Allocate a thread alot *--------------------------------------------------------------------------- */struct thread_entry * thread_alloc(void){ struct thread_entry *thread = NULL;
corelock_lock(&threadalloc.cl);
unsigned int slotnum = threadbit_ffs(&threadalloc.avail); if (slotnum < MAXTHREADS) { threadbit_clear_bit(&threadalloc.avail, slotnum); thread = __threads[slotnum]; }
corelock_unlock(&threadalloc.cl);
return thread;}
/*--------------------------------------------------------------------------- * Free the thread slot of 'thread' *--------------------------------------------------------------------------- */void thread_free(struct thread_entry *thread){ corelock_lock(&threadalloc.cl); threadbit_set_bit(&threadalloc.avail, THREAD_ID_SLOT(thread->id)); corelock_unlock(&threadalloc.cl);}
/*--------------------------------------------------------------------------- * Assign the thread slot a new ID. Version is 0x00000100..0xffffff00. *--------------------------------------------------------------------------- */void new_thread_id(struct thread_entry *thread){ uint32_t id = thread->id + (1u << THREAD_ID_VERSION_SHIFT);
/* If wrapped to 0, make it 1 */ if ((id & THREAD_ID_VERSION_MASK) == 0) id |= (1u << THREAD_ID_VERSION_SHIFT);
thread->id = id;}
/*--------------------------------------------------------------------------- * Wakeup an entire queue of threads - returns bitwise-or of return bitmask * from each operation or THREAD_NONE of nothing was awakened. *--------------------------------------------------------------------------- */unsigned int wait_queue_wake(struct __wait_queue *wqp){ unsigned result = THREAD_NONE; struct thread_entry *thread;
while ((thread = WQ_THREAD_FIRST(wqp))) result |= wakeup_thread(thread, WAKEUP_DEFAULT);
return result;}
/** Public functions **/
#ifdef RB_PROFILEvoid profile_thread(void){ profstart(THREAD_ID_SLOT(__running_self_entry()->id));}#endif
/*--------------------------------------------------------------------------- * Return the thread id of the calling thread * -------------------------------------------------------------------------- */unsigned int thread_self(void){ return __running_self_entry()->id;}
/*--------------------------------------------------------------------------- * Suspends a thread's execution for at least the specified number of ticks. * * May result in CPU core entering wait-for-interrupt mode if no other thread * may be scheduled. * * NOTE: sleep(0) sleeps until the end of the current tick * sleep(n) that doesn't result in rescheduling: * n <= ticks suspended < n + 1 * n to n+1 is a lower bound. Other factors may affect the actual time * a thread is suspended before it runs again. *--------------------------------------------------------------------------- */unsigned sleep(unsigned ticks){ /* In certain situations, certain bootloaders in particular, a normal * threading call is inappropriate. */ if (SLEEP_KERNEL_HOOK(ticks)) return 0; /* Handled */
disable_irq(); sleep_thread(ticks); switch_thread(); return 0;}
/*--------------------------------------------------------------------------- * Elects another thread to run or, if no other thread may be made ready to * run, immediately returns control back to the calling thread. *--------------------------------------------------------------------------- */void yield(void){ /* In certain situations, certain bootloaders in particular, a normal * threading call is inappropriate. */ if (YIELD_KERNEL_HOOK()) return; /* Handled */
switch_thread();}
/** Debug screen stuff **/
void format_thread_name(char *buf, size_t bufsize, const struct thread_entry *thread){ const char *name = thread->name; if (!name) name = "";
const char *fmt = *name ? "%s" : "%s%08lX"; snprintf(buf, bufsize, fmt, name, thread->id);}
#if !defined(HAVE_SDL_THREADS) && !defined(HAVE_POSIX_THREADS) && \ !(CONFIG_PLATFORM & PLATFORM_GAME_CONSOLE)/*--------------------------------------------------------------------------- * Returns the maximum percentage of the stack ever used during runtime. *--------------------------------------------------------------------------- */static unsigned int stack_usage(uintptr_t *stackptr, size_t stack_size){ unsigned int usage = 0; unsigned int stack_words = stack_size / sizeof (uintptr_t);
for (unsigned int i = 0; i < stack_words; i++) { if (stackptr[i] != DEADBEEF) { usage = (stack_words - i) * 100 / stack_words; break; } }
return usage;}#endif /* !HAVE_SDL_THREADS && !HAVE_POSIX_THREADS && !PLATFORM_GAME_CONSOLE */
#if NUM_CORES > 1int core_get_debug_info(unsigned int core, struct core_debug_info *infop){ extern uintptr_t * const idle_stacks[NUM_CORES];
if (core >= NUM_CORES || !infop) return -1;
infop->idle_stack_usage = stack_usage(idle_stacks[core], IDLE_STACK_SIZE); return 1;}#endif /* NUM_CORES > 1 */
int thread_get_debug_info(unsigned int thread_id, struct thread_debug_info *infop){ static const char status_chars[THREAD_NUM_STATES+1] = { [0 ... THREAD_NUM_STATES] = '?', [STATE_RUNNING] = 'R', [STATE_BLOCKED] = 'B', [STATE_SLEEPING] = 'S', [STATE_BLOCKED_W_TMO] = 'T', [STATE_FROZEN] = 'F', [STATE_KILLED] = 'K', };
if (!infop) return -1;
unsigned int slotnum = THREAD_ID_SLOT(thread_id); if (slotnum >= MAXTHREADS) return -1;
struct thread_entry *thread = __thread_slot_entry(slotnum);
int oldlevel = disable_irq_save(); corelock_lock(&threadalloc.cl); corelock_lock(&thread->slot_cl);
unsigned int state = thread->state;
int ret = 0;
if (threadbit_test_bit(&threadalloc.avail, slotnum) == 0) { bool cpu_boost = false;#ifdef HAVE_SCHEDULER_BOOSTCTRL cpu_boost = thread->cpu_boost;#endif#if !defined(HAVE_SDL_THREADS) && !defined(HAVE_POSIX_THREADS) && \ !(CONFIG_PLATFORM & PLATFORM_GAME_CONSOLE) infop->stack_usage = stack_usage(thread->stack, thread->stack_size);
size_t stack_used_current = thread->stack_size - (thread->context.sp - (uintptr_t)thread->stack);
/* Hosted implementations typically have the main stack managed by the OS, so we create a fake entry with 0 length */ infop->stack_usage_cur = thread->stack_size ? stack_used_current * 100 / thread->stack_size : 0;#endif#if NUM_CORES > 1 infop->core = thread->core;#endif#ifdef HAVE_PRIORITY_SCHEDULING infop->base_priority = thread->base_priority; infop->current_priority = thread->priority;#endif
snprintf(infop->statusstr, sizeof (infop->statusstr), "%c%c", cpu_boost ? '+' : (state == STATE_RUNNING ? '*' : ' '), status_chars[state]);
format_thread_name(infop->name, sizeof (infop->name), thread); ret = 1; }
corelock_unlock(&thread->slot_cl); corelock_unlock(&threadalloc.cl); restore_irq(oldlevel);
return ret;}