summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiika Pekkarinen <miipekk@ihme.org>2006-09-16 16:18:11 +0000
committerMiika Pekkarinen <miipekk@ihme.org>2006-09-16 16:18:11 +0000
commita85044bf9eaa0a7206c1978d3cfd57ab2d7fae2f (patch)
treea30695ed540bf32365d577f46398f712c7a494c4
parentbaf5494341cdd6cdb9590e21d429920b9bc4a2c6 (diff)
downloadrockbox-a85044bf9eaa0a7206c1978d3cfd57ab2d7fae2f.tar.gz
rockbox-a85044bf9eaa0a7206c1978d3cfd57ab2d7fae2f.zip
New scheduler, with priorities for swcodec platforms. Frequent task
switching should be more efficient and tasks are stored in linked lists to eliminate unnecessary task switching to improve performance. Audio should no longer skip on swcodec targets caused by too CPU hungry UI thread or background threads. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@10958 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/codecs.c2
-rw-r--r--apps/codecs.h6
-rw-r--r--apps/debug_menu.c56
-rw-r--r--apps/pcmbuf.c42
-rw-r--r--apps/playback.c45
-rw-r--r--apps/playlist.c4
-rw-r--r--apps/plugin.c129
-rw-r--r--apps/plugin.h156
-rw-r--r--apps/plugins/alpine_cdc.c5
-rw-r--r--apps/plugins/battery_bench.c7
-rw-r--r--apps/tagcache.c9
-rw-r--r--firmware/backlight.c5
-rw-r--r--firmware/buffer.c4
-rw-r--r--firmware/common/dircache.c4
-rw-r--r--firmware/drivers/ata.c5
-rw-r--r--firmware/drivers/ata_mmc.c4
-rw-r--r--firmware/drivers/button.c2
-rw-r--r--firmware/drivers/fmradio_i2c.c6
-rw-r--r--firmware/drivers/i2c.c6
-rw-r--r--firmware/drivers/lcd-16bit.c2
-rw-r--r--firmware/drivers/lcd-2bit-horz.c2
-rw-r--r--firmware/drivers/lcd-h100-remote.c7
-rw-r--r--firmware/drivers/lcd-h100.c4
-rw-r--r--firmware/drivers/lcd-player.c2
-rw-r--r--firmware/drivers/lcd-recorder.c4
-rwxr-xr-xfirmware/drivers/lcd-remote-2bit-vi.c7
-rw-r--r--firmware/export/config.h8
-rw-r--r--firmware/export/kernel.h4
-rw-r--r--firmware/export/thread.h88
-rw-r--r--firmware/kernel.c65
-rw-r--r--firmware/mpeg.c14
-rw-r--r--firmware/pcm_record.c28
-rw-r--r--firmware/powermgmt.c2
-rw-r--r--firmware/thread.c485
-rw-r--r--firmware/usb.c5
-rw-r--r--uisimulator/sdl/kernel.c13
36 files changed, 829 insertions, 408 deletions
diff --git a/apps/codecs.c b/apps/codecs.c
index addb8b5e40..b4b8c9833a 100644
--- a/apps/codecs.c
+++ b/apps/codecs.c
@@ -123,7 +123,7 @@ struct codec_api ci = {
123 &current_tick, 123 &current_tick,
124 default_event_handler, 124 default_event_handler,
125 default_event_handler_ex, 125 default_event_handler_ex,
126 create_thread, 126 create_thread_on_core,
127 remove_thread, 127 remove_thread,
128 reset_poweroff_timer, 128 reset_poweroff_timer,
129#ifndef SIMULATOR 129#ifndef SIMULATOR
diff --git a/apps/codecs.h b/apps/codecs.h
index dde376d73c..96804a889b 100644
--- a/apps/codecs.h
+++ b/apps/codecs.h
@@ -196,8 +196,10 @@ struct codec_api {
196 long* current_tick; 196 long* current_tick;
197 long (*default_event_handler)(long event); 197 long (*default_event_handler)(long event);
198 long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter); 198 long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter);
199 int (*create_thread)(void (*function)(void), void* stack, int stack_size, const char *name); 199 struct thread_entry* (*create_thread)(unsigned int core, void (*function)(void),
200 void (*remove_thread)(int threadnum); 200 void* stack, int stack_size, const char *name
201 IF_PRIO(, int priority));
202 void (*remove_thread)(struct thread_entry *thread);
201 void (*reset_poweroff_timer)(void); 203 void (*reset_poweroff_timer)(void);
202#ifndef SIMULATOR 204#ifndef SIMULATOR
203 int (*system_memory_guard)(int newmode); 205 int (*system_memory_guard)(int newmode);
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index 60f405ae50..bda5a5c4f0 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -80,13 +80,27 @@ extern char ata_device;
80extern int ata_io_address; 80extern int ata_io_address;
81extern struct core_entry cores[NUM_CORES]; 81extern struct core_entry cores[NUM_CORES];
82 82
83char thread_status_char(int status)
84{
85 switch (status)
86 {
87 case STATE_RUNNING : return 'R';
88 case STATE_BLOCKED : return 'B';
89 case STATE_SLEEPING : return 'S';
90 case STATE_BLOCKED_W_TMO: return 'T';
91 }
92
93 return '?';
94}
83#ifdef HAVE_LCD_BITMAP 95#ifdef HAVE_LCD_BITMAP
84/* Test code!!! */ 96/* Test code!!! */
85bool dbg_os(void) 97bool dbg_os(void)
86{ 98{
99 struct thread_entry *thread;
87 char buf[32]; 100 char buf[32];
88 int i; 101 int i;
89 int usage; 102 int usage;
103 int status;
90#if NUM_CORES > 1 104#if NUM_CORES > 1
91 unsigned int core; 105 unsigned int core;
92 int line; 106 int line;
@@ -98,24 +112,54 @@ bool dbg_os(void)
98 112
99 while(1) 113 while(1)
100 { 114 {
115#if 0 /* Enable to simulate UI lag. */
116 int _x;
117 for (_x = 0; _x < 1000000L; _x++) ;
118#endif
101#if NUM_CORES > 1 119#if NUM_CORES > 1
102 lcd_puts(0, 0, "Core and stack usage:"); 120 lcd_puts(0, 0, "Core and stack usage:");
103 line = 0; 121 line = 0;
104 for(core = 0; core < NUM_CORES; core++) 122 for(core = 0; core < NUM_CORES; core++)
105 { 123 {
106 for(i = 0; i < num_threads[core]; i++) 124 for(i = 0; i < MAXTHREADS; i++)
107 { 125 {
108 usage = thread_stack_usage_on_core(core, i); 126 thread = &cores[core].threads[i];
109 snprintf(buf, 32, "(%d) %s: %d%%", core, thread_name[core][i], usage); 127 if (thread->name == NULL)
128 continue;
129
130 usage = thread_stack_usage(thread);
131 status = thread_get_status(thread);
132
133 snprintf(buf, 32, "(%d) %c%c %d %s: %d%%", core,
134 (status == STATE_RUNNING) ? '*' : ' ',
135 thread_status_char(status),
136 cores[CURRENT_CORE].threads[i].priority,
137 cores[core].threads[i].name, usage);
110 lcd_puts(0, ++line, buf); 138 lcd_puts(0, ++line, buf);
111 } 139 }
112 } 140 }
113#else 141#else
114 lcd_puts(0, 0, "Stack usage:"); 142 lcd_puts(0, 0, "Stack usage:");
115 for(i = 0; i < cores[CURRENT_CORE].num_threads;i++) 143 for(i = 0; i < MAXTHREADS; i++)
116 { 144 {
117 usage = thread_stack_usage(i); 145 thread = &cores[CURRENT_CORE].threads[i];
118 snprintf(buf, 32, "%s: %d%%", cores[CURRENT_CORE].threads[i].name, usage); 146 if (thread->name == NULL)
147 continue;
148
149 usage = thread_stack_usage(thread);
150 status = thread_get_status(thread);
151# ifdef HAVE_PRIORITY_SCHEDULING
152 snprintf(buf, 32, "%c%c %d %s: %d%%",
153 (status == STATE_RUNNING) ? '*' : ' ',
154 thread_status_char(status),
155 cores[CURRENT_CORE].threads[i].priority,
156 cores[CURRENT_CORE].threads[i].name, usage);
157# else
158 snprintf(buf, 32, "%c%c %s: %d%%",
159 (status == STATE_RUNNING) ? '*' : ' ',
160 (status == STATE_BLOCKED) ? 'B' : ' ',
161 cores[CURRENT_CORE].threads[i].name, usage);
162# endif
119 lcd_puts(0, 1+i, buf); 163 lcd_puts(0, 1+i, buf);
120 } 164 }
121#endif 165#endif
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c
index b18d411db6..f8fd2af82a 100644
--- a/apps/pcmbuf.c
+++ b/apps/pcmbuf.c
@@ -35,9 +35,10 @@
35#include "settings.h" 35#include "settings.h"
36#include "audio.h" 36#include "audio.h"
37#include "dsp.h" 37#include "dsp.h"
38#include "thread.h"
38 39
39/* 1.5s low mark */ 40/* Keep watermark high for iPods at least (2s) */
40#define PCMBUF_WATERMARK (NATIVE_FREQUENCY * 6) 41#define PCMBUF_WATERMARK (NATIVE_FREQUENCY * 8)
41 42
42/* Structure we can use to queue pcm chunks in memory to be played 43/* Structure we can use to queue pcm chunks in memory to be played
43 * by the driver code. */ 44 * by the driver code. */
@@ -94,6 +95,8 @@ static size_t pcmbuf_mix_sample IDATA_ATTR;
94static bool low_latency_mode = false; 95static bool low_latency_mode = false;
95static bool pcmbuf_flush; 96static bool pcmbuf_flush;
96 97
98extern struct thread_entry *codec_thread_p;
99
97/* Helpful macros for use in conditionals this assumes some of the above 100/* Helpful macros for use in conditionals this assumes some of the above
98 * static variable names */ 101 * static variable names */
99#define NEED_FLUSH(position) \ 102#define NEED_FLUSH(position) \
@@ -109,14 +112,37 @@ static bool pcmbuf_flush_fillpos(void);
109void pcmbuf_boost(bool state) 112void pcmbuf_boost(bool state)
110{ 113{
111 static bool boost_state = false; 114 static bool boost_state = false;
112 115#ifdef HAVE_PRIORITY_SCHEDULING
116 static bool priority_modified = false;
117#endif
118
113 if (crossfade_init || crossfade_active) 119 if (crossfade_init || crossfade_active)
114 return; 120 return;
115 121
116 if (state != boost_state) { 122 if (state != boost_state)
123 {
117 cpu_boost(state); 124 cpu_boost(state);
118 boost_state = state; 125 boost_state = state;
119 } 126 }
127
128#ifdef HAVE_PRIORITY_SCHEDULING
129 if (state && LOW_DATA(2) && pcm_is_playing())
130 {
131 if (!priority_modified)
132 {
133 /* Buffer is critically low so override UI priority. */
134 priority_modified = true;
135 thread_set_priority(codec_thread_p, PRIORITY_REALTIME);
136 }
137 }
138 else if (priority_modified)
139 {
140 /* Set back the original priority. */
141 thread_set_priority(codec_thread_p, PRIORITY_PLAYBACK);
142 priority_modified = false;
143 }
144
145#endif
120} 146}
121#endif 147#endif
122 148
@@ -244,7 +270,9 @@ static void pcmbuf_under_watermark(void)
244 pcmbuf_boost(true); 270 pcmbuf_boost(true);
245 /* Disable crossfade if < .5s of audio */ 271 /* Disable crossfade if < .5s of audio */
246 if (LOW_DATA(2)) 272 if (LOW_DATA(2))
273 {
247 crossfade_active = false; 274 crossfade_active = false;
275 }
248} 276}
249 277
250void pcmbuf_set_event_handler(void (*event_handler)(void)) 278void pcmbuf_set_event_handler(void (*event_handler)(void))
@@ -270,8 +298,8 @@ bool pcmbuf_is_lowdata(void)
270 crossfade_init || crossfade_active) 298 crossfade_init || crossfade_active)
271 return false; 299 return false;
272 300
273 /* 0.5 seconds of buffer is low data */ 301 /* 1 seconds of buffer is low data */
274 return LOW_DATA(2); 302 return LOW_DATA(4);
275} 303}
276 304
277/* Amount of bytes left in the buffer. */ 305/* Amount of bytes left in the buffer. */
@@ -443,7 +471,7 @@ static bool pcmbuf_flush_fillpos(void)
443 pcmbuf_play_start(); 471 pcmbuf_play_start();
444 } 472 }
445 /* Let approximately one chunk of data playback */ 473 /* Let approximately one chunk of data playback */
446 sleep(PCMBUF_TARGET_CHUNK/(NATIVE_FREQUENCY * 4) / 5); 474 sleep(HZ*PCMBUF_TARGET_CHUNK/(NATIVE_FREQUENCY*4));
447 } 475 }
448 pcmbuf_add_chunk(); 476 pcmbuf_add_chunk();
449 return true; 477 return true;
diff --git a/apps/playback.c b/apps/playback.c
index 352c99b390..33667cc656 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -176,7 +176,7 @@ static char *voicebuf;
176static size_t voice_remaining; 176static size_t voice_remaining;
177static bool voice_is_playing; 177static bool voice_is_playing;
178static void (*voice_getmore)(unsigned char** start, int* size); 178static void (*voice_getmore)(unsigned char** start, int* size);
179static int voice_thread_num = -1; 179static struct thread_entry *voice_thread_p = NULL;
180 180
181/* Is file buffer currently being refilled? */ 181/* Is file buffer currently being refilled? */
182static volatile bool filling IDATA_ATTR; 182static volatile bool filling IDATA_ATTR;
@@ -267,6 +267,8 @@ static struct event_queue codec_queue;
267static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] 267static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
268IBSS_ATTR; 268IBSS_ATTR;
269static const char codec_thread_name[] = "codec"; 269static const char codec_thread_name[] = "codec";
270/* For modifying thread priority later. */
271struct thread_entry *codec_thread_p;
270 272
271/* Voice thread */ 273/* Voice thread */
272static struct event_queue voice_queue; 274static struct event_queue voice_queue;
@@ -628,13 +630,13 @@ void audio_preinit(void)
628 630
629 mutex_init(&mutex_codecthread); 631 mutex_init(&mutex_codecthread);
630 632
631 queue_init(&audio_queue); 633 queue_init(&audio_queue, true);
632 queue_init(&codec_queue); 634 queue_init(&codec_queue, true);
633 /* clear, not init to create a private queue */ 635 /* create a private queue */
634 queue_clear(&codec_callback_queue); 636 queue_init(&codec_callback_queue, false);
635 637
636 create_thread(audio_thread, audio_stack, sizeof(audio_stack), 638 create_thread(audio_thread, audio_stack, sizeof(audio_stack),
637 audio_thread_name); 639 audio_thread_name IF_PRIO(, PRIORITY_BUFFERING));
638} 640}
639 641
640void audio_init(void) 642void audio_init(void)
@@ -648,14 +650,14 @@ void voice_init(void)
648 if (!filebuf) 650 if (!filebuf)
649 return; /* Audio buffers not yet set up */ 651 return; /* Audio buffers not yet set up */
650 652
651 if (voice_thread_num >= 0) 653 if (voice_thread_p)
652 { 654 {
653 logf("Terminating voice codec"); 655 logf("Terminating voice codec");
654 remove_thread(voice_thread_num); 656 remove_thread(voice_thread_p);
655 if (current_codec == CODEC_IDX_VOICE) 657 if (current_codec == CODEC_IDX_VOICE)
656 mutex_unlock(&mutex_codecthread); 658 mutex_unlock(&mutex_codecthread);
657 queue_delete(&voice_queue); 659 queue_delete(&voice_queue);
658 voice_thread_num = -1; 660 voice_thread_p = NULL;
659 voice_codec_loaded = false; 661 voice_codec_loaded = false;
660 } 662 }
661 663
@@ -663,9 +665,10 @@ void voice_init(void)
663 return; 665 return;
664 666
665 logf("Starting voice codec"); 667 logf("Starting voice codec");
666 queue_init(&voice_queue); 668 queue_init(&voice_queue, true);
667 voice_thread_num = create_thread(voice_thread, voice_stack, 669 voice_thread_p = create_thread(voice_thread, voice_stack,
668 sizeof(voice_stack), voice_thread_name); 670 sizeof(voice_stack), voice_thread_name
671 IF_PRIO(, PRIORITY_PLAYBACK));
669 672
670 while (!voice_codec_loaded) 673 while (!voice_codec_loaded)
671 yield(); 674 yield();
@@ -1740,7 +1743,7 @@ static void codec_thread(void)
1740#endif 1743#endif
1741 1744
1742#ifndef SIMULATOR 1745#ifndef SIMULATOR
1743 case SYS_USB_CONNECTED: 1746 case SYS_USB_CONNECTED:
1744 LOGFQUEUE("codec < SYS_USB_CONNECTED"); 1747 LOGFQUEUE("codec < SYS_USB_CONNECTED");
1745 queue_clear(&codec_queue); 1748 queue_clear(&codec_queue);
1746 usb_acknowledge(SYS_USB_CONNECTED_ACK); 1749 usb_acknowledge(SYS_USB_CONNECTED_ACK);
@@ -1982,13 +1985,15 @@ static bool audio_yield_codecs(void)
1982{ 1985{
1983 yield(); 1986 yield();
1984 1987
1985 if (!queue_empty(&audio_queue)) return true; 1988 if (!queue_empty(&audio_queue))
1989 return true;
1986 1990
1987 while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata()) 1991 while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata())
1988 && !ci.stop_codec && playing && !audio_filebuf_is_lowdata()) 1992 && !ci.stop_codec && playing && !audio_filebuf_is_lowdata())
1989 { 1993 {
1990 sleep(1); 1994 sleep(1);
1991 if (!queue_empty(&audio_queue)) return true; 1995 if (!queue_empty(&audio_queue))
1996 return true;
1992 } 1997 }
1993 1998
1994 return false; 1999 return false;
@@ -3178,8 +3183,9 @@ static void audio_playback_init(void)
3178 id3_voice.frequency = 11200; 3183 id3_voice.frequency = 11200;
3179 id3_voice.length = 1000000L; 3184 id3_voice.length = 1000000L;
3180 3185
3181 create_thread(codec_thread, codec_stack, sizeof(codec_stack), 3186 codec_thread_p = create_thread(codec_thread, codec_stack,
3182 codec_thread_name); 3187 sizeof(codec_stack),
3188 codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK));
3183 3189
3184 while (1) 3190 while (1)
3185 { 3191 {
@@ -3213,7 +3219,8 @@ static void audio_thread(void)
3213 /* At first initialize audio system in background. */ 3219 /* At first initialize audio system in background. */
3214 audio_playback_init(); 3220 audio_playback_init();
3215 3221
3216 while (1) { 3222 while (1)
3223 {
3217 if (filling) 3224 if (filling)
3218 { 3225 {
3219 queue_wait_w_tmo(&audio_queue, &ev, 0); 3226 queue_wait_w_tmo(&audio_queue, &ev, 0);
@@ -3221,7 +3228,7 @@ static void audio_thread(void)
3221 ev.id = Q_AUDIO_FILL_BUFFER; 3228 ev.id = Q_AUDIO_FILL_BUFFER;
3222 } 3229 }
3223 else 3230 else
3224 queue_wait_w_tmo(&audio_queue, &ev, HZ); 3231 queue_wait_w_tmo(&audio_queue, &ev, HZ/2);
3225 3232
3226 switch (ev.id) { 3233 switch (ev.id) {
3227 case Q_AUDIO_FILL_BUFFER: 3234 case Q_AUDIO_FILL_BUFFER:
diff --git a/apps/playlist.c b/apps/playlist.c
index a75e32aed5..4ab98ab3c6 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -1777,8 +1777,8 @@ void playlist_init(void)
1777 memset(playlist->filenames, 0, 1777 memset(playlist->filenames, 0,
1778 playlist->max_playlist_size * sizeof(int)); 1778 playlist->max_playlist_size * sizeof(int));
1779 create_thread(playlist_thread, playlist_stack, sizeof(playlist_stack), 1779 create_thread(playlist_thread, playlist_stack, sizeof(playlist_stack),
1780 playlist_thread_name); 1780 playlist_thread_name IF_PRIO(, PRIORITY_BACKGROUND));
1781 queue_init(&playlist_queue); 1781 queue_init(&playlist_queue, true);
1782#endif 1782#endif
1783} 1783}
1784 1784
diff --git a/apps/plugin.c b/apps/plugin.c
index 6e2a8bca37..9ffb980300 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -108,6 +108,7 @@ static const struct plugin_api rockbox_api = {
108 PREFIX(lcd_icon), 108 PREFIX(lcd_icon),
109 lcd_double_height, 109 lcd_double_height,
110#else 110#else
111 lcd_setmargins,
111 lcd_set_drawmode, 112 lcd_set_drawmode,
112 lcd_get_drawmode, 113 lcd_get_drawmode,
113 lcd_setfont, 114 lcd_setfont,
@@ -132,6 +133,9 @@ static const struct plugin_api rockbox_api = {
132 lcd_bitmap_transparent_part, 133 lcd_bitmap_transparent_part,
133 lcd_bitmap_transparent, 134 lcd_bitmap_transparent,
134#endif 135#endif
136 bidi_l2v,
137 font_get_bits,
138 font_load,
135 lcd_putsxy, 139 lcd_putsxy,
136 lcd_puts_style, 140 lcd_puts_style,
137 lcd_puts_scroll_style, 141 lcd_puts_scroll_style,
@@ -178,6 +182,45 @@ static const struct plugin_api rockbox_api = {
178 remote_backlight_on, 182 remote_backlight_on,
179 remote_backlight_off, 183 remote_backlight_off,
180#endif 184#endif
185#if NB_SCREENS == 2
186 {&screens[SCREEN_MAIN], &screens[SCREEN_REMOTE]},
187#else
188 {&screens[SCREEN_MAIN]},
189#endif
190#if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
191 lcd_remote_set_foreground,
192 lcd_remote_get_foreground,
193 lcd_remote_set_background,
194 lcd_remote_get_background,
195 lcd_remote_bitmap_part,
196 lcd_remote_bitmap,
197#endif
198
199#if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR)
200 lcd_yuv_blit,
201#endif
202 /* list */
203 gui_synclist_init,
204 gui_synclist_set_nb_items,
205 gui_synclist_set_icon_callback,
206 gui_synclist_get_nb_items,
207 gui_synclist_get_sel_pos,
208 gui_synclist_draw,
209 gui_synclist_select_item,
210 gui_synclist_select_next,
211 gui_synclist_select_previous,
212 gui_synclist_select_next_page,
213 gui_synclist_select_previous_page,
214 gui_synclist_add_item,
215 gui_synclist_del_item,
216 gui_synclist_limit_scroll,
217 gui_synclist_flash,
218#ifdef HAVE_LCD_BITMAP
219 gui_synclist_scroll_right,
220 gui_synclist_scroll_left,
221#endif
222 gui_synclist_do_button,
223
181 /* button */ 224 /* button */
182 button_get, 225 button_get,
183 button_get_w_tmo, 226 button_get_w_tmo,
@@ -205,12 +248,14 @@ static const struct plugin_api rockbox_api = {
205 ata_sleep, 248 ata_sleep,
206 ata_disk_is_active, 249 ata_disk_is_active,
207#endif 250#endif
251 reload_directory,
208 252
209 /* dir */ 253 /* dir */
210 PREFIX(opendir), 254 PREFIX(opendir),
211 PREFIX(closedir), 255 PREFIX(closedir),
212 PREFIX(readdir), 256 PREFIX(readdir),
213 PREFIX(mkdir), 257 PREFIX(mkdir),
258 PREFIX(rmdir),
214 259
215 /* kernel/ system */ 260 /* kernel/ system */
216 PREFIX(sleep), 261 PREFIX(sleep),
@@ -253,6 +298,7 @@ static const struct plugin_api rockbox_api = {
253 298
254 /* strings and memory */ 299 /* strings and memory */
255 snprintf, 300 snprintf,
301 vsnprintf,
256 strcpy, 302 strcpy,
257 strncpy, 303 strncpy,
258 strlen, 304 strlen,
@@ -268,6 +314,7 @@ static const struct plugin_api rockbox_api = {
268 atoi, 314 atoi,
269 strchr, 315 strchr,
270 strcat, 316 strcat,
317 memchr,
271 memcmp, 318 memcmp,
272 strcasestr, 319 strcasestr,
273 /* unicode stuff */ 320 /* unicode stuff */
@@ -277,9 +324,12 @@ static const struct plugin_api rockbox_api = {
277 utf16BEdecode, 324 utf16BEdecode,
278 utf8encode, 325 utf8encode,
279 utf8length, 326 utf8length,
327 utf8seek,
280 328
281 /* sound */ 329 /* sound */
282 sound_set, 330 sound_set,
331 set_sound,
332
283 sound_min, 333 sound_min,
284 sound_max, 334 sound_max,
285#ifndef SIMULATOR 335#ifndef SIMULATOR
@@ -334,6 +384,9 @@ static const struct plugin_api rockbox_api = {
334#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) 384#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
335 mas_codec_writereg, 385 mas_codec_writereg,
336 mas_codec_readreg, 386 mas_codec_readreg,
387 i2c_begin,
388 i2c_end,
389 i2c_write,
337#endif 390#endif
338#endif /* !SIMULATOR && CONFIG_CODEC != SWCODEC */ 391#endif /* !SIMULATOR && CONFIG_CODEC != SWCODEC */
339 392
@@ -352,7 +405,15 @@ static const struct plugin_api rockbox_api = {
352 menu_insert, 405 menu_insert,
353 menu_set_cursor, 406 menu_set_cursor,
354 set_option, 407 set_option,
408 set_int,
409 set_bool,
355 410
411 /* action handling */
412 get_custom_action,
413 get_action,
414 action_signalscreenchange,
415 action_userabort,
416
356 /* power */ 417 /* power */
357 battery_level, 418 battery_level,
358 battery_level_safe, 419 battery_level_safe,
@@ -405,74 +466,6 @@ static const struct plugin_api rockbox_api = {
405 466
406 /* new stuff at the end, sort into place next time 467 /* new stuff at the end, sort into place next time
407 the API gets incompatible */ 468 the API gets incompatible */
408 set_sound,
409#if ((CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)) && !defined(SIMULATOR)
410 i2c_begin,
411 i2c_end,
412 i2c_write,
413#endif
414
415 vsnprintf,
416 memchr,
417 /* list */
418 gui_synclist_init,
419 gui_synclist_set_nb_items,
420 gui_synclist_set_icon_callback,
421 gui_synclist_get_nb_items,
422 gui_synclist_get_sel_pos,
423 gui_synclist_draw,
424 gui_synclist_select_item,
425 gui_synclist_select_next,
426 gui_synclist_select_previous,
427 gui_synclist_select_next_page,
428 gui_synclist_select_previous_page,
429 gui_synclist_add_item,
430 gui_synclist_del_item,
431 gui_synclist_limit_scroll,
432 gui_synclist_flash,
433#ifdef HAVE_LCD_BITMAP
434 gui_synclist_scroll_right,
435 gui_synclist_scroll_left,
436#endif
437 gui_synclist_do_button,
438
439#ifdef HAVE_LCD_BITMAP
440 lcd_setmargins,
441#endif
442 utf8seek,
443
444 set_int,
445 reload_directory,
446 set_bool,
447#if NB_SCREENS == 2
448 {&screens[SCREEN_MAIN], &screens[SCREEN_REMOTE]},
449#else
450 {&screens[SCREEN_MAIN]},
451#endif
452#ifdef HAVE_LCD_BITMAP
453 bidi_l2v,
454 font_get_bits,
455 font_load,
456#endif
457#if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
458 lcd_remote_set_foreground,
459 lcd_remote_get_foreground,
460 lcd_remote_set_background,
461 lcd_remote_get_background,
462 lcd_remote_bitmap_part,
463 lcd_remote_bitmap,
464#endif
465
466#if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR)
467 lcd_yuv_blit,
468#endif
469
470 PREFIX(rmdir),
471 /* action handling */
472 get_custom_action,
473 get_action,
474 action_signalscreenchange,
475 action_userabort,
476}; 469};
477 470
478int plugin_load(const char* plugin, void* parameter) 471int plugin_load(const char* plugin, void* parameter)
diff --git a/apps/plugin.h b/apps/plugin.h
index 9b3cec5cde..b89dfd0d81 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -105,12 +105,12 @@
105#define PLUGIN_MAGIC 0x526F634B /* RocK */ 105#define PLUGIN_MAGIC 0x526F634B /* RocK */
106 106
107/* increase this every time the api struct changes */ 107/* increase this every time the api struct changes */
108#define PLUGIN_API_VERSION 29 108#define PLUGIN_API_VERSION 30
109 109
110/* update this to latest version if a change to the api struct breaks 110/* update this to latest version if a change to the api struct breaks
111 backwards compatibility (and please take the opportunity to sort in any 111 backwards compatibility (and please take the opportunity to sort in any
112 new function which are "waiting" at the end of the function table) */ 112 new function which are "waiting" at the end of the function table) */
113#define PLUGIN_MIN_API_VERSION 14 113#define PLUGIN_MIN_API_VERSION 30
114 114
115/* plugin return codes */ 115/* plugin return codes */
116enum plugin_status { 116enum plugin_status {
@@ -143,6 +143,7 @@ struct plugin_api {
143 void (*PREFIX(lcd_icon))(int icon, bool enable); 143 void (*PREFIX(lcd_icon))(int icon, bool enable);
144 void (*lcd_double_height)(bool on); 144 void (*lcd_double_height)(bool on);
145#else 145#else
146 void (*lcd_setmargins)(int x, int y);
146 void (*lcd_set_drawmode)(int mode); 147 void (*lcd_set_drawmode)(int mode);
147 int (*lcd_get_drawmode)(void); 148 int (*lcd_get_drawmode)(void);
148 void (*lcd_setfont)(int font); 149 void (*lcd_setfont)(int font);
@@ -174,6 +175,9 @@ struct plugin_api {
174 void (*lcd_bitmap_transparent)(const fb_data *src, int x, int y, 175 void (*lcd_bitmap_transparent)(const fb_data *src, int x, int y,
175 int width, int height); 176 int width, int height);
176#endif 177#endif
178 unsigned short *(*bidi_l2v)( const unsigned char *str, int orientation );
179 const unsigned char *(*font_get_bits)( struct font *pf, unsigned short char_code );
180 struct font* (*font_load)(const char *path);
177 void (*lcd_putsxy)(int x, int y, const unsigned char *string); 181 void (*lcd_putsxy)(int x, int y, const unsigned char *string);
178 void (*lcd_puts_style)(int x, int y, const unsigned char *str, int style); 182 void (*lcd_puts_style)(int x, int y, const unsigned char *str, int style);
179 void (*lcd_puts_scroll_style)(int x, int y, const unsigned char* string, 183 void (*lcd_puts_scroll_style)(int x, int y, const unsigned char* string,
@@ -229,7 +233,50 @@ struct plugin_api {
229 void (*remote_backlight_on)(void); 233 void (*remote_backlight_on)(void);
230 void (*remote_backlight_off)(void); 234 void (*remote_backlight_off)(void);
231#endif 235#endif
236 struct screen* screens[NB_SCREENS];
237#if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
238 void (*lcd_remote_set_foreground)(unsigned foreground);
239 unsigned (*lcd_remote_get_foreground)(void);
240 void (*lcd_remote_set_background)(unsigned foreground);
241 unsigned (*lcd_remote_get_background)(void);
242 void (*lcd_remote_bitmap_part)(const fb_remote_data *src, int src_x, int src_y,
243 int stride, int x, int y, int width, int height);
244 void (*lcd_remote_bitmap)(const fb_remote_data *src, int x, int y, int width,
245 int height);
246#endif
247#if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR)
248 void (*lcd_yuv_blit)(unsigned char * const src[3],
249 int src_x, int src_y, int stride,
250 int x, int y, int width, int height);
251#endif
232 252
253 /* list */
254 void (*gui_synclist_init)(struct gui_synclist * lists,
255 list_get_name callback_get_item_name,void * data,
256 bool scroll_all,int selected_size);
257 void (*gui_synclist_set_nb_items)(struct gui_synclist * lists, int nb_items);
258 void (*gui_synclist_set_icon_callback)(struct gui_synclist * lists, list_get_icon icon_callback);
259 int (*gui_synclist_get_nb_items)(struct gui_synclist * lists);
260 int (*gui_synclist_get_sel_pos)(struct gui_synclist * lists);
261 void (*gui_synclist_draw)(struct gui_synclist * lists);
262 void (*gui_synclist_select_item)(struct gui_synclist * lists,
263 int item_number);
264 void (*gui_synclist_select_next)(struct gui_synclist * lists);
265 void (*gui_synclist_select_previous)(struct gui_synclist * lists);
266 void (*gui_synclist_select_next_page)(struct gui_synclist * lists,
267 enum screen_type screen);
268 void (*gui_synclist_select_previous_page)(struct gui_synclist * lists,
269 enum screen_type screen);
270 void (*gui_synclist_add_item)(struct gui_synclist * lists);
271 void (*gui_synclist_del_item)(struct gui_synclist * lists);
272 void (*gui_synclist_limit_scroll)(struct gui_synclist * lists, bool scroll);
273 void (*gui_synclist_flash)(struct gui_synclist * lists);
274#ifdef HAVE_LCD_BITMAP
275 void (*gui_synclist_scroll_right)(struct gui_synclist * lists);
276 void (*gui_synclist_scroll_left)(struct gui_synclist * lists);
277#endif
278 unsigned (*gui_synclist_do_button)(struct gui_synclist * lists, unsigned button);
279
233 /* button */ 280 /* button */
234 long (*button_get)(bool block); 281 long (*button_get)(bool block);
235 long (*button_get_w_tmo)(int ticks); 282 long (*button_get_w_tmo)(int ticks);
@@ -257,12 +304,14 @@ struct plugin_api {
257 void (*ata_sleep)(void); 304 void (*ata_sleep)(void);
258 bool (*ata_disk_is_active)(void); 305 bool (*ata_disk_is_active)(void);
259#endif 306#endif
307 void (*reload_directory)(void);
260 308
261 /* dir */ 309 /* dir */
262 DIR* (*PREFIX(opendir))(const char* name); 310 DIR* (*PREFIX(opendir))(const char* name);
263 int (*PREFIX(closedir))(DIR* dir); 311 int (*PREFIX(closedir))(DIR* dir);
264 struct dirent* (*PREFIX(readdir))(DIR* dir); 312 struct dirent* (*PREFIX(readdir))(DIR* dir);
265 int (*PREFIX(mkdir))(const char *name, int mode); 313 int (*PREFIX(mkdir))(const char *name, int mode);
314 int (*PREFIX(rmdir))(const char *name);
266 315
267 /* kernel/ system */ 316 /* kernel/ system */
268 void (*PREFIX(sleep))(int ticks); 317 void (*PREFIX(sleep))(int ticks);
@@ -270,8 +319,10 @@ struct plugin_api {
270 long* current_tick; 319 long* current_tick;
271 long (*default_event_handler)(long event); 320 long (*default_event_handler)(long event);
272 long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter); 321 long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter);
273 int (*create_thread)(void (*function)(void), void* stack, int stack_size, const char *name); 322 struct thread_entry* (*create_thread)(void (*function)(void), void* stack,
274 void (*remove_thread)(int threadnum); 323 int stack_size, const char *name
324 IF_PRIO(, int priority));
325 void (*remove_thread)(struct thread_entry *thread);
275 void (*reset_poweroff_timer)(void); 326 void (*reset_poweroff_timer)(void);
276#ifndef SIMULATOR 327#ifndef SIMULATOR
277 int (*system_memory_guard)(int newmode); 328 int (*system_memory_guard)(int newmode);
@@ -285,7 +336,7 @@ struct plugin_api {
285 void (*timer_unregister)(void); 336 void (*timer_unregister)(void);
286 bool (*timer_set_period)(long count); 337 bool (*timer_set_period)(long count);
287#endif 338#endif
288 void (*queue_init)(struct event_queue *q); 339 void (*queue_init)(struct event_queue *q, bool register_queue);
289 void (*queue_delete)(struct event_queue *q); 340 void (*queue_delete)(struct event_queue *q);
290 void (*queue_post)(struct event_queue *q, long id, void *data); 341 void (*queue_post)(struct event_queue *q, long id, void *data);
291 void (*queue_wait_w_tmo)(struct event_queue *q, struct event *ev, 342 void (*queue_wait_w_tmo)(struct event_queue *q, struct event *ev,
@@ -308,6 +359,7 @@ struct plugin_api {
308 359
309 /* strings and memory */ 360 /* strings and memory */
310 int (*snprintf)(char *buf, size_t size, const char *fmt, ...); 361 int (*snprintf)(char *buf, size_t size, const char *fmt, ...);
362 int (*vsnprintf)(char *buf, int size, const char *fmt, va_list ap);
311 char* (*strcpy)(char *dst, const char *src); 363 char* (*strcpy)(char *dst, const char *src);
312 char* (*strncpy)(char *dst, const char *src, size_t length); 364 char* (*strncpy)(char *dst, const char *src, size_t length);
313 size_t (*strlen)(const char *str); 365 size_t (*strlen)(const char *str);
@@ -323,6 +375,7 @@ struct plugin_api {
323 int (*atoi)(const char *str); 375 int (*atoi)(const char *str);
324 char *(*strchr)(const char *s, int c); 376 char *(*strchr)(const char *s, int c);
325 char *(*strcat)(char *s1, const char *s2); 377 char *(*strcat)(char *s1, const char *s2);
378 void *(*memchr)(const void *s1, int c, size_t n);
326 int (*memcmp)(const void *s1, const void *s2, size_t n); 379 int (*memcmp)(const void *s1, const void *s2, size_t n);
327 char *(*strcasestr) (const char* phaystack, const char* pneedle); 380 char *(*strcasestr) (const char* phaystack, const char* pneedle);
328 /* unicode stuff */ 381 /* unicode stuff */
@@ -332,9 +385,12 @@ struct plugin_api {
332 unsigned char* (*utf16BEdecode)(const unsigned char *utf16, unsigned char *utf8, int count); 385 unsigned char* (*utf16BEdecode)(const unsigned char *utf16, unsigned char *utf8, int count);
333 unsigned char* (*utf8encode)(unsigned long ucs, unsigned char *utf8); 386 unsigned char* (*utf8encode)(unsigned long ucs, unsigned char *utf8);
334 unsigned long (*utf8length)(const unsigned char *utf8); 387 unsigned long (*utf8length)(const unsigned char *utf8);
388 int (*utf8seek)(const unsigned char* utf8, int offset);
335 389
336 /* sound */ 390 /* sound */
337 void (*sound_set)(int setting, int value); 391 void (*sound_set)(int setting, int value);
392 bool (*set_sound)(const unsigned char * string,
393 int* variable, int setting);
338 int (*sound_min)(int setting); 394 int (*sound_min)(int setting);
339 int (*sound_max)(int setting); 395 int (*sound_max)(int setting);
340#ifndef SIMULATOR 396#ifndef SIMULATOR
@@ -390,6 +446,9 @@ struct plugin_api {
390#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) 446#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
391 int (*mas_codec_writereg)(int reg, unsigned int val); 447 int (*mas_codec_writereg)(int reg, unsigned int val);
392 int (*mas_codec_readreg)(int reg); 448 int (*mas_codec_readreg)(int reg);
449 void (*i2c_begin)(void);
450 void (*i2c_end)(void);
451 int (*i2c_write)(int address, unsigned char* buf, int count );
393#endif 452#endif
394#endif 453#endif
395 454
@@ -413,7 +472,17 @@ struct plugin_api {
413 bool (*set_option)(const char* string, void* variable, 472 bool (*set_option)(const char* string, void* variable,
414 enum optiontype type, const struct opt_items* options, 473 enum optiontype type, const struct opt_items* options,
415 int numoptions, void (*function)(int)); 474 int numoptions, void (*function)(int));
475 bool (*set_int)(const unsigned char* string, const char* unit, int voice_unit,
476 int* variable, void (*function)(int), int step, int min,
477 int max, void (*formatter)(char*, int, int, const char*) );
478 bool (*set_bool)(const char* string, bool* variable );
416 479
480 /* action handling */
481 int (*get_custom_action)(int context,int timeout,
482 const struct button_mapping* (*get_context_map)(int));
483 int (*get_action)(int context, int timeout);
484 void (*action_signalscreenchange)(void);
485 bool (*action_userabort)(int timeout);
417 486
418 /* power */ 487 /* power */
419 int (*battery_level)(void); 488 int (*battery_level)(void);
@@ -476,83 +545,6 @@ struct plugin_api {
476 545
477 /* new stuff at the end, sort into place next time 546 /* new stuff at the end, sort into place next time
478 the API gets incompatible */ 547 the API gets incompatible */
479 bool (*set_sound)(const unsigned char * string,
480 int* variable, int setting);
481#if ((CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)) && !defined(SIMULATOR)
482 void (*i2c_begin)(void);
483 void (*i2c_end)(void);
484 int (*i2c_write)(int address, unsigned char* buf, int count );
485#endif
486
487 int (*vsnprintf)(char *buf, int size, const char *fmt, va_list ap);
488 void *(*memchr)(const void *s1, int c, size_t n);
489
490 /* list */
491 void (*gui_synclist_init)(struct gui_synclist * lists,
492 list_get_name callback_get_item_name,void * data,
493 bool scroll_all,int selected_size);
494 void (*gui_synclist_set_nb_items)(struct gui_synclist * lists, int nb_items);
495 void (*gui_synclist_set_icon_callback)(struct gui_synclist * lists, list_get_icon icon_callback);
496 int (*gui_synclist_get_nb_items)(struct gui_synclist * lists);
497 int (*gui_synclist_get_sel_pos)(struct gui_synclist * lists);
498 void (*gui_synclist_draw)(struct gui_synclist * lists);
499 void (*gui_synclist_select_item)(struct gui_synclist * lists,
500 int item_number);
501 void (*gui_synclist_select_next)(struct gui_synclist * lists);
502 void (*gui_synclist_select_previous)(struct gui_synclist * lists);
503 void (*gui_synclist_select_next_page)(struct gui_synclist * lists,
504 enum screen_type screen);
505 void (*gui_synclist_select_previous_page)(struct gui_synclist * lists,
506 enum screen_type screen);
507 void (*gui_synclist_add_item)(struct gui_synclist * lists);
508 void (*gui_synclist_del_item)(struct gui_synclist * lists);
509 void (*gui_synclist_limit_scroll)(struct gui_synclist * lists, bool scroll);
510 void (*gui_synclist_flash)(struct gui_synclist * lists);
511#ifdef HAVE_LCD_BITMAP
512 void (*gui_synclist_scroll_right)(struct gui_synclist * lists);
513 void (*gui_synclist_scroll_left)(struct gui_synclist * lists);
514#endif
515 unsigned (*gui_synclist_do_button)(struct gui_synclist * lists, unsigned button);
516
517#ifdef HAVE_LCD_BITMAP
518 void (*lcd_setmargins)(int x, int y);
519#endif
520 int (*utf8seek)(const unsigned char* utf8, int offset);
521
522 bool (*set_int)(const unsigned char* string, const char* unit, int voice_unit,
523 int* variable, void (*function)(int), int step, int min,
524 int max, void (*formatter)(char*, int, int, const char*) );
525 void (*reload_directory)(void);
526 bool (*set_bool)(const char* string, bool* variable );
527 struct screen* screens[NB_SCREENS];
528#ifdef HAVE_LCD_BITMAP
529 unsigned short *(*bidi_l2v)( const unsigned char *str, int orientation );
530 const unsigned char *(*font_get_bits)( struct font *pf, unsigned short char_code );
531 struct font* (*font_load)(const char *path);
532#endif
533#if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
534 void (*lcd_remote_set_foreground)(unsigned foreground);
535 unsigned (*lcd_remote_get_foreground)(void);
536 void (*lcd_remote_set_background)(unsigned foreground);
537 unsigned (*lcd_remote_get_background)(void);
538 void (*lcd_remote_bitmap_part)(const fb_remote_data *src, int src_x, int src_y,
539 int stride, int x, int y, int width, int height);
540 void (*lcd_remote_bitmap)(const fb_remote_data *src, int x, int y, int width,
541 int height);
542#endif
543#if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR)
544 void (*lcd_yuv_blit)(unsigned char * const src[3],
545 int src_x, int src_y, int stride,
546 int x, int y, int width, int height);
547#endif
548
549 int (*PREFIX(rmdir))(const char *name);
550 /* action handling */
551 int (*get_custom_action)(int context,int timeout,
552 const struct button_mapping* (*get_context_map)(int));
553 int (*get_action)(int context, int timeout);
554 void (*action_signalscreenchange)(void);
555 bool (*action_userabort)(int timeout);
556}; 548};
557 549
558/* plugin header */ 550/* plugin header */
diff --git a/apps/plugins/alpine_cdc.c b/apps/plugins/alpine_cdc.c
index a482664d6a..134bb3dee6 100644
--- a/apps/plugins/alpine_cdc.c
+++ b/apps/plugins/alpine_cdc.c
@@ -202,7 +202,7 @@ struct
202/* communication to the worker thread */ 202/* communication to the worker thread */
203struct 203struct
204{ 204{
205 int id; /* ID of the thread */ 205 struct thread_entry *id; /* Pointer of the thread */
206 bool foreground; /* set as long as we're owning the UI */ 206 bool foreground; /* set as long as we're owning the UI */
207 bool exiting; /* signal to the thread that we want to exit */ 207 bool exiting; /* signal to the thread that we want to exit */
208 bool ended; /* response from the thread, that is has exited */ 208 bool ended; /* response from the thread, that is has exited */
@@ -1169,7 +1169,8 @@ int main(void* parameter)
1169 1169
1170 rb->memset(&gTread, 0, sizeof(gTread)); 1170 rb->memset(&gTread, 0, sizeof(gTread));
1171 gTread.foreground = true; 1171 gTread.foreground = true;
1172 gTread.id = rb->create_thread(thread, stack, stacksize, "CDC"); 1172 gTread.id = rb->create_thread(thread, stack, stacksize, "CDC"
1173 IF_PRIO(, PRIORITY_BACKGROUND));
1173 1174
1174#ifdef DEBUG 1175#ifdef DEBUG
1175 do 1176 do
diff --git a/apps/plugins/battery_bench.c b/apps/plugins/battery_bench.c
index 9400bd2018..3c56f84309 100644
--- a/apps/plugins/battery_bench.c
+++ b/apps/plugins/battery_bench.c
@@ -102,7 +102,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
102 102
103struct 103struct
104{ 104{
105 int id; 105 struct thread_entry *id;
106 bool ended; 106 bool ended;
107} s_thread; 107} s_thread;
108 108
@@ -454,10 +454,11 @@ int main(void)
454 rb->close(fd); 454 rb->close(fd);
455 } 455 }
456 456
457 rb->queue_init(&thread_q); /* put the thread's queue in the bcast list */ 457 rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */
458 rb->memset(&s_thread, 0, sizeof(s_thread)); /* zero the struct */ 458 rb->memset(&s_thread, 0, sizeof(s_thread)); /* zero the struct */
459 if((s_thread.id = rb->create_thread(thread, thread_stack, 459 if((s_thread.id = rb->create_thread(thread, thread_stack,
460 sizeof(thread_stack), "Battery Benchmark"))<0) 460 sizeof(thread_stack), "Battery Benchmark"
461 IF_PRIO(, PRIORITY_BACKGROUND))) == NULL)
461 { 462 {
462 rb->splash(HZ,true,"Cannot create thread!"); 463 rb->splash(HZ,true,"Cannot create thread!");
463 return PLUGIN_ERROR; 464 return PLUGIN_ERROR;
diff --git a/apps/tagcache.c b/apps/tagcache.c
index 2ed80a860b..f478598dad 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -54,6 +54,7 @@
54 */ 54 */
55 55
56#include <stdio.h> 56#include <stdio.h>
57#include "config.h"
57#include "thread.h" 58#include "thread.h"
58#include "kernel.h" 59#include "kernel.h"
59#include "system.h" 60#include "system.h"
@@ -1062,7 +1063,6 @@ static bool get_next(struct tagcache_search *tcs)
1062 1063
1063 if (tagcache_is_numeric_tag(tcs->type)) 1064 if (tagcache_is_numeric_tag(tcs->type))
1064 { 1065 {
1065 logf("r:%d", tcs->position);
1066 snprintf(buf, sizeof(buf), "%d", tcs->position); 1066 snprintf(buf, sizeof(buf), "%d", tcs->position);
1067 tcs->result_seek = tcs->position; 1067 tcs->result_seek = tcs->position;
1068 tcs->result = buf; 1068 tcs->result = buf;
@@ -3455,7 +3455,6 @@ static void tagcache_thread(void)
3455 sleep(HZ); 3455 sleep(HZ);
3456 stat.ready = check_all_headers(); 3456 stat.ready = check_all_headers();
3457 3457
3458
3459 while (1) 3458 while (1)
3460 { 3459 {
3461 queue_wait_w_tmo(&tagcache_queue, &ev, HZ); 3460 queue_wait_w_tmo(&tagcache_queue, &ev, HZ);
@@ -3503,6 +3502,7 @@ static void tagcache_thread(void)
3503 3502
3504 3503
3505 logf("tagcache check done"); 3504 logf("tagcache check done");
3505
3506 check_done = true; 3506 check_done = true;
3507 break ; 3507 break ;
3508 3508
@@ -3612,9 +3612,10 @@ void tagcache_init(void)
3612 current_serial = 0; 3612 current_serial = 0;
3613 write_lock = read_lock = 0; 3613 write_lock = read_lock = 0;
3614 3614
3615 queue_init(&tagcache_queue); 3615 queue_init(&tagcache_queue, true);
3616 create_thread(tagcache_thread, tagcache_stack, 3616 create_thread(tagcache_thread, tagcache_stack,
3617 sizeof(tagcache_stack), tagcache_thread_name); 3617 sizeof(tagcache_stack), tagcache_thread_name
3618 IF_PRIO(, PRIORITY_BACKGROUND));
3618} 3619}
3619 3620
3620bool tagcache_is_initialized(void) 3621bool tagcache_is_initialized(void)
diff --git a/firmware/backlight.c b/firmware/backlight.c
index bf88cbe9bc..4e76072822 100644
--- a/firmware/backlight.c
+++ b/firmware/backlight.c
@@ -618,12 +618,13 @@ static void backlight_tick(void)
618 618
619void backlight_init(void) 619void backlight_init(void)
620{ 620{
621 queue_init(&backlight_queue); 621 queue_init(&backlight_queue, true);
622#ifdef X5_BACKLIGHT_SHUTDOWN 622#ifdef X5_BACKLIGHT_SHUTDOWN
623 backlight_thread_id = 623 backlight_thread_id =
624#endif 624#endif
625 create_thread(backlight_thread, backlight_stack, 625 create_thread(backlight_thread, backlight_stack,
626 sizeof(backlight_stack), backlight_thread_name); 626 sizeof(backlight_stack), backlight_thread_name
627 IF_PRIO(, PRIORITY_SYSTEM));
627 tick_add_task(backlight_tick); 628 tick_add_task(backlight_tick);
628#ifdef SIMULATOR 629#ifdef SIMULATOR
629 /* do nothing */ 630 /* do nothing */
diff --git a/firmware/buffer.c b/firmware/buffer.c
index 1eaff33de1..6af8eb9432 100644
--- a/firmware/buffer.c
+++ b/firmware/buffer.c
@@ -40,7 +40,9 @@ void *buffer_alloc(size_t size)
40 void *retval = audiobuf; 40 void *retval = audiobuf;
41 41
42 audiobuf += size; 42 audiobuf += size;
43 /* 32-bit aligned */; 43 /* 32-bit aligned */
44 audiobuf = (void *)(((unsigned long)audiobuf + 3) & ~3); 44 audiobuf = (void *)(((unsigned long)audiobuf + 3) & ~3);
45
45 return retval; 46 return retval;
46} 47}
48
diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c
index 17033e1827..0bdd0657bd 100644
--- a/firmware/common/dircache.c
+++ b/firmware/common/dircache.c
@@ -690,9 +690,9 @@ void dircache_init(void)
690 opendirs[i].secondary_entry.d_name = buffer_alloc(MAX_PATH); 690 opendirs[i].secondary_entry.d_name = buffer_alloc(MAX_PATH);
691 } 691 }
692 692
693 queue_init(&dircache_queue); 693 queue_init(&dircache_queue, true);
694 create_thread(dircache_thread, dircache_stack, 694 create_thread(dircache_thread, dircache_stack,
695 sizeof(dircache_stack), dircache_thread_name); 695 sizeof(dircache_stack), dircache_thread_name IF_PRIO(, PRIORITY_BACKGROUND));
696} 696}
697 697
698/** 698/**
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c
index 8593eebea1..f57088504b 100644
--- a/firmware/drivers/ata.c
+++ b/firmware/drivers/ata.c
@@ -1932,11 +1932,12 @@ int ata_init(void)
1932 if (rc) 1932 if (rc)
1933 return -60 + rc; 1933 return -60 + rc;
1934 1934
1935 queue_init(&ata_queue); 1935 queue_init(&ata_queue, true);
1936 1936
1937 last_disk_activity = current_tick; 1937 last_disk_activity = current_tick;
1938 create_thread(ata_thread, ata_stack, 1938 create_thread(ata_thread, ata_stack,
1939 sizeof(ata_stack), ata_thread_name); 1939 sizeof(ata_stack), ata_thread_name
1940 IF_PRIO(, PRIORITY_SYSTEM));
1940 initialized = true; 1941 initialized = true;
1941 1942
1942 } 1943 }
diff --git a/firmware/drivers/ata_mmc.c b/firmware/drivers/ata_mmc.c
index b2e79c419a..6303ca2851 100644
--- a/firmware/drivers/ata_mmc.c
+++ b/firmware/drivers/ata_mmc.c
@@ -1182,9 +1182,9 @@ int ata_init(void)
1182 if (!last_mmc_status) 1182 if (!last_mmc_status)
1183 mmc_status = MMC_UNTOUCHED; 1183 mmc_status = MMC_UNTOUCHED;
1184#ifdef HAVE_HOTSWAP 1184#ifdef HAVE_HOTSWAP
1185 queue_init(&mmc_queue); 1185 queue_init(&mmc_queue, true);
1186 create_thread(mmc_thread, mmc_stack, 1186 create_thread(mmc_thread, mmc_stack,
1187 sizeof(mmc_stack), mmc_thread_name); 1187 sizeof(mmc_stack), mmc_thread_name IF_PRIO(, PRIORITY_SYSTEM));
1188#endif 1188#endif
1189 tick_add_task(mmc_tick); 1189 tick_add_task(mmc_tick);
1190 initialized = true; 1190 initialized = true;
diff --git a/firmware/drivers/button.c b/firmware/drivers/button.c
index daad4f17de..6536a34037 100644
--- a/firmware/drivers/button.c
+++ b/firmware/drivers/button.c
@@ -674,7 +674,7 @@ void button_init(void)
674 GPIOA_INT_CLR = GPIOA_INT_STAT; 674 GPIOA_INT_CLR = GPIOA_INT_STAT;
675 GPIOA_INT_EN = 0xff; 675 GPIOA_INT_EN = 0xff;
676#endif /* CONFIG_KEYPAD */ 676#endif /* CONFIG_KEYPAD */
677 queue_init(&button_queue); 677 queue_init(&button_queue, true);
678 button_read(); 678 button_read();
679 lastbtn = button_read(); 679 lastbtn = button_read();
680 tick_add_task(button_tick); 680 tick_add_task(button_tick);
diff --git a/firmware/drivers/fmradio_i2c.c b/firmware/drivers/fmradio_i2c.c
index 6f87e15b3e..62761b3aa7 100644
--- a/firmware/drivers/fmradio_i2c.c
+++ b/firmware/drivers/fmradio_i2c.c
@@ -317,8 +317,7 @@ static void fmradio_i2c_ack(int bit)
317 317
318 SCL_INPUT; /* Set the clock to input */ 318 SCL_INPUT; /* Set the clock to input */
319 while(!SCL) /* and wait for the slave to release it */ 319 while(!SCL) /* and wait for the slave to release it */
320 sleep_thread(); 320 sleep_thread(0);
321 wake_up_thread();
322 321
323 DELAY; 322 DELAY;
324 SCL_OUTPUT; 323 SCL_OUTPUT;
@@ -337,8 +336,7 @@ static int fmradio_i2c_getack(void)
337 SDA_INPUT; /* And set to input */ 336 SDA_INPUT; /* And set to input */
338 SCL_INPUT; /* Set the clock to input */ 337 SCL_INPUT; /* Set the clock to input */
339 while(!SCL) /* and wait for the slave to release it */ 338 while(!SCL) /* and wait for the slave to release it */
340 sleep_thread(); 339 sleep_thread(0);
341 wake_up_thread();
342 340
343 if (SDA) 341 if (SDA)
344 /* ack failed */ 342 /* ack failed */
diff --git a/firmware/drivers/i2c.c b/firmware/drivers/i2c.c
index 71cb9cf8b0..2b439c23ad 100644
--- a/firmware/drivers/i2c.c
+++ b/firmware/drivers/i2c.c
@@ -145,8 +145,7 @@ void i2c_ack(int bit)
145 145
146 SCL_INPUT; /* Set the clock to input */ 146 SCL_INPUT; /* Set the clock to input */
147 while(!SCL) /* and wait for the MAS to release it */ 147 while(!SCL) /* and wait for the MAS to release it */
148 sleep_thread(); 148 sleep_thread(1);
149 wake_up_thread();
150 149
151 DELAY; 150 DELAY;
152 SCL_OUTPUT; 151 SCL_OUTPUT;
@@ -168,8 +167,7 @@ int i2c_getack(void)
168 SDA_INPUT; /* And set to input */ 167 SDA_INPUT; /* And set to input */
169 SCL_INPUT; /* Set the clock to input */ 168 SCL_INPUT; /* Set the clock to input */
170 while(!SCL) /* and wait for the MAS to release it */ 169 while(!SCL) /* and wait for the MAS to release it */
171 sleep_thread(); 170 sleep_thread(1);
172 wake_up_thread();
173 171
174 if (SDA) 172 if (SDA)
175 /* ack failed */ 173 /* ack failed */
diff --git a/firmware/drivers/lcd-16bit.c b/firmware/drivers/lcd-16bit.c
index e6ae28bc19..47c02ea7b7 100644
--- a/firmware/drivers/lcd-16bit.c
+++ b/firmware/drivers/lcd-16bit.c
@@ -79,7 +79,7 @@ void lcd_init(void)
79 /* Call device specific init */ 79 /* Call device specific init */
80 lcd_init_device(); 80 lcd_init_device();
81 create_thread(scroll_thread, scroll_stack, 81 create_thread(scroll_thread, scroll_stack,
82 sizeof(scroll_stack), scroll_name); 82 sizeof(scroll_stack), scroll_name, PRIORITY_SYSTEM);
83} 83}
84 84
85/*** parameter handling ***/ 85/*** parameter handling ***/
diff --git a/firmware/drivers/lcd-2bit-horz.c b/firmware/drivers/lcd-2bit-horz.c
index 33f483d38d..dc49a37c8a 100644
--- a/firmware/drivers/lcd-2bit-horz.c
+++ b/firmware/drivers/lcd-2bit-horz.c
@@ -76,7 +76,7 @@ void lcd_init(void)
76 /* Call device specific init */ 76 /* Call device specific init */
77 lcd_init_device(); 77 lcd_init_device();
78 create_thread(scroll_thread, scroll_stack, 78 create_thread(scroll_thread, scroll_stack,
79 sizeof(scroll_stack), scroll_name); 79 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
80} 80}
81 81
82/*** parameter handling ***/ 82/*** parameter handling ***/
diff --git a/firmware/drivers/lcd-h100-remote.c b/firmware/drivers/lcd-h100-remote.c
index ed5816cebf..5db6d548ff 100644
--- a/firmware/drivers/lcd-h100-remote.c
+++ b/firmware/drivers/lcd-h100-remote.c
@@ -573,7 +573,7 @@ static void remote_tick(void)
573void lcd_remote_init(void) 573void lcd_remote_init(void)
574{ 574{
575 create_thread(scroll_thread, scroll_stack, 575 create_thread(scroll_thread, scroll_stack,
576 sizeof(scroll_stack), scroll_name); 576 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
577} 577}
578#else /* !SIMULATOR */ 578#else /* !SIMULATOR */
579 579
@@ -601,10 +601,11 @@ void lcd_remote_init(void)
601#endif 601#endif
602 lcd_remote_clear_display(); 602 lcd_remote_clear_display();
603 603
604 queue_clear(&remote_scroll_queue); /* no queue_init() -- private queue */ 604 /* private queue */
605 queue_init(&remote_scroll_queue, false);
605 tick_add_task(remote_tick); 606 tick_add_task(remote_tick);
606 create_thread(scroll_thread, scroll_stack, 607 create_thread(scroll_thread, scroll_stack,
607 sizeof(scroll_stack), scroll_name); 608 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
608} 609}
609 610
610/*** update functions ***/ 611/*** update functions ***/
diff --git a/firmware/drivers/lcd-h100.c b/firmware/drivers/lcd-h100.c
index 8407876d34..ada6f29216 100644
--- a/firmware/drivers/lcd-h100.c
+++ b/firmware/drivers/lcd-h100.c
@@ -144,7 +144,7 @@ void lcd_set_flip(bool yesno)
144void lcd_init(void) 144void lcd_init(void)
145{ 145{
146 create_thread(scroll_thread, scroll_stack, 146 create_thread(scroll_thread, scroll_stack,
147 sizeof(scroll_stack), scroll_name); 147 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
148} 148}
149#else 149#else
150 150
@@ -193,7 +193,7 @@ void lcd_init(void)
193 lcd_write_command(LCD_CNTL_ON_OFF | 1); /* LCD ON */ 193 lcd_write_command(LCD_CNTL_ON_OFF | 1); /* LCD ON */
194 194
195 create_thread(scroll_thread, scroll_stack, 195 create_thread(scroll_thread, scroll_stack,
196 sizeof(scroll_stack), scroll_name); 196 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
197} 197}
198 198
199/*** update functions ***/ 199/*** update functions ***/
diff --git a/firmware/drivers/lcd-player.c b/firmware/drivers/lcd-player.c
index 16012470fa..050258d1f8 100644
--- a/firmware/drivers/lcd-player.c
+++ b/firmware/drivers/lcd-player.c
@@ -610,7 +610,7 @@ void lcd_init (void)
610 lcd_set_contrast(lcd_default_contrast()); 610 lcd_set_contrast(lcd_default_contrast());
611 611
612 create_thread(scroll_thread, scroll_stack, 612 create_thread(scroll_thread, scroll_stack,
613 sizeof(scroll_stack), scroll_name); 613 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
614} 614}
615 615
616void lcd_jump_scroll (int mode) /* 0=off, 1=once, ..., JUMP_SCROLL_ALWAYS */ 616void lcd_jump_scroll (int mode) /* 0=off, 1=once, ..., JUMP_SCROLL_ALWAYS */
diff --git a/firmware/drivers/lcd-recorder.c b/firmware/drivers/lcd-recorder.c
index 1987d9a3ed..e74cad7f03 100644
--- a/firmware/drivers/lcd-recorder.c
+++ b/firmware/drivers/lcd-recorder.c
@@ -232,7 +232,7 @@ void lcd_set_flip(bool yesno)
232void lcd_init(void) 232void lcd_init(void)
233{ 233{
234 create_thread(scroll_thread, scroll_stack, 234 create_thread(scroll_thread, scroll_stack,
235 sizeof(scroll_stack), scroll_name); 235 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
236} 236}
237#else 237#else
238 238
@@ -278,7 +278,7 @@ void lcd_init(void)
278 lcd_update(); 278 lcd_update();
279 279
280 create_thread(scroll_thread, scroll_stack, 280 create_thread(scroll_thread, scroll_stack,
281 sizeof(scroll_stack), scroll_name); 281 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
282} 282}
283 283
284/*** Update functions ***/ 284/*** Update functions ***/
diff --git a/firmware/drivers/lcd-remote-2bit-vi.c b/firmware/drivers/lcd-remote-2bit-vi.c
index 48f8b8a25f..bae2824050 100755
--- a/firmware/drivers/lcd-remote-2bit-vi.c
+++ b/firmware/drivers/lcd-remote-2bit-vi.c
@@ -1167,7 +1167,7 @@ static void scroll_thread(void)
1167void lcd_remote_init(void) 1167void lcd_remote_init(void)
1168{ 1168{
1169 create_thread(scroll_thread, scroll_stack, 1169 create_thread(scroll_thread, scroll_stack,
1170 sizeof(scroll_stack), scroll_name); 1170 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
1171} 1171}
1172#else 1172#else
1173void lcd_remote_init(void) 1173void lcd_remote_init(void)
@@ -1176,9 +1176,10 @@ void lcd_remote_init(void)
1176 lcd_remote_init_device(); 1176 lcd_remote_init_device();
1177 1177
1178 lcd_remote_clear_display(); 1178 lcd_remote_clear_display();
1179 queue_clear(&remote_scroll_queue); /* no queue_init() -- private queue */ 1179 /* private queue */
1180 queue_init(&remote_scroll_queue, false);
1180 tick_add_task(remote_tick); 1181 tick_add_task(remote_tick);
1181 create_thread(scroll_thread, scroll_stack, 1182 create_thread(scroll_thread, scroll_stack,
1182 sizeof(scroll_stack), scroll_name); 1183 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
1183} 1184}
1184#endif 1185#endif
diff --git a/firmware/export/config.h b/firmware/export/config.h
index 18adaeeca2..1b756cc6bd 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -216,8 +216,12 @@
216/* Enable the directory cache and tagcache in RAM if we have 216/* Enable the directory cache and tagcache in RAM if we have
217 * plenty of RAM. Both features can be enabled independently. */ 217 * plenty of RAM. Both features can be enabled independently. */
218#if (MEMORYSIZE > 8 || MEM > 8) && !defined(BOOTLOADER) 218#if (MEMORYSIZE > 8 || MEM > 8) && !defined(BOOTLOADER)
219#define HAVE_DIRCACHE 1 219#define HAVE_DIRCACHE
220#define HAVE_TC_RAMCACHE 1 220#define HAVE_TC_RAMCACHE
221#endif
222
223#if (CONFIG_CODEC == SWCODEC) && !defined(SIMULATOR) && !defined(BOOTLOADER)
224#define HAVE_PRIORITY_SCHEDULING
221#endif 225#endif
222 226
223/* define for all cpus from coldfire family */ 227/* define for all cpus from coldfire family */
diff --git a/firmware/export/kernel.h b/firmware/export/kernel.h
index 26b1cbe2e7..482516b9dc 100644
--- a/firmware/export/kernel.h
+++ b/firmware/export/kernel.h
@@ -56,12 +56,14 @@ struct event
56struct event_queue 56struct event_queue
57{ 57{
58 struct event events[QUEUE_LENGTH]; 58 struct event events[QUEUE_LENGTH];
59 struct thread_entry *thread;
59 unsigned int read; 60 unsigned int read;
60 unsigned int write; 61 unsigned int write;
61}; 62};
62 63
63struct mutex 64struct mutex
64{ 65{
66 struct thread_entry *thread;
65 bool locked; 67 bool locked;
66}; 68};
67 69
@@ -85,7 +87,7 @@ extern void sleep(int ticks);
85int tick_add_task(void (*f)(void)); 87int tick_add_task(void (*f)(void));
86int tick_remove_task(void (*f)(void)); 88int tick_remove_task(void (*f)(void));
87 89
88extern void queue_init(struct event_queue *q); 90extern void queue_init(struct event_queue *q, bool register_queue);
89extern void queue_delete(struct event_queue *q); 91extern void queue_delete(struct event_queue *q);
90extern void queue_wait(struct event_queue *q, struct event *ev); 92extern void queue_wait(struct event_queue *q, struct event *ev);
91extern void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks); 93extern void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks);
diff --git a/firmware/export/thread.h b/firmware/export/thread.h
index e102997dae..7e053bc507 100644
--- a/firmware/export/thread.h
+++ b/firmware/export/thread.h
@@ -21,8 +21,24 @@
21 21
22#include <stdbool.h> 22#include <stdbool.h>
23 23
24/* Priority scheduling (when enabled with HAVE_PRIORITY_SCHEDULING) works
25 * by giving high priority threads more CPU time than less priority threads
26 * when they need it.
27 *
28 * If software playback codec pcm buffer is going down to critical, codec
29 * can change it own priority to REALTIME to override user interface and
30 * prevent playback skipping.
31 */
32#define PRIORITY_REALTIME 1
33#define PRIORITY_USER_INTERFACE 4 /* The main thread */
34#define PRIORITY_RECORDING 4 /* Recording thread */
35#define PRIORITY_PLAYBACK 4 /* or REALTIME when needed */
36#define PRIORITY_BUFFERING 4 /* Codec buffering thread */
37#define PRIORITY_SYSTEM 6 /* All other firmware threads */
38#define PRIORITY_BACKGROUND 8 /* Normal application threads */
39
24#if CONFIG_CODEC == SWCODEC 40#if CONFIG_CODEC == SWCODEC
25#define MAXTHREADS 16 41#define MAXTHREADS 15
26#else 42#else
27#define MAXTHREADS 11 43#define MAXTHREADS 11
28#endif 44#endif
@@ -32,7 +48,7 @@
32#ifndef SIMULATOR 48#ifndef SIMULATOR
33/* Need to keep structures inside the header file because debug_menu 49/* Need to keep structures inside the header file because debug_menu
34 * needs them. */ 50 * needs them. */
35#ifdef CPU_COLDFIRE 51# ifdef CPU_COLDFIRE
36struct regs 52struct regs
37{ 53{
38 unsigned int macsr; /* EMAC status register */ 54 unsigned int macsr; /* EMAC status register */
@@ -41,7 +57,7 @@ struct regs
41 void *sp; /* Stack pointer (a7) */ 57 void *sp; /* Stack pointer (a7) */
42 void *start; /* Thread start address, or NULL when started */ 58 void *start; /* Thread start address, or NULL when started */
43}; 59};
44#elif CONFIG_CPU == SH7034 60# elif CONFIG_CPU == SH7034
45struct regs 61struct regs
46{ 62{
47 unsigned int r[7]; /* Registers r8 thru r14 */ 63 unsigned int r[7]; /* Registers r8 thru r14 */
@@ -49,7 +65,7 @@ struct regs
49 void *pr; /* Procedure register */ 65 void *pr; /* Procedure register */
50 void *start; /* Thread start address, or NULL when started */ 66 void *start; /* Thread start address, or NULL when started */
51}; 67};
52#elif defined(CPU_ARM) 68# elif defined(CPU_ARM)
53struct regs 69struct regs
54{ 70{
55 unsigned int r[8]; /* Registers r4-r11 */ 71 unsigned int r[8]; /* Registers r4-r11 */
@@ -57,42 +73,72 @@ struct regs
57 unsigned int lr; /* r14 (lr) */ 73 unsigned int lr; /* r14 (lr) */
58 void *start; /* Thread start address, or NULL when started */ 74 void *start; /* Thread start address, or NULL when started */
59}; 75};
60#elif CONFIG_CPU == TCC730 76# elif CONFIG_CPU == TCC730
61struct regs 77struct regs
62{ 78{
63 void *sp; /* Stack pointer (a15) */ 79 void *sp; /* Stack pointer (a15) */
64 void *start; /* Thread start address */ 80 void *start; /* Thread start address */
65 int started; /* 0 when not started */ 81 int started; /* 0 when not started */
66}; 82};
67#endif 83# endif
84
85#endif /* !SIMULATOR */
86
87#define STATE_RUNNING 0
88#define STATE_BLOCKED 1
89#define STATE_SLEEPING 2
90#define STATE_BLOCKED_W_TMO 3
91
92#define GET_STATE_ARG(state) (state & 0x3FFFFFFF)
93#define GET_STATE(state) ((state >> 30) & 3)
94#define SET_STATE(state,arg) ((state << 30) | (arg))
68 95
69struct thread_entry { 96struct thread_entry {
97#ifndef SIMULATOR
70 struct regs context; 98 struct regs context;
99#endif
71 const char *name; 100 const char *name;
72 void *stack; 101 void *stack;
73 int stack_size; 102 unsigned long statearg;
103 unsigned short stack_size;
104#ifdef HAVE_PRIORITY_SCHEDULING
105 unsigned short priority;
106 long last_run;
107#endif
108 struct thread_entry *next, *prev;
74}; 109};
75 110
76struct core_entry { 111struct core_entry {
77 int num_threads;
78 volatile int num_sleepers;
79 int current_thread;
80 struct thread_entry threads[MAXTHREADS]; 112 struct thread_entry threads[MAXTHREADS];
113 struct thread_entry *running;
114 struct thread_entry *sleeping;
81}; 115};
116
117#ifdef HAVE_PRIORITY_SCHEDULING
118#define IF_PRIO(empty, type) , type
119#else
120#define IF_PRIO(empty, type)
82#endif 121#endif
83 122
84int create_thread(void (*function)(void), void* stack, int stack_size, 123struct thread_entry*
85 const char *name); 124 create_thread(void (*function)(void), void* stack, int stack_size,
86int create_thread_on_core(unsigned int core, void (*function)(void), void* stack, int stack_size, 125 const char *name IF_PRIO(, int priority));
87 const char *name); 126
88void remove_thread(int threadnum); 127struct thread_entry*
89void remove_thread_on_core(unsigned int core, int threadnum); 128 create_thread_on_core(unsigned int core, void (*function)(void),
90void switch_thread(void); 129 void* stack, int stack_size,
91void sleep_thread(void); 130 const char *name
92void wake_up_thread(void); 131 IF_PRIO(, int priority));
132
133void remove_thread(struct thread_entry *thread);
134void switch_thread(bool save_context, struct thread_entry **blocked_list);
135void sleep_thread(int ticks);
136void block_thread(struct thread_entry **thread, int timeout);
137void wakeup_thread(struct thread_entry **thread);
138void thread_set_priority(struct thread_entry *thread, int priority);
93void init_threads(void); 139void init_threads(void);
94int thread_stack_usage(int threadnum); 140int thread_stack_usage(const struct thread_entry *thread);
95int thread_stack_usage_on_core(unsigned int core, int threadnum); 141int thread_get_status(const struct thread_entry *thread);
96#ifdef RB_PROFILE 142#ifdef RB_PROFILE
97void profile_thread(void); 143void profile_thread(void);
98#endif 144#endif
diff --git a/firmware/kernel.c b/firmware/kernel.c
index 889f950252..4a6d61515a 100644
--- a/firmware/kernel.c
+++ b/firmware/kernel.c
@@ -35,7 +35,6 @@ static void (*tick_funcs[MAX_NUM_TICK_TASKS])(void);
35static struct event_queue *all_queues[32]; 35static struct event_queue *all_queues[32];
36static int num_queues; 36static int num_queues;
37 37
38void sleep(int ticks) ICODE_ATTR;
39void queue_wait(struct event_queue *q, struct event *ev) ICODE_ATTR; 38void queue_wait(struct event_queue *q, struct event *ev) ICODE_ATTR;
40 39
41/**************************************************************************** 40/****************************************************************************
@@ -71,13 +70,7 @@ void sleep(int ticks)
71 } while(counter > 0); 70 } while(counter > 0);
72 71
73#else 72#else
74 /* Always sleep at least 1 tick */ 73 sleep_thread(ticks);
75 int timeout = current_tick + ticks + 1;
76
77 while (TIME_BEFORE( current_tick, timeout )) {
78 sleep_thread();
79 }
80 wake_up_thread();
81#endif 74#endif
82} 75}
83 76
@@ -86,21 +79,24 @@ void yield(void)
86#if (CONFIG_CPU == S3C2440 || defined(ELIO_TPJ1022) && defined(BOOTLOADER)) 79#if (CONFIG_CPU == S3C2440 || defined(ELIO_TPJ1022) && defined(BOOTLOADER))
87 /* Some targets don't like yielding in the bootloader */ 80 /* Some targets don't like yielding in the bootloader */
88#else 81#else
89 switch_thread(); 82 switch_thread(true, NULL);
90 wake_up_thread();
91#endif 83#endif
92} 84}
93 85
94/**************************************************************************** 86/****************************************************************************
95 * Queue handling stuff 87 * Queue handling stuff
96 ****************************************************************************/ 88 ****************************************************************************/
97void queue_init(struct event_queue *q) 89void queue_init(struct event_queue *q, bool register_queue)
98{ 90{
99 q->read = 0; 91 q->read = 0;
100 q->write = 0; 92 q->write = 0;
101 93 q->thread = NULL;
102 /* Add it to the all_queues array */ 94
103 all_queues[num_queues++] = q; 95 if (register_queue)
96 {
97 /* Add it to the all_queues array */
98 all_queues[num_queues++] = q;
99 }
104} 100}
105 101
106void queue_delete(struct event_queue *q) 102void queue_delete(struct event_queue *q)
@@ -108,6 +104,8 @@ void queue_delete(struct event_queue *q)
108 int i; 104 int i;
109 bool found = false; 105 bool found = false;
110 106
107 wakeup_thread(&q->thread);
108
111 /* Find the queue to be deleted */ 109 /* Find the queue to be deleted */
112 for(i = 0;i < num_queues;i++) 110 for(i = 0;i < num_queues;i++)
113 { 111 {
@@ -132,26 +130,22 @@ void queue_delete(struct event_queue *q)
132 130
133void queue_wait(struct event_queue *q, struct event *ev) 131void queue_wait(struct event_queue *q, struct event *ev)
134{ 132{
135 while(q->read == q->write) 133 if (q->read == q->write)
136 { 134 {
137 sleep_thread(); 135 block_thread(&q->thread, 0);
138 } 136 }
139 wake_up_thread();
140 137
141 *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK]; 138 *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK];
142} 139}
143 140
144void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks) 141void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks)
145{ 142{
146 unsigned int timeout = current_tick + ticks; 143 if (q->read == q->write && ticks > 0)
147
148 while(q->read == q->write && TIME_BEFORE( current_tick, timeout ))
149 { 144 {
150 sleep_thread(); 145 block_thread(&q->thread, ticks);
151 } 146 }
152 wake_up_thread();
153 147
154 if(q->read != q->write) 148 if (q->read != q->write)
155 { 149 {
156 *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK]; 150 *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK];
157 } 151 }
@@ -171,6 +165,9 @@ void queue_post(struct event_queue *q, long id, void *data)
171 165
172 q->events[wr].id = id; 166 q->events[wr].id = id;
173 q->events[wr].data = data; 167 q->events[wr].data = data;
168
169 wakeup_thread(&q->thread);
170
174 set_irq_level(oldlevel); 171 set_irq_level(oldlevel);
175} 172}
176 173
@@ -250,7 +247,6 @@ void IMIA0(void)
250 } 247 }
251 248
252 current_tick++; 249 current_tick++;
253 wake_up_thread();
254 250
255 TSR0 &= ~0x01; 251 TSR0 &= ~0x01;
256} 252}
@@ -301,7 +297,6 @@ void TIMER0(void)
301 } 297 }
302 298
303 current_tick++; 299 current_tick++;
304 wake_up_thread();
305 300
306 TER0 = 0xff; /* Clear all events */ 301 TER0 = 0xff; /* Clear all events */
307} 302}
@@ -330,7 +325,6 @@ void TIMER0(void)
330 } 325 }
331 326
332 current_tick++; 327 current_tick++;
333 wake_up_thread();
334 328
335 /* re-enable timer by clearing the counter */ 329 /* re-enable timer by clearing the counter */
336 TACON |= 0x80; 330 TACON |= 0x80;
@@ -382,7 +376,6 @@ void TIMER1(void)
382 } 376 }
383 377
384 current_tick++; 378 current_tick++;
385 wake_up_thread();
386} 379}
387#endif 380#endif
388 381
@@ -415,7 +408,6 @@ void timer_handler(void)
415 } 408 }
416 409
417 current_tick++; 410 current_tick++;
418 wake_up_thread();
419 411
420 TIMERR0C = 1; 412 TIMERR0C = 1;
421} 413}
@@ -513,22 +505,27 @@ int tick_remove_task(void (*f)(void))
513void mutex_init(struct mutex *m) 505void mutex_init(struct mutex *m)
514{ 506{
515 m->locked = false; 507 m->locked = false;
508 m->thread = NULL;
516} 509}
517 510
518void mutex_lock(struct mutex *m) 511void mutex_lock(struct mutex *m)
519{ 512{
520 /* Wait until the lock is open... */ 513 if (m->locked)
521 while(m->locked) 514 {
522 sleep_thread(); 515 /* Wait until the lock is open... */
523 wake_up_thread(); 516 block_thread(&m->thread, 0);
524 517 }
518
525 /* ...and lock it */ 519 /* ...and lock it */
526 m->locked = true; 520 m->locked = true;
527} 521}
528 522
529void mutex_unlock(struct mutex *m) 523void mutex_unlock(struct mutex *m)
530{ 524{
531 m->locked = false; 525 if (m->thread == NULL)
526 m->locked = false;
527 else
528 wakeup_thread(&m->thread);
532} 529}
533 530
534#endif 531#endif
diff --git a/firmware/mpeg.c b/firmware/mpeg.c
index df0cbbad12..61b0a22d87 100644
--- a/firmware/mpeg.c
+++ b/firmware/mpeg.c
@@ -761,7 +761,6 @@ void rec_tick(void)
761 { 761 {
762 prerecord_timeout = current_tick + HZ; 762 prerecord_timeout = current_tick + HZ;
763 queue_post(&mpeg_queue, MPEG_PRERECORDING_TICK, 0); 763 queue_post(&mpeg_queue, MPEG_PRERECORDING_TICK, 0);
764 wake_up_thread();
765 } 764 }
766 } 765 }
767 else 766 else
@@ -773,7 +772,6 @@ void rec_tick(void)
773 { 772 {
774 saving_status = BUFFER_FULL; 773 saving_status = BUFFER_FULL;
775 queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); 774 queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
776 wake_up_thread();
777 } 775 }
778 } 776 }
779 } 777 }
@@ -894,8 +892,6 @@ static void transfer_end(unsigned char** ppbuf, int* psize)
894 *psize = 0; /* no more transfer */ 892 *psize = 0; /* no more transfer */
895 } 893 }
896 } 894 }
897
898 wake_up_thread();
899} 895}
900 896
901static struct trackdata *add_track_to_tag_list(const char *filename) 897static struct trackdata *add_track_to_tag_list(const char *filename)
@@ -2119,8 +2115,7 @@ void audio_init_playback(void)
2119 queue_post(&mpeg_queue, MPEG_INIT_PLAYBACK, NULL); 2115 queue_post(&mpeg_queue, MPEG_INIT_PLAYBACK, NULL);
2120 2116
2121 while(!init_playback_done) 2117 while(!init_playback_done)
2122 sleep_thread(); 2118 sleep_thread(1);
2123 wake_up_thread();
2124} 2119}
2125 2120
2126 2121
@@ -2134,8 +2129,7 @@ void audio_init_recording(unsigned int buffer_offset)
2134 queue_post(&mpeg_queue, MPEG_INIT_RECORDING, NULL); 2129 queue_post(&mpeg_queue, MPEG_INIT_RECORDING, NULL);
2135 2130
2136 while(!init_recording_done) 2131 while(!init_recording_done)
2137 sleep_thread(); 2132 sleep_thread(1);
2138 wake_up_thread();
2139} 2133}
2140 2134
2141static void init_recording(void) 2135static void init_recording(void)
@@ -2886,10 +2880,10 @@ void audio_init(void)
2886 2880
2887#ifndef SIMULATOR 2881#ifndef SIMULATOR
2888 audiobuflen = audiobufend - audiobuf; 2882 audiobuflen = audiobufend - audiobuf;
2889 queue_init(&mpeg_queue); 2883 queue_init(&mpeg_queue, true);
2890#endif /* !SIMULATOR */ 2884#endif /* !SIMULATOR */
2891 create_thread(mpeg_thread, mpeg_stack, 2885 create_thread(mpeg_thread, mpeg_stack,
2892 sizeof(mpeg_stack), mpeg_thread_name); 2886 sizeof(mpeg_stack), mpeg_thread_name IF_PRIO(, PRIORITY_SYSTEM));
2893 2887
2894 memset(trackdata, sizeof(trackdata), 0); 2888 memset(trackdata, sizeof(trackdata), 0);
2895 2889
diff --git a/firmware/pcm_record.c b/firmware/pcm_record.c
index 68fc22b937..bce6fb5f25 100644
--- a/firmware/pcm_record.c
+++ b/firmware/pcm_record.c
@@ -172,9 +172,9 @@ static void close_wave(void);
172/* Creates pcmrec_thread */ 172/* Creates pcmrec_thread */
173void pcm_rec_init(void) 173void pcm_rec_init(void)
174{ 174{
175 queue_init(&pcmrec_queue); 175 queue_init(&pcmrec_queue, true);
176 create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), 176 create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack),
177 pcmrec_thread_name); 177 pcmrec_thread_name IF_PRIO(, PRIORITY_RECORDING));
178} 178}
179 179
180 180
@@ -196,8 +196,7 @@ void audio_init_recording(unsigned int buffer_offset)
196 queue_post(&pcmrec_queue, PCMREC_INIT, 0); 196 queue_post(&pcmrec_queue, PCMREC_INIT, 0);
197 197
198 while(!init_done) 198 while(!init_done)
199 sleep_thread(); 199 sleep_thread(1);
200 wake_up_thread();
201} 200}
202 201
203void audio_close_recording(void) 202void audio_close_recording(void)
@@ -206,8 +205,7 @@ void audio_close_recording(void)
206 queue_post(&pcmrec_queue, PCMREC_CLOSE, 0); 205 queue_post(&pcmrec_queue, PCMREC_CLOSE, 0);
207 206
208 while(!close_done) 207 while(!close_done)
209 sleep_thread(); 208 sleep_thread(1);
210 wake_up_thread();
211 209
212 audio_remove_encoder(); 210 audio_remove_encoder();
213} 211}
@@ -421,8 +419,7 @@ void audio_record(const char *filename)
421 queue_post(&pcmrec_queue, PCMREC_START, 0); 419 queue_post(&pcmrec_queue, PCMREC_START, 0);
422 420
423 while(!record_done) 421 while(!record_done)
424 sleep_thread(); 422 sleep_thread(1);
425 wake_up_thread();
426} 423}
427 424
428 425
@@ -438,8 +435,7 @@ void audio_new_file(const char *filename)
438 queue_post(&pcmrec_queue, PCMREC_NEW_FILE, 0); 435 queue_post(&pcmrec_queue, PCMREC_NEW_FILE, 0);
439 436
440 while(!new_file_done) 437 while(!new_file_done)
441 sleep_thread(); 438 sleep_thread(1);
442 wake_up_thread();
443 439
444 logf("pcm_new_file done"); 440 logf("pcm_new_file done");
445} 441}
@@ -459,8 +455,7 @@ void audio_stop_recording(void)
459 queue_post(&pcmrec_queue, PCMREC_STOP, 0); 455 queue_post(&pcmrec_queue, PCMREC_STOP, 0);
460 456
461 while(!stop_done) 457 while(!stop_done)
462 sleep_thread(); 458 sleep_thread(1);
463 wake_up_thread();
464 459
465 logf("pcm_stop done"); 460 logf("pcm_stop done");
466} 461}
@@ -482,8 +477,7 @@ void audio_pause_recording(void)
482 queue_post(&pcmrec_queue, PCMREC_PAUSE, 0); 477 queue_post(&pcmrec_queue, PCMREC_PAUSE, 0);
483 478
484 while(!pause_done) 479 while(!pause_done)
485 sleep_thread(); 480 sleep_thread(1);
486 wake_up_thread();
487} 481}
488 482
489void audio_resume_recording(void) 483void audio_resume_recording(void)
@@ -498,8 +492,7 @@ void audio_resume_recording(void)
498 queue_post(&pcmrec_queue, PCMREC_RESUME, 0); 492 queue_post(&pcmrec_queue, PCMREC_RESUME, 0);
499 493
500 while(!resume_done) 494 while(!resume_done)
501 sleep_thread(); 495 sleep_thread(1);
502 wake_up_thread();
503} 496}
504 497
505/* return peaks as int, so convert from short first 498/* return peaks as int, so convert from short first
@@ -817,9 +810,8 @@ static void pcmrec_stop(void)
817 /* wait for encoding finish */ 810 /* wait for encoding finish */
818 is_paused = true; 811 is_paused = true;
819 while(!wav_queue_empty) 812 while(!wav_queue_empty)
820 sleep_thread(); 813 sleep_thread(1);
821 814
822 wake_up_thread();
823 is_recording = false; 815 is_recording = false;
824 816
825 /* Flush buffers to file */ 817 /* Flush buffers to file */
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c
index 8f832964b5..f1e1aac57f 100644
--- a/firmware/powermgmt.c
+++ b/firmware/powermgmt.c
@@ -998,7 +998,7 @@ void powermgmt_init(void)
998 memset(power_history, 0x00, sizeof(power_history)); 998 memset(power_history, 0x00, sizeof(power_history));
999 999
1000 create_thread(power_thread, power_stack, sizeof(power_stack), 1000 create_thread(power_thread, power_stack, sizeof(power_stack),
1001 power_thread_name); 1001 power_thread_name IF_PRIO(, PRIORITY_SYSTEM));
1002} 1002}
1003 1003
1004#endif /* SIMULATOR */ 1004#endif /* SIMULATOR */
diff --git a/firmware/thread.c b/firmware/thread.c
index eb39c7ad32..e4dcbbcf9a 100644
--- a/firmware/thread.c
+++ b/firmware/thread.c
@@ -23,12 +23,18 @@
23#include "system.h" 23#include "system.h"
24#include "kernel.h" 24#include "kernel.h"
25#include "cpu.h" 25#include "cpu.h"
26 26#include "string.h"
27 27
28#define DEADBEEF ((unsigned int)0xdeadbeef) 28#define DEADBEEF ((unsigned int)0xdeadbeef)
29/* Cast to the the machine int type, whose size could be < 4. */ 29/* Cast to the the machine int type, whose size could be < 4. */
30 30
31struct core_entry cores[NUM_CORES] IBSS_ATTR; 31struct core_entry cores[NUM_CORES] IBSS_ATTR;
32#ifdef HAVE_PRIORITY_SCHEDULING
33static unsigned short highest_priority IBSS_ATTR;
34#endif
35
36/* Define to enable additional checks for blocking violations etc. */
37// #define THREAD_EXTRA_CHECKS
32 38
33static const char main_thread_name[] = "main"; 39static const char main_thread_name[] = "main";
34 40
@@ -48,7 +54,16 @@ int *cop_stackend = stackend;
48#endif 54#endif
49#endif 55#endif
50 56
51void switch_thread(void) ICODE_ATTR; 57/* Conserve IRAM
58static void add_to_list(struct thread_entry **list,
59 struct thread_entry *thread) ICODE_ATTR;
60static void remove_from_list(struct thread_entry **list,
61 struct thread_entry *thread) ICODE_ATTR;
62*/
63
64void switch_thread(bool save_context, struct thread_entry **blocked_list)
65 ICODE_ATTR;
66
52static inline void store_context(void* addr) __attribute__ ((always_inline)); 67static inline void store_context(void* addr) __attribute__ ((always_inline));
53static inline void load_context(const void* addr) __attribute__ ((always_inline)); 68static inline void load_context(const void* addr) __attribute__ ((always_inline));
54 69
@@ -219,24 +234,109 @@ static inline void load_context(const void* addr)
219 234
220#endif 235#endif
221 236
222/*--------------------------------------------------------------------------- 237static void add_to_list(struct thread_entry **list,
223 * Switch thread in round robin fashion. 238 struct thread_entry *thread)
224 *---------------------------------------------------------------------------
225 */
226void switch_thread(void)
227{ 239{
228#ifdef RB_PROFILE 240 if (*list == NULL)
229 profile_thread_stopped(cores[CURRENT_CORE].current_thread); 241 {
230#endif 242 thread->next = thread;
231 int current; 243 thread->prev = thread;
232 unsigned int *stackptr; 244 *list = thread;
245 }
246 else
247 {
248 /* Insert last */
249 thread->next = *list;
250 thread->prev = (*list)->prev;
251 thread->prev->next = thread;
252 (*list)->prev = thread;
253
254 /* Insert next
255 thread->next = (*list)->next;
256 thread->prev = *list;
257 thread->next->prev = thread;
258 (*list)->next = thread;
259 */
260 }
261}
233 262
234#ifdef SIMULATOR 263static void remove_from_list(struct thread_entry **list,
235 /* Do nothing */ 264 struct thread_entry *thread)
236#else 265{
237 while (cores[CURRENT_CORE].num_sleepers == cores[CURRENT_CORE].num_threads) 266 if (list != NULL)
267 {
268 if (thread == thread->next)
269 {
270 *list = NULL;
271 return;
272 }
273
274 if (thread == *list)
275 *list = thread->next;
276 }
277
278 /* Fix links to jump over the removed entry. */
279 thread->prev->next = thread->next;
280 thread->next->prev = thread->prev;
281}
282
283/* Compiler trick: Don't declare as static to prevent putting
284 * function in IRAM. */
285void check_sleepers(void)
286{
287 struct thread_entry *current, *next;
288
289 /* Check sleeping threads. */
290 current = cores[CURRENT_CORE].sleeping;
291 if (current == NULL)
292 return ;
293
294 for (;;)
295 {
296 next = current->next;
297
298 if ((unsigned)current_tick >= GET_STATE_ARG(current->statearg))
299 {
300 /* Sleep timeout has been reached so bring the thread
301 * back to life again. */
302 remove_from_list(&cores[CURRENT_CORE].sleeping, current);
303 add_to_list(&cores[CURRENT_CORE].running, current);
304
305 /* If there is no more processes in the list, break the loop. */
306 if (cores[CURRENT_CORE].sleeping == NULL)
307 break;
308
309 current = next;
310 continue;
311 }
312
313 current = next;
314
315 /* Break the loop once we have walked through the list of all
316 * sleeping processes. */
317 if (current == cores[CURRENT_CORE].sleeping)
318 break;
319 }
320}
321
322static inline void sleep_core(void)
323{
324 static long last_tick = 0;
325
326 for (;;)
238 { 327 {
239 /* Enter sleep mode, woken up on interrupt */ 328 if (last_tick != current_tick)
329 {
330 check_sleepers();
331 last_tick = current_tick;
332 }
333
334 /* We must sleep until there is at least one process in the list
335 * of running processes. */
336 if (cores[CURRENT_CORE].running != NULL)
337 break;
338
339 /* Enter sleep mode to reduce power usage, woken up on interrupt */
240#ifdef CPU_COLDFIRE 340#ifdef CPU_COLDFIRE
241 asm volatile ("stop #0x2000"); 341 asm volatile ("stop #0x2000");
242#elif CONFIG_CPU == SH7034 342#elif CONFIG_CPU == SH7034
@@ -257,49 +357,232 @@ void switch_thread(void)
257 CLKCON |= 2; 357 CLKCON |= 2;
258#endif 358#endif
259 } 359 }
260#endif 360}
261 current = cores[CURRENT_CORE].current_thread; 361
262 store_context(&cores[CURRENT_CORE].threads[current].context); 362#ifdef RB_PROFILE
263 363static int get_threadnum(struct thread_entry *thread)
264#if CONFIG_CPU != TCC730 364{
265 /* Check if the current thread stack is overflown */ 365 int i;
266 stackptr = cores[CURRENT_CORE].threads[current].stack; 366
267 if(stackptr[0] != DEADBEEF) 367 for (i = 0; i < MAXTHREADS; i++)
268 panicf("Stkov %s", cores[CURRENT_CORE].threads[current].name); 368 {
369 if (&cores[CURRENT_CORE].threads[i] == thread)
370 return i;
371 }
372
373 return -1;
374}
269#endif 375#endif
270 376
271 if (++current >= cores[CURRENT_CORE].num_threads) 377/* Compiler trick: Don't declare as static to prevent putting
272 current = 0; 378 * function in IRAM. */
379void change_thread_state(struct thread_entry **blocked_list)
380{
381 struct thread_entry *old;
382
383 /* Remove the thread from the list of running threads. */
384 old = cores[CURRENT_CORE].running;
385 remove_from_list(&cores[CURRENT_CORE].running, old);
386
387 /* And put the thread into a new list of inactive threads. */
388 if (GET_STATE(old->statearg) == STATE_BLOCKED)
389 add_to_list(blocked_list, old);
390 else
391 add_to_list(&cores[CURRENT_CORE].sleeping, old);
392
393#ifdef HAVE_PRIORITY_SCHEDULING
394 /* Reset priorities */
395 if (old->priority == highest_priority)
396 highest_priority = 100;
397#endif
398}
273 399
274 cores[CURRENT_CORE].current_thread = current; 400/*---------------------------------------------------------------------------
275 load_context(&cores[CURRENT_CORE].threads[current].context); 401 * Switch thread in round robin fashion.
402 *---------------------------------------------------------------------------
403 */
404void switch_thread(bool save_context, struct thread_entry **blocked_list)
405{
276#ifdef RB_PROFILE 406#ifdef RB_PROFILE
277 profile_thread_started(cores[CURRENT_CORE].current_thread); 407 profile_thread_stopped(get_threadnum(cores[CURRENT_CORE].running));
408#endif
409 unsigned int *stackptr;
410
411#ifdef SIMULATOR
412 /* Do nothing */
413#else
414
415 /* Begin task switching by saving our current context so that we can
416 * restore the state of the current thread later to the point prior
417 * to this call. */
418 if (save_context)
419 {
420 store_context(&cores[CURRENT_CORE].running->context);
421
422# if CONFIG_CPU != TCC730
423 /* Check if the current thread stack is overflown */
424 stackptr = cores[CURRENT_CORE].running->stack;
425 if(stackptr[0] != DEADBEEF)
426 panicf("Stkov %s", cores[CURRENT_CORE].running->name);
427# endif
428
429 /* Check if a thread state change has been requested. */
430 if (cores[CURRENT_CORE].running->statearg)
431 {
432 /* Change running thread state and switch to next thread. */
433 change_thread_state(blocked_list);
434 }
435 else
436 {
437 /* Switch to the next running thread. */
438 cores[CURRENT_CORE].running = cores[CURRENT_CORE].running->next;
439 }
440 }
441
442 /* Go through the list of sleeping task to check if we need to wake up
443 * any of them due to timeout. Also puts core into sleep state until
444 * there is at least one running process again. */
445 sleep_core();
446
447#ifdef HAVE_PRIORITY_SCHEDULING
448 /* Select the new task based on priorities and the last time a process
449 * got CPU time. */
450 for (;;)
451 {
452 int priority = cores[CURRENT_CORE].running->priority;
453
454 if (priority < highest_priority)
455 highest_priority = priority;
456
457 if (priority == highest_priority || (current_tick
458 - cores[CURRENT_CORE].running->last_run > priority * 8))
459 {
460 break;
461 }
462 cores[CURRENT_CORE].running = cores[CURRENT_CORE].running->next;
463 }
464
465 /* Reset the value of thread's last running time to the current time. */
466 cores[CURRENT_CORE].running->last_run = current_tick;
467#endif
468
469#endif
470 /* And finally give control to the next thread. */
471 load_context(&cores[CURRENT_CORE].running->context);
472
473#ifdef RB_PROFILE
474 profile_thread_started(get_threadnum(cores[CURRENT_CORE].running));
278#endif 475#endif
279} 476}
280 477
281void sleep_thread(void) 478void sleep_thread(int ticks)
282{ 479{
283 ++cores[CURRENT_CORE].num_sleepers; 480 /* Set the thread's new state and timeout and finally force a task switch
284 switch_thread(); 481 * so that scheduler removes thread from the list of running processes
482 * and puts it in list of sleeping tasks. */
483 cores[CURRENT_CORE].running->statearg =
484 SET_STATE(STATE_SLEEPING, current_tick + ticks + 1);
485 switch_thread(true, NULL);
486
487 /* Clear all flags to indicate we are up and running again. */
488 cores[CURRENT_CORE].running->statearg = 0;
285} 489}
286 490
287void wake_up_thread(void) 491void block_thread(struct thread_entry **list, int timeout)
288{ 492{
289 cores[CURRENT_CORE].num_sleepers = 0; 493 struct thread_entry *current;
494
495 /* Get the entry for the current running thread. */
496 current = cores[CURRENT_CORE].running;
497
498 /* At next task switch scheduler will immediately change the thread
499 * state (and we also force the task switch to happen). */
500 if (timeout)
501 {
502#ifdef THREAD_EXTRA_CHECKS
503 /* We can store only one thread to the "list" if thread is used
504 * in other list (such as core's list for sleeping tasks). */
505 if (*list)
506 panicf("Blocking violation T->*B");
507#endif
508
509 current->statearg =
510 SET_STATE(STATE_BLOCKED_W_TMO, current_tick + timeout);
511 *list = current;
512
513 /* Now force a task switch and block until we have been woken up
514 * by another thread or timeout is reached. */
515 switch_thread(true, NULL);
516
517 /* If timeout is reached, we must set list back to NULL here. */
518 *list = NULL;
519 }
520 else
521 {
522#ifdef THREAD_EXTRA_CHECKS
523 /* We are not allowed to mix blocking types in one queue. */
524 if (*list && GET_STATE((*list)->statearg) == STATE_BLOCKED_W_TMO)
525 panicf("Blocking violation B->*T");
526#endif
527
528 current->statearg = SET_STATE(STATE_BLOCKED, 0);
529
530 /* Now force a task switch and block until we have been woken up
531 * by another thread or timeout is reached. */
532 switch_thread(true, list);
533 }
534
535 /* Clear all flags to indicate we are up and running again. */
536 current->statearg = 0;
290} 537}
291 538
539void wakeup_thread(struct thread_entry **list)
540{
541 struct thread_entry *thread;
542
543 /* Check if there is a blocked thread at all. */
544 if (*list == NULL)
545 return ;
546
547 /* Wake up the last thread first. */
548 thread = *list;
549
550 /* Determine thread's current state. */
551 switch (GET_STATE(thread->statearg))
552 {
553 case STATE_BLOCKED:
554 /* Remove thread from the list of blocked threads and add it
555 * to the scheduler's list of running processes. */
556 remove_from_list(list, thread);
557 add_to_list(&cores[CURRENT_CORE].running, thread);
558 thread->statearg = 0;
559 break;
560
561 case STATE_BLOCKED_W_TMO:
562 /* Just remove the timeout to cause scheduler to immediately
563 * wake up the thread. */
564 thread->statearg &= 0xC0000000;
565 *list = NULL;
566 break;
567
568 default:
569 /* Nothing to do. Thread has already been woken up
570 * or it's state is not blocked or blocked with timeout. */
571 return ;
572 }
573}
292 574
293/*--------------------------------------------------------------------------- 575/*---------------------------------------------------------------------------
294 * Create thread on the current core. 576 * Create thread on the current core.
295 * Return ID if context area could be allocated, else -1. 577 * Return ID if context area could be allocated, else -1.
296 *--------------------------------------------------------------------------- 578 *---------------------------------------------------------------------------
297 */ 579 */
298int create_thread(void (*function)(void), void* stack, int stack_size, 580struct thread_entry*
299 const char *name) 581 create_thread(void (*function)(void), void* stack, int stack_size,
582 const char *name IF_PRIO(, int priority))
300{ 583{
301 return create_thread_on_core(CURRENT_CORE, function, stack, stack_size, 584 return create_thread_on_core(CURRENT_CORE, function, stack, stack_size,
302 name); 585 name IF_PRIO(, priority));
303} 586}
304 587
305/*--------------------------------------------------------------------------- 588/*---------------------------------------------------------------------------
@@ -307,18 +590,28 @@ int create_thread(void (*function)(void), void* stack, int stack_size,
307 * Return ID if context area could be allocated, else -1. 590 * Return ID if context area could be allocated, else -1.
308 *--------------------------------------------------------------------------- 591 *---------------------------------------------------------------------------
309 */ 592 */
310int create_thread_on_core(unsigned int core, void (*function)(void), void* stack, int stack_size, 593struct thread_entry*
311 const char *name) 594 create_thread_on_core(unsigned int core, void (*function)(void),
595 void* stack, int stack_size,
596 const char *name IF_PRIO(, int priority))
312{ 597{
313 unsigned int i; 598 unsigned int i;
314 unsigned int stacklen; 599 unsigned int stacklen;
315 unsigned int *stackptr; 600 unsigned int *stackptr;
601 int n;
316 struct regs *regs; 602 struct regs *regs;
317 struct thread_entry *thread; 603 struct thread_entry *thread;
318 604
319 if (cores[core].num_threads >= MAXTHREADS) 605 for (n = 0; n < MAXTHREADS; n++)
320 return -1; 606 {
321 607 if (cores[core].threads[n].name == NULL)
608 break;
609 }
610
611 if (n == MAXTHREADS)
612 return NULL;
613
614
322 /* Munge the stack to make it easy to spot stack overflows */ 615 /* Munge the stack to make it easy to spot stack overflows */
323 stacklen = stack_size / sizeof(int); 616 stacklen = stack_size / sizeof(int);
324 stackptr = stack; 617 stackptr = stack;
@@ -328,10 +621,17 @@ int create_thread_on_core(unsigned int core, void (*function)(void), void* stack
328 } 621 }
329 622
330 /* Store interesting information */ 623 /* Store interesting information */
331 thread = &cores[core].threads[cores[core].num_threads]; 624 thread = &cores[core].threads[n];
332 thread->name = name; 625 thread->name = name;
333 thread->stack = stack; 626 thread->stack = stack;
334 thread->stack_size = stack_size; 627 thread->stack_size = stack_size;
628 thread->statearg = 0;
629#ifdef HAVE_PRIORITY_SCHEDULING
630 thread->priority = priority;
631 highest_priority = 100;
632#endif
633 add_to_list(&cores[core].running, thread);
634
335 regs = &thread->context; 635 regs = &thread->context;
336#if defined(CPU_COLDFIRE) || (CONFIG_CPU == SH7034) || defined(CPU_ARM) 636#if defined(CPU_COLDFIRE) || (CONFIG_CPU == SH7034) || defined(CPU_ARM)
337 /* Align stack to an even 32 bit boundary */ 637 /* Align stack to an even 32 bit boundary */
@@ -343,8 +643,7 @@ int create_thread_on_core(unsigned int core, void (*function)(void), void* stack
343#endif 643#endif
344 regs->start = (void*)function; 644 regs->start = (void*)function;
345 645
346 wake_up_thread(); 646 return thread;
347 return cores[core].num_threads++; /* return the current ID, e.g for remove_thread() */
348} 647}
349 648
350/*--------------------------------------------------------------------------- 649/*---------------------------------------------------------------------------
@@ -352,44 +651,58 @@ int create_thread_on_core(unsigned int core, void (*function)(void), void* stack
352 * Parameter is the ID as returned from create_thread(). 651 * Parameter is the ID as returned from create_thread().
353 *--------------------------------------------------------------------------- 652 *---------------------------------------------------------------------------
354 */ 653 */
355void remove_thread(int threadnum) 654void remove_thread(struct thread_entry *thread)
356{ 655{
357 remove_thread_on_core(CURRENT_CORE, threadnum); 656 if (thread == NULL)
657 thread = cores[CURRENT_CORE].running;
658
659 /* Free the entry by removing thread name. */
660 thread->name = NULL;
661#ifdef HAVE_PRIORITY_SCHEDULING
662 highest_priority = 100;
663#endif
664
665 if (thread == cores[CURRENT_CORE].running)
666 {
667 remove_from_list(&cores[CURRENT_CORE].running, thread);
668 switch_thread(false, NULL);
669 return ;
670 }
671
672 if (thread == cores[CURRENT_CORE].sleeping)
673 remove_from_list(&cores[CURRENT_CORE].sleeping, thread);
674
675 remove_from_list(NULL, thread);
358} 676}
359 677
360/*--------------------------------------------------------------------------- 678#ifdef HAVE_PRIORITY_SCHEDULING
361 * Remove a thread on the specified core from the scheduler. 679void thread_set_priority(struct thread_entry *thread, int priority)
362 * Parameters are the core and the ID as returned from create_thread().
363 *---------------------------------------------------------------------------
364 */
365void remove_thread_on_core(unsigned int core, int threadnum)
366{ 680{
367 int i; 681 if (thread == NULL)
368 682 thread = cores[CURRENT_CORE].running;
369 if (threadnum >= cores[core].num_threads) 683
370 return; 684 thread->priority = priority;
371 685 highest_priority = 100;
372 cores[core].num_threads--;
373 for (i=threadnum; i<cores[core].num_threads-1; i++)
374 { /* move all entries which are behind */
375 cores[core].threads[i] = cores[core].threads[i+1];
376 }
377
378 if (cores[core].current_thread == threadnum) /* deleting the current one? */
379 cores[core].current_thread = cores[core].num_threads; /* set beyond last, avoid store harm */
380 else if (cores[core].current_thread > threadnum) /* within the moved positions? */
381 cores[core].current_thread--; /* adjust it, point to same context again */
382} 686}
687#endif
383 688
384void init_threads(void) 689void init_threads(void)
385{ 690{
386 unsigned int core = CURRENT_CORE; 691 unsigned int core = CURRENT_CORE;
387 692
388 cores[core].num_threads = 1; /* We have 1 thread to begin with */ 693 memset(cores, 0, sizeof cores);
389 cores[core].current_thread = 0; /* The current thread is number 0 */ 694 cores[core].sleeping = NULL;
695 cores[core].running = NULL;
390 cores[core].threads[0].name = main_thread_name; 696 cores[core].threads[0].name = main_thread_name;
391/* In multiple core setups, each core has a different stack. There is probably 697 cores[core].threads[0].statearg = 0;
392 a much better way to do this. */ 698#ifdef HAVE_PRIORITY_SCHEDULING
699 cores[core].threads[0].priority = PRIORITY_USER_INTERFACE;
700 highest_priority = 100;
701#endif
702 add_to_list(&cores[core].running, &cores[core].threads[0]);
703
704 /* In multiple core setups, each core has a different stack. There is probably
705 a much better way to do this. */
393 if (core == CPU) 706 if (core == CPU)
394 { 707 {
395 cores[CPU].threads[0].stack = stackbegin; 708 cores[CPU].threads[0].stack = stackbegin;
@@ -405,28 +718,24 @@ void init_threads(void)
405#else 718#else
406 cores[core].threads[0].context.start = 0; /* thread 0 already running */ 719 cores[core].threads[0].context.start = 0; /* thread 0 already running */
407#endif 720#endif
408 cores[core].num_sleepers = 0;
409}
410
411int thread_stack_usage(int threadnum)
412{
413 return thread_stack_usage_on_core(CURRENT_CORE, threadnum);
414} 721}
415 722
416int thread_stack_usage_on_core(unsigned int core, int threadnum) 723int thread_stack_usage(const struct thread_entry *thread)
417{ 724{
418 unsigned int i; 725 unsigned int i;
419 unsigned int *stackptr = cores[core].threads[threadnum].stack; 726 unsigned int *stackptr = thread->stack;
420
421 if (threadnum >= cores[core].num_threads)
422 return -1;
423 727
424 for (i = 0;i < cores[core].threads[threadnum].stack_size/sizeof(int);i++) 728 for (i = 0;i < thread->stack_size/sizeof(int);i++)
425 { 729 {
426 if (stackptr[i] != DEADBEEF) 730 if (stackptr[i] != DEADBEEF)
427 break; 731 break;
428 } 732 }
429 733
430 return ((cores[core].threads[threadnum].stack_size - i * sizeof(int)) * 100) / 734 return ((thread->stack_size - i * sizeof(int)) * 100) /
431 cores[core].threads[threadnum].stack_size; 735 thread->stack_size;
736}
737
738int thread_get_status(const struct thread_entry *thread)
739{
740 return GET_STATE(thread->statearg);
432} 741}
diff --git a/firmware/usb.c b/firmware/usb.c
index 6be5fda093..0be6c4011e 100644
--- a/firmware/usb.c
+++ b/firmware/usb.c
@@ -558,8 +558,9 @@ void usb_init(void)
558 last_usb_status = false; 558 last_usb_status = false;
559 559
560#ifndef BOOTLOADER 560#ifndef BOOTLOADER
561 queue_init(&usb_queue); 561 queue_init(&usb_queue, true);
562 create_thread(usb_thread, usb_stack, sizeof(usb_stack), usb_thread_name); 562 create_thread(usb_thread, usb_stack, sizeof(usb_stack),
563 usb_thread_name IF_PRIO(, PRIORITY_SYSTEM));
563 564
564 tick_add_task(usb_tick); 565 tick_add_task(usb_tick);
565#endif 566#endif
diff --git a/uisimulator/sdl/kernel.c b/uisimulator/sdl/kernel.c
index b9ffe0eefe..bfe6062450 100644
--- a/uisimulator/sdl/kernel.c
+++ b/uisimulator/sdl/kernel.c
@@ -32,8 +32,10 @@ int set_irq_level (int level)
32 return (_lv = level); 32 return (_lv = level);
33} 33}
34 34
35void queue_init(struct event_queue *q) 35void queue_init(struct event_queue *q, bool register_queue)
36{ 36{
37 (void)register_queue;
38
37 q->read = 0; 39 q->read = 0;
38 q->write = 0; 40 q->write = 0;
39} 41}
@@ -47,7 +49,7 @@ void queue_wait(struct event_queue *q, struct event *ev)
47{ 49{
48 while(q->read == q->write) 50 while(q->read == q->write)
49 { 51 {
50 switch_thread(); 52 switch_thread(true, NULL);
51 } 53 }
52 54
53 *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK]; 55 *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK];
@@ -97,8 +99,11 @@ void queue_clear(struct event_queue* q)
97 q->write = 0; 99 q->write = 0;
98} 100}
99 101
100void switch_thread (void) 102void switch_thread(bool save_context, struct thread_entry **blocked_list)
101{ 103{
104 (void)save_context;
105 (void)blocked_list;
106
102 yield (); 107 yield ();
103} 108}
104 109
@@ -160,7 +165,7 @@ void mutex_init(struct mutex *m)
160void mutex_lock(struct mutex *m) 165void mutex_lock(struct mutex *m)
161{ 166{
162 while(m->locked) 167 while(m->locked)
163 switch_thread(); 168 switch_thread(true, NULL);
164 m->locked = true; 169 m->locked = true;
165} 170}
166 171