summaryrefslogtreecommitdiff
path: root/uisimulator/sdl/kernel-sdl.c
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2008-03-25 02:34:12 +0000
committerMichael Sevakis <jethead71@rockbox.org>2008-03-25 02:34:12 +0000
commit27cf67733936abd75fcb1f8da765977cd75906ee (patch)
treef894211a8a0c77b402dd3250b2bee2d17dcfe13f /uisimulator/sdl/kernel-sdl.c
parentbc2f8fd8f38a3e010cd67bbac358f6e9991153c6 (diff)
Add a complete priority inheritance implementation to the scheduler (all mutex ownership and queue_send calls are inheritable). Priorities are differential so that dispatch depends on the runnable range of priorities. Codec priority can therefore be raised in small steps (pcmbuf updated to enable). Simplify the kernel functions to ease implementation and use the same kernel.c for both sim and target (I'm tired of maintaining two ;_). 1) Not sure if a minor audio break at first buffering issue will exist on large-sector disks (the main mutex speed issue was genuinely resolved earlier). At this point it's best dealt with at the buffering level. It seems a larger filechunk could be used again. 2) Perhaps 64-bit sims will have some minor issues (finicky) but a backroll of the code of concern there is a 5-minute job. All kernel objects become incompatible so a full rebuild and update is needed.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16791 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'uisimulator/sdl/kernel-sdl.c')
-rw-r--r--uisimulator/sdl/kernel-sdl.c168
1 files changed, 168 insertions, 0 deletions
diff --git a/uisimulator/sdl/kernel-sdl.c b/uisimulator/sdl/kernel-sdl.c
new file mode 100644
index 0000000000..b6e6a34551
--- /dev/null
+++ b/uisimulator/sdl/kernel-sdl.c
@@ -0,0 +1,168 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2002 by Felix Arends
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdlib.h>
+#include <SDL.h>
+#include <SDL_thread.h>
+#include "memory.h"
+#include "system-sdl.h"
+#include "uisdl.h"
+#include "kernel.h"
+#include "thread-sdl.h"
+#include "thread.h"
+#include "debug.h"
+
+static SDL_TimerID tick_timer_id;
+long start_tick;
+
+/* Condition to signal that "interrupts" may proceed */
+static SDL_cond *sim_thread_cond;
+/* Mutex to serialize changing levels and exclude other threads while
+ * inside a handler */
+static SDL_mutex *sim_irq_mtx;
+static int interrupt_level = HIGHEST_IRQ_LEVEL;
+static int handlers_pending = 0;
+static int status_reg = 0;
+
+extern void (*tick_funcs[MAX_NUM_TICK_TASKS])(void);
+
+/* Nescessary logic:
+ * 1) All threads must pass unblocked
+ * 2) Current handler must always pass unblocked
+ * 3) Threads must be excluded when irq routine is running
+ * 4) No more than one handler routine should execute at a time
+ */
+int set_irq_level(int level)
+{
+ SDL_LockMutex(sim_irq_mtx);
+
+ int oldlevel = interrupt_level;
+
+ if (status_reg == 0 && level == 0 && oldlevel != 0)
+ {
+ /* Not in a handler and "interrupts" are being reenabled */
+ if (handlers_pending > 0)
+ SDL_CondSignal(sim_thread_cond);
+ }
+
+ interrupt_level = level; /* save new level */
+
+ SDL_UnlockMutex(sim_irq_mtx);
+ return oldlevel;
+}
+
+void sim_enter_irq_handler(void)
+{
+ SDL_LockMutex(sim_irq_mtx);
+ handlers_pending++;
+
+ if(interrupt_level != 0)
+ {
+ /* "Interrupts" are disabled. Wait for reenable */
+ SDL_CondWait(sim_thread_cond, sim_irq_mtx);
+ }
+
+ status_reg = 1;
+}
+
+void sim_exit_irq_handler(void)
+{
+ if (--handlers_pending > 0)
+ SDL_CondSignal(sim_thread_cond);
+
+ status_reg = 0;
+ SDL_UnlockMutex(sim_irq_mtx);
+}
+
+bool sim_kernel_init(void)
+{
+ sim_irq_mtx = SDL_CreateMutex();
+ if (sim_irq_mtx == NULL)
+ {
+ fprintf(stderr, "Cannot create sim_handler_mtx\n");
+ return false;
+ }
+
+ sim_thread_cond = SDL_CreateCond();
+ if (sim_thread_cond == NULL)
+ {
+ fprintf(stderr, "Cannot create sim_thread_cond\n");
+ return false;
+ }
+
+ return true;
+}
+
+void sim_kernel_shutdown(void)
+{
+ SDL_RemoveTimer(tick_timer_id);
+ SDL_DestroyMutex(sim_irq_mtx);
+ SDL_DestroyCond(sim_thread_cond);
+}
+
+Uint32 tick_timer(Uint32 interval, void *param)
+{
+ long new_tick;
+
+ (void) interval;
+ (void) param;
+
+ new_tick = (SDL_GetTicks() - start_tick) / (1000/HZ);
+
+ if(new_tick != current_tick)
+ {
+ long t;
+ for(t = new_tick - current_tick; t > 0; t--)
+ {
+ int i;
+
+ sim_enter_irq_handler();
+
+ /* Run through the list of tick tasks */
+ for(i = 0;i < MAX_NUM_TICK_TASKS;i++)
+ {
+ if(tick_funcs[i])
+ {
+ tick_funcs[i]();
+ }
+ }
+
+ sim_exit_irq_handler();
+ }
+
+ current_tick = new_tick;
+ }
+
+ return 1;
+}
+
+void tick_start(unsigned int interval_in_ms)
+{
+ if (tick_timer_id != NULL)
+ {
+ SDL_RemoveTimer(tick_timer_id);
+ tick_timer_id = NULL;
+ }
+ else
+ {
+ start_tick = SDL_GetTicks();
+ }
+
+ tick_timer_id = SDL_AddTimer(interval_in_ms, tick_timer, NULL);
+}