Index: apps/codecs.c
===================================================================
RCS file: /cvsroot/rockbox/apps/codecs.c,v
retrieving revision 1.30
diff -u -3 -p -r1.30 codecs.c
--- apps/codecs.c	28 Aug 2006 22:38:37 -0000	1.30
+++ apps/codecs.c	11 Sep 2006 16:44:02 -0000
@@ -123,7 +123,7 @@ struct codec_api ci = {
     &current_tick,
     default_event_handler,
     default_event_handler_ex,
-    create_thread,
+    create_thread_on_core,
     remove_thread,
     reset_poweroff_timer,
 #ifndef SIMULATOR
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	11 Sep 2006 16:44:02 -0000
@@ -193,10 +193,12 @@ 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)(unsigned int core, void (*function)(void), 
+                         void* stack, int stack_size, const char *name
+                         IF_PRIO(, 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	11 Sep 2006 16:44:03 -0000
@@ -80,6 +80,18 @@ extern char ata_device;
 extern int ata_io_address;
 extern struct core_entry cores[NUM_CORES];
 
+char thread_status_char(int status)
+{
+    switch (status)
+    {
+        case STATE_RUNNING      : return 'R';
+        case STATE_BLOCKED      : return 'B';
+        case STATE_SLEEPING     : return 'S';
+        case STATE_BLOCKED_W_TMO: return 'T';
+    }
+    
+    return '?';
+}
 #ifdef HAVE_LCD_BITMAP
 /* Test code!!! */
 bool dbg_os(void)
@@ -87,6 +99,7 @@ bool dbg_os(void)
     char buf[32];
     int i;
     int usage;
+    int status;
 #if NUM_CORES > 1
     unsigned int core;
     int line;
@@ -98,24 +111,52 @@ 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;
         for(core = 0; core < NUM_CORES; core++)
         {
-            for(i = 0; i < num_threads[core]; i++)
+            for(i = 0; i < MAXTHREADS; i++)
             {
+                if (cores[core].threads[i].name == NULL)
+                    continue;
+                
                 usage = thread_stack_usage_on_core(core, i);
-                snprintf(buf, 32, "(%d) %s: %d%%", core, thread_name[core][i], usage);
+                status = thread_get_status_on_core(core, i);
+                
+                snprintf(buf, 32, "(%d) %c%c %d %s: %d%%", core, 
+                         (status == STATE_RUNNING) ? '*' : ' ', 
+                         thread_status_char(status),
+                         cores[CURRENT_CORE].threads[i].priority,
+                         cores[core].threads[i].name, usage);
                 lcd_puts(0, ++line, buf);
             }
         }
 #else
         lcd_puts(0, 0, "Stack usage:");
-        for(i = 0; i < cores[CURRENT_CORE].num_threads;i++)
+        for(i = 0; i < MAXTHREADS; i++)
         {
+            if (cores[CURRENT_CORE].threads[i].name == NULL)
+                continue;
+            
             usage = thread_stack_usage(i);
-            snprintf(buf, 32, "%s: %d%%", cores[CURRENT_CORE].threads[i].name, usage);
+            status = thread_get_status_on_core(CURRENT_CORE, i);
+# ifdef HAVE_PRIORITY_SCHEDULING
+            snprintf(buf, 32, "%c%c %d %s: %d%%",
+                     (status == STATE_RUNNING) ? '*' : ' ', 
+                     thread_status_char(status),
+                     cores[CURRENT_CORE].threads[i].priority,
+                     cores[CURRENT_CORE].threads[i].name, usage);
+# else
+            snprintf(buf, 32, "%c%c %s: %d%%",
+                     (status == STATE_RUNNING) ? '*' : ' ', 
+                     (status == STATE_BLOCKED) ? 'B' : ' ', 
+                     cores[CURRENT_CORE].threads[i].name, usage);
+# endif
             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	11 Sep 2006 16:44:03 -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	11 Sep 2006 16:44:03 -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 IF_PRIO(, PRIORITY_BUFFERING));
 }
 
 void audio_init(void)
@@ -665,7 +666,8 @@ 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 
+            IF_PRIO(, PRIORITY_PLAYBACK));
     
     while (!voice_codec_loaded)
         yield();
@@ -1982,13 +1984,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 +3182,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 IF_PRIO(, PRIORITY_PLAYBACK));
 
     while (1)
     {
@@ -3213,7 +3218,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 +3227,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.168
diff -u -3 -p -r1.168 playlist.c
--- apps/playlist.c	10 Sep 2006 10:59:51 -0000	1.168
+++ apps/playlist.c	11 Sep 2006 16:44:03 -0000
@@ -1772,7 +1772,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 IF_PRIO(, PRIORITY_BACKGROUND));
     queue_init(&playlist_queue);
 #endif
 }
Index: apps/plugin.c
===================================================================
RCS file: /cvsroot/rockbox/apps/plugin.c,v
retrieving revision 1.182
diff -u -3 -p -r1.182 plugin.c
--- apps/plugin.c	16 Aug 2006 04:05:17 -0000	1.182
+++ apps/plugin.c	11 Sep 2006 16:44:03 -0000
@@ -108,6 +108,7 @@ static const struct plugin_api rockbox_a
     PREFIX(lcd_icon),
     lcd_double_height,
 #else
+    lcd_setmargins,
     lcd_set_drawmode,
     lcd_get_drawmode,
     lcd_setfont,
@@ -132,6 +133,9 @@ static const struct plugin_api rockbox_a
     lcd_bitmap_transparent_part,
     lcd_bitmap_transparent,
 #endif
+    bidi_l2v,
+    font_get_bits,
+    font_load,
     lcd_putsxy,
     lcd_puts_style,
     lcd_puts_scroll_style,
@@ -178,6 +182,45 @@ static const struct plugin_api rockbox_a
     remote_backlight_on,
     remote_backlight_off,
 #endif
+#if NB_SCREENS == 2
+    {&screens[SCREEN_MAIN], &screens[SCREEN_REMOTE]},
+#else
+    {&screens[SCREEN_MAIN]},
+#endif
+#if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
+    lcd_remote_set_foreground,
+    lcd_remote_get_foreground,
+    lcd_remote_set_background,
+    lcd_remote_get_background,
+    lcd_remote_bitmap_part,
+    lcd_remote_bitmap,
+#endif
+
+#if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR)
+    lcd_yuv_blit,
+#endif
+    /* list */
+    gui_synclist_init,
+    gui_synclist_set_nb_items,
+    gui_synclist_set_icon_callback,
+    gui_synclist_get_nb_items,
+    gui_synclist_get_sel_pos,
+    gui_synclist_draw,
+    gui_synclist_select_item,
+    gui_synclist_select_next,
+    gui_synclist_select_previous,
+    gui_synclist_select_next_page,
+    gui_synclist_select_previous_page,
+    gui_synclist_add_item,
+    gui_synclist_del_item,
+    gui_synclist_limit_scroll,
+    gui_synclist_flash,
+#ifdef HAVE_LCD_BITMAP
+    gui_synclist_scroll_right,
+    gui_synclist_scroll_left,
+#endif
+    gui_synclist_do_button,
+    
     /* button */
     button_get,
     button_get_w_tmo,
@@ -205,12 +248,14 @@ static const struct plugin_api rockbox_a
     ata_sleep,
     ata_disk_is_active,
 #endif
+    reload_directory,
 
     /* dir */
     PREFIX(opendir),
     PREFIX(closedir),
     PREFIX(readdir),
     PREFIX(mkdir),
+    PREFIX(rmdir),
 
     /* kernel/ system */
     PREFIX(sleep),
@@ -253,6 +298,7 @@ static const struct plugin_api rockbox_a
 
     /* strings and memory */
     snprintf,
+    vsnprintf,
     strcpy,
     strncpy,
     strlen,
@@ -268,6 +314,7 @@ static const struct plugin_api rockbox_a
     atoi,
     strchr,
     strcat,
+    memchr,
     memcmp,
     strcasestr,
     /* unicode stuff */
@@ -277,9 +324,12 @@ static const struct plugin_api rockbox_a
     utf16BEdecode,
     utf8encode,
     utf8length,
+    utf8seek,
 
     /* sound */
     sound_set,
+    set_sound,
+
     sound_min,
     sound_max,
 #ifndef SIMULATOR
@@ -334,6 +384,9 @@ static const struct plugin_api rockbox_a
 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
     mas_codec_writereg,
     mas_codec_readreg,
+    i2c_begin,
+    i2c_end,
+    i2c_write,
 #endif
 #endif /* !SIMULATOR && CONFIG_CODEC != SWCODEC */
 
@@ -352,7 +405,15 @@ static const struct plugin_api rockbox_a
     menu_insert,
     menu_set_cursor,
     set_option,
+    set_int,
+    set_bool,
 
+    /* action handling */
+    get_custom_action,
+    get_action,
+    action_signalscreenchange,
+    action_userabort,
+    
     /* power */
     battery_level,
     battery_level_safe,
@@ -405,74 +466,6 @@ static const struct plugin_api rockbox_a
 
     /* new stuff at the end, sort into place next time
        the API gets incompatible */
-    set_sound,
-#if ((CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)) && !defined(SIMULATOR)
-    i2c_begin,
-    i2c_end,
-    i2c_write,
-#endif
-
-    vsnprintf,
-    memchr,
-    /* list */
-    gui_synclist_init,
-    gui_synclist_set_nb_items,
-    gui_synclist_set_icon_callback,
-    gui_synclist_get_nb_items,
-    gui_synclist_get_sel_pos,
-    gui_synclist_draw,
-    gui_synclist_select_item,
-    gui_synclist_select_next,
-    gui_synclist_select_previous,
-    gui_synclist_select_next_page,
-    gui_synclist_select_previous_page,
-    gui_synclist_add_item,
-    gui_synclist_del_item,
-    gui_synclist_limit_scroll,
-    gui_synclist_flash,
-#ifdef HAVE_LCD_BITMAP
-    gui_synclist_scroll_right,
-    gui_synclist_scroll_left,
-#endif
-    gui_synclist_do_button,
-
-#ifdef HAVE_LCD_BITMAP
-    lcd_setmargins,
-#endif
-    utf8seek,
-
-    set_int,
-    reload_directory,
-    set_bool,
-#if NB_SCREENS == 2
-    {&screens[SCREEN_MAIN], &screens[SCREEN_REMOTE]},
-#else
-    {&screens[SCREEN_MAIN]},
-#endif
-#ifdef HAVE_LCD_BITMAP
-    bidi_l2v,
-    font_get_bits,
-    font_load,
-#endif
-#if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
-    lcd_remote_set_foreground,
-    lcd_remote_get_foreground,
-    lcd_remote_set_background,
-    lcd_remote_get_background,
-    lcd_remote_bitmap_part,
-    lcd_remote_bitmap,
-#endif
-
-#if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR)
-    lcd_yuv_blit,
-#endif
-
-    PREFIX(rmdir),
-    /* action handling */
-    get_custom_action,
-    get_action,
-    action_signalscreenchange,
-    action_userabort,
 };
 
 int plugin_load(const char* plugin, void* parameter)
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	11 Sep 2006 16:44:03 -0000
@@ -105,12 +105,12 @@
 #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
    new function which are "waiting" at the end of the function table) */
-#define PLUGIN_MIN_API_VERSION 14
+#define PLUGIN_MIN_API_VERSION 30
 
 /* plugin return codes */
 enum plugin_status {
@@ -143,6 +143,7 @@ struct plugin_api {
     void (*PREFIX(lcd_icon))(int icon, bool enable);
     void (*lcd_double_height)(bool on);
 #else
+    void (*lcd_setmargins)(int x, int y);
     void (*lcd_set_drawmode)(int mode);
     int  (*lcd_get_drawmode)(void);
     void (*lcd_setfont)(int font);
@@ -174,6 +175,9 @@ struct plugin_api {
     void (*lcd_bitmap_transparent)(const fb_data *src, int x, int y,
             int width, int height);
 #endif
+    unsigned short *(*bidi_l2v)( const unsigned char *str, int orientation );
+    const unsigned char *(*font_get_bits)( struct font *pf, unsigned short char_code );
+    struct font* (*font_load)(const char *path);
     void (*lcd_putsxy)(int x, int y, const unsigned char *string);
     void (*lcd_puts_style)(int x, int y, const unsigned char *str, int style);
     void (*lcd_puts_scroll_style)(int x, int y, const unsigned char* string,
@@ -229,7 +233,66 @@ struct plugin_api {
     void (*remote_backlight_on)(void);
     void (*remote_backlight_off)(void);
 #endif
+    struct screen* screens[NB_SCREENS];
+#if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
+    void     (*lcd_remote_set_foreground)(unsigned foreground);
+    unsigned (*lcd_remote_get_foreground)(void);
+    void     (*lcd_remote_set_background)(unsigned foreground);
+    unsigned (*lcd_remote_get_background)(void);
+    void (*lcd_remote_bitmap_part)(const fb_remote_data *src, int src_x, int src_y,
+                                   int stride, int x, int y, int width, int height);
+    void (*lcd_remote_bitmap)(const fb_remote_data *src, int x, int y, int width,
+                              int height);
+#endif
+#if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR)
+    void (*lcd_yuv_blit)(unsigned char * const src[3],
+                         int src_x, int src_y, int stride,
+                         int x, int y, int width, int height);
+#endif
 
+#if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
+    void     (*lcd_remote_set_foreground)(unsigned foreground);
+    unsigned (*lcd_remote_get_foreground)(void);
+    void     (*lcd_remote_set_background)(unsigned foreground);
+    unsigned (*lcd_remote_get_background)(void);
+    void (*lcd_remote_bitmap_part)(const fb_remote_data *src, int src_x, int src_y,
+                                   int stride, int x, int y, int width, int height);
+    void (*lcd_remote_bitmap)(const fb_remote_data *src, int x, int y, int width,
+                              int height);
+#endif
+#if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR)
+    void (*lcd_yuv_blit)(unsigned char * const src[3],
+                         int src_x, int src_y, int stride,
+                         int x, int y, int width, int height);
+#endif
+
+    /* list */
+    void (*gui_synclist_init)(struct gui_synclist * lists,
+            list_get_name callback_get_item_name,void * data,
+            bool scroll_all,int selected_size);
+    void (*gui_synclist_set_nb_items)(struct gui_synclist * lists, int nb_items);
+    void (*gui_synclist_set_icon_callback)(struct gui_synclist * lists, list_get_icon icon_callback);
+    int (*gui_synclist_get_nb_items)(struct gui_synclist * lists);
+    int  (*gui_synclist_get_sel_pos)(struct gui_synclist * lists);
+    void (*gui_synclist_draw)(struct gui_synclist * lists);
+    void (*gui_synclist_select_item)(struct gui_synclist * lists,
+    int item_number);
+    void (*gui_synclist_select_next)(struct gui_synclist * lists);
+    void (*gui_synclist_select_previous)(struct gui_synclist * lists);
+    void (*gui_synclist_select_next_page)(struct gui_synclist * lists,
+    enum screen_type screen);
+    void (*gui_synclist_select_previous_page)(struct gui_synclist * lists,
+    enum screen_type screen);
+    void (*gui_synclist_add_item)(struct gui_synclist * lists);
+    void (*gui_synclist_del_item)(struct gui_synclist * lists);
+    void (*gui_synclist_limit_scroll)(struct gui_synclist * lists, bool scroll);
+    void (*gui_synclist_flash)(struct gui_synclist * lists);
+#ifdef HAVE_LCD_BITMAP
+    void (*gui_synclist_scroll_right)(struct gui_synclist * lists);
+    void (*gui_synclist_scroll_left)(struct gui_synclist * lists);
+#endif
+    unsigned (*gui_synclist_do_button)(struct gui_synclist * lists, unsigned button);
+    
     /* button */
     long (*button_get)(bool block);
     long (*button_get_w_tmo)(int ticks);
@@ -257,20 +320,23 @@ struct plugin_api {
     void (*ata_sleep)(void);
     bool (*ata_disk_is_active)(void);
 #endif
+    void (*reload_directory)(void);
 
     /* dir */
     DIR* (*PREFIX(opendir))(const char* name);
     int (*PREFIX(closedir))(DIR* dir);
     struct dirent* (*PREFIX(readdir))(DIR* dir);
     int (*PREFIX(mkdir))(const char *name, int mode);
+    int (*PREFIX(rmdir))(const char *name);
 
     /* 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 IF_PRIO(, int priority));
     void (*remove_thread)(int threadnum);
     void (*reset_poweroff_timer)(void);
 #ifndef SIMULATOR
@@ -308,6 +374,7 @@ struct plugin_api {
 
     /* strings and memory */
     int (*snprintf)(char *buf, size_t size, const char *fmt, ...);
+    int (*vsnprintf)(char *buf, int size, const char *fmt, va_list ap);
     char* (*strcpy)(char *dst, const char *src);
     char* (*strncpy)(char *dst, const char *src, size_t length);
     size_t (*strlen)(const char *str);
@@ -323,6 +390,7 @@ struct plugin_api {
     int (*atoi)(const char *str);
     char *(*strchr)(const char *s, int c);
     char *(*strcat)(char *s1, const char *s2);
+    void *(*memchr)(const void *s1, int c, size_t n);
     int (*memcmp)(const void *s1, const void *s2, size_t n);
     char *(*strcasestr) (const char* phaystack, const char* pneedle);
     /* unicode stuff */
@@ -332,9 +400,12 @@ struct plugin_api {
     unsigned char* (*utf16BEdecode)(const unsigned char *utf16, unsigned char *utf8, int count);
     unsigned char* (*utf8encode)(unsigned long ucs, unsigned char *utf8);
     unsigned long (*utf8length)(const unsigned char *utf8);
+    int (*utf8seek)(const unsigned char* utf8, int offset);
 
     /* sound */
     void (*sound_set)(int setting, int value);
+    bool (*set_sound)(const unsigned char * string,
+                      int* variable, int setting);
     int (*sound_min)(int setting);
     int (*sound_max)(int setting);
 #ifndef SIMULATOR
@@ -390,6 +461,9 @@ struct plugin_api {
 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
     int (*mas_codec_writereg)(int reg, unsigned int val);
     int (*mas_codec_readreg)(int reg);
+    void (*i2c_begin)(void);
+    void (*i2c_end)(void);
+    int  (*i2c_write)(int address, unsigned char* buf, int count );
 #endif
 #endif
 
@@ -413,7 +487,17 @@ struct plugin_api {
     bool (*set_option)(const char* string, void* variable,
                        enum optiontype type, const struct opt_items* options,
                        int numoptions, void (*function)(int));
+    bool (*set_int)(const unsigned char* string, const char* unit, int voice_unit,
+                    int* variable, void (*function)(int), int step, int min,
+                    int max, void (*formatter)(char*, int, int, const char*) );
+    bool (*set_bool)(const char* string, bool* variable );
 
+    /* action handling */
+    int (*get_custom_action)(int context,int timeout,
+                          const struct button_mapping* (*get_context_map)(int));
+    int (*get_action)(int context, int timeout);
+    void (*action_signalscreenchange)(void);
+    bool (*action_userabort)(int timeout);
 
     /* power */
     int (*battery_level)(void);
@@ -476,83 +560,6 @@ struct plugin_api {
 
     /* new stuff at the end, sort into place next time
        the API gets incompatible */
-    bool (*set_sound)(const unsigned char * string,
-                      int* variable, int setting);
-#if ((CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)) && !defined(SIMULATOR)
-    void (*i2c_begin)(void);
-    void (*i2c_end)(void);
-    int  (*i2c_write)(int address, unsigned char* buf, int count );
-#endif
-
-    int (*vsnprintf)(char *buf, int size, const char *fmt, va_list ap);
-    void *(*memchr)(const void *s1, int c, size_t n);
-
-    /* list */
-    void (*gui_synclist_init)(struct gui_synclist * lists,
-            list_get_name callback_get_item_name,void * data,
-            bool scroll_all,int selected_size);
-    void (*gui_synclist_set_nb_items)(struct gui_synclist * lists, int nb_items);
-    void (*gui_synclist_set_icon_callback)(struct gui_synclist * lists, list_get_icon icon_callback);
-    int (*gui_synclist_get_nb_items)(struct gui_synclist * lists);
-    int  (*gui_synclist_get_sel_pos)(struct gui_synclist * lists);
-    void (*gui_synclist_draw)(struct gui_synclist * lists);
-    void (*gui_synclist_select_item)(struct gui_synclist * lists,
-    int item_number);
-    void (*gui_synclist_select_next)(struct gui_synclist * lists);
-    void (*gui_synclist_select_previous)(struct gui_synclist * lists);
-    void (*gui_synclist_select_next_page)(struct gui_synclist * lists,
-    enum screen_type screen);
-    void (*gui_synclist_select_previous_page)(struct gui_synclist * lists,
-    enum screen_type screen);
-    void (*gui_synclist_add_item)(struct gui_synclist * lists);
-    void (*gui_synclist_del_item)(struct gui_synclist * lists);
-    void (*gui_synclist_limit_scroll)(struct gui_synclist * lists, bool scroll);
-    void (*gui_synclist_flash)(struct gui_synclist * lists);
-#ifdef HAVE_LCD_BITMAP
-    void (*gui_synclist_scroll_right)(struct gui_synclist * lists);
-    void (*gui_synclist_scroll_left)(struct gui_synclist * lists);
-#endif
-    unsigned (*gui_synclist_do_button)(struct gui_synclist * lists, unsigned button);
-
-#ifdef HAVE_LCD_BITMAP
-    void (*lcd_setmargins)(int x, int y);
-#endif
-    int (*utf8seek)(const unsigned char* utf8, int offset);
-
-    bool (*set_int)(const unsigned char* string, const char* unit, int voice_unit,
-                    int* variable, void (*function)(int), int step, int min,
-                    int max, void (*formatter)(char*, int, int, const char*) );
-    void (*reload_directory)(void);
-    bool (*set_bool)(const char* string, bool* variable );
-    struct screen* screens[NB_SCREENS];
-#ifdef HAVE_LCD_BITMAP
-    unsigned short *(*bidi_l2v)( const unsigned char *str, int orientation );
-    const unsigned char *(*font_get_bits)( struct font *pf, unsigned short char_code );
-    struct font* (*font_load)(const char *path);
-#endif
-#if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
-    void     (*lcd_remote_set_foreground)(unsigned foreground);
-    unsigned (*lcd_remote_get_foreground)(void);
-    void     (*lcd_remote_set_background)(unsigned foreground);
-    unsigned (*lcd_remote_get_background)(void);
-    void (*lcd_remote_bitmap_part)(const fb_remote_data *src, int src_x, int src_y,
-                                   int stride, int x, int y, int width, int height);
-    void (*lcd_remote_bitmap)(const fb_remote_data *src, int x, int y, int width,
-                              int height);
-#endif
-#if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR)
-    void (*lcd_yuv_blit)(unsigned char * const src[3],
-                         int src_x, int src_y, int stride,
-                         int x, int y, int width, int height);
-#endif
-
-    int (*PREFIX(rmdir))(const char *name);
-    /* action handling */
-    int (*get_custom_action)(int context,int timeout,
-                          const struct button_mapping* (*get_context_map)(int));
-    int (*get_action)(int context, int timeout);
-    void (*action_signalscreenchange)(void);
-    bool (*action_userabort)(int timeout);
 };
 
 /* plugin header */
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	11 Sep 2006 16:44:03 -0000
@@ -54,6 +54,7 @@
  */
 
 #include <stdio.h>
+#include "config.h"
 #include "thread.h"
 #include "kernel.h"
 #include "system.h"
@@ -1062,7 +1063,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 +3614,8 @@ 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 
+                  IF_PRIO(, PRIORITY_BACKGROUND));
 }
 
 bool tagcache_is_initialized(void)
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	11 Sep 2006 16:44:03 -0000
@@ -1169,7 +1169,8 @@ 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"
+                                  IF_PRIO(, 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	11 Sep 2006 16:44:04 -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" IF_PRIO(, PRIORITY_BACKGROUND)))<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.100
diff -u -3 -p -r1.100 backlight.c
--- firmware/backlight.c	10 Sep 2006 02:00:33 -0000	1.100
+++ firmware/backlight.c	11 Sep 2006 16:44:04 -0000
@@ -623,7 +623,8 @@ 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 
+                  IF_PRIO(, PRIORITY_SYSTEM));
     tick_add_task(backlight_tick);
 #ifdef SIMULATOR
     /* do nothing */
Index: firmware/buffer.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/buffer.c,v
retrieving revision 1.6
diff -u -3 -p -r1.6 buffer.c
--- firmware/buffer.c	1 Aug 2006 09:43:14 -0000	1.6
+++ firmware/buffer.c	11 Sep 2006 16:44:04 -0000
@@ -40,7 +40,9 @@ void *buffer_alloc(size_t size)
     void *retval = audiobuf;
     
     audiobuf += size;
-    /* 32-bit aligned */;
+    /* 32-bit aligned */
     audiobuf = (void *)(((unsigned long)audiobuf + 3) & ~3);
+    
     return retval;
 }
+
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	11 Sep 2006 16:44:04 -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);
@@ -37,6 +37,10 @@ static int num_queues;
 
 void sleep(int ticks) ICODE_ATTR;
 void queue_wait(struct event_queue *q, struct event *ev) ICODE_ATTR;
+void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks)
+    ICODE_ATTR;
+void mutex_lock(struct mutex *m) ICODE_ATTR;
+void mutex_unlock(struct mutex *m) ICODE_ATTR;
 
 /****************************************************************************
  * Standard kernel stuff
@@ -54,6 +58,15 @@ void kernel_init(void)
     tick_start(1000/HZ);
 }
 
+void yield(void)
+{
+#if (CONFIG_CPU == S3C2440 || defined(ELIO_TPJ1022) && defined(BOOTLOADER))
+    /* Some targets don't like yielding in the bootloader */
+#else
+    switch_thread(true, NULL);
+#endif
+}
+
 void sleep(int ticks)
 {
 #if CONFIG_CPU == S3C2440 && defined(BOOTLOADER)
@@ -71,23 +84,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();
-#endif
-}
-
-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();
+    sleep_thread(ticks);
 #endif
 }
 
@@ -98,7 +95,8 @@ void queue_init(struct event_queue *q)
 {
     q->read = 0;
     q->write = 0;
-
+    q->thread = NULL;
+    
     /* Add it to the all_queues array */
     all_queues[num_queues++] = q;
 }
@@ -108,6 +106,8 @@ void queue_delete(struct event_queue *q)
     int i;
     bool found = false;
 
+    wakeup_thread(&q->thread);
+    
     /* Find the queue to be deleted */
     for(i = 0;i < num_queues;i++)
     {
@@ -132,26 +132,22 @@ void queue_delete(struct event_queue *q)
 
 void queue_wait(struct event_queue *q, struct event *ev)
 {
-    while(q->read == q->write)
+    if (q->read == q->write)
     {
-        sleep_thread();
+        block_thread(&q->thread, 0);
     }
-    wake_up_thread();
 
     *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK];
 }
 
 void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks)
 {
-    unsigned int timeout = current_tick + ticks;
-
-    while(q->read == q->write && TIME_BEFORE( current_tick, timeout ))
+    if (q->read == q->write && ticks > 0)
     {
-        sleep_thread();
+        block_thread(&q->thread, ticks);
     }
-    wake_up_thread();
 
-    if(q->read != q->write)
+    if (q->read != q->write)
     {
         *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK];
     }
@@ -171,6 +167,9 @@ void queue_post(struct event_queue *q, l
 
     q->events[wr].id = id;
     q->events[wr].data = data;
+    
+    wakeup_thread(&q->thread);
+    
     set_irq_level(oldlevel);
 }
 
@@ -250,7 +249,6 @@ void IMIA0(void)
     }
 
     current_tick++;
-    wake_up_thread();
 
     TSR0 &= ~0x01;
 }
@@ -301,7 +299,6 @@ void TIMER0(void)
     }
 
     current_tick++;
-    wake_up_thread();
 
     TER0 = 0xff; /* Clear all events */
 }
@@ -330,7 +327,6 @@ void TIMER0(void)
     }
 
     current_tick++;
-    wake_up_thread();
 
     /* re-enable timer by clearing the counter */
     TACON |= 0x80;
@@ -382,7 +378,6 @@ void TIMER1(void)
     }
 
     current_tick++;
-    wake_up_thread();
 }
 #endif
 
@@ -415,7 +410,6 @@ void timer_handler(void)
     }
 
     current_tick++;
-    wake_up_thread();
 
     TIMERR0C = 1;
 }
@@ -513,22 +507,27 @@ int tick_remove_task(void (*f)(void))
 void mutex_init(struct mutex *m)
 {
     m->locked = false;
+    m->thread = NULL;
 }
 
 void mutex_lock(struct mutex *m)
 {
-    /* Wait until the lock is open... */
-    while(m->locked)
-        sleep_thread();
-    wake_up_thread();
-
+    if (m->locked)
+    {
+        /* Wait until the lock is open... */
+        block_thread(&m->thread, 0);
+    }
+    
     /* ...and lock it */
     m->locked = true;
 }
 
 void mutex_unlock(struct mutex *m)
 {
-    m->locked = false;
+    if (m->thread == NULL)
+        m->locked = false;
+    else
+        wakeup_thread(&m->thread);
 }
 
 #endif
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	11 Sep 2006 16:44:04 -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 IF_PRIO(, 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	11 Sep 2006 16:44:04 -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 IF_PRIO(, 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	11 Sep 2006 16:44:04 -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 IF_PRIO(, 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	11 Sep 2006 16:44:04 -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,15 @@ int *cop_stackend = stackend;
 #endif
 #endif
 
-void switch_thread(void) ICODE_ATTR;
+static void add_to_list(struct thread_entry **list,
+                        struct thread_entry *thread) ICODE_ATTR;
+static void remove_from_list(struct thread_entry **list,
+                             struct thread_entry *thread) ICODE_ATTR;
+
+/* Put switch_thread to RAM instead of IRAM. There is no measurable
+ * performance penalty. */
+void switch_thread(bool save_context, struct thread_entry **blocked_list);
+
 static inline void store_context(void* addr) __attribute__ ((always_inline));
 static inline void load_context(const void* addr) __attribute__ ((always_inline));
 
@@ -219,24 +230,99 @@ static inline void load_context(const vo
 
 #endif
 
-/*---------------------------------------------------------------------------
- * Switch thread in round robin fashion.
- *---------------------------------------------------------------------------
- */
-void switch_thread(void)
+static 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 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 void check_sleepers(void)
+{
+    struct thread_entry *current, *next;
+    
+    /* Check sleeping threads. */
+    current = cores[CURRENT_CORE].sleeping;
+    if (current == NULL)
+        return ;
+    
+    for (;;)
     {
-        /* Enter sleep mode, woken up on interrupt */
+        next = current->next;
+        
+        if ((unsigned)current_tick >= GET_STATE_ARG(current->statearg))
+        {
+            /* Sleep timeout has been reached so bring the thread
+             * back to life again. */
+            remove_from_list(&cores[CURRENT_CORE].sleeping, current);
+            add_to_list(&cores[CURRENT_CORE].running, current);
+            
+#ifdef HAVE_PRIORITY_SCHEDULING
+            /* Update the highest priority level if the thread has a higher
+             * priority than all current running threads. */
+            if (current->priority < highest_priority)
+                highest_priority = current->priority;
+#endif
+            
+            /* If there is no more processes in the list, break the loop. */
+            if (cores[CURRENT_CORE].sleeping == NULL)
+                break;
+            
+            current = next;
+            continue;
+        }
+        
+        current = next;
+        
+        /* Break the loop once we have walked through the list of all
+         * sleeping processes. */
+        if (current == cores[CURRENT_CORE].sleeping)
+            break;
+    }
+}
+
+static inline void sleep_core(void)
+{
+    for (;;)
+    {
+        check_sleepers();
+        
+        /* We must sleep until there is at least one process in the list
+         * of running processes. */
+        if (cores[CURRENT_CORE].running != NULL)
+            break;
+
+        /* Enter sleep mode to reduce power usage, woken up on interrupt */
 #ifdef CPU_COLDFIRE
         asm volatile ("stop #0x2000");
 #elif CONFIG_CPU == SH7034
@@ -257,38 +343,202 @@ void switch_thread(void)
         CLKCON |= 2;
 #endif
     }
+}
+
+#ifdef RB_PROFILE
+static int get_threadnum(struct thread_entry *thread)
+{
+    int i;
+    
+    for (i = 0; i < MAXTHREADS; i++)
+    {
+        if (&cores[CURRENT_CORE].threads[i] == thread)
+            return i;
+    }
+    
+    return -1;
+}
 #endif
-    current = cores[CURRENT_CORE].current_thread;
-    store_context(&cores[CURRENT_CORE].threads[current].context);
+
+/*---------------------------------------------------------------------------
+ * Switch thread in round robin fashion.
+ *---------------------------------------------------------------------------
+ */
+void switch_thread(bool save_context, struct thread_entry **blocked_list)
+{
+#ifdef RB_PROFILE
+    profile_thread_stopped(get_threadnum(cores[CURRENT_CORE].running));
+#endif
+    unsigned int *stackptr;
+    struct thread_entry *old;
+    
+#ifdef SIMULATOR
+    /* Do nothing */
+#else
+    
+    /* Begin task switching by saving our current context so that we can
+     * restore the state of the current thread later to the point prior
+     * to this call. */
+    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);
+    /* Check if a thread state change has been requested. */
+    if (cores[CURRENT_CORE].running->statearg)
+    {
+        /* Remove the thread from the list of running threads. */
+        old = cores[CURRENT_CORE].running;
+        remove_from_list(&cores[CURRENT_CORE].running, old);
+        
+        /* And put the thread into a new list of inactive threads. */
+        if (GET_STATE(old->statearg) == STATE_BLOCKED)
+            add_to_list(blocked_list, old);
+        else
+            add_to_list(&cores[CURRENT_CORE].sleeping, old);
+        
+#ifdef HAVE_PRIORITY_SCHEDULING
+        /* Reset priorities */
+        if (old->priority == highest_priority)
+            highest_priority = 100;
+#endif
+    }
+    else
+    {
+        /* Switch to the next running thread. */
+        cores[CURRENT_CORE].running = cores[CURRENT_CORE].running->next;
+    }
+    
+    /* Go through the list of sleeping task to check if we need to wake up
+     * any of them due to timeout. Also puts core into sleep state until
+     * there is at least one running process again. */
+    sleep_core();
+    
+#ifdef HAVE_PRIORITY_SCHEDULING
+    /* Select the new task based on priorities and the last time a process
+     * got CPU time. */
+    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;
+    }
+    
+    /* Reset the value of thread's last running time to the current time. */
+    cores[CURRENT_CORE].running->last_run = current_tick;
+#endif
+    
+#endif
+    /* And finally give control to the next thread. */
+    load_context(&cores[CURRENT_CORE].running->context);
+    
 #ifdef RB_PROFILE
-    profile_thread_started(cores[CURRENT_CORE].current_thread);
+    profile_thread_started(get_threadnum(cores[CURRENT_CORE].running));
 #endif
 }
 
-void sleep_thread(void)
+void sleep_thread(int ticks)
 {
-    ++cores[CURRENT_CORE].num_sleepers;
-    switch_thread();
+    /* Set the thread's new state and timeout and finally force a task switch
+     * so that scheduler removes thread from the list of running processes
+     * and puts it in list of sleeping tasks. */
+    cores[CURRENT_CORE].running->statearg = 
+        SET_STATE(STATE_SLEEPING, current_tick + ticks + 1);
+    switch_thread(true, NULL);
+    
+    /* Clear all flags to indicate we are up and running again. */
+    cores[CURRENT_CORE].running->statearg = 0;
 }
 
-void wake_up_thread(void)
+void block_thread(struct thread_entry **list, int timeout)
 {
-    cores[CURRENT_CORE].num_sleepers = 0;
+    struct thread_entry *current;
+    
+    /* Get the entry for the current running thread. */
+    current = cores[CURRENT_CORE].running;
+    
+    /* At next task switch scheduler will immediately change the thread
+     * state (and we also force the task switch to happen). */
+    if (timeout)
+    {
+        /* We can store only one thread to the "list" if thread is used
+         * in other list (such as core's list for sleeping tasks). */
+        while (*list)
+            sleep_thread(1);
+        
+        current->statearg = 
+            SET_STATE(STATE_BLOCKED_W_TMO, current_tick + timeout);
+        *list = current;
+
+        /* Now force a task switch and block until we have been woken up
+         * by another thread or timeout is reached. */
+        switch_thread(true, NULL);
+        
+        /* If timeout is reached, we must set list back to NULL here. */
+        *list = NULL;
+    }
+    else
+    {
+        current->statearg = SET_STATE(STATE_BLOCKED, 0);
+        
+        /* Now force a task switch and block until we have been woken up
+         * by another thread or timeout is reached. */
+        switch_thread(true, list);
+    }
+    
+    /* Clear all flags to indicate we are up and running again. */
+    current->statearg = 0;
 }
 
+void wakeup_thread(struct thread_entry **list)
+{
+    struct thread_entry *thread;
+    
+    /* Check if there is a blocked thread at all. */
+    if (*list == NULL)
+        return ;
+    
+    /* Wake up the last thread first. */
+    // thread = (*list)->prev;
+    thread = *list;
+    
+    /* Determine thread's current state. */
+    switch (GET_STATE(thread->statearg)) 
+    {
+        case STATE_BLOCKED:
+            /* Remove thread from the list of blocked threads and add it
+             * to the scheduler's list of running processes. */
+            remove_from_list(list, thread);
+            add_to_list(&cores[CURRENT_CORE].running, thread);
+            thread->statearg = 0;
+            break;
+        
+        case STATE_BLOCKED_W_TMO:
+            /* Just remove the timeout to cause scheduler to immediately
+             * wake up the thread. */
+            thread->statearg &= 0xC0000000;
+            *list = NULL;
+            break;
+        
+        default:
+            /* Nothing to do. Thread has already been woken up
+             * or it's state is not blocked or blocked with timeout. */
+            return ;
+    }
+}
 
 /*---------------------------------------------------------------------------
  * Create thread on the current core.
@@ -296,10 +546,10 @@ void wake_up_thread(void)
  *---------------------------------------------------------------------------
  */
 int create_thread(void (*function)(void), void* stack, int stack_size,
-                  const char *name)
+                  const char *name IF_PRIO(, int priority))
 {
     return create_thread_on_core(CURRENT_CORE, function, stack, stack_size,
-                  name);
+                  name IF_PRIO(, priority));
 }
 
 /*---------------------------------------------------------------------------
@@ -308,17 +558,25 @@ 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 IF_PRIO(, int priority))
 {
     unsigned int i;
     unsigned int stacklen;
     unsigned int *stackptr;
+    int n;
     struct regs *regs;
     struct thread_entry *thread;
 
-    if (cores[core].num_threads >= MAXTHREADS)
+    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 +586,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->statearg = 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 +608,7 @@ 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() */
+    return n;
 }
 
 /*---------------------------------------------------------------------------
@@ -364,32 +628,53 @@ void remove_thread(int threadnum)
  */
 void remove_thread_on_core(unsigned int core, int threadnum)
 {
-    int i;
-
-    if (threadnum >= cores[core].num_threads)
-       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 (threadnum >= MAXTHREADS)
+        return;
+    
+    /* Free the entry by removing thread name. */
+    cores[core].threads[threadnum].name = NULL;
+#ifdef HAVE_PRIORITY_SCHEDULING
+    highest_priority = 100;
+#endif
+    
+    if (&cores[core].threads[threadnum] == cores[core].running)
+    {
+        remove_from_list(&cores[core].running, cores[core].running);
+        switch_thread(false, NULL);
+        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;
 
-    cores[core].num_threads = 1; /* We have 1 thread to begin with */
-    cores[core].current_thread = 0; /* The current thread is number 0 */
+    memset(cores, 0, sizeof cores);
+    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].statearg = 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 +690,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)
@@ -418,7 +702,7 @@ int thread_stack_usage_on_core(unsigned 
     unsigned int i;
     unsigned int *stackptr = cores[core].threads[threadnum].stack;
 
-    if (threadnum >= cores[core].num_threads)
+    if (threadnum >= MAXTHREADS)
         return -1;
 
     for (i = 0;i < cores[core].threads[threadnum].stack_size/sizeof(int);i++)
@@ -430,3 +714,10 @@ int thread_stack_usage_on_core(unsigned 
     return ((cores[core].threads[threadnum].stack_size - i * sizeof(int)) * 100) /
         cores[core].threads[threadnum].stack_size;
 }
+
+int thread_get_status_on_core(unsigned int core, int threadnum)
+{
+    struct thread_entry *thread = &cores[core].threads[threadnum];
+    
+    return GET_STATE(thread->statearg);
+}
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	11 Sep 2006 16:44:04 -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 IF_PRIO(, 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	11 Sep 2006 16:44:04 -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 IF_PRIO(, 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	11 Sep 2006 16:44:04 -0000
@@ -1936,7 +1936,8 @@ 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
+                      IF_PRIO(, 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	11 Sep 2006 16:44:04 -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 IF_PRIO(, 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	11 Sep 2006 16:44:04 -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	11 Sep 2006 16:44:04 -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	11 Sep 2006 16:44:04 -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 IF_PRIO(, 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	11 Sep 2006 16:44:04 -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 IF_PRIO(, 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 IF_PRIO(, 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	11 Sep 2006 16:44:04 -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 IF_PRIO(, 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 IF_PRIO(, 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	11 Sep 2006 16:44:04 -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 IF_PRIO(, 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	11 Sep 2006 16:44:04 -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 IF_PRIO(, 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 IF_PRIO(, 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	11 Sep 2006 16:44:05 -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 IF_PRIO(, 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 IF_PRIO(, 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	11 Sep 2006 16:44:05 -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) && !defined(BOOTLOADER)
+#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	11 Sep 2006 16:44:05 -0000
@@ -56,12 +56,14 @@ struct event
 struct event_queue
 {
     struct event events[QUEUE_LENGTH];
+    struct thread_entry *thread;
     unsigned int read;
     unsigned int write;
 };
 
 struct mutex
 {
+    struct thread_entry *thread;
     bool locked;
 };
 
@@ -71,7 +73,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	11 Sep 2006 16:44:05 -0000
@@ -21,8 +21,24 @@
 
 #include <stdbool.h>
 
+/* Priority scheduling (when enabled with HAVE_PRIORITY_SCHEDULING) works
+ * by giving high priority threads more CPU time than less priority threads
+ * when they need it.
+ * 
+ * If software playback codec pcm buffer is going down to critical, codec
+ * can change it own priority to REALTIME to override user interface and
+ * prevent playback skipping.
+ */
+#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       4 /* 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
+#define MAXTHREADS	15
 #else
 #define MAXTHREADS  11
 #endif
@@ -32,7 +48,7 @@
 #ifndef SIMULATOR
 /* Need to keep structures inside the header file because debug_menu
  * needs them. */
-#ifdef CPU_COLDFIRE
+# ifdef CPU_COLDFIRE
 struct regs
 {
     unsigned int macsr;  /* EMAC status register */
@@ -41,7 +57,7 @@ struct regs
     void         *sp;    /* Stack pointer (a7) */
     void         *start; /* Thread start address, or NULL when started */
 };
-#elif CONFIG_CPU == SH7034
+# elif CONFIG_CPU == SH7034
 struct regs
 {
     unsigned int r[7];   /* Registers r8 thru r14 */
@@ -49,7 +65,7 @@ struct regs
     void         *pr;    /* Procedure register */
     void         *start; /* Thread start address, or NULL when started */
 };
-#elif defined(CPU_ARM)
+# elif defined(CPU_ARM)
 struct regs
 {
     unsigned int r[8];   /* Registers r4-r11 */
@@ -57,42 +73,71 @@ struct regs
     unsigned int lr;     /* r14 (lr) */
     void         *start; /* Thread start address, or NULL when started */
 };
-#elif CONFIG_CPU == TCC730
+# elif CONFIG_CPU == TCC730
 struct regs
 {
     void *sp;    /* Stack pointer (a15) */
     void *start; /* Thread start address */
     int started; /* 0 when not started */
 };
-#endif
+# endif
+
+#endif /* !SIMULATOR */
+
+#define STATE_RUNNING         0
+#define STATE_BLOCKED         1
+#define STATE_SLEEPING        2
+#define STATE_BLOCKED_W_TMO   3
+
+#define GET_STATE_ARG(state)  (state & 0x3FFFFFFF)
+#define GET_STATE(state)      ((state >> 30) & 3)
+#define SET_STATE(state,arg)  ((state << 30) | (arg))
 
 struct thread_entry {
+#ifndef SIMULATOR
     struct regs context;
+#endif
     const char *name;
     void *stack;
-    int stack_size;
+    unsigned long statearg;
+    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
 
+#ifdef HAVE_PRIORITY_SCHEDULING
+#define IF_PRIO(empty, type)  , type
+#else
+#define IF_PRIO(empty, type)
+#endif
 int create_thread(void (*function)(void), void* stack, int stack_size,
-                  const char *name);
-int create_thread_on_core(unsigned int core, void (*function)(void), void* stack, int stack_size,
-                  const char *name);
+                  const char *name IF_PRIO(, int priority));
+
+int create_thread_on_core(unsigned int core, void (*function)(void), 
+                          void* stack, int stack_size,
+                          const char *name
+                          IF_PRIO(, 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, struct thread_entry **blocked_list);
+void sleep_thread(int ticks);
+void block_thread(struct thread_entry **thread, int timeout);
+void wakeup_thread(struct thread_entry **thread);
+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);
+int thread_get_status_on_core(unsigned int core, int threadnum);
 #ifdef RB_PROFILE
 void profile_thread(void);
 #endif
Index: tools/configure
===================================================================
RCS file: /cvsroot/rockbox/tools/configure,v
retrieving revision 1.220
diff -u -3 -p -r1.220 configure
--- tools/configure	9 Sep 2006 19:02:18 -0000	1.220
+++ tools/configure	11 Sep 2006 16:44:05 -0000
@@ -302,6 +302,7 @@ whichdevel () {
   fi
   if [ "yes" = "$logf" ]; then
     use_logf="#define ROCKBOX_HAS_LOGF 1"
+    GCCOPTS="$GCCOPTS $GCCOPTIMIZE"
   fi
   if [ "yes" = "$simulator" ]; then
     debug="-DDEBUG"
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	11 Sep 2006 16:44:05 -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.6
diff -u -3 -p -r1.6 thread-sdl.c
--- uisimulator/sdl/thread-sdl.c	3 Sep 2006 21:00:17 -0000	1.6
+++ uisimulator/sdl/thread-sdl.c	11 Sep 2006 16:44:05 -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)
