summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 = {
&current_tick,
default_event_handler,
default_event_handler_ex,
- create_thread,
+ create_thread_on_core,
remove_thread,
reset_poweroff_timer,
#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 {
long* current_tick;
long (*default_event_handler)(long event);
long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter);
- int (*create_thread)(void (*function)(void), void* stack, int stack_size, const char *name);
- void (*remove_thread)(int threadnum);
+ struct thread_entry* (*create_thread)(unsigned int core, void (*function)(void),
+ void* stack, int stack_size, const char *name
+ IF_PRIO(, int priority));
+ void (*remove_thread)(struct thread_entry *thread);
void (*reset_poweroff_timer)(void);
#ifndef SIMULATOR
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;
extern int ata_io_address;
extern struct core_entry cores[NUM_CORES];
+char thread_status_char(int status)
+{
+ switch (status)
+ {
+ case STATE_RUNNING : return 'R';
+ case STATE_BLOCKED : return 'B';
+ case STATE_SLEEPING : return 'S';
+ case STATE_BLOCKED_W_TMO: return 'T';
+ }
+
+ return '?';
+}
#ifdef HAVE_LCD_BITMAP
/* Test code!!! */
bool dbg_os(void)
{
+ struct thread_entry *thread;
char buf[32];
int i;
int usage;
+ int status;
#if NUM_CORES > 1
unsigned int core;
int line;
@@ -98,24 +112,54 @@ bool dbg_os(void)
while(1)
{
+#if 0 /* Enable to simulate UI lag. */
+ int _x;
+ for (_x = 0; _x < 1000000L; _x++) ;
+#endif
#if NUM_CORES > 1
lcd_puts(0, 0, "Core and stack usage:");
line = 0;
for(core = 0; core < NUM_CORES; core++)
{
- for(i = 0; i < num_threads[core]; i++)
+ for(i = 0; i < MAXTHREADS; i++)
{
- usage = thread_stack_usage_on_core(core, i);
- snprintf(buf, 32, "(%d) %s: %d%%", core, thread_name[core][i], usage);
+ thread = &cores[core].threads[i];
+ if (thread->name == NULL)
+ continue;
+
+ usage = thread_stack_usage(thread);
+ status = thread_get_status(thread);
+
+ snprintf(buf, 32, "(%d) %c%c %d %s: %d%%", core,
+ (status == STATE_RUNNING) ? '*' : ' ',
+ thread_status_char(status),
+ cores[CURRENT_CORE].threads[i].priority,
+ cores[core].threads[i].name, usage);
lcd_puts(0, ++line, buf);
}
}
#else
lcd_puts(0, 0, "Stack usage:");
- for(i = 0; i < cores[CURRENT_CORE].num_threads;i++)
+ for(i = 0; i < MAXTHREADS; i++)
{
- usage = thread_stack_usage(i);
- snprintf(buf, 32, "%s: %d%%", cores[CURRENT_CORE].threads[i].name, usage);
+ thread = &cores[CURRENT_CORE].threads[i];
+ if (thread->name == NULL)
+ continue;
+
+ usage = thread_stack_usage(thread);
+ status = thread_get_status(thread);
+# ifdef HAVE_PRIORITY_SCHEDULING
+ snprintf(buf, 32, "%c%c %d %s: %d%%",
+ (status == STATE_RUNNING) ? '*' : ' ',
+ thread_status_char(status),
+ cores[CURRENT_CORE].threads[i].priority,
+ cores[CURRENT_CORE].threads[i].name, usage);
+# else
+ snprintf(buf, 32, "%c%c %s: %d%%",
+ (status == STATE_RUNNING) ? '*' : ' ',
+ (status == STATE_BLOCKED) ? 'B' : ' ',
+ cores[CURRENT_CORE].threads[i].name, usage);
+# endif
lcd_puts(0, 1+i, buf);
}
#endif
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 @@
#include "settings.h"
#include "audio.h"
#include "dsp.h"
+#include "thread.h"
-/* 1.5s low mark */
-#define PCMBUF_WATERMARK (NATIVE_FREQUENCY * 6)
+/* Keep watermark high for iPods at least (2s) */
+#define PCMBUF_WATERMARK (NATIVE_FREQUENCY * 8)
/* Structure we can use to queue pcm chunks in memory to be played
* by the driver code. */
@@ -94,6 +95,8 @@ static size_t pcmbuf_mix_sample IDATA_ATTR;
static bool low_latency_mode = false;
static bool pcmbuf_flush;
+extern struct thread_entry *codec_thread_p;
+
/* Helpful macros for use in conditionals this assumes some of the above
* static variable names */
#define NEED_FLUSH(position) \
@@ -109,14 +112,37 @@ static bool pcmbuf_flush_fillpos(void);
void pcmbuf_boost(bool state)
{
static bool boost_state = false;
-
+#ifdef HAVE_PRIORITY_SCHEDULING
+ static bool priority_modified = false;
+#endif
+
if (crossfade_init || crossfade_active)
return;
- if (state != boost_state) {
+ if (state != boost_state)
+ {
cpu_boost(state);
boost_state = state;
}
+
+#ifdef HAVE_PRIORITY_SCHEDULING
+ if (state && LOW_DATA(2) && pcm_is_playing())
+ {
+ if (!priority_modified)
+ {
+ /* Buffer is critically low so override UI priority. */
+ priority_modified = true;
+ thread_set_priority(codec_thread_p, PRIORITY_REALTIME);
+ }
+ }
+ else if (priority_modified)
+ {
+ /* Set back the original priority. */
+ thread_set_priority(codec_thread_p, PRIORITY_PLAYBACK);
+ priority_modified = false;
+ }
+
+#endif
}
#endif
@@ -244,7 +270,9 @@ static void pcmbuf_under_watermark(void)
pcmbuf_boost(true);
/* Disable crossfade if < .5s of audio */
if (LOW_DATA(2))
+ {
crossfade_active = false;
+ }
}
void pcmbuf_set_event_handler(void (*event_handler)(void))
@@ -270,8 +298,8 @@ bool pcmbuf_is_lowdata(void)
crossfade_init || crossfade_active)
return false;
- /* 0.5 seconds of buffer is low data */
- return LOW_DATA(2);
+ /* 1 seconds of buffer is low data */
+ return LOW_DATA(4);
}
/* Amount of bytes left in the buffer. */
@@ -443,7 +471,7 @@ static bool pcmbuf_flush_fillpos(void)
pcmbuf_play_start();
}
/* Let approximately one chunk of data playback */
- sleep(PCMBUF_TARGET_CHUNK/(NATIVE_FREQUENCY * 4) / 5);
+ sleep(HZ*PCMBUF_TARGET_CHUNK/(NATIVE_FREQUENCY*4));
}
pcmbuf_add_chunk();
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;
static size_t voice_remaining;
static bool voice_is_playing;
static void (*voice_getmore)(unsigned char** start, int* size);
-static int voice_thread_num = -1;
+static struct thread_entry *voice_thread_p = NULL;
/* Is file buffer currently being refilled? */
static volatile bool filling IDATA_ATTR;
@@ -267,6 +267,8 @@ static struct event_queue codec_queue;
static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
IBSS_ATTR;
static const char codec_thread_name[] = "codec";
+/* For modifying thread priority later. */
+struct thread_entry *codec_thread_p;
/* Voice thread */
static struct event_queue voice_queue;
@@ -628,13 +630,13 @@ void audio_preinit(void)
mutex_init(&mutex_codecthread);
- queue_init(&audio_queue);
- queue_init(&codec_queue);
- /* clear, not init to create a private queue */
- queue_clear(&codec_callback_queue);
+ queue_init(&audio_queue, true);
+ queue_init(&codec_queue, true);
+ /* create a private queue */
+ queue_init(&codec_callback_queue, false);
create_thread(audio_thread, audio_stack, sizeof(audio_stack),
- audio_thread_name);
+ audio_thread_name IF_PRIO(, PRIORITY_BUFFERING));
}
void audio_init(void)
@@ -648,14 +650,14 @@ void voice_init(void)
if (!filebuf)
return; /* Audio buffers not yet set up */
- if (voice_thread_num >= 0)
+ if (voice_thread_p)
{
logf("Terminating voice codec");
- remove_thread(voice_thread_num);
+ remove_thread(voice_thread_p);
if (current_codec == CODEC_IDX_VOICE)
mutex_unlock(&mutex_codecthread);
queue_delete(&voice_queue);
- voice_thread_num = -1;
+ voice_thread_p = NULL;
voice_codec_loaded = false;
}
@@ -663,9 +665,10 @@ void voice_init(void)
return;
logf("Starting voice codec");
- queue_init(&voice_queue);
- voice_thread_num = create_thread(voice_thread, voice_stack,
- sizeof(voice_stack), voice_thread_name);
+ queue_init(&voice_queue, true);
+ voice_thread_p = create_thread(voice_thread, voice_stack,
+ sizeof(voice_stack), voice_thread_name
+ IF_PRIO(, PRIORITY_PLAYBACK));
while (!voice_codec_loaded)
yield();
@@ -1740,7 +1743,7 @@ static void codec_thread(void)
#endif
#ifndef SIMULATOR
- case SYS_USB_CONNECTED:
+ case SYS_USB_CONNECTED:
LOGFQUEUE("codec < SYS_USB_CONNECTED");
queue_clear(&codec_queue);
usb_acknowledge(SYS_USB_CONNECTED_ACK);
@@ -1982,13 +1985,15 @@ static bool audio_yield_codecs(void)
{
yield();
- if (!queue_empty(&audio_queue)) return true;
+ if (!queue_empty(&audio_queue))
+ return true;
while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata())
&& !ci.stop_codec && playing && !audio_filebuf_is_lowdata())
{
sleep(1);
- if (!queue_empty(&audio_queue)) return true;
+ if (!queue_empty(&audio_queue))
+ return true;
}
return false;
@@ -3178,8 +3183,9 @@ static void audio_playback_init(void)
id3_voice.frequency = 11200;
id3_voice.length = 1000000L;
- create_thread(codec_thread, codec_stack, sizeof(codec_stack),
- codec_thread_name);
+ codec_thread_p = create_thread(codec_thread, codec_stack,
+ sizeof(codec_stack),
+ codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK));
while (1)
{
@@ -3213,7 +3219,8 @@ static void audio_thread(void)
/* At first initialize audio system in background. */
audio_playback_init();
- while (1) {
+ while (1)
+ {
if (filling)
{
queue_wait_w_tmo(&audio_queue, &ev, 0);
@@ -3221,7 +3228,7 @@ static void audio_thread(void)
ev.id = Q_AUDIO_FILL_BUFFER;
}
else
- queue_wait_w_tmo(&audio_queue, &ev, HZ);
+ queue_wait_w_tmo(&audio_queue, &ev, HZ/2);
switch (ev.id) {
case Q_AUDIO_FILL_BUFFER:
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)
memset(playlist->filenames, 0,
playlist->max_playlist_size * sizeof(int));
create_thread(playlist_thread, playlist_stack, sizeof(playlist_stack),
- playlist_thread_name);
- queue_init(&playlist_queue);
+ playlist_thread_name IF_PRIO(, PRIORITY_BACKGROUND));
+ queue_init(&playlist_queue, true);
#endif
}
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 = {
PREFIX(lcd_icon),
lcd_double_height,
#else
+ lcd_setmargins,
lcd_set_drawmode,
lcd_get_drawmode,
lcd_setfont,
@@ -132,6 +133,9 @@ static const struct plugin_api rockbox_api = {
lcd_bitmap_transparent_part,
lcd_bitmap_transparent,
#endif
+ bidi_l2v,
+ font_get_bits,
+ font_load,
lcd_putsxy,
lcd_puts_style,
lcd_puts_scroll_style,
@@ -178,6 +182,45 @@ static const struct plugin_api rockbox_api = {
remote_backlight_on,
remote_backlight_off,
#endif
+#if NB_SCREENS == 2
+ {&screens[SCREEN_MAIN], &screens[SCREEN_REMOTE]},
+#else
+ {&screens[SCREEN_MAIN]},
+#endif
+#if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
+ lcd_remote_set_foreground,
+ lcd_remote_get_foreground,
+ lcd_remote_set_background,
+ lcd_remote_get_background,
+ lcd_remote_bitmap_part,
+ lcd_remote_bitmap,
+#endif
+
+#if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR)
+ lcd_yuv_blit,
+#endif
+ /* list */
+ gui_synclist_init,
+ gui_synclist_set_nb_items,
+ gui_synclist_set_icon_callback,
+ gui_synclist_get_nb_items,
+ gui_synclist_get_sel_pos,
+ gui_synclist_draw,
+ gui_synclist_select_item,
+ gui_synclist_select_next,
+ gui_synclist_select_previous,
+ gui_synclist_select_next_page,
+ gui_synclist_select_previous_page,
+ gui_synclist_add_item,
+ gui_synclist_del_item,
+ gui_synclist_limit_scroll,
+ gui_synclist_flash,
+#ifdef HAVE_LCD_BITMAP
+ gui_synclist_scroll_right,
+ gui_synclist_scroll_left,
+#endif
+ gui_synclist_do_button,
+
/* button */
button_get,
button_get_w_tmo,
@@ -205,12 +248,14 @@ static const struct plugin_api rockbox_api = {
ata_sleep,
ata_disk_is_active,
#endif
+ reload_directory,
/* dir */
PREFIX(opendir),
PREFIX(closedir),
PREFIX(readdir),
PREFIX(mkdir),
+ PREFIX(rmdir),
/* kernel/ system */
PREFIX(sleep),
@@ -253,6 +298,7 @@ static const struct plugin_api rockbox_api = {
/* strings and memory */
snprintf,
+ vsnprintf,
strcpy,
strncpy,
strlen,
@@ -268,6 +314,7 @@ static const struct plugin_api rockbox_api = {
atoi,
strchr,
strcat,
+ memchr,
memcmp,
strcasestr,
/* unicode stuff */
@@ -277,9 +324,12 @@ static const struct plugin_api rockbox_api = {
utf16BEdecode,
utf8encode,
utf8length,
+ utf8seek,
/* sound */
sound_set,
+ set_sound,
+
sound_min,
sound_max,
#ifndef SIMULATOR
@@ -334,6 +384,9 @@ static const struct plugin_api rockbox_api = {
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
mas_codec_writereg,
mas_codec_readreg,
+ i2c_begin,
+ i2c_end,
+ i2c_write,
#endif
#endif /* !SIMULATOR && CONFIG_CODEC != SWCODEC */
@@ -352,7 +405,15 @@ static const struct plugin_api rockbox_api = {
menu_insert,
menu_set_cursor,
set_option,
+ set_int,
+ set_bool,
+ /* action handling */
+ get_custom_action,
+ get_action,
+ action_signalscreenchange,
+ action_userabort,
+
/* power */
battery_level,
battery_level_safe,
@@ -405,74 +466,6 @@ static const struct plugin_api rockbox_api = {
/* new stuff at the end, sort into place next time
the API gets incompatible */
- set_sound,
-#if ((CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)) && !defined(SIMULATOR)
- i2c_begin,
- i2c_end,
- i2c_write,
-#endif
-
- vsnprintf,
- memchr,
- /* list */
- gui_synclist_init,
- gui_synclist_set_nb_items,
- gui_synclist_set_icon_callback,
- gui_synclist_get_nb_items,
- gui_synclist_get_sel_pos,
- gui_synclist_draw,
- gui_synclist_select_item,
- gui_synclist_select_next,
- gui_synclist_select_previous,
- gui_synclist_select_next_page,
- gui_synclist_select_previous_page,
- gui_synclist_add_item,
- gui_synclist_del_item,
- gui_synclist_limit_scroll,
- gui_synclist_flash,
-#ifdef HAVE_LCD_BITMAP
- gui_synclist_scroll_right,
- gui_synclist_scroll_left,
-#endif
- gui_synclist_do_button,
-
-#ifdef HAVE_LCD_BITMAP
- lcd_setmargins,
-#endif
- utf8seek,
-
- set_int,
- reload_directory,
- set_bool,
-#if NB_SCREENS == 2
- {&screens[SCREEN_MAIN], &screens[SCREEN_REMOTE]},
-#else
- {&screens[SCREEN_MAIN]},
-#endif
-#ifdef HAVE_LCD_BITMAP
- bidi_l2v,
- font_get_bits,
- font_load,
-#endif
-#if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
- lcd_remote_set_foreground,
- lcd_remote_get_foreground,
- lcd_remote_set_background,
- lcd_remote_get_background,
- lcd_remote_bitmap_part,
- lcd_remote_bitmap,
-#endif
-
-#if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR)
- lcd_yuv_blit,
-#endif
-
- PREFIX(rmdir),
- /* action handling */
- get_custom_action,
- get_action,
- action_signalscreenchange,
- action_userabort,
};
int plugin_load(const char* plugin, void* parameter)
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 @@
#define PLUGIN_MAGIC 0x526F634B /* RocK */
/* increase this every time the api struct changes */
-#define PLUGIN_API_VERSION 29
+#define PLUGIN_API_VERSION 30
/* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any
new function which are "waiting" at the end of the function table) */
-#define PLUGIN_MIN_API_VERSION 14
+#define PLUGIN_MIN_API_VERSION 30
/* plugin return codes */
enum plugin_status {
@@ -143,6 +143,7 @@ struct plugin_api {
void (*PREFIX(lcd_icon))(int icon, bool enable);
void (*lcd_double_height)(bool on);
#else
+ void (*lcd_setmargins)(int x, int y);
void (*lcd_set_drawmode)(int mode);
int (*lcd_get_drawmode)(void);
void (*lcd_setfont)(int font);
@@ -174,6 +175,9 @@ struct plugin_api {
void (*lcd_bitmap_transparent)(const fb_data *src, int x, int y,
int width, int height);
#endif
+ unsigned short *(*bidi_l2v)( const unsigned char *str, int orientation );
+ const unsigned char *(*font_get_bits)( struct font *pf, unsigned short char_code );
+ struct font* (*font_load)(const char *path);
void (*lcd_putsxy)(int x, int y, const unsigned char *string);
void (*lcd_puts_style)(int x, int y, const unsigned char *str, int style);
void (*lcd_puts_scroll_style)(int x, int y, const unsigned char* string,
@@ -229,7 +233,50 @@ struct plugin_api {
void (*remote_backlight_on)(void);
void (*remote_backlight_off)(void);
#endif
+ struct screen* screens[NB_SCREENS];
+#if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
+ void (*lcd_remote_set_foreground)(unsigned foreground);
+ unsigned (*lcd_remote_get_foreground)(void);
+ void (*lcd_remote_set_background)(unsigned foreground);
+ unsigned (*lcd_remote_get_background)(void);
+ void (*lcd_remote_bitmap_part)(const fb_remote_data *src, int src_x, int src_y,
+ int stride, int x, int y, int width, int height);
+ void (*lcd_remote_bitmap)(const fb_remote_data *src, int x, int y, int width,
+ int height);
+#endif
+#if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR)
+ void (*lcd_yuv_blit)(unsigned char * const src[3],
+ int src_x, int src_y, int stride,
+ int x, int y, int width, int height);
+#endif
+ /* list */
+ void (*gui_synclist_init)(struct gui_synclist * lists,
+ list_get_name callback_get_item_name,void * data,
+ bool scroll_all,int selected_size);
+ void (*gui_synclist_set_nb_items)(struct gui_synclist * lists, int nb_items);
+ void (*gui_synclist_set_icon_callback)(struct gui_synclist * lists, list_get_icon icon_callback);
+ int (*gui_synclist_get_nb_items)(struct gui_synclist * lists);
+ int (*gui_synclist_get_sel_pos)(struct gui_synclist * lists);
+ void (*gui_synclist_draw)(struct gui_synclist * lists);
+ void (*gui_synclist_select_item)(struct gui_synclist * lists,
+ int item_number);
+ void (*gui_synclist_select_next)(struct gui_synclist * lists);
+ void (*gui_synclist_select_previous)(struct gui_synclist * lists);
+ void (*gui_synclist_select_next_page)(struct gui_synclist * lists,
+ enum screen_type screen);
+ void (*gui_synclist_select_previous_page)(struct gui_synclist * lists,
+ enum screen_type screen);
+ void (*gui_synclist_add_item)(struct gui_synclist * lists);
+ void (*gui_synclist_del_item)(struct gui_synclist * lists);
+ void (*gui_synclist_limit_scroll)(struct gui_synclist * lists, bool scroll);
+ void (*gui_synclist_flash)(struct gui_synclist * lists);
+#ifdef HAVE_LCD_BITMAP
+ void (*gui_synclist_scroll_right)(struct gui_synclist * lists);
+ void (*gui_synclist_scroll_left)(struct gui_synclist * lists);
+#endif
+ unsigned (*gui_synclist_do_button)(struct gui_synclist * lists, unsigned button);
+
/* button */
long (*button_get)(bool block);
long (*button_get_w_tmo)(int ticks);
@@ -257,12 +304,14 @@ struct plugin_api {
void (*ata_sleep)(void);
bool (*ata_disk_is_active)(void);
#endif
+ void (*reload_directory)(void);
/* dir */
DIR* (*PREFIX(opendir))(const char* name);
int (*PREFIX(closedir))(DIR* dir);
struct dirent* (*PREFIX(readdir))(DIR* dir);
int (*PREFIX(mkdir))(const char *name, int mode);
+ int (*PREFIX(rmdir))(const char *name);
/* kernel/ system */
void (*PREFIX(sleep))(int ticks);
@@ -270,8 +319,10 @@ struct plugin_api {
long* current_tick;
long (*default_event_handler)(long event);
long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter);
- int (*create_thread)(void (*function)(void), void* stack, int stack_size, const char *name);
- void (*remove_thread)(int threadnum);
+ struct thread_entry* (*create_thread)(void (*function)(void), void* stack,
+ int stack_size, const char *name
+ IF_PRIO(, int priority));
+ void (*remove_thread)(struct thread_entry *thread);
void (*reset_poweroff_timer)(void);
#ifndef SIMULATOR
int (*system_memory_guard)(int newmode);
@@ -285,7 +336,7 @@ struct plugin_api {
void (*timer_unregister)(void);
bool (*timer_set_period)(long count);
#endif
- void (*queue_init)(struct event_queue *q);
+ void (*queue_init)(struct event_queue *q, bool register_queue);
void (*queue_delete)(struct event_queue *q);
void (*queue_post)(struct event_queue *q, long id, void *data);
void (*queue_wait_w_tmo)(struct event_queue *q, struct event *ev,
@@ -308,6 +359,7 @@ struct plugin_api {
/* strings and memory */
int (*snprintf)(char *buf, size_t size, const char *fmt, ...);
+ int (*vsnprintf)(char *buf, int size, const char *fmt, va_list ap);
char* (*strcpy)(char *dst, const char *src);
char* (*strncpy)(char *dst, const char *src, size_t length);
size_t (*strlen)(const char *str);
@@ -323,6 +375,7 @@ struct plugin_api {
int (*atoi)(const char *str);
char *(*strchr)(const char *s, int c);
char *(*strcat)(char *s1, const char *s2);
+ void *(*memchr)(const void *s1, int c, size_t n);
int (*memcmp)(const void *s1, const void *s2, size_t n);
char *(*strcasestr) (const char* phaystack, const char* pneedle);
/* unicode stuff */
@@ -332,9 +385,12 @@ struct plugin_api {
unsigned char* (*utf16BEdecode)(const unsigned char *utf16, unsigned char *utf8, int count);
unsigned char* (*utf8encode)(unsigned long ucs, unsigned char *utf8);
unsigned long (*utf8length)(const unsigned char *utf8);
+ int (*utf8seek)(const unsigned char* utf8, int offset);
/* sound */
void (*sound_set)(int setting, int value);
+ bool (*set_sound)(const unsigned char * string,
+ int* variable, int setting);
int (*sound_min)(int setting);
int (*sound_max)(int setting);
#ifndef SIMULATOR
@@ -390,6 +446,9 @@ struct plugin_api {
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
int (*mas_codec_writereg)(int reg, unsigned int val);
int (*mas_codec_readreg)(int reg);
+ void (*i2c_begin)(void);
+ void (*i2c_end)(void);
+ int (*i2c_write)(int address, unsigned char* buf, int count );
#endif
#endif
@@ -413,7 +472,17 @@ struct plugin_api {
bool (*set_option)(const char* string, void* variable,
enum optiontype type, const struct opt_items* options,
int numoptions, void (*function)(int));
+ bool (*set_int)(const unsigned char* string, const char* unit, int voice_unit,
+ int* variable, void (*function)(int), int step, int min,
+ int max, void (*formatter)(char*, int, int, const char*) );
+ bool (*set_bool)(const char* string, bool* variable );
+ /* action handling */
+ int (*get_custom_action)(int context,int timeout,
+ const struct button_mapping* (*get_context_map)(int));
+ int (*get_action)(int context, int timeout);
+ void (*action_signalscreenchange)(void);
+ bool (*action_userabort)(int timeout);
/* power */
int (*battery_level)(void);
@@ -476,83 +545,6 @@ struct plugin_api {
/* new stuff at the end, sort into place next time
the API gets incompatible */
- bool (*set_sound)(const unsigned char * string,
- int* variable, int setting);
-#if ((CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)) && !defined(SIMULATOR)
- void (*i2c_begin)(void);
- void (*i2c_end)(void);
- int (*i2c_write)(int address, unsigned char* buf, int count );
-#endif
-
- int (*vsnprintf)(char *buf, int size, const char *fmt, va_list ap);
- void *(*memchr)(const void *s1, int c, size_t n);
-
- /* list */
- void (*gui_synclist_init)(struct gui_synclist * lists,
- list_get_name callback_get_item_name,void * data,
- bool scroll_all,int selected_size);
- void (*gui_synclist_set_nb_items)(struct gui_synclist * lists, int nb_items);
- void (*gui_synclist_set_icon_callback)(struct gui_synclist * lists, list_get_icon icon_callback);
- int (*gui_synclist_get_nb_items)(struct gui_synclist * lists);
- int (*gui_synclist_get_sel_pos)(struct gui_synclist * lists);
- void (*gui_synclist_draw)(struct gui_synclist * lists);
- void (*gui_synclist_select_item)(struct gui_synclist * lists,
- int item_number);
- void (*gui_synclist_select_next)(struct gui_synclist * lists);
- void (*gui_synclist_select_previous)(struct gui_synclist * lists);
- void (*gui_synclist_select_next_page)(struct gui_synclist * lists,
- enum screen_type screen);
- void (*gui_synclist_select_previous_page)(struct gui_synclist * lists,
- enum screen_type screen);
- void (*gui_synclist_add_item)(struct gui_synclist * lists);
- void (*gui_synclist_del_item)(struct gui_synclist * lists);
- void (*gui_synclist_limit_scroll)(struct gui_synclist * lists, bool scroll);
- void (*gui_synclist_flash)(struct gui_synclist * lists);
-#ifdef HAVE_LCD_BITMAP
- void (*gui_synclist_scroll_right)(struct gui_synclist * lists);
- void (*gui_synclist_scroll_left)(struct gui_synclist * lists);
-#endif
- unsigned (*gui_synclist_do_button)(struct gui_synclist * lists, unsigned button);
-
-#ifdef HAVE_LCD_BITMAP
- void (*lcd_setmargins)(int x, int y);
-#endif
- int (*utf8seek)(const unsigned char* utf8, int offset);
-
- bool (*set_int)(const unsigned char* string, const char* unit, int voice_unit,
- int* variable, void (*function)(int), int step, int min,
- int max, void (*formatter)(char*, int, int, const char*) );
- void (*reload_directory)(void);
- bool (*set_bool)(const char* string, bool* variable );
- struct screen* screens[NB_SCREENS];
-#ifdef HAVE_LCD_BITMAP
- unsigned short *(*bidi_l2v)( const unsigned char *str, int orientation );
- const unsigned char *(*font_get_bits)( struct font *pf, unsigned short char_code );
- struct font* (*font_load)(const char *path);
-#endif
-#if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
- void (*lcd_remote_set_foreground)(unsigned foreground);
- unsigned (*lcd_remote_get_foreground)(void);
- void (*lcd_remote_set_background)(unsigned foreground);
- unsigned (*lcd_remote_get_background)(void);
- void (*lcd_remote_bitmap_part)(const fb_remote_data *src, int src_x, int src_y,
- int stride, int x, int y, int width, int height);
- void (*lcd_remote_bitmap)(const fb_remote_data *src, int x, int y, int width,
- int height);
-#endif
-#if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR)
- void (*lcd_yuv_blit)(unsigned char * const src[3],
- int src_x, int src_y, int stride,
- int x, int y, int width, int height);
-#endif
-
- int (*PREFIX(rmdir))(const char *name);
- /* action handling */
- int (*get_custom_action)(int context,int timeout,
- const struct button_mapping* (*get_context_map)(int));
- int (*get_action)(int context, int timeout);
- void (*action_signalscreenchange)(void);
- bool (*action_userabort)(int timeout);
};
/* plugin header */
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
/* communication to the worker thread */
struct
{
- int id; /* ID of the thread */
+ struct thread_entry *id; /* Pointer of the thread */
bool foreground; /* set as long as we're owning the UI */
bool exiting; /* signal to the thread that we want to exit */
bool ended; /* response from the thread, that is has exited */
@@ -1169,7 +1169,8 @@ int main(void* parameter)
rb->memset(&gTread, 0, sizeof(gTread));
gTread.foreground = true;
- gTread.id = rb->create_thread(thread, stack, stacksize, "CDC");
+ gTread.id = rb->create_thread(thread, stack, stacksize, "CDC"
+ IF_PRIO(, PRIORITY_BACKGROUND));
#ifdef DEBUG
do
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)
struct
{
- int id;
+ struct thread_entry *id;
bool ended;
} s_thread;
@@ -454,10 +454,11 @@ int main(void)
rb->close(fd);
}
- rb->queue_init(&thread_q); /* put the thread's queue in the bcast list */
+ rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */
rb->memset(&s_thread, 0, sizeof(s_thread)); /* zero the struct */
if((s_thread.id = rb->create_thread(thread, thread_stack,
- sizeof(thread_stack), "Battery Benchmark"))<0)
+ sizeof(thread_stack), "Battery Benchmark"
+ IF_PRIO(, PRIORITY_BACKGROUND))) == NULL)
{
rb->splash(HZ,true,"Cannot create thread!");
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 @@
*/
#include <stdio.h>
+#include "config.h"
#include "thread.h"
#include "kernel.h"
#include "system.h"
@@ -1062,7 +1063,6 @@ static bool get_next(struct tagcache_search *tcs)
if (tagcache_is_numeric_tag(tcs->type))
{
- logf("r:%d", tcs->position);
snprintf(buf, sizeof(buf), "%d", tcs->position);
tcs->result_seek = tcs->position;
tcs->result = buf;
@@ -3455,7 +3455,6 @@ static void tagcache_thread(void)
sleep(HZ);
stat.ready = check_all_headers();
-
while (1)
{
queue_wait_w_tmo(&tagcache_queue, &ev, HZ);
@@ -3503,6 +3502,7 @@ static void tagcache_thread(void)
logf("tagcache check done");
+
check_done = true;
break ;
@@ -3612,9 +3612,10 @@ void tagcache_init(void)
current_serial = 0;
write_lock = read_lock = 0;
- queue_init(&tagcache_queue);
+ queue_init(&tagcache_queue, true);
create_thread(tagcache_thread, tagcache_stack,
- sizeof(tagcache_stack), tagcache_thread_name);
+ sizeof(tagcache_stack), tagcache_thread_name
+ IF_PRIO(, PRIORITY_BACKGROUND));
}
bool tagcache_is_initialized(void)
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)
void backlight_init(void)
{
- queue_init(&backlight_queue);
+ queue_init(&backlight_queue, true);
#ifdef X5_BACKLIGHT_SHUTDOWN
backlight_thread_id =
#endif
create_thread(backlight_thread, backlight_stack,
- sizeof(backlight_stack), backlight_thread_name);
+ sizeof(backlight_stack), backlight_thread_name
+ IF_PRIO(, PRIORITY_SYSTEM));
tick_add_task(backlight_tick);
#ifdef SIMULATOR
/* do nothing */
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)
void *retval = audiobuf;
audiobuf += size;
- /* 32-bit aligned */;
+ /* 32-bit aligned */
audiobuf = (void *)(((unsigned long)audiobuf + 3) & ~3);
+
return retval;
}
+
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)
opendirs[i].secondary_entry.d_name = buffer_alloc(MAX_PATH);
}
- queue_init(&dircache_queue);
+ queue_init(&dircache_queue, true);
create_thread(dircache_thread, dircache_stack,
- sizeof(dircache_stack), dircache_thread_name);
+ sizeof(dircache_stack), dircache_thread_name IF_PRIO(, PRIORITY_BACKGROUND));
}
/**
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)
if (rc)
return -60 + rc;
- queue_init(&ata_queue);
+ queue_init(&ata_queue, true);
last_disk_activity = current_tick;
create_thread(ata_thread, ata_stack,
- sizeof(ata_stack), ata_thread_name);
+ sizeof(ata_stack), ata_thread_name
+ IF_PRIO(, PRIORITY_SYSTEM));
initialized = true;
}
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)
if (!last_mmc_status)
mmc_status = MMC_UNTOUCHED;
#ifdef HAVE_HOTSWAP
- queue_init(&mmc_queue);
+ queue_init(&mmc_queue, true);
create_thread(mmc_thread, mmc_stack,
- sizeof(mmc_stack), mmc_thread_name);
+ sizeof(mmc_stack), mmc_thread_name IF_PRIO(, PRIORITY_SYSTEM));
#endif
tick_add_task(mmc_tick);
initialized = true;
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)
GPIOA_INT_CLR = GPIOA_INT_STAT;
GPIOA_INT_EN = 0xff;
#endif /* CONFIG_KEYPAD */
- queue_init(&button_queue);
+ queue_init(&button_queue, true);
button_read();
lastbtn = button_read();
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)
SCL_INPUT; /* Set the clock to input */
while(!SCL) /* and wait for the slave to release it */
- sleep_thread();
- wake_up_thread();
+ sleep_thread(0);
DELAY;
SCL_OUTPUT;
@@ -337,8 +336,7 @@ static int fmradio_i2c_getack(void)
SDA_INPUT; /* And set to input */
SCL_INPUT; /* Set the clock to input */
while(!SCL) /* and wait for the slave to release it */
- sleep_thread();
- wake_up_thread();
+ sleep_thread(0);
if (SDA)
/* 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)
SCL_INPUT; /* Set the clock to input */
while(!SCL) /* and wait for the MAS to release it */
- sleep_thread();
- wake_up_thread();
+ sleep_thread(1);
DELAY;
SCL_OUTPUT;
@@ -168,8 +167,7 @@ int i2c_getack(void)
SDA_INPUT; /* And set to input */
SCL_INPUT; /* Set the clock to input */
while(!SCL) /* and wait for the MAS to release it */
- sleep_thread();
- wake_up_thread();
+ sleep_thread(1);
if (SDA)
/* ack failed */
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)
/* Call device specific init */
lcd_init_device();
create_thread(scroll_thread, scroll_stack,
- sizeof(scroll_stack), scroll_name);
+ sizeof(scroll_stack), scroll_name, PRIORITY_SYSTEM);
}
/*** parameter handling ***/
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)
/* Call device specific init */
lcd_init_device();
create_thread(scroll_thread, scroll_stack,
- sizeof(scroll_stack), scroll_name);
+ sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
}
/*** parameter handling ***/
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)
void lcd_remote_init(void)
{
create_thread(scroll_thread, scroll_stack,
- sizeof(scroll_stack), scroll_name);
+ sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
}
#else /* !SIMULATOR */
@@ -601,10 +601,11 @@ void lcd_remote_init(void)
#endif
lcd_remote_clear_display();
- queue_clear(&remote_scroll_queue); /* no queue_init() -- private queue */
+ /* private queue */
+ queue_init(&remote_scroll_queue, false);
tick_add_task(remote_tick);
create_thread(scroll_thread, scroll_stack,
- sizeof(scroll_stack), scroll_name);
+ sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
}
/*** update functions ***/
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)
void lcd_init(void)
{
create_thread(scroll_thread, scroll_stack,
- sizeof(scroll_stack), scroll_name);
+ sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
}
#else
@@ -193,7 +193,7 @@ void lcd_init(void)
lcd_write_command(LCD_CNTL_ON_OFF | 1); /* LCD ON */
create_thread(scroll_thread, scroll_stack,
- sizeof(scroll_stack), scroll_name);
+ sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
}
/*** update functions ***/
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)
lcd_set_contrast(lcd_default_contrast());
create_thread(scroll_thread, scroll_stack,
- sizeof(scroll_stack), scroll_name);
+ sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
}
void lcd_jump_scroll (int mode) /* 0=off, 1=once, ..., JUMP_SCROLL_ALWAYS */
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)
void lcd_init(void)
{
create_thread(scroll_thread, scroll_stack,
- sizeof(scroll_stack), scroll_name);
+ sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
}
#else
@@ -278,7 +278,7 @@ void lcd_init(void)
lcd_update();
create_thread(scroll_thread, scroll_stack,
- sizeof(scroll_stack), scroll_name);
+ sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
}
/*** Update functions ***/
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)
void lcd_remote_init(void)
{
create_thread(scroll_thread, scroll_stack,
- sizeof(scroll_stack), scroll_name);
+ sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
}
#else
void lcd_remote_init(void)
@@ -1176,9 +1176,10 @@ void lcd_remote_init(void)
lcd_remote_init_device();
lcd_remote_clear_display();
- queue_clear(&remote_scroll_queue); /* no queue_init() -- private queue */
+ /* private queue */
+ queue_init(&remote_scroll_queue, false);
tick_add_task(remote_tick);
create_thread(scroll_thread, scroll_stack,
- sizeof(scroll_stack), scroll_name);
+ sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM));
}
#endif
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 @@
/* Enable the directory cache and tagcache in RAM if we have
* plenty of RAM. Both features can be enabled independently. */
#if (MEMORYSIZE > 8 || MEM > 8) && !defined(BOOTLOADER)
-#define HAVE_DIRCACHE 1
-#define HAVE_TC_RAMCACHE 1
+#define HAVE_DIRCACHE
+#define HAVE_TC_RAMCACHE
+#endif
+
+#if (CONFIG_CODEC == SWCODEC) && !defined(SIMULATOR) && !defined(BOOTLOADER)
+#define HAVE_PRIORITY_SCHEDULING
#endif
/* define for all cpus from coldfire family */
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
struct event_queue
{
struct event events[QUEUE_LENGTH];
+ struct thread_entry *thread;
unsigned int read;
unsigned int write;
};
struct mutex
{
+ struct thread_entry *thread;
bool locked;
};
@@ -85,7 +87,7 @@ extern void sleep(int ticks);
int tick_add_task(void (*f)(void));
int tick_remove_task(void (*f)(void));
-extern void queue_init(struct event_queue *q);
+extern void queue_init(struct event_queue *q, bool register_queue);
extern void queue_delete(struct event_queue *q);
extern void queue_wait(struct event_queue *q, struct event *ev);
extern 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 @@
#include <stdbool.h>
+/* Priority scheduling (when enabled with HAVE_PRIORITY_SCHEDULING) works
+ * by giving high priority threads more CPU time than less priority threads
+ * when they need it.
+ *
+ * If software playback codec pcm buffer is going down to critical, codec
+ * can change it own priority to REALTIME to override user interface and
+ * prevent playback skipping.
+ */
+#define PRIORITY_REALTIME 1
+#define PRIORITY_USER_INTERFACE 4 /* The main thread */
+#define PRIORITY_RECORDING 4 /* Recording thread */
+#define PRIORITY_PLAYBACK 4 /* or REALTIME when needed */
+#define PRIORITY_BUFFERING 4 /* Codec buffering thread */
+#define PRIORITY_SYSTEM 6 /* All other firmware threads */
+#define PRIORITY_BACKGROUND 8 /* Normal application threads */
+
#if CONFIG_CODEC == SWCODEC
-#define MAXTHREADS 16
+#define MAXTHREADS 15
#else
#define MAXTHREADS 11
#endif
@@ -32,7 +48,7 @@
#ifndef SIMULATOR
/* Need to keep structures inside the header file because debug_menu
* needs them. */
-#ifdef CPU_COLDFIRE
+# ifdef CPU_COLDFIRE
struct regs
{
unsigned int macsr; /* EMAC status register */
@@ -41,7 +57,7 @@ struct regs
void *sp; /* Stack pointer (a7) */
void *start; /* Thread start address, or NULL when started */
};
-#elif CONFIG_CPU == SH7034
+# elif CONFIG_CPU == SH7034
struct regs
{
unsigned int r[7]; /* Registers r8 thru r14 */
@@ -49,7 +65,7 @@ struct regs
void *pr; /* Procedure register */
void *start; /* Thread start address, or NULL when started */
};
-#elif defined(CPU_ARM)
+# elif defined(CPU_ARM)
struct regs
{
unsigned int r[8]; /* Registers r4-r11 */
@@ -57,42 +73,72 @@ struct regs
unsigned int lr; /* r14 (lr) */
void *start; /* Thread start address, or NULL when started */
};
-#elif CONFIG_CPU == TCC730
+# elif CONFIG_CPU == TCC730
struct regs
{
void *sp; /* Stack pointer (a15) */
void *start; /* Thread start address */
int started; /* 0 when not started */
};
-#endif
+# endif
+
+#endif /* !SIMULATOR */
+
+#define STATE_RUNNING 0
+#define STATE_BLOCKED 1
+#define STATE_SLEEPING 2
+#define STATE_BLOCKED_W_TMO 3
+
+#define GET_STATE_ARG(state) (state & 0x3FFFFFFF)
+#define GET_STATE(state) ((state >> 30) & 3)
+#define SET_STATE(state,arg) ((state << 30) | (arg))
struct thread_entry {
+#ifndef SIMULATOR
struct regs context;
+#endif
const char *name;
void *stack;
- int stack_size;
+ unsigned long statearg;
+ unsigned short stack_size;
+#ifdef HAVE_PRIORITY_SCHEDULING
+ unsigned short priority;
+ long last_run;
+#endif
+ struct thread_entry *next, *prev;
};
struct core_entry {
- int num_threads;
- volatile int num_sleepers;
- int current_thread;
struct thread_entry threads[MAXTHREADS];
+ struct thread_entry *running;
+ struct thread_entry *sleeping;
};
+
+#ifdef HAVE_PRIORITY_SCHEDULING
+#define IF_PRIO(empty, type) , type
+#else
+#define IF_PRIO(empty, type)
#endif
-int create_thread(void (*function)(void), void* stack, int stack_size,
- const char *name);
-int create_thread_on_core(unsigned int core, void (*function)(void), void* stack, int stack_size,
- const char *name);
-void remove_thread(int threadnum);
-void remove_thread_on_core(unsigned int core, int threadnum);
-void switch_thread(void);
-void sleep_thread(void);
-void wake_up_thread(void);
+struct thread_entry*
+ create_thread(void (*function)(void), void* stack, int stack_size,
+ const char *name IF_PRIO(, int priority));
+
+struct thread_entry*
+ create_thread_on_core(unsigned int core, void (*function)(void),
+ void* stack, int stack_size,
+ const char *name
+ IF_PRIO(, int priority));
+
+void remove_thread(struct thread_entry *thread);
+void switch_thread(bool save_context, struct thread_entry **blocked_list);
+void sleep_thread(int ticks);
+void block_thread(struct thread_entry **thread, int timeout);
+void wakeup_thread(struct thread_entry **thread);
+void thread_set_priority(struct thread_entry *thread, int priority);
void init_threads(void);
-int thread_stack_usage(int threadnum);
-int thread_stack_usage_on_core(unsigned int core, int threadnum);
+int thread_stack_usage(const struct thread_entry *thread);
+int thread_get_status(const struct thread_entry *thread);
#ifdef RB_PROFILE
void profile_thread(void);
#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);
static struct event_queue *all_queues[32];
static int num_queues;
-void sleep(int ticks) ICODE_ATTR;
void queue_wait(struct event_queue *q, struct event *ev) ICODE_ATTR;
/****************************************************************************
@@ -71,13 +70,7 @@ void sleep(int ticks)
} while(counter > 0);
#else
- /* Always sleep at least 1 tick */
- int timeout = current_tick + ticks + 1;
-
- while (TIME_BEFORE( current_tick, timeout )) {
- sleep_thread();
- }
- wake_up_thread();
+ sleep_thread(ticks);
#endif
}
@@ -86,21 +79,24 @@ void yield(void)
#if (CONFIG_CPU == S3C2440 || defined(ELIO_TPJ1022) && defined(BOOTLOADER))
/* Some targets don't like yielding in the bootloader */
#else
- switch_thread();
- wake_up_thread();
+ switch_thread(true, NULL);
#endif
}
/****************************************************************************
* Queue handling stuff
****************************************************************************/
-void queue_init(struct event_queue *q)
+void queue_init(struct event_queue *q, bool register_queue)
{
q->read = 0;
q->write = 0;
-
- /* Add it to the all_queues array */
- all_queues[num_queues++] = q;
+ q->thread = NULL;
+
+ if (register_queue)
+ {
+ /* Add it to the all_queues array */
+ all_queues[num_queues++] = q;
+ }
}
void queue_delete(struct event_queue *q)
@@ -108,6 +104,8 @@ void queue_delete(struct event_queue *q)
int i;
bool found = false;
+ wakeup_thread(&q->thread);
+
/* Find the queue to be deleted */
for(i = 0;i < num_queues;i++)
{
@@ -132,26 +130,22 @@ void queue_delete(struct event_queue *q)
void queue_wait(struct event_queue *q, struct event *ev)
{
- while(q->read == q->write)
+ if (q->read == q->write)
{
- sleep_thread();
+ block_thread(&q->thread, 0);
}
- wake_up_thread();
*ev = q->events[(q->read++) & QUEUE_LENGTH_MASK];
}
void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks)
{
- unsigned int timeout = current_tick + ticks;
-
- while(q->read == q->write && TIME_BEFORE( current_tick, timeout ))
+ if (q->read == q->write && ticks > 0)
{
- sleep_thread();
+ block_thread(&q->thread, ticks);
}
- wake_up_thread();
- if(q->read != q->write)
+ if (q->read != q->write)
{
*ev = q->events[(q->read++) & QUEUE_LENGTH_MASK];
}
@@ -171,6 +165,9 @@ void queue_post(struct event_queue *q, long id, void *data)
q->events[wr].id = id;
q->events[wr].data = data;
+
+ wakeup_thread(&q->thread);
+
set_irq_level(oldlevel);
}
@@ -250,7 +247,6 @@ void IMIA0(void)
}
current_tick++;
- wake_up_thread();
TSR0 &= ~0x01;
}
@@ -301,7 +297,6 @@ void TIMER0(void)
}
current_tick++;
- wake_up_thread();
TER0 = 0xff; /* Clear all events */
}
@@ -330,7 +325,6 @@ void TIMER0(void)
}
current_tick++;
- wake_up_thread();
/* re-enable timer by clearing the counter */
TACON |= 0x80;
@@ -382,7 +376,6 @@ void TIMER1(void)
}
current_tick++;
- wake_up_thread();
}
#endif
@@ -415,7 +408,6 @@ void timer_handler(void)
}
current_tick++;
- wake_up_thread();
TIMERR0C = 1;
}
@@ -513,22 +505,27 @@ int tick_remove_task(void (*f)(void))
void mutex_init(struct mutex *m)
{
m->locked = false;
+ m->thread = NULL;
}
void mutex_lock(struct mutex *m)
{
- /* Wait until the lock is open... */
- while(m->locked)
- sleep_thread();
- wake_up_thread();
-
+ if (m->locked)
+ {
+ /* Wait until the lock is open... */
+ block_thread(&m->thread, 0);
+ }
+
/* ...and lock it */
m->locked = true;
}
void mutex_unlock(struct mutex *m)
{
- m->locked = false;
+ if (m->thread == NULL)
+ m->locked = false;
+ else
+ wakeup_thread(&m->thread);
}
#endif
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)
{
prerecord_timeout = current_tick + HZ;
queue_post(&mpeg_queue, MPEG_PRERECORDING_TICK, 0);
- wake_up_thread();
}
}
else
@@ -773,7 +772,6 @@ void rec_tick(void)
{
saving_status = BUFFER_FULL;
queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
- wake_up_thread();
}
}
}
@@ -894,8 +892,6 @@ static void transfer_end(unsigned char** ppbuf, int* psize)
*psize = 0; /* no more transfer */
}
}
-
- wake_up_thread();
}
static struct trackdata *add_track_to_tag_list(const char *filename)
@@ -2119,8 +2115,7 @@ void audio_init_playback(void)
queue_post(&mpeg_queue, MPEG_INIT_PLAYBACK, NULL);
while(!init_playback_done)
- sleep_thread();
- wake_up_thread();
+ sleep_thread(1);
}
@@ -2134,8 +2129,7 @@ void audio_init_recording(unsigned int buffer_offset)
queue_post(&mpeg_queue, MPEG_INIT_RECORDING, NULL);
while(!init_recording_done)
- sleep_thread();
- wake_up_thread();
+ sleep_thread(1);
}
static void init_recording(void)
@@ -2886,10 +2880,10 @@ void audio_init(void)
#ifndef SIMULATOR
audiobuflen = audiobufend - audiobuf;
- queue_init(&mpeg_queue);
+ queue_init(&mpeg_queue, true);
#endif /* !SIMULATOR */
create_thread(mpeg_thread, mpeg_stack,
- sizeof(mpeg_stack), mpeg_thread_name);
+ sizeof(mpeg_stack), mpeg_thread_name IF_PRIO(, PRIORITY_SYSTEM));
memset(trackdata, sizeof(trackdata), 0);
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);
/* Creates pcmrec_thread */
void pcm_rec_init(void)
{
- queue_init(&pcmrec_queue);
+ queue_init(&pcmrec_queue, true);
create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack),
- pcmrec_thread_name);
+ pcmrec_thread_name IF_PRIO(, PRIORITY_RECORDING));
}
@@ -196,8 +196,7 @@ void audio_init_recording(unsigned int buffer_offset)
queue_post(&pcmrec_queue, PCMREC_INIT, 0);
while(!init_done)
- sleep_thread();
- wake_up_thread();
+ sleep_thread(1);
}
void audio_close_recording(void)
@@ -206,8 +205,7 @@ void audio_close_recording(void)
queue_post(&pcmrec_queue, PCMREC_CLOSE, 0);
while(!close_done)
- sleep_thread();
- wake_up_thread();
+ sleep_thread(1);
audio_remove_encoder();
}
@@ -421,8 +419,7 @@ void audio_record(const char *filename)
queue_post(&pcmrec_queue, PCMREC_START, 0);
while(!record_done)
- sleep_thread();
- wake_up_thread();
+ sleep_thread(1);
}
@@ -438,8 +435,7 @@ void audio_new_file(const char *filename)
queue_post(&pcmrec_queue, PCMREC_NEW_FILE, 0);
while(!new_file_done)
- sleep_thread();
- wake_up_thread();
+ sleep_thread(1);
logf("pcm_new_file done");
}
@@ -459,8 +455,7 @@ void audio_stop_recording(void)
queue_post(&pcmrec_queue, PCMREC_STOP, 0);
while(!stop_done)
- sleep_thread();
- wake_up_thread();
+ sleep_thread(1);
logf("pcm_stop done");
}
@@ -482,8 +477,7 @@ void audio_pause_recording(void)
queue_post(&pcmrec_queue, PCMREC_PAUSE, 0);
while(!pause_done)
- sleep_thread();
- wake_up_thread();
+ sleep_thread(1);
}
void audio_resume_recording(void)
@@ -498,8 +492,7 @@ void audio_resume_recording(void)
queue_post(&pcmrec_queue, PCMREC_RESUME, 0);
while(!resume_done)
- sleep_thread();
- wake_up_thread();
+ sleep_thread(1);
}
/* return peaks as int, so convert from short first
@@ -817,9 +810,8 @@ static void pcmrec_stop(void)
/* wait for encoding finish */
is_paused = true;
while(!wav_queue_empty)
- sleep_thread();
+ sleep_thread(1);
- wake_up_thread();
is_recording = false;
/* Flush buffers to file */
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)
memset(power_history, 0x00, sizeof(power_history));
create_thread(power_thread, power_stack, sizeof(power_stack),
- power_thread_name);
+ power_thread_name IF_PRIO(, PRIORITY_SYSTEM));
}
#endif /* SIMULATOR */
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 @@
#include "system.h"
#include "kernel.h"
#include "cpu.h"
-
+#include "string.h"
#define DEADBEEF ((unsigned int)0xdeadbeef)
/* Cast to the the machine int type, whose size could be < 4. */
struct core_entry cores[NUM_CORES] IBSS_ATTR;
+#ifdef HAVE_PRIORITY_SCHEDULING
+static unsigned short highest_priority IBSS_ATTR;
+#endif
+
+/* Define to enable additional checks for blocking violations etc. */
+// #define THREAD_EXTRA_CHECKS
static const char main_thread_name[] = "main";
@@ -48,7 +54,16 @@ int *cop_stackend = stackend;
#endif
#endif
-void switch_thread(void) ICODE_ATTR;
+/* Conserve IRAM
+static void add_to_list(struct thread_entry **list,
+ struct thread_entry *thread) ICODE_ATTR;
+static void remove_from_list(struct thread_entry **list,
+ struct thread_entry *thread) ICODE_ATTR;
+*/
+
+void switch_thread(bool save_context, struct thread_entry **blocked_list)
+ ICODE_ATTR;
+
static inline void store_context(void* addr) __attribute__ ((always_inline));
static inline void load_context(const void* addr) __attribute__ ((always_inline));
@@ -219,24 +234,109 @@ static inline void load_context(const void* addr)
#endif
-/*---------------------------------------------------------------------------
- * Switch thread in round robin fashion.
- *---------------------------------------------------------------------------
- */
-void switch_thread(void)
+static void add_to_list(struct thread_entry **list,
+ struct thread_entry *thread)
{
-#ifdef RB_PROFILE
- profile_thread_stopped(cores[CURRENT_CORE].current_thread);
-#endif
- int current;
- unsigned int *stackptr;
+ if (*list == NULL)
+ {
+ thread->next = thread;
+ thread->prev = thread;
+ *list = thread;
+ }
+ else
+ {
+ /* Insert last */
+ thread->next = *list;
+ thread->prev = (*list)->prev;
+ thread->prev->next = thread;
+ (*list)->prev = thread;
+
+ /* Insert next
+ thread->next = (*list)->next;
+ thread->prev = *list;
+ thread->next->prev = thread;
+ (*list)->next = thread;
+ */
+ }
+}
-#ifdef SIMULATOR
- /* Do nothing */
-#else
- while (cores[CURRENT_CORE].num_sleepers == cores[CURRENT_CORE].num_threads)
+static void remove_from_list(struct thread_entry **list,
+ struct thread_entry *thread)
+{
+ if (list != NULL)
+ {
+ if (thread == thread->next)
+ {
+ *list = NULL;
+ return;
+ }
+
+ if (thread == *list)
+ *list = thread->next;
+ }
+
+ /* Fix links to jump over the removed entry. */
+ thread->prev->next = thread->next;
+ thread->next->prev = thread->prev;
+}
+
+/* Compiler trick: Don't declare as static to prevent putting
+ * function in IRAM. */
+void check_sleepers(void)
+{
+ struct thread_entry *current, *next;
+
+ /* Check sleeping threads. */
+ current = cores[CURRENT_CORE].sleeping;
+ if (current == NULL)
+ return ;
+
+ for (;;)
+ {
+ next = current->next;
+
+ if ((unsigned)current_tick >= GET_STATE_ARG(current->statearg))
+ {
+ /* Sleep timeout has been reached so bring the thread
+ * back to life again. */
+ remove_from_list(&cores[CURRENT_CORE].sleeping, current);
+ add_to_list(&cores[CURRENT_CORE].running, current);
+
+ /* If there is no more processes in the list, break the loop. */
+ if (cores[CURRENT_CORE].sleeping == NULL)
+ break;
+
+ current = next;
+ continue;
+ }
+
+ current = next;
+
+ /* Break the loop once we have walked through the list of all
+ * sleeping processes. */
+ if (current == cores[CURRENT_CORE].sleeping)
+ break;
+ }
+}
+
+static inline void sleep_core(void)
+{
+ static long last_tick = 0;
+
+ for (;;)
{
- /* Enter sleep mode, woken up on interrupt */
+ if (last_tick != current_tick)
+ {
+ check_sleepers();
+ last_tick = current_tick;
+ }
+
+ /* We must sleep until there is at least one process in the list
+ * of running processes. */
+ if (cores[CURRENT_CORE].running != NULL)
+ break;
+
+ /* Enter sleep mode to reduce power usage, woken up on interrupt */
#ifdef CPU_COLDFIRE
asm volatile ("stop #0x2000");
#elif CONFIG_CPU == SH7034
@@ -257,49 +357,232 @@ void switch_thread(void)
CLKCON |= 2;
#endif
}
-#endif
- current = cores[CURRENT_CORE].current_thread;
- store_context(&cores[CURRENT_CORE].threads[current].context);
-
-#if CONFIG_CPU != TCC730
- /* Check if the current thread stack is overflown */
- stackptr = cores[CURRENT_CORE].threads[current].stack;
- if(stackptr[0] != DEADBEEF)
- panicf("Stkov %s", cores[CURRENT_CORE].threads[current].name);
+}
+
+#ifdef RB_PROFILE
+static int get_threadnum(struct thread_entry *thread)
+{
+ int i;
+
+ for (i = 0; i < MAXTHREADS; i++)
+ {
+ if (&cores[CURRENT_CORE].threads[i] == thread)
+ return i;
+ }
+
+ return -1;
+}
#endif
- if (++current >= cores[CURRENT_CORE].num_threads)
- current = 0;
+/* Compiler trick: Don't declare as static to prevent putting
+ * function in IRAM. */
+void change_thread_state(struct thread_entry **blocked_list)
+{
+ struct thread_entry *old;
+
+ /* Remove the thread from the list of running threads. */
+ old = cores[CURRENT_CORE].running;
+ remove_from_list(&cores[CURRENT_CORE].running, old);
+
+ /* And put the thread into a new list of inactive threads. */
+ if (GET_STATE(old->statearg) == STATE_BLOCKED)
+ add_to_list(blocked_list, old);
+ else
+ add_to_list(&cores[CURRENT_CORE].sleeping, old);
+
+#ifdef HAVE_PRIORITY_SCHEDULING
+ /* Reset priorities */
+ if (old->priority == highest_priority)
+ highest_priority = 100;
+#endif
+}
- cores[CURRENT_CORE].current_thread = current;
- load_context(&cores[CURRENT_CORE].threads[current].context);
+/*---------------------------------------------------------------------------
+ * Switch thread in round robin fashion.
+ *---------------------------------------------------------------------------
+ */
+void switch_thread(bool save_context, struct thread_entry **blocked_list)
+{
#ifdef RB_PROFILE
- profile_thread_started(cores[CURRENT_CORE].current_thread);
+ profile_thread_stopped(get_threadnum(cores[CURRENT_CORE].running));
+#endif
+ unsigned int *stackptr;
+
+#ifdef SIMULATOR
+ /* Do nothing */
+#else
+
+ /* Begin task switching by saving our current context so that we can
+ * restore the state of the current thread later to the point prior
+ * to this call. */
+ if (save_context)
+ {
+ store_context(&cores[CURRENT_CORE].running->context);
+
+# if CONFIG_CPU != TCC730
+ /* Check if the current thread stack is overflown */
+ stackptr = cores[CURRENT_CORE].running->stack;
+ if(stackptr[0] != DEADBEEF)
+ panicf("Stkov %s", cores[CURRENT_CORE].running->name);
+# endif
+
+ /* Check if a thread state change has been requested. */
+ if (cores[CURRENT_CORE].running->statearg)
+ {
+ /* Change running thread state and switch to next thread. */
+ change_thread_state(blocked_list);
+ }
+ else
+ {
+ /* Switch to the next running thread. */
+ cores[CURRENT_CORE].running = cores[CURRENT_CORE].running->next;
+ }
+ }
+
+ /* Go through the list of sleeping task to check if we need to wake up
+ * any of them due to timeout. Also puts core into sleep state until
+ * there is at least one running process again. */
+ sleep_core();
+
+#ifdef HAVE_PRIORITY_SCHEDULING
+ /* Select the new task based on priorities and the last time a process
+ * got CPU time. */
+ for (;;)
+ {
+ int priority = cores[CURRENT_CORE].running->priority;
+
+ if (priority < highest_priority)
+ highest_priority = priority;
+
+ if (priority == highest_priority || (current_tick
+ - cores[CURRENT_CORE].running->last_run > priority * 8))
+ {
+ break;
+ }
+ cores[CURRENT_CORE].running = cores[CURRENT_CORE].running->next;
+ }
+
+ /* Reset the value of thread's last running time to the current time. */
+ cores[CURRENT_CORE].running->last_run = current_tick;
+#endif
+
+#endif
+ /* And finally give control to the next thread. */
+ load_context(&cores[CURRENT_CORE].running->context);
+
+#ifdef RB_PROFILE
+ profile_thread_started(get_threadnum(cores[CURRENT_CORE].running));
#endif
}
-void sleep_thread(void)
+void sleep_thread(int ticks)
{
- ++cores[CURRENT_CORE].num_sleepers;
- switch_thread();
+ /* Set the thread's new state and timeout and finally force a task switch
+ * so that scheduler removes thread from the list of running processes
+ * and puts it in list of sleeping tasks. */
+ cores[CURRENT_CORE].running->statearg =
+ SET_STATE(STATE_SLEEPING, current_tick + ticks + 1);
+ switch_thread(true, NULL);
+
+ /* Clear all flags to indicate we are up and running again. */
+ cores[CURRENT_CORE].running->statearg = 0;
}
-void wake_up_thread(void)
+void block_thread(struct thread_entry **list, int timeout)
{
- cores[CURRENT_CORE].num_sleepers = 0;
+ struct thread_entry *current;
+
+ /* Get the entry for the current running thread. */
+ current = cores[CURRENT_CORE].running;
+
+ /* At next task switch scheduler will immediately change the thread
+ * state (and we also force the task switch to happen). */
+ if (timeout)
+ {
+#ifdef THREAD_EXTRA_CHECKS
+ /* We can store only one thread to the "list" if thread is used
+ * in other list (such as core's list for sleeping tasks). */
+ if (*list)
+ panicf("Blocking violation T->*B");
+#endif
+
+ current->statearg =
+ SET_STATE(STATE_BLOCKED_W_TMO, current_tick + timeout);
+ *list = current;
+
+ /* Now force a task switch and block until we have been woken up
+ * by another thread or timeout is reached. */
+ switch_thread(true, NULL);
+
+ /* If timeout is reached, we must set list back to NULL here. */
+ *list = NULL;
+ }
+ else
+ {
+#ifdef THREAD_EXTRA_CHECKS
+ /* We are not allowed to mix blocking types in one queue. */
+ if (*list && GET_STATE((*list)->statearg) == STATE_BLOCKED_W_TMO)
+ panicf("Blocking violation B->*T");
+#endif
+
+ current->statearg = SET_STATE(STATE_BLOCKED, 0);
+
+ /* Now force a task switch and block until we have been woken up
+ * by another thread or timeout is reached. */
+ switch_thread(true, list);
+ }
+
+ /* Clear all flags to indicate we are up and running again. */
+ current->statearg = 0;
}
+void wakeup_thread(struct thread_entry **list)
+{
+ struct thread_entry *thread;
+
+ /* Check if there is a blocked thread at all. */
+ if (*list == NULL)
+ return ;
+
+ /* Wake up the last thread first. */
+ thread = *list;
+
+ /* Determine thread's current state. */
+ switch (GET_STATE(thread->statearg))
+ {
+ case STATE_BLOCKED:
+ /* Remove thread from the list of blocked threads and add it
+ * to the scheduler's list of running processes. */
+ remove_from_list(list, thread);
+ add_to_list(&cores[CURRENT_CORE].running, thread);
+ thread->statearg = 0;
+ break;
+
+ case STATE_BLOCKED_W_TMO:
+ /* Just remove the timeout to cause scheduler to immediately
+ * wake up the thread. */
+ thread->statearg &= 0xC0000000;
+ *list = NULL;
+ break;
+
+ default:
+ /* Nothing to do. Thread has already been woken up
+ * or it's state is not blocked or blocked with timeout. */
+ return ;
+ }
+}
/*---------------------------------------------------------------------------
* Create thread on the current core.
* Return ID if context area could be allocated, else -1.
*---------------------------------------------------------------------------
*/
-int create_thread(void (*function)(void), void* stack, int stack_size,
- const char *name)
+struct thread_entry*
+ create_thread(void (*function)(void), void* stack, int stack_size,
+ const char *name IF_PRIO(, int priority))
{
return create_thread_on_core(CURRENT_CORE, function, stack, stack_size,
- name);
+ name IF_PRIO(, priority));
}
/*---------------------------------------------------------------------------
@@ -307,18 +590,28 @@ int create_thread(void (*function)(void), void* stack, int stack_size,
* Return ID if context area could be allocated, else -1.
*---------------------------------------------------------------------------
*/
-int create_thread_on_core(unsigned int core, void (*function)(void), void* stack, int stack_size,
- const char *name)
+struct thread_entry*
+ create_thread_on_core(unsigned int core, void (*function)(void),
+ void* stack, int stack_size,
+ const char *name IF_PRIO(, int priority))
{
unsigned int i;
unsigned int stacklen;
unsigned int *stackptr;
+ int n;
struct regs *regs;
struct thread_entry *thread;
- if (cores[core].num_threads >= MAXTHREADS)
- return -1;
-
+ for (n = 0; n < MAXTHREADS; n++)
+ {
+ if (cores[core].threads[n].name == NULL)
+ break;
+ }
+
+ if (n == MAXTHREADS)
+ return NULL;
+
+
/* Munge the stack to make it easy to spot stack overflows */
stacklen = stack_size / sizeof(int);
stackptr = stack;
@@ -328,10 +621,17 @@ int create_thread_on_core(unsigned int core, void (*function)(void), void* stack
}
/* Store interesting information */
- thread = &cores[core].threads[cores[core].num_threads];
+ thread = &cores[core].threads[n];
thread->name = name;
thread->stack = stack;
thread->stack_size = stack_size;
+ thread->statearg = 0;
+#ifdef HAVE_PRIORITY_SCHEDULING
+ thread->priority = priority;
+ highest_priority = 100;
+#endif
+ add_to_list(&cores[core].running, thread);
+
regs = &thread->context;
#if defined(CPU_COLDFIRE) || (CONFIG_CPU == SH7034) || defined(CPU_ARM)
/* Align stack to an even 32 bit boundary */
@@ -343,8 +643,7 @@ int create_thread_on_core(unsigned int core, void (*function)(void), void* stack
#endif
regs->start = (void*)function;
- wake_up_thread();
- return cores[core].num_threads++; /* return the current ID, e.g for remove_thread() */
+ return thread;
}
/*---------------------------------------------------------------------------
@@ -352,44 +651,58 @@ int create_thread_on_core(unsigned int core, void (*function)(void), void* stack
* Parameter is the ID as returned from create_thread().
*---------------------------------------------------------------------------
*/
-void remove_thread(int threadnum)
+void remove_thread(struct thread_entry *thread)
{
- remove_thread_on_core(CURRENT_CORE, threadnum);
+ if (thread == NULL)
+ thread = cores[CURRENT_CORE].running;
+
+ /* Free the entry by removing thread name. */
+ thread->name = NULL;
+#ifdef HAVE_PRIORITY_SCHEDULING
+ highest_priority = 100;
+#endif
+
+ if (thread == cores[CURRENT_CORE].running)
+ {
+ remove_from_list(&cores[CURRENT_CORE].running, thread);
+ switch_thread(false, NULL);
+ return ;
+ }
+
+ if (thread == cores[CURRENT_CORE].sleeping)
+ remove_from_list(&cores[CURRENT_CORE].sleeping, thread);
+
+ remove_from_list(NULL, thread);
}
-/*---------------------------------------------------------------------------
- * Remove a thread on the specified core from the scheduler.
- * Parameters are the core and the ID as returned from create_thread().
- *---------------------------------------------------------------------------
- */
-void remove_thread_on_core(unsigned int core, int threadnum)
+#ifdef HAVE_PRIORITY_SCHEDULING
+void thread_set_priority(struct thread_entry *thread, int priority)
{
- int i;
-
- if (threadnum >= cores[core].num_threads)
- return;
-
- cores[core].num_threads--;
- for (i=threadnum; i<cores[core].num_threads-1; i++)
- { /* move all entries which are behind */
- cores[core].threads[i] = cores[core].threads[i+1];
- }
-
- if (cores[core].current_thread == threadnum) /* deleting the current one? */
- cores[core].current_thread = cores[core].num_threads; /* set beyond last, avoid store harm */
- else if (cores[core].current_thread > threadnum) /* within the moved positions? */
- cores[core].current_thread--; /* adjust it, point to same context again */
+ if (thread == NULL)
+ thread = cores[CURRENT_CORE].running;
+
+ thread->priority = priority;
+ highest_priority = 100;
}
+#endif
void init_threads(void)
{
unsigned int core = CURRENT_CORE;
- cores[core].num_threads = 1; /* We have 1 thread to begin with */
- cores[core].current_thread = 0; /* The current thread is number 0 */
+ memset(cores, 0, sizeof cores);
+ cores[core].sleeping = NULL;
+ cores[core].running = NULL;
cores[core].threads[0].name = main_thread_name;
-/* In multiple core setups, each core has a different stack. There is probably
- a much better way to do this. */
+ cores[core].threads[0].statearg = 0;
+#ifdef HAVE_PRIORITY_SCHEDULING
+ cores[core].threads[0].priority = PRIORITY_USER_INTERFACE;
+ highest_priority = 100;
+#endif
+ add_to_list(&cores[core].running, &cores[core].threads[0]);
+
+ /* In multiple core setups, each core has a different stack. There is probably
+ a much better way to do this. */
if (core == CPU)
{
cores[CPU].threads[0].stack = stackbegin;
@@ -405,28 +718,24 @@ void init_threads(void)
#else
cores[core].threads[0].context.start = 0; /* thread 0 already running */
#endif
- cores[core].num_sleepers = 0;
-}
-
-int thread_stack_usage(int threadnum)
-{
- return thread_stack_usage_on_core(CURRENT_CORE, threadnum);
}
-int thread_stack_usage_on_core(unsigned int core, int threadnum)
+int thread_stack_usage(const struct thread_entry *thread)
{
unsigned int i;
- unsigned int *stackptr = cores[core].threads[threadnum].stack;
-
- if (threadnum >= cores[core].num_threads)
- return -1;
+ unsigned int *stackptr = thread->stack;
- for (i = 0;i < cores[core].threads[threadnum].stack_size/sizeof(int);i++)
+ for (i = 0;i < thread->stack_size/sizeof(int);i++)
{
if (stackptr[i] != DEADBEEF)
break;
}
- return ((cores[core].threads[threadnum].stack_size - i * sizeof(int)) * 100) /
- cores[core].threads[threadnum].stack_size;
+ return ((thread->stack_size - i * sizeof(int)) * 100) /
+ thread->stack_size;
+}
+
+int thread_get_status(const struct thread_entry *thread)
+{
+ return GET_STATE(thread->statearg);
}
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)
last_usb_status = false;
#ifndef BOOTLOADER
- queue_init(&usb_queue);
- create_thread(usb_thread, usb_stack, sizeof(usb_stack), usb_thread_name);
+ queue_init(&usb_queue, true);
+ create_thread(usb_thread, usb_stack, sizeof(usb_stack),
+ usb_thread_name IF_PRIO(, PRIORITY_SYSTEM));
tick_add_task(usb_tick);
#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)
return (_lv = level);
}
-void queue_init(struct event_queue *q)
+void queue_init(struct event_queue *q, bool register_queue)
{
+ (void)register_queue;
+
q->read = 0;
q->write = 0;
}
@@ -47,7 +49,7 @@ void queue_wait(struct event_queue *q, struct event *ev)
{
while(q->read == q->write)
{
- switch_thread();
+ switch_thread(true, NULL);
}
*ev = q->events[(q->read++) & QUEUE_LENGTH_MASK];
@@ -97,8 +99,11 @@ void queue_clear(struct event_queue* q)
q->write = 0;
}
-void switch_thread (void)
+void switch_thread(bool save_context, struct thread_entry **blocked_list)
{
+ (void)save_context;
+ (void)blocked_list;
+
yield ();
}
@@ -160,7 +165,7 @@ void mutex_init(struct mutex *m)
void mutex_lock(struct mutex *m)
{
while(m->locked)
- switch_thread();
+ switch_thread(true, NULL);
m->locked = true;
}