Index: apps/codecs.h
===================================================================
RCS file: /cvsroot/rockbox/apps/codecs.h,v
retrieving revision 1.37
diff -u -3 -p -r1.37 codecs.h
--- apps/codecs.h	28 Aug 2006 22:38:37 -0000	1.37
+++ apps/codecs.h	3 Sep 2006 16:47:26 -0000
@@ -193,10 +193,10 @@ struct codec_api {
     /* kernel/ system */
     void (*PREFIX(sleep))(int ticks);
     void (*yield)(void);
-    long* current_tick;
+    volatile long* current_tick;
     long (*default_event_handler)(long event);
     long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter);
-    int (*create_thread)(void (*function)(void), void* stack, int stack_size, const char *name);
+    int (*create_thread)(void (*function)(void), void* stack, int stack_size, const char *name, int priority);
     void (*remove_thread)(int threadnum);
     void (*reset_poweroff_timer)(void);
 #ifndef SIMULATOR
Index: apps/debug_menu.c
===================================================================
RCS file: /cvsroot/rockbox/apps/debug_menu.c,v
retrieving revision 1.206
diff -u -3 -p -r1.206 debug_menu.c
--- apps/debug_menu.c	2 Sep 2006 08:14:52 -0000	1.206
+++ apps/debug_menu.c	3 Sep 2006 16:47:27 -0000
@@ -87,6 +87,7 @@ bool dbg_os(void)
     char buf[32];
     int i;
     int usage;
+    bool status;
 #if NUM_CORES > 1
     unsigned int core;
     int line;
@@ -98,6 +99,10 @@ bool dbg_os(void)
 
     while(1)
     {
+#if 0 /* Enable to simulate UI lag. */
+        int _x;
+        for (_x = 0; _x < 1000000L; _x++) ;
+#endif
 #if NUM_CORES > 1
         lcd_puts(0, 0, "Core and stack usage:");
         line = 0;
@@ -106,7 +111,10 @@ bool dbg_os(void)
             for(i = 0; i < num_threads[core]; i++)
             {
                 usage = thread_stack_usage_on_core(core, i);
-                snprintf(buf, 32, "(%d) %s: %d%%", core, thread_name[core][i], usage);
+                status = thread_is_running_on_core(core, i);
+                snprintf(buf, 32, "(%d) %s %d %s: %d%%", core, 
+                         status ? "*" : " ", cores[CURRENT_CORE].threads[i].priority,
+                         thread_name[core][i], usage);
                 lcd_puts(0, ++line, buf);
             }
         }
@@ -115,7 +123,11 @@ bool dbg_os(void)
         for(i = 0; i < cores[CURRENT_CORE].num_threads;i++)
         {
             usage = thread_stack_usage(i);
-            snprintf(buf, 32, "%s: %d%%", cores[CURRENT_CORE].threads[i].name, usage);
+            status = thread_is_running(i);
+            
+            snprintf(buf, 32, "%s %d %s: %d%%", 
+                     status ? "*" : " ", cores[CURRENT_CORE].threads[i].priority,
+                     cores[CURRENT_CORE].threads[i].name, usage);
             lcd_puts(0, 1+i, buf);
         }
 #endif
Index: apps/pcmbuf.c
===================================================================
RCS file: /cvsroot/rockbox/apps/pcmbuf.c,v
retrieving revision 1.60
diff -u -3 -p -r1.60 pcmbuf.c
--- apps/pcmbuf.c	13 Aug 2006 09:19:24 -0000	1.60
+++ apps/pcmbuf.c	3 Sep 2006 16:47:27 -0000
@@ -35,6 +35,7 @@
 #include "settings.h"
 #include "audio.h"
 #include "dsp.h"
+#include "thread.h"
 
 /* 1.5s low mark */
 #define PCMBUF_WATERMARK     (NATIVE_FREQUENCY * 6)
@@ -94,6 +95,8 @@ static size_t pcmbuf_mix_sample IDATA_AT
 static bool low_latency_mode = false;
 static bool pcmbuf_flush;
 
+extern int codec_thread_id;
+
 /* Helpful macros for use in conditionals this assumes some of the above
  * static variable names */
 #define NEED_FLUSH(position) \
@@ -109,14 +112,37 @@ static bool pcmbuf_flush_fillpos(void);
 void pcmbuf_boost(bool state)
 {
     static bool boost_state = false;
-
+#ifdef HAVE_PRIORITY_SCHEDULING
+    static bool priority_modified = false;
+#endif
+    
     if (crossfade_init || crossfade_active)
         return;
 
-    if (state != boost_state) {
+    if (state != boost_state)
+    {
         cpu_boost(state);
         boost_state = state;
     }
+    
+#ifdef HAVE_PRIORITY_SCHEDULING
+    if (state && LOW_DATA(3))
+    {
+        if (!priority_modified)
+        {
+            /* Buffer is critically low so override UI priority. */
+            priority_modified = true;
+            thread_set_priority(codec_thread_id, PRIORITY_REALTIME);
+        }
+    }
+    else
+    {
+        /* Set back the original priority. */
+        thread_set_priority(codec_thread_id, PRIORITY_PLAYBACK);
+        priority_modified = false;
+    }
+    
+#endif
 }
 #endif
 
@@ -244,7 +270,9 @@ static void pcmbuf_under_watermark(void)
     pcmbuf_boost(true);
     /* Disable crossfade if < .5s of audio */
     if (LOW_DATA(2))
+    {
         crossfade_active = false;
+    }
 }
 
 void pcmbuf_set_event_handler(void (*event_handler)(void))
Index: apps/playback.c
===================================================================
RCS file: /cvsroot/rockbox/apps/playback.c,v
retrieving revision 1.349
diff -u -3 -p -r1.349 playback.c
--- apps/playback.c	1 Sep 2006 07:59:31 -0000	1.349
+++ apps/playback.c	3 Sep 2006 16:47:27 -0000
@@ -267,6 +267,7 @@ static struct event_queue codec_queue;
 static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
 IBSS_ATTR;
 static const char codec_thread_name[] = "codec";
+int codec_thread_id; /* For modifying thread priority later. */
 
 /* Voice thread */
 static struct event_queue voice_queue;
@@ -634,7 +635,7 @@ void audio_preinit(void)
     queue_clear(&codec_callback_queue);
 
     create_thread(audio_thread, audio_stack, sizeof(audio_stack),
-                  audio_thread_name);
+                  audio_thread_name, PRIORITY_BUFFERING);
 }
 
 void audio_init(void)
@@ -665,7 +666,7 @@ void voice_init(void)
     logf("Starting voice codec");
     queue_init(&voice_queue);
     voice_thread_num = create_thread(voice_thread, voice_stack,
-            sizeof(voice_stack), voice_thread_name);
+            sizeof(voice_stack), voice_thread_name, PRIORITY_PLAYBACK);
     
     while (!voice_codec_loaded)
         yield();
@@ -1982,13 +1983,15 @@ static bool audio_yield_codecs(void)
 {
     yield();
     
-    if (!queue_empty(&audio_queue)) return true;
+    if (!queue_empty(&audio_queue)) 
+        return true;
 
     while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata())
             && !ci.stop_codec && playing && !audio_filebuf_is_lowdata())
     {
         sleep(1);
-        if (!queue_empty(&audio_queue)) return true;
+        if (!queue_empty(&audio_queue)) 
+            return true;
     }
     
     return false;
@@ -3178,8 +3181,9 @@ static void audio_playback_init(void)
     id3_voice.frequency = 11200;
     id3_voice.length = 1000000L;
 
-    create_thread(codec_thread, codec_stack, sizeof(codec_stack),
-            codec_thread_name);
+    codec_thread_id = create_thread(codec_thread, codec_stack, 
+                                    sizeof(codec_stack),
+                                    codec_thread_name, PRIORITY_PLAYBACK);
 
     while (1)
     {
@@ -3213,7 +3217,8 @@ static void audio_thread(void)
     /* At first initialize audio system in background. */
     audio_playback_init();
 
-    while (1) {
+    while (1) 
+    {
         if (filling)
         {
             queue_wait_w_tmo(&audio_queue, &ev, 0);
@@ -3221,7 +3226,7 @@ static void audio_thread(void)
                 ev.id = Q_AUDIO_FILL_BUFFER;
         }
         else
-            queue_wait_w_tmo(&audio_queue, &ev, HZ);
+            queue_wait_w_tmo(&audio_queue, &ev, HZ/2);
 
         switch (ev.id) {
             case Q_AUDIO_FILL_BUFFER:
Index: apps/playlist.c
===================================================================
RCS file: /cvsroot/rockbox/apps/playlist.c,v
retrieving revision 1.167
diff -u -3 -p -r1.167 playlist.c
--- apps/playlist.c	15 Aug 2006 12:27:04 -0000	1.167
+++ apps/playlist.c	3 Sep 2006 16:47:27 -0000
@@ -1764,7 +1764,7 @@ void playlist_init(void)
     memset(playlist->filenames, 0,
            playlist->max_playlist_size * sizeof(int));
     create_thread(playlist_thread, playlist_stack, sizeof(playlist_stack),
-                  playlist_thread_name);
+                  playlist_thread_name, PRIORITY_BACKGROUND);
     queue_init(&playlist_queue);
 #endif
 }
Index: apps/plugin.h
===================================================================
RCS file: /cvsroot/rockbox/apps/plugin.h,v
retrieving revision 1.192
diff -u -3 -p -r1.192 plugin.h
--- apps/plugin.h	16 Aug 2006 00:32:45 -0000	1.192
+++ apps/plugin.h	3 Sep 2006 16:47:27 -0000
@@ -105,7 +105,7 @@
 #define PLUGIN_MAGIC 0x526F634B /* RocK */
 
 /* increase this every time the api struct changes */
-#define PLUGIN_API_VERSION 29
+#define PLUGIN_API_VERSION 30
 
 /* update this to latest version if a change to the api struct breaks
    backwards compatibility (and please take the opportunity to sort in any
@@ -267,10 +267,10 @@ struct plugin_api {
     /* kernel/ system */
     void (*PREFIX(sleep))(int ticks);
     void (*yield)(void);
-    long* current_tick;
+    volatile long* current_tick;
     long (*default_event_handler)(long event);
     long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter);
-    int (*create_thread)(void (*function)(void), void* stack, int stack_size, const char *name);
+    int (*create_thread)(void (*function)(void), void* stack, int stack_size, const char *name, int priority);
     void (*remove_thread)(int threadnum);
     void (*reset_poweroff_timer)(void);
 #ifndef SIMULATOR
Index: apps/tagcache.c
===================================================================
RCS file: /cvsroot/rockbox/apps/tagcache.c,v
retrieving revision 1.61
diff -u -3 -p -r1.61 tagcache.c
--- apps/tagcache.c	30 Aug 2006 18:18:36 -0000	1.61
+++ apps/tagcache.c	3 Sep 2006 16:47:27 -0000
@@ -1062,7 +1062,6 @@ static bool get_next(struct tagcache_sea
     
     if (tagcache_is_numeric_tag(tcs->type))
     {
-        logf("r:%d", tcs->position);
         snprintf(buf, sizeof(buf), "%d", tcs->position);
         tcs->result_seek = tcs->position;
         tcs->result = buf;
@@ -3614,7 +3613,7 @@ void tagcache_init(void)
     
     queue_init(&tagcache_queue);
     create_thread(tagcache_thread, tagcache_stack,
-                  sizeof(tagcache_stack), tagcache_thread_name);
+                  sizeof(tagcache_stack), tagcache_thread_name, PRIORITY_BACKGROUND);
 }
 
 bool tagcache_is_initialized(void)
Index: apps/tree.c
===================================================================
RCS file: /cvsroot/rockbox/apps/tree.c,v
retrieving revision 1.439
diff -u -3 -p -r1.439 tree.c
--- apps/tree.c	1 Sep 2006 02:27:12 -0000	1.439
+++ apps/tree.c	3 Sep 2006 16:47:27 -0000
@@ -619,7 +619,7 @@ static bool dirbrowse(void)
 #endif
         button = get_action(CONTEXT_TREE,HZ/5);
         need_update = gui_synclist_do_button(&tree_lists, button);
-
+        
         switch ( button ) {
             case ACTION_STD_OK:
                 /* nothing to do if no files to display */
Index: apps/plugins/alpine_cdc.c
===================================================================
RCS file: /cvsroot/rockbox/apps/plugins/alpine_cdc.c,v
retrieving revision 1.11
diff -u -3 -p -r1.11 alpine_cdc.c
--- apps/plugins/alpine_cdc.c	2 Apr 2006 12:45:25 -0000	1.11
+++ apps/plugins/alpine_cdc.c	3 Sep 2006 16:47:27 -0000
@@ -1169,7 +1169,7 @@ int main(void* parameter)
 
     rb->memset(&gTread, 0, sizeof(gTread));
     gTread.foreground = true;
-    gTread.id = rb->create_thread(thread, stack, stacksize, "CDC");
+    gTread.id = rb->create_thread(thread, stack, stacksize, "CDC", PRIORITY_BACKGROUND);
 
 #ifdef DEBUG
     do
Index: apps/plugins/battery_bench.c
===================================================================
RCS file: /cvsroot/rockbox/apps/plugins/battery_bench.c,v
retrieving revision 1.11
diff -u -3 -p -r1.11 battery_bench.c
--- apps/plugins/battery_bench.c	20 Aug 2006 23:05:47 -0000	1.11
+++ apps/plugins/battery_bench.c	3 Sep 2006 16:47:27 -0000
@@ -457,7 +457,7 @@ int main(void)
     rb->queue_init(&thread_q); /* put the thread's queue in the bcast list */
     rb->memset(&s_thread, 0, sizeof(s_thread)); /* zero the struct */
     if((s_thread.id = rb->create_thread(thread, thread_stack,
-        sizeof(thread_stack), "Battery Benchmark"))<0)
+        sizeof(thread_stack), "Battery Benchmark", 9))<0)
     {
         rb->splash(HZ,true,"Cannot create thread!");
         return PLUGIN_ERROR;
Index: firmware/backlight.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/backlight.c,v
retrieving revision 1.99
diff -u -3 -p -r1.99 backlight.c
--- firmware/backlight.c	1 Sep 2006 22:03:14 -0000	1.99
+++ firmware/backlight.c	3 Sep 2006 16:47:27 -0000
@@ -600,7 +600,7 @@ void backlight_init(void)
     backlight_thread_id =
 #endif
     create_thread(backlight_thread, backlight_stack,
-                  sizeof(backlight_stack), backlight_thread_name);
+                  sizeof(backlight_stack), backlight_thread_name, PRIORITY_SYSTEM);
     tick_add_task(backlight_tick);
 #ifdef SIMULATOR
     /* do nothing */
Index: firmware/kernel.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/kernel.c,v
retrieving revision 1.58
diff -u -3 -p -r1.58 kernel.c
--- firmware/kernel.c	1 Sep 2006 06:13:33 -0000	1.58
+++ firmware/kernel.c	3 Sep 2006 16:47:27 -0000
@@ -26,7 +26,7 @@
 #include "panic.h"
 
 #if ((CONFIG_CPU != PP5020) && (CONFIG_CPU != PP5002)) || !defined(BOOTLOADER) 
-long current_tick = 0;
+volatile long current_tick = 0;
 #endif
 
 static void (*tick_funcs[MAX_NUM_TICK_TASKS])(void);
@@ -71,13 +71,7 @@ void sleep(int ticks)
     } while(counter > 0);
 
 #else
-    /* Always sleep at least 1 tick */
-    int timeout = current_tick + ticks + 1;
-
-    while (TIME_BEFORE( current_tick, timeout )) {
-        sleep_thread();
-    }
-    wake_up_thread();
+    sleep_thread(ticks);
 #endif
 }
 
@@ -86,8 +80,7 @@ void yield(void)
 #if (CONFIG_CPU == S3C2440 || defined(ELIO_TPJ1022) && defined(BOOTLOADER))
     /* Some targets don't like yielding in the bootloader */
 #else
-    switch_thread();
-    wake_up_thread();
+    switch_thread(true);
 #endif
 }
 
@@ -134,9 +127,8 @@ void queue_wait(struct event_queue *q, s
 {
     while(q->read == q->write)
     {
-        sleep_thread();
+        sleep_thread(1);
     }
-    wake_up_thread();
 
     *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK];
 }
@@ -147,9 +139,8 @@ void queue_wait_w_tmo(struct event_queue
 
     while(q->read == q->write && TIME_BEFORE( current_tick, timeout ))
     {
-        sleep_thread();
+        sleep_thread(1);
     }
-    wake_up_thread();
 
     if(q->read != q->write)
     {
@@ -250,7 +241,6 @@ void IMIA0(void)
     }
 
     current_tick++;
-    wake_up_thread();
 
     TSR0 &= ~0x01;
 }
@@ -301,7 +291,6 @@ void TIMER0(void)
     }
 
     current_tick++;
-    wake_up_thread();
 
     TER0 = 0xff; /* Clear all events */
 }
@@ -330,7 +319,6 @@ void TIMER0(void)
     }
 
     current_tick++;
-    wake_up_thread();
 
     /* re-enable timer by clearing the counter */
     TACON |= 0x80;
@@ -382,7 +370,6 @@ void TIMER1(void)
     }
 
     current_tick++;
-    wake_up_thread();
 }
 #endif
 
@@ -415,7 +402,6 @@ void timer_handler(void)
     }
 
     current_tick++;
-    wake_up_thread();
 
     TIMERR0C = 1;
 }
@@ -519,8 +505,7 @@ void mutex_lock(struct mutex *m)
 {
     /* Wait until the lock is open... */
     while(m->locked)
-        sleep_thread();
-    wake_up_thread();
+        sleep_thread(1);
 
     /* ...and lock it */
     m->locked = true;
Index: firmware/mpeg.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/mpeg.c,v
retrieving revision 1.360
diff -u -3 -p -r1.360 mpeg.c
--- firmware/mpeg.c	28 Aug 2006 22:38:40 -0000	1.360
+++ firmware/mpeg.c	3 Sep 2006 16:47:27 -0000
@@ -761,7 +761,6 @@ void rec_tick(void)
             {
                 prerecord_timeout = current_tick + HZ;
                 queue_post(&mpeg_queue, MPEG_PRERECORDING_TICK, 0);
-                wake_up_thread();
             }
         }
         else
@@ -773,7 +772,6 @@ void rec_tick(void)
             {
                 saving_status = BUFFER_FULL;
                 queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
-                wake_up_thread();
             }
         }
     }
@@ -894,8 +892,6 @@ static void transfer_end(unsigned char**
             *psize = 0; /* no more transfer */
         }
     }
-
-    wake_up_thread();
 }
 
 static struct trackdata *add_track_to_tag_list(const char *filename)
@@ -2119,8 +2115,7 @@ void audio_init_playback(void)
     queue_post(&mpeg_queue, MPEG_INIT_PLAYBACK, NULL);
 
     while(!init_playback_done)
-        sleep_thread();
-    wake_up_thread();
+        sleep_thread(1);
 }
 
 
@@ -2134,8 +2129,7 @@ void audio_init_recording(unsigned int b
     queue_post(&mpeg_queue, MPEG_INIT_RECORDING, NULL);
 
     while(!init_recording_done)
-        sleep_thread();
-    wake_up_thread();
+        sleep_thread(1);
 }
 
 static void init_recording(void)
@@ -2889,7 +2883,7 @@ void audio_init(void)
     queue_init(&mpeg_queue);
 #endif /* !SIMULATOR */
     create_thread(mpeg_thread, mpeg_stack,
-                  sizeof(mpeg_stack), mpeg_thread_name);
+                  sizeof(mpeg_stack), mpeg_thread_name, PRIORITY_SYSTEM);
 
     memset(trackdata, sizeof(trackdata), 0);
 
Index: firmware/pcm_record.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/pcm_record.c,v
retrieving revision 1.30
diff -u -3 -p -r1.30 pcm_record.c
--- firmware/pcm_record.c	2 Sep 2006 17:30:30 -0000	1.30
+++ firmware/pcm_record.c	3 Sep 2006 16:47:27 -0000
@@ -174,7 +174,7 @@ void pcm_rec_init(void)
 {
     queue_init(&pcmrec_queue);
     create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack),
-        pcmrec_thread_name);
+                  pcmrec_thread_name, PRIORITY_RECORDING);
 }
 
 
@@ -196,8 +196,7 @@ void audio_init_recording(unsigned int b
     queue_post(&pcmrec_queue, PCMREC_INIT, 0);
     
     while(!init_done)
-        sleep_thread();
-    wake_up_thread();
+        sleep_thread(1);
 }
 
 void audio_close_recording(void)
@@ -206,8 +205,7 @@ void audio_close_recording(void)
     queue_post(&pcmrec_queue, PCMREC_CLOSE, 0);
     
     while(!close_done)
-        sleep_thread();
-    wake_up_thread();
+        sleep_thread(1);
 
     audio_remove_encoder();
 }
@@ -421,8 +419,7 @@ void audio_record(const char *filename)
     queue_post(&pcmrec_queue, PCMREC_START, 0);
     
     while(!record_done)
-        sleep_thread();
-    wake_up_thread();    
+        sleep_thread(1);
 }
 
 
@@ -438,8 +435,7 @@ void audio_new_file(const char *filename
     queue_post(&pcmrec_queue, PCMREC_NEW_FILE, 0);
     
     while(!new_file_done)
-        sleep_thread();
-    wake_up_thread();    
+        sleep_thread(1);
     
     logf("pcm_new_file done");
 }
@@ -459,8 +455,7 @@ void audio_stop_recording(void)
     queue_post(&pcmrec_queue, PCMREC_STOP, 0);
 
     while(!stop_done)
-        sleep_thread();
-    wake_up_thread();    
+        sleep_thread(1);
 
     logf("pcm_stop done");
 }
@@ -482,8 +477,7 @@ void audio_pause_recording(void)
     queue_post(&pcmrec_queue, PCMREC_PAUSE, 0);
 
     while(!pause_done)
-        sleep_thread();
-    wake_up_thread();    
+        sleep_thread(1);
 }
 
 void audio_resume_recording(void)
@@ -498,8 +492,7 @@ void audio_resume_recording(void)
     queue_post(&pcmrec_queue, PCMREC_RESUME, 0);
 
     while(!resume_done)
-        sleep_thread();
-    wake_up_thread();    
+        sleep_thread(1);
 }
 
 /* return peaks as int, so convert from short first
@@ -817,9 +810,8 @@ static void pcmrec_stop(void)
         /* wait for encoding finish */
         is_paused = true;
         while(!wav_queue_empty)
-            sleep_thread();
+            sleep_thread(1);
 
-        wake_up_thread();
         is_recording = false;
 
         /* Flush buffers to file */
Index: firmware/powermgmt.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/powermgmt.c,v
retrieving revision 1.120
diff -u -3 -p -r1.120 powermgmt.c
--- firmware/powermgmt.c	28 Aug 2006 22:54:20 -0000	1.120
+++ firmware/powermgmt.c	3 Sep 2006 16:47:27 -0000
@@ -992,7 +992,7 @@ void powermgmt_init(void)
     memset(power_history, 0x00, sizeof(power_history));
 
     create_thread(power_thread, power_stack, sizeof(power_stack),
-                  power_thread_name);
+                  power_thread_name, PRIORITY_SYSTEM);
 }
 
 #endif /* SIMULATOR */
Index: firmware/thread.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/thread.c,v
retrieving revision 1.63
diff -u -3 -p -r1.63 thread.c
--- firmware/thread.c	2 Sep 2006 07:56:52 -0000	1.63
+++ firmware/thread.c	3 Sep 2006 16:47:27 -0000
@@ -23,12 +23,15 @@
 #include "system.h"
 #include "kernel.h"
 #include "cpu.h"
-
+#include "string.h"
 
 #define DEADBEEF ((unsigned int)0xdeadbeef)
 /* Cast to the the machine int type, whose size could be < 4. */
 
 struct core_entry cores[NUM_CORES] IBSS_ATTR;
+#ifdef HAVE_PRIORITY_SCHEDULING
+static unsigned short highest_priority IBSS_ATTR;
+#endif
 
 static const char main_thread_name[] = "main";
 
@@ -48,7 +51,7 @@ int *cop_stackend = stackend;
 #endif
 #endif
 
-void switch_thread(void) ICODE_ATTR;
+void switch_thread(bool store_context) ICODE_ATTR;
 static inline void store_context(void* addr) __attribute__ ((always_inline));
 static inline void load_context(const void* addr) __attribute__ ((always_inline));
 
@@ -219,22 +222,87 @@ static inline void load_context(const vo
 
 #endif
 
-/*---------------------------------------------------------------------------
- * Switch thread in round robin fashion.
- *---------------------------------------------------------------------------
- */
-void switch_thread(void)
+static inline void add_to_list(struct thread_entry **list,
+                               struct thread_entry *thread)
 {
-#ifdef RB_PROFILE
-    profile_thread_stopped(cores[CURRENT_CORE].current_thread);
-#endif
-    int current;
-    unsigned int *stackptr;
+    if (*list == NULL)
+    {
+        thread->next = thread;
+        thread->prev = thread;
+        *list = thread;
+    }
+    else
+    {
+        thread->next = (*list)->next;
+        thread->prev = *list;
+        thread->next->prev = thread;
+        (*list)->next = thread;
+    }
+}
 
-#ifdef SIMULATOR
-    /* Do nothing */
-#else
-    while (cores[CURRENT_CORE].num_sleepers == cores[CURRENT_CORE].num_threads)
+static inline void remove_from_list(struct thread_entry **list,
+                                    struct thread_entry *thread)
+{
+    if (list != NULL)
+    {
+        if (thread == thread->next)
+        {
+            *list = NULL;
+            return;
+        }
+        
+        if (thread == *list)
+            *list = thread->next;
+    }
+    
+    thread->prev->next = thread->next;
+    thread->next->prev = thread->prev;
+}
+
+static inline int check_sleepers(void)
+{
+    struct thread_entry *current, *next;
+    int count = 0;
+    
+    /* Check sleeping threads. */
+    current = cores[CURRENT_CORE].sleeping;
+    if (current == NULL)
+        return 0;
+    
+    for (;;)
+    {
+        next = current->next;
+        
+        if (current_tick >= current->sleep_tick)
+        {
+            remove_from_list(&cores[CURRENT_CORE].sleeping, current);
+            add_to_list(&cores[CURRENT_CORE].running, current);
+#ifdef HAVE_PRIORITY_SCHEDULING
+            if (current->priority < highest_priority)
+                highest_priority = current->priority;
+#endif
+            if (cores[CURRENT_CORE].sleeping == NULL)
+                break;
+            
+            current = next;
+            continue;
+        }
+        
+        count++;
+        current = next;
+        
+        if (current == cores[CURRENT_CORE].sleeping)
+        {
+            break;
+        }
+    }
+    
+    return count;
+}
+
+static inline void sleep_core(void)
+{
+    while (check_sleepers() == cores[CURRENT_CORE].num_threads)
     {
         /* Enter sleep mode, woken up on interrupt */
 #ifdef CPU_COLDFIRE
@@ -257,49 +325,105 @@ void switch_thread(void)
         CLKCON |= 2;
 #endif
     }
+}
+
+/*---------------------------------------------------------------------------
+ * Switch thread in round robin fashion.
+ *---------------------------------------------------------------------------
+ */
+void switch_thread(bool save_context)
+{
+#ifdef RB_PROFILE
+    profile_thread_stopped(cores[CURRENT_CORE].current_thread);
 #endif
-    current = cores[CURRENT_CORE].current_thread;
-    store_context(&cores[CURRENT_CORE].threads[current].context);
+    unsigned int *stackptr;
+    struct thread_entry *old;
+    
+#ifdef SIMULATOR
+    /* Do nothing */
+#else
+    if (save_context)
+        store_context(&cores[CURRENT_CORE].running->context);
 
 #if CONFIG_CPU != TCC730
     /* Check if the current thread stack is overflown */
-    stackptr = cores[CURRENT_CORE].threads[current].stack;
+    stackptr = cores[CURRENT_CORE].running->stack;
     if(stackptr[0] != DEADBEEF)
-       panicf("Stkov %s", cores[CURRENT_CORE].threads[current].name);
+       panicf("Stkov %s", cores[CURRENT_CORE].running->name);
 #endif
 
-    if (++current >= cores[CURRENT_CORE].num_threads)
-        current = 0;
-
-    cores[CURRENT_CORE].current_thread = current;
-    load_context(&cores[CURRENT_CORE].threads[current].context);
+    if (cores[CURRENT_CORE].running->sleep_tick)
+    {
+        old = cores[CURRENT_CORE].running;
+        remove_from_list(&cores[CURRENT_CORE].running, old);
+        add_to_list(&cores[CURRENT_CORE].sleeping, old);
+#ifdef HAVE_PRIORITY_SCHEDULING
+        /* Reset priorities */
+        highest_priority = 100;
+        /*
+        if (old->priority == highest_priority && cores[CURRENT_CORE].running)
+        {
+            highest_priority = 100;
+            old = cores[CURRENT_CORE].running;
+            do {
+                if (old->priority < highest_priority)
+                    highest_priority = old->priority;
+                old = old->next;
+            } while (old != cores[CURRENT_CORE].running);
+        }
+        */
+#endif
+    }
+    else
+    {
+        /* Switch to the next running thread. */
+        cores[CURRENT_CORE].running = cores[CURRENT_CORE].running->next;
+    }
+    
+    sleep_core();
+    
+#ifdef HAVE_PRIORITY_SCHEDULING
+    for (;;)
+    {
+        int priority = cores[CURRENT_CORE].running->priority;
+        
+        if (priority < highest_priority)
+            highest_priority = priority;
+        
+        if (priority == highest_priority
+            || (current_tick - cores[CURRENT_CORE].running->last_run > priority * 10))
+        {
+            break;
+        }
+        cores[CURRENT_CORE].running = cores[CURRENT_CORE].running->next;
+    }
+    cores[CURRENT_CORE].running->last_run = current_tick;
+#endif
+    
+    cores[CURRENT_CORE].running->sleep_tick = 0;
+#endif
+    load_context(&cores[CURRENT_CORE].running->context);
 #ifdef RB_PROFILE
-    profile_thread_started(cores[CURRENT_CORE].current_thread);
+    profile_thread_started(cores[CURRENT_CORE].running);
 #endif
 }
 
-void sleep_thread(void)
+void sleep_thread(int ticks)
 {
-    ++cores[CURRENT_CORE].num_sleepers;
-    switch_thread();
+    cores[CURRENT_CORE].running->sleep_tick = current_tick + ticks + 1;
+    switch_thread(true);
 }
 
-void wake_up_thread(void)
-{
-    cores[CURRENT_CORE].num_sleepers = 0;
-}
-
-
 /*---------------------------------------------------------------------------
  * Create thread on the current core.
  * Return ID if context area could be allocated, else -1.
  *---------------------------------------------------------------------------
  */
 int create_thread(void (*function)(void), void* stack, int stack_size,
-                  const char *name)
+                  const char *name, int priority)
 {
     return create_thread_on_core(CURRENT_CORE, function, stack, stack_size,
-                  name);
+                  name, priority);
 }
 
 /*---------------------------------------------------------------------------
@@ -308,17 +432,29 @@ int create_thread(void (*function)(void)
  *---------------------------------------------------------------------------
  */
 int create_thread_on_core(unsigned int core, void (*function)(void), void* stack, int stack_size,
-                  const char *name)
+                  const char *name, int priority)
 {
     unsigned int i;
     unsigned int stacklen;
     unsigned int *stackptr;
+    int n;
     struct regs *regs;
     struct thread_entry *thread;
+    (void)priority;
 
     if (cores[core].num_threads >= MAXTHREADS)
         return -1;
 
+    for (n = 0; n < MAXTHREADS; n++)
+    {
+        if (cores[core].threads[n].name == NULL)
+            break;
+    }
+    
+    if (n == MAXTHREADS)
+        return -1;
+    
+    
     /* Munge the stack to make it easy to spot stack overflows */
     stacklen = stack_size / sizeof(int);
     stackptr = stack;
@@ -328,10 +464,17 @@ int create_thread_on_core(unsigned int c
     }
 
     /* Store interesting information */
-    thread = &cores[core].threads[cores[core].num_threads];
+    thread = &cores[core].threads[n];
     thread->name = name;
     thread->stack = stack;
     thread->stack_size = stack_size;
+    thread->sleep_tick = 0;
+#ifdef HAVE_PRIORITY_SCHEDULING
+    thread->priority = priority;
+    highest_priority = 100;
+#endif
+    add_to_list(&cores[core].running, thread);
+    
     regs = &thread->context;
 #if defined(CPU_COLDFIRE) || (CONFIG_CPU == SH7034) || defined(CPU_ARM)
     /* Align stack to an even 32 bit boundary */
@@ -343,8 +486,8 @@ int create_thread_on_core(unsigned int c
 #endif
     regs->start = (void*)function;
 
-    wake_up_thread();
-    return cores[core].num_threads++; /* return the current ID, e.g for remove_thread() */
+    cores[core].num_threads++;
+    return n;
 }
 
 /*---------------------------------------------------------------------------
@@ -364,32 +507,49 @@ void remove_thread(int threadnum)
  */
 void remove_thread_on_core(unsigned int core, int threadnum)
 {
-    int i;
-
-    if (threadnum >= cores[core].num_threads)
-       return;
-
+    if (threadnum >= MAXTHREADS)
+        return;
+    
     cores[core].num_threads--;
-    for (i=threadnum; i<cores[core].num_threads-1; i++)
-    {   /* move all entries which are behind */
-        cores[core].threads[i] = cores[core].threads[i+1];
+    if (&cores[core].threads[threadnum] == cores[core].running)
+    {
+        remove_from_list(&cores[core].running, cores[core].running);
+        switch_thread(false);
+        return ;
     }
+    
+    if (&cores[core].threads[threadnum] == cores[core].sleeping)
+        remove_from_list(&cores[core].sleeping, cores[core].sleeping);
+    
+    remove_from_list(NULL, &cores[core].threads[threadnum]);
+}
 
-    if (cores[core].current_thread == threadnum) /* deleting the current one? */
-        cores[core].current_thread = cores[core].num_threads; /* set beyond last, avoid store harm */
-    else if (cores[core].current_thread > threadnum) /* within the moved positions? */
-        cores[core].current_thread--; /* adjust it, point to same context again */
+#ifdef HAVE_PRIORITY_SCHEDULING
+void thread_set_priority(int threadnum, int priority)
+{
+    cores[CURRENT_CORE].threads[threadnum].priority = priority;
+    highest_priority = 100;
 }
+#endif
 
 void init_threads(void)
 {
     unsigned int core = CURRENT_CORE;
 
+    memset(cores, 0, sizeof cores);
     cores[core].num_threads = 1; /* We have 1 thread to begin with */
-    cores[core].current_thread = 0; /* The current thread is number 0 */
+    cores[core].sleeping = NULL;
+    cores[core].running = NULL;
     cores[core].threads[0].name = main_thread_name;
-/* In multiple core setups, each core has a different stack.  There is probably
-   a much better way to do this. */
+    cores[core].threads[0].sleep_tick = 0;
+#ifdef HAVE_PRIORITY_SCHEDULING
+    cores[core].threads[0].priority = PRIORITY_USER_INTERFACE;
+    highest_priority = 100;
+#endif
+    add_to_list(&cores[core].running, &cores[core].threads[0]);
+    
+    /* In multiple core setups, each core has a different stack.  There is probably
+     a much better way to do this. */
     if (core == CPU)
     {
         cores[CPU].threads[0].stack = stackbegin;
@@ -405,7 +565,6 @@ void init_threads(void)
 #else
     cores[core].threads[0].context.start = 0; /* thread 0 already running */
 #endif
-    cores[core].num_sleepers = 0;
 }
 
 int thread_stack_usage(int threadnum)
@@ -430,3 +589,13 @@ int thread_stack_usage_on_core(unsigned 
     return ((cores[core].threads[threadnum].stack_size - i * sizeof(int)) * 100) /
         cores[core].threads[threadnum].stack_size;
 }
+
+bool thread_is_running(int threadnum)
+{
+    return thread_is_running_on_core(CURRENT_CORE, threadnum);
+}
+
+bool thread_is_running_on_core(unsigned int core, int threadnum)
+{
+    return cores[core].threads[threadnum].sleep_tick == 0;
+}
Index: firmware/usb.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/usb.c,v
retrieving revision 1.93
diff -u -3 -p -r1.93 usb.c
--- firmware/usb.c	12 Aug 2006 08:01:52 -0000	1.93
+++ firmware/usb.c	3 Sep 2006 16:47:28 -0000
@@ -559,7 +559,8 @@ void usb_init(void)
 
 #ifndef BOOTLOADER
     queue_init(&usb_queue);
-    create_thread(usb_thread, usb_stack, sizeof(usb_stack), usb_thread_name);
+    create_thread(usb_thread, usb_stack, sizeof(usb_stack), 
+                  usb_thread_name, PRIORITY_SYSTEM);
 
     tick_add_task(usb_tick);
 #endif
Index: firmware/common/dircache.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/common/dircache.c,v
retrieving revision 1.22
diff -u -3 -p -r1.22 dircache.c
--- firmware/common/dircache.c	26 Aug 2006 09:24:19 -0000	1.22
+++ firmware/common/dircache.c	3 Sep 2006 16:47:28 -0000
@@ -692,7 +692,7 @@ void dircache_init(void)
     
     queue_init(&dircache_queue);
     create_thread(dircache_thread, dircache_stack,
-                sizeof(dircache_stack), dircache_thread_name);
+                sizeof(dircache_stack), dircache_thread_name, PRIORITY_BACKGROUND);
 }
 
 /**
Index: firmware/drivers/ata.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/drivers/ata.c,v
retrieving revision 1.177
diff -u -3 -p -r1.177 ata.c
--- firmware/drivers/ata.c	12 Aug 2006 08:01:53 -0000	1.177
+++ firmware/drivers/ata.c	3 Sep 2006 16:47:28 -0000
@@ -1936,7 +1936,7 @@ int ata_init(void)
 
         last_disk_activity = current_tick;
         create_thread(ata_thread, ata_stack,
-                      sizeof(ata_stack), ata_thread_name);
+                      sizeof(ata_stack), ata_thread_name, PRIORITY_SYSTEM);
         initialized = true;
 
     }
Index: firmware/drivers/ata_mmc.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/drivers/ata_mmc.c,v
retrieving revision 1.53
diff -u -3 -p -r1.53 ata_mmc.c
--- firmware/drivers/ata_mmc.c	7 May 2006 20:20:27 -0000	1.53
+++ firmware/drivers/ata_mmc.c	3 Sep 2006 16:47:28 -0000
@@ -1184,7 +1184,7 @@ int ata_init(void)
 #ifdef HAVE_HOTSWAP
         queue_init(&mmc_queue);
         create_thread(mmc_thread, mmc_stack,
-                      sizeof(mmc_stack), mmc_thread_name);
+                      sizeof(mmc_stack), mmc_thread_name, PRIORITY_SYSTEM);
 #endif
         tick_add_task(mmc_tick);
         initialized = true;
Index: firmware/drivers/i2c.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/drivers/i2c.c,v
retrieving revision 1.16
diff -u -3 -p -r1.16 i2c.c
--- firmware/drivers/i2c.c	7 May 2005 22:29:35 -0000	1.16
+++ firmware/drivers/i2c.c	3 Sep 2006 16:47:28 -0000
@@ -5,7 +5,7 @@
  *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
  *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
  *                     \/            \/     \/    \/            \/
- * $Id: i2c.c,v 1.16 2005-05-07 22:29:35 amiconn Exp $
+ * $Id: i2c.c,v 1.16 2005/05/07 22:29:35 amiconn Exp $
  *
  * Copyright (C) 2002 by Linus Nielsen Feltzing
  *
@@ -145,8 +145,7 @@ void i2c_ack(int bit)
     
     SCL_INPUT;   /* Set the clock to input */
     while(!SCL)  /* and wait for the MAS to release it */
-        sleep_thread();
-    wake_up_thread();
+        sleep_thread(1);
 
     DELAY;
     SCL_OUTPUT;
@@ -168,8 +167,7 @@ int i2c_getack(void)
     SDA_INPUT;   /* And set to input */
     SCL_INPUT;   /* Set the clock to input */
     while(!SCL)  /* and wait for the MAS to release it */
-        sleep_thread();
-    wake_up_thread();
+        sleep_thread(1);
     
     if (SDA)
         /* ack failed */
Index: firmware/drivers/lcd-16bit.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/drivers/lcd-16bit.c,v
retrieving revision 1.36
diff -u -3 -p -r1.36 lcd-16bit.c
--- firmware/drivers/lcd-16bit.c	23 Aug 2006 20:07:54 -0000	1.36
+++ firmware/drivers/lcd-16bit.c	3 Sep 2006 16:47:28 -0000
@@ -79,7 +79,7 @@ void lcd_init(void)
     /* Call device specific init */
     lcd_init_device();
     create_thread(scroll_thread, scroll_stack,
-                  sizeof(scroll_stack), scroll_name);
+                  sizeof(scroll_stack), scroll_name, PRIORITY_SYSTEM);
 }
 
 /*** parameter handling ***/
Index: firmware/drivers/lcd-2bit-horz.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/drivers/lcd-2bit-horz.c,v
retrieving revision 1.19
diff -u -3 -p -r1.19 lcd-2bit-horz.c
--- firmware/drivers/lcd-2bit-horz.c	23 Aug 2006 20:07:54 -0000	1.19
+++ firmware/drivers/lcd-2bit-horz.c	3 Sep 2006 16:47:28 -0000
@@ -76,7 +76,7 @@ void lcd_init(void)
     /* Call device specific init */
     lcd_init_device();
     create_thread(scroll_thread, scroll_stack,
-                  sizeof(scroll_stack), scroll_name);
+                  sizeof(scroll_stack), scroll_name, PRIORITY_SYSTEM);
 }
 
 /*** parameter handling ***/
Index: firmware/drivers/lcd-h100-remote.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/drivers/lcd-h100-remote.c,v
retrieving revision 1.62
diff -u -3 -p -r1.62 lcd-h100-remote.c
--- firmware/drivers/lcd-h100-remote.c	23 Aug 2006 20:07:58 -0000	1.62
+++ firmware/drivers/lcd-h100-remote.c	3 Sep 2006 16:47:28 -0000
@@ -573,7 +573,7 @@ static void remote_tick(void)
 void lcd_remote_init(void)
 {
     create_thread(scroll_thread, scroll_stack,
-                  sizeof(scroll_stack), scroll_name);
+                  sizeof(scroll_stack), scroll_name, PRIORITY_SYSTEM);
 }
 #else /* !SIMULATOR */
 
@@ -604,7 +604,7 @@ void lcd_remote_init(void)
     queue_clear(&remote_scroll_queue); /* no queue_init() -- private queue */
     tick_add_task(remote_tick);
     create_thread(scroll_thread, scroll_stack,
-                  sizeof(scroll_stack), scroll_name);
+                  sizeof(scroll_stack), scroll_name, PRIORITY_SYSTEM);
 }
 
 /*** update functions ***/
Index: firmware/drivers/lcd-h100.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/drivers/lcd-h100.c,v
retrieving revision 1.53
diff -u -3 -p -r1.53 lcd-h100.c
--- firmware/drivers/lcd-h100.c	23 Aug 2006 20:07:58 -0000	1.53
+++ firmware/drivers/lcd-h100.c	3 Sep 2006 16:47:28 -0000
@@ -144,7 +144,7 @@ void lcd_set_flip(bool yesno)
 void lcd_init(void)
 {
     create_thread(scroll_thread, scroll_stack,
-                  sizeof(scroll_stack), scroll_name);
+                  sizeof(scroll_stack), scroll_name, PRIORITY_SYSTEM);
 }
 #else
 
@@ -193,7 +193,7 @@ void lcd_init(void)
     lcd_write_command(LCD_CNTL_ON_OFF | 1); /* LCD ON */
 
     create_thread(scroll_thread, scroll_stack,
-                  sizeof(scroll_stack), scroll_name);
+                  sizeof(scroll_stack), scroll_name, PRIORITY_SYSTEM);
 }
 
 /*** update functions ***/
Index: firmware/drivers/lcd-player.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/drivers/lcd-player.c,v
retrieving revision 1.54
diff -u -3 -p -r1.54 lcd-player.c
--- firmware/drivers/lcd-player.c	15 Aug 2006 20:05:09 -0000	1.54
+++ firmware/drivers/lcd-player.c	3 Sep 2006 16:47:28 -0000
@@ -610,7 +610,7 @@ void lcd_init (void)
     lcd_set_contrast(lcd_default_contrast());
 
     create_thread(scroll_thread, scroll_stack,
-                  sizeof(scroll_stack), scroll_name);
+                  sizeof(scroll_stack), scroll_name, PRIORITY_SYSTEM);
 }
 
 void lcd_jump_scroll (int mode) /* 0=off, 1=once, ..., JUMP_SCROLL_ALWAYS */
Index: firmware/drivers/lcd-recorder.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/drivers/lcd-recorder.c,v
retrieving revision 1.85
diff -u -3 -p -r1.85 lcd-recorder.c
--- firmware/drivers/lcd-recorder.c	23 Aug 2006 20:07:59 -0000	1.85
+++ firmware/drivers/lcd-recorder.c	3 Sep 2006 16:47:28 -0000
@@ -232,7 +232,7 @@ void lcd_set_flip(bool yesno)
 void lcd_init(void)
 {
     create_thread(scroll_thread, scroll_stack,
-                  sizeof(scroll_stack), scroll_name);
+                  sizeof(scroll_stack), scroll_name, PRIORITY_SYSTEM);
 }
 #else
 
@@ -278,7 +278,7 @@ void lcd_init(void)
     lcd_update();
 
     create_thread(scroll_thread, scroll_stack,
-                  sizeof(scroll_stack), scroll_name);
+                  sizeof(scroll_stack), scroll_name, PRIORITY_SYSTEM);
 }
 
 /*** Update functions ***/
Index: firmware/drivers/lcd-remote-2bit-vi.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/drivers/lcd-remote-2bit-vi.c,v
retrieving revision 1.3
diff -u -3 -p -r1.3 lcd-remote-2bit-vi.c
--- firmware/drivers/lcd-remote-2bit-vi.c	23 Aug 2006 20:07:59 -0000	1.3
+++ firmware/drivers/lcd-remote-2bit-vi.c	3 Sep 2006 16:47:28 -0000
@@ -1167,7 +1167,7 @@ static void scroll_thread(void)
 void lcd_remote_init(void)
 {
     create_thread(scroll_thread, scroll_stack,
-                  sizeof(scroll_stack), scroll_name);
+                  sizeof(scroll_stack), scroll_name, PRIORITY_SYSTEM);
 }
 #else
 void lcd_remote_init(void)
@@ -1179,6 +1179,6 @@ void lcd_remote_init(void)
     queue_clear(&remote_scroll_queue); /* no queue_init() -- private queue */
     tick_add_task(remote_tick);
     create_thread(scroll_thread, scroll_stack,
-                  sizeof(scroll_stack), scroll_name);
+                  sizeof(scroll_stack), scroll_name, PRIORITY_SYSTEM);
 }
 #endif
Index: firmware/export/config.h
===================================================================
RCS file: /cvsroot/rockbox/firmware/export/config.h,v
retrieving revision 1.82
diff -u -3 -p -r1.82 config.h
--- firmware/export/config.h	31 Aug 2006 19:19:35 -0000	1.82
+++ firmware/export/config.h	3 Sep 2006 16:47:28 -0000
@@ -216,8 +216,12 @@
 /* Enable the directory cache and tagcache in RAM if we have
  * plenty of RAM. Both features can be enabled independently. */
 #if (MEMORYSIZE > 8 || MEM > 8) && !defined(BOOTLOADER)
-#define HAVE_DIRCACHE 1
-#define HAVE_TC_RAMCACHE 1
+#define HAVE_DIRCACHE
+#define HAVE_TC_RAMCACHE
+#endif
+
+#if (CONFIG_CODEC == SWCODEC) && !defined(SIMULATOR)
+#define HAVE_PRIORITY_SCHEDULING
 #endif
 
 /* define for all cpus from coldfire family */
Index: firmware/export/kernel.h
===================================================================
RCS file: /cvsroot/rockbox/firmware/export/kernel.h,v
retrieving revision 1.25
diff -u -3 -p -r1.25 kernel.h
--- firmware/export/kernel.h	5 Mar 2006 18:40:51 -0000	1.25
+++ firmware/export/kernel.h	3 Sep 2006 16:47:28 -0000
@@ -71,7 +71,7 @@ struct mutex
    the current_tick variable */
 #define current_tick (signed)(USEC_TIMER/10000)
 #else
-extern long current_tick;
+extern volatile long current_tick;
 #endif
 
 #ifdef SIMULATOR
Index: firmware/export/thread.h
===================================================================
RCS file: /cvsroot/rockbox/firmware/export/thread.h,v
retrieving revision 1.14
diff -u -3 -p -r1.14 thread.h
--- firmware/export/thread.h	2 Sep 2006 08:14:52 -0000	1.14
+++ firmware/export/thread.h	3 Sep 2006 16:47:28 -0000
@@ -21,6 +21,14 @@
 
 #include <stdbool.h>
 
+#define PRIORITY_REALTIME        1
+#define PRIORITY_USER_INTERFACE  4 /* The main thread */
+#define PRIORITY_RECORDING       4 /* Recording thread */
+#define PRIORITY_PLAYBACK        4 /* or REALTIME when needed */
+#define PRIORITY_BUFFERING       5 /* Codec buffering thread */
+#define PRIORITY_SYSTEM          6 /* All other firmware threads */
+#define PRIORITY_BACKGROUND      8 /* Normal application threads */
+
 #if CONFIG_CODEC == SWCODEC
 #define MAXTHREADS	16
 #else
@@ -70,29 +78,37 @@ struct thread_entry {
     struct regs context;
     const char *name;
     void *stack;
-    int stack_size;
+    long sleep_tick;
+    unsigned short stack_size;
+#ifdef HAVE_PRIORITY_SCHEDULING
+    unsigned short priority;
+    long last_run;
+#endif
+    struct thread_entry *next, *prev;
 };
 
 struct core_entry {
     int num_threads;
-    volatile int num_sleepers;
-    int current_thread;
     struct thread_entry threads[MAXTHREADS];
+    struct thread_entry *running;
+    struct thread_entry *sleeping;
 };
 #endif
 
 int create_thread(void (*function)(void), void* stack, int stack_size,
-                  const char *name);
+                  const char *name, int priority);
 int create_thread_on_core(unsigned int core, void (*function)(void), void* stack, int stack_size,
-                  const char *name);
+                  const char *name, int priority);
 void remove_thread(int threadnum);
 void remove_thread_on_core(unsigned int core, int threadnum);
-void switch_thread(void);
-void sleep_thread(void);
-void wake_up_thread(void);
+void switch_thread(bool save_context);
+void sleep_thread(int ticks);
+void thread_set_priority(int threadnum, int priority);
 void init_threads(void);
 int thread_stack_usage(int threadnum);
 int thread_stack_usage_on_core(unsigned int core, int threadnum);
+bool thread_is_running(int threadnum);
+bool thread_is_running_on_core(unsigned int core, int threadnum);
 #ifdef RB_PROFILE
 void profile_thread(void);
 #endif
Index: uisimulator/sdl/kernel.c
===================================================================
RCS file: /cvsroot/rockbox/uisimulator/sdl/kernel.c,v
retrieving revision 1.6
diff -u -3 -p -r1.6 kernel.c
--- uisimulator/sdl/kernel.c	12 Apr 2006 15:38:56 -0000	1.6
+++ uisimulator/sdl/kernel.c	3 Sep 2006 16:47:28 -0000
@@ -47,7 +47,7 @@ void queue_wait(struct event_queue *q, s
 {
     while(q->read == q->write)
     {
-        switch_thread();
+        switch_thread(true);
     }
 
     *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK];
@@ -97,8 +97,9 @@ void queue_clear(struct event_queue* q)
     q->write = 0;
 }
 
-void switch_thread (void)
+void switch_thread(bool save_context)
 {
+    (void)save_context;
     yield ();
 }
 
@@ -160,7 +161,7 @@ void mutex_init(struct mutex *m)
 void mutex_lock(struct mutex *m)
 {
     while(m->locked)
-        switch_thread();
+        switch_thread(true);
     m->locked = true;
 }
 
Index: uisimulator/sdl/thread-sdl.c
===================================================================
RCS file: /cvsroot/rockbox/uisimulator/sdl/thread-sdl.c,v
retrieving revision 1.4
diff -u -3 -p -r1.4 thread-sdl.c
--- uisimulator/sdl/thread-sdl.c	31 Jul 2006 15:13:31 -0000	1.4
+++ uisimulator/sdl/thread-sdl.c	3 Sep 2006 16:47:28 -0000
@@ -27,7 +27,7 @@
 
 SDL_Thread          *threads[256];
 int                 threadCount = 0;
-long                current_tick = 0;
+volatile long       current_tick = 0;
 SDL_mutex *m;
 
 void yield(void)
@@ -35,7 +35,7 @@ void yield(void)
     static int counter = 0;
     
     SDL_mutexV(m);
-    if (counter++ >= 50)
+    if (counter++ >= 500)
     {
         SDL_Delay(1);
         counter = 0;
