diff options
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 = { ¤t_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; } |