diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2008-03-25 02:34:12 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2008-03-25 02:34:12 +0000 |
commit | 27cf67733936abd75fcb1f8da765977cd75906ee (patch) | |
tree | f894211a8a0c77b402dd3250b2bee2d17dcfe13f /apps | |
parent | bc2f8fd8f38a3e010cd67bbac358f6e9991153c6 (diff) |
Add a complete priority inheritance implementation to the scheduler (all mutex ownership and queue_send calls are inheritable). Priorities are differential so that dispatch depends on the runnable range of priorities. Codec priority can therefore be raised in small steps (pcmbuf updated to enable). Simplify the kernel functions to ease implementation and use the same kernel.c for both sim and target (I'm tired of maintaining two ;_). 1) Not sure if a minor audio break at first buffering issue will exist on large-sector disks (the main mutex speed issue was genuinely resolved earlier). At this point it's best dealt with at the buffering level. It seems a larger filechunk could be used again. 2) Perhaps 64-bit sims will have some minor issues (finicky) but a backroll of the code of concern there is a 5-minute job. All kernel objects become incompatible so a full rebuild and update is needed.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16791 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r-- | apps/buffering.c | 9 | ||||
-rw-r--r-- | apps/codecs.c | 36 | ||||
-rw-r--r-- | apps/codecs.h | 52 | ||||
-rw-r--r-- | apps/debug_menu.c | 11 | ||||
-rw-r--r-- | apps/main.c | 2 | ||||
-rw-r--r-- | apps/pcmbuf.c | 23 | ||||
-rw-r--r-- | apps/playback.c | 10 | ||||
-rw-r--r-- | apps/plugin.c | 5 | ||||
-rw-r--r-- | apps/plugin.h | 14 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/audio_thread.c | 6 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/disk_buf.c | 4 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/stream_mgr.c | 4 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/video_thread.c | 6 | ||||
-rw-r--r-- | apps/voice_thread.c | 4 |
14 files changed, 100 insertions, 86 deletions
diff --git a/apps/buffering.c b/apps/buffering.c index 64f522c52f..0cb428c947 100644 --- a/apps/buffering.c +++ b/apps/buffering.c @@ -1446,16 +1446,21 @@ void buffering_thread(void) void buffering_init(void) { mutex_init(&llist_mutex); +#ifdef HAVE_PRIORITY_SCHEDULING + /* This behavior not safe atm */ + mutex_set_preempt(&llist_mutex, false); +#endif conf_watermark = BUFFERING_DEFAULT_WATERMARK; queue_init(&buffering_queue, true); - queue_enable_queue_send(&buffering_queue, &buffering_queue_sender_list); - buffering_thread_p = create_thread( buffering_thread, buffering_stack, sizeof(buffering_stack), CREATE_THREAD_FROZEN, buffering_thread_name IF_PRIO(, PRIORITY_BUFFERING) IF_COP(, CPU)); + + queue_enable_queue_send(&buffering_queue, &buffering_queue_sender_list, + buffering_thread_p); } /* Initialise the buffering subsystem */ diff --git a/apps/codecs.c b/apps/codecs.c index dfae463865..f2c74522cc 100644 --- a/apps/codecs.c +++ b/apps/codecs.c @@ -76,6 +76,7 @@ struct codec_api ci = { false, /* stop_codec */ 0, /* new_track */ 0, /* seek_time */ + NULL, /* struct dsp_config *dsp */ NULL, /* get_codec_memory */ NULL, /* pcmbuf_insert */ NULL, /* set_elapsed */ @@ -95,6 +96,23 @@ struct codec_api ci = { PREFIX(sleep), yield, +#if NUM_CORES > 1 + create_thread, + thread_thaw, + thread_wait, + semaphore_init, + semaphore_wait, + semaphore_release, + event_init, + event_wait, + event_set_state, +#endif + +#ifdef CACHE_FUNCTIONS_AS_CALL + flush_icache, + invalidate_icache, +#endif + /* strings and memory */ strcpy, strncpy, @@ -147,24 +165,6 @@ struct codec_api ci = { /* new stuff at the end, sort into place next time the API gets incompatible */ -#ifdef CACHE_FUNCTIONS_AS_CALL - flush_icache, - invalidate_icache, -#endif - - NULL, /* struct dsp_config *dsp */ - -#if NUM_CORES > 1 - create_thread, - thread_thaw, - thread_wait, - semaphore_init, - semaphore_wait, - semaphore_release, - event_init, - event_wait, - event_set_state, -#endif }; void codec_get_full_path(char *path, const char *codec_root_fn) diff --git a/apps/codecs.h b/apps/codecs.h index ad6b831b61..fb5675fd84 100644 --- a/apps/codecs.h +++ b/apps/codecs.h @@ -80,12 +80,12 @@ #define CODEC_ENC_MAGIC 0x52454E43 /* RENC */ /* increase this every time the api struct changes */ -#define CODEC_API_VERSION 22 +#define CODEC_API_VERSION 23 /* 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 CODEC_MIN_API_VERSION 22 +#define CODEC_MIN_API_VERSION 23 /* codec return codes */ enum codec_status { @@ -118,6 +118,9 @@ struct codec_api { /* If seek_time != 0, codec should seek to that song position (in ms) if codec supports seeking. */ long seek_time; + + /* The dsp instance to be used for audio output */ + struct dsp_config *dsp; /* Returns buffer to malloc array. Only codeclib should need this. */ void* (*get_codec_memory)(size_t *size); @@ -160,6 +163,28 @@ struct codec_api { void (*PREFIX(sleep))(int ticks); void (*yield)(void); +#if NUM_CORES > 1 + struct thread_entry * + (*create_thread)(void (*function)(void), void* stack, + size_t stack_size, unsigned flags, const char *name + IF_PRIO(, int priority) + IF_COP(, unsigned int core)); + + void (*thread_thaw)(struct thread_entry *thread); + void (*thread_wait)(struct thread_entry *thread); + void (*semaphore_init)(struct semaphore *s, int max, int start); + void (*semaphore_wait)(struct semaphore *s); + void (*semaphore_release)(struct semaphore *s); + void (*event_init)(struct event *e, unsigned int flags); + void (*event_wait)(struct event *e, unsigned int for_state); + void (*event_set_state)(struct event *e, unsigned int state); +#endif /* NUM_CORES */ + +#ifdef CACHE_FUNCTIONS_AS_CALL + void (*flush_icache)(void); + void (*invalidate_icache)(void); +#endif + /* strings and memory */ char* (*strcpy)(char *dst, const char *src); char* (*strncpy)(char *dst, const char *src, size_t length); @@ -218,29 +243,6 @@ struct codec_api { /* new stuff at the end, sort into place next time the API gets incompatible */ -#ifdef CACHE_FUNCTIONS_AS_CALL - void (*flush_icache)(void); - void (*invalidate_icache)(void); -#endif - - struct dsp_config *dsp; - -#if NUM_CORES > 1 - struct thread_entry * - (*create_thread)(void (*function)(void), void* stack, - int stack_size, unsigned flags, const char *name - IF_PRIO(, int priority) - IF_COP(, unsigned int core)); - - void (*thread_thaw)(struct thread_entry *thread); - void (*thread_wait)(struct thread_entry *thread); - void (*semaphore_init)(struct semaphore *s, int max, int start); - void (*semaphore_wait)(struct semaphore *s); - void (*semaphore_release)(struct semaphore *s); - void (*event_init)(struct event *e, unsigned int flags); - void (*event_wait)(struct event *e, unsigned int for_state); - void (*event_set_state)(struct event *e, unsigned int state); -#endif /* NUM_CORES */ }; /* codec header */ diff --git a/apps/debug_menu.c b/apps/debug_menu.c index d865f12e65..fc509ce236 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c @@ -127,11 +127,6 @@ static char thread_status_char(unsigned status) [STATE_KILLED] = 'K', }; -#if NUM_CORES > 1 - if (status == STATE_BUSY) /* Not a state index */ - return '.'; -#endif - if (status > THREAD_NUM_STATES) status = THREAD_NUM_STATES; @@ -166,15 +161,15 @@ static char* threads_getname(int selected_item, void * data, char *buffer) thread_get_name(name, 32, thread); snprintf(buffer, MAX_PATH, - "%2d: " IF_COP("(%d) ") "%c%c " IF_PRIO("%d ") "%2d%% %s", + "%2d: " IF_COP("(%d) ") "%c%c " IF_PRIO("%d %d ") "%2d%% %s", selected_item, IF_COP(thread->core,) #ifdef HAVE_SCHEDULER_BOOSTCTRL - (thread->boosted) ? '+' : + (thread->cpu_boost) ? '+' : #endif ((thread->state == STATE_RUNNING) ? '*' : ' '), thread_status_char(thread->state), - IF_PRIO(thread->priority,) + IF_PRIO(thread->base_priority, thread->priority, ) thread_stack_usage(thread), name); return buffer; diff --git a/apps/main.c b/apps/main.c index 5dd92e5e02..a3a2241f44 100644 --- a/apps/main.c +++ b/apps/main.c @@ -270,7 +270,7 @@ static void init_tagcache(void) static void init(void) { - init_threads(); + kernel_init(); buffer_init(); set_irq_level(0); lcd_init(); diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index 8153118715..8f16c90523 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c @@ -116,7 +116,7 @@ static bool low_latency_mode = false; static bool pcmbuf_flush; #ifdef HAVE_PRIORITY_SCHEDULING -static int codec_thread_priority = 0; +static int codec_thread_priority = PRIORITY_PLAYBACK; #endif extern struct thread_entry *codec_thread_p; @@ -256,18 +256,21 @@ static void boost_codec_thread(bool boost) * will starve if the codec thread's priority is boosted. */ if (boost) { - if (codec_thread_priority == 0) + int priority = (PRIORITY_PLAYBACK - PRIORITY_PLAYBACK_MAX)*pcmbuf_unplayed_bytes + / (2*NATIVE_FREQUENCY) + PRIORITY_PLAYBACK_MAX; + + if (priority != codec_thread_priority) { - codec_thread_priority = thread_set_priority( - codec_thread_p, PRIORITY_REALTIME); - voice_thread_set_priority(PRIORITY_REALTIME); + codec_thread_priority = priority; + thread_set_priority(codec_thread_p, priority); + voice_thread_set_priority(priority); } } - else if (codec_thread_priority != 0) + else if (codec_thread_priority != PRIORITY_PLAYBACK) { - thread_set_priority(codec_thread_p, codec_thread_priority); - voice_thread_set_priority(codec_thread_priority); - codec_thread_priority = 0; + thread_set_priority(codec_thread_p, PRIORITY_PLAYBACK); + voice_thread_set_priority(PRIORITY_PLAYBACK); + codec_thread_priority = PRIORITY_PLAYBACK; } } #endif /* HAVE_PRIORITY_SCHEDULING */ @@ -818,7 +821,7 @@ static bool prepare_insert(size_t length) if (low_latency_mode) { /* 1/4s latency. */ - if (pcmbuf_unplayed_bytes > NATIVE_FREQUENCY * 4 / 4 + if (pcmbuf_unplayed_bytes > NATIVE_FREQUENCY * 4 / 2 && pcm_is_playing()) return false; } diff --git a/apps/playback.c b/apps/playback.c index 7eecd23e35..9005b3485c 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -2549,9 +2549,7 @@ void audio_init(void) to send messages. Thread creation will be delayed however so nothing starts running until ready if something yields such as talk_init. */ queue_init(&audio_queue, true); - queue_enable_queue_send(&audio_queue, &audio_queue_sender_list); queue_init(&codec_queue, false); - queue_enable_queue_send(&codec_queue, &codec_queue_sender_list); queue_init(&pcmbuf_queue, false); pcm_init(); @@ -2587,11 +2585,17 @@ void audio_init(void) codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK) IF_COP(, CPU)); + queue_enable_queue_send(&codec_queue, &codec_queue_sender_list, + codec_thread_p); + audio_thread_p = create_thread(audio_thread, audio_stack, sizeof(audio_stack), CREATE_THREAD_FROZEN, - audio_thread_name IF_PRIO(, PRIORITY_SYSTEM) + audio_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) IF_COP(, CPU)); + queue_enable_queue_send(&audio_queue, &audio_queue_sender_list, + audio_thread_p); + #ifdef PLAYBACK_VOICE voice_thread_init(); #endif diff --git a/apps/plugin.c b/apps/plugin.c index 57f836c5d2..db9bd2574a 100644 --- a/apps/plugin.c +++ b/apps/plugin.c @@ -253,15 +253,12 @@ static const struct plugin_api rockbox_api = { /* kernel/ system */ PREFIX(sleep), yield, -#ifdef HAVE_PRIORITY_SCHEDULING - priority_yield, -#endif ¤t_tick, default_event_handler, default_event_handler_ex, threads, create_thread, - remove_thread, + thread_exit, thread_wait, #if (CONFIG_CODEC == SWCODEC) mutex_init, diff --git a/apps/plugin.h b/apps/plugin.h index cd426564ba..57624739c7 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -119,12 +119,12 @@ #define PLUGIN_MAGIC 0x526F634B /* RocK */ /* increase this every time the api struct changes */ -#define PLUGIN_API_VERSION 100 +#define PLUGIN_API_VERSION 101 /* 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 100 +#define PLUGIN_MIN_API_VERSION 101 /* plugin return codes */ enum plugin_status { @@ -351,19 +351,16 @@ struct plugin_api { /* kernel/ system */ void (*PREFIX(sleep))(int ticks); void (*yield)(void); -#ifdef HAVE_PRIORITY_SCHEDULING - void (*priority_yield)(void); -#endif volatile long* current_tick; long (*default_event_handler)(long event); long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter); struct thread_entry* threads; struct thread_entry* (*create_thread)(void (*function)(void), void* stack, - int stack_size, unsigned flags, + size_t stack_size, unsigned flags, const char *name IF_PRIO(, int priority) IF_COP(, unsigned int core)); - void (*remove_thread)(struct thread_entry *thread); + void (*thread_exit)(void); void (*thread_wait)(struct thread_entry *thread); #if CONFIG_CODEC == SWCODEC void (*mutex_init)(struct mutex *m); @@ -405,7 +402,8 @@ struct plugin_api { int ticks); #if CONFIG_CODEC == SWCODEC void (*queue_enable_queue_send)(struct event_queue *q, - struct queue_sender_list *send); + struct queue_sender_list *send, + struct thread_entry *owner); bool (*queue_empty)(const struct event_queue *q); void (*queue_wait)(struct event_queue *q, struct queue_event *ev); intptr_t (*queue_send)(struct event_queue *q, long id, diff --git a/apps/plugins/mpegplayer/audio_thread.c b/apps/plugins/mpegplayer/audio_thread.c index 2bb766ad88..7d2f849a44 100644 --- a/apps/plugins/mpegplayer/audio_thread.c +++ b/apps/plugins/mpegplayer/audio_thread.c @@ -714,12 +714,14 @@ bool audio_thread_init(void) /* Start the audio thread */ audio_str.hdr.q = &audio_str_queue; rb->queue_init(audio_str.hdr.q, false); - rb->queue_enable_queue_send(audio_str.hdr.q, &audio_str_queue_send); /* One-up on the priority since the core DSP over-yields internally */ audio_str.thread = rb->create_thread( audio_thread, audio_stack, audio_stack_size, 0, - "mpgaudio" IF_PRIO(,PRIORITY_PLAYBACK-1) IF_COP(, CPU)); + "mpgaudio" IF_PRIO(,PRIORITY_PLAYBACK-4) IF_COP(, CPU)); + + rb->queue_enable_queue_send(audio_str.hdr.q, &audio_str_queue_send, + audio_str.thread); if (audio_str.thread == NULL) return false; diff --git a/apps/plugins/mpegplayer/disk_buf.c b/apps/plugins/mpegplayer/disk_buf.c index a408b90a67..289918fc63 100644 --- a/apps/plugins/mpegplayer/disk_buf.c +++ b/apps/plugins/mpegplayer/disk_buf.c @@ -837,7 +837,6 @@ bool disk_buf_init(void) disk_buf.q = &disk_buf_queue; rb->queue_init(disk_buf.q, false); - rb->queue_enable_queue_send(disk_buf.q, &disk_buf_queue_send); disk_buf.state = TSTATE_EOS; disk_buf.status = STREAM_STOPPED; @@ -886,6 +885,9 @@ bool disk_buf_init(void) disk_buf_thread, disk_buf_stack, sizeof(disk_buf_stack), 0, "mpgbuffer" IF_PRIO(, PRIORITY_BUFFERING) IF_COP(, CPU)); + rb->queue_enable_queue_send(disk_buf.q, &disk_buf_queue_send, + disk_buf.thread); + if (disk_buf.thread == NULL) return false; diff --git a/apps/plugins/mpegplayer/stream_mgr.c b/apps/plugins/mpegplayer/stream_mgr.c index 9da664effe..b962c5b993 100644 --- a/apps/plugins/mpegplayer/stream_mgr.c +++ b/apps/plugins/mpegplayer/stream_mgr.c @@ -987,7 +987,6 @@ int stream_init(void) stream_mgr.q = &stream_mgr_queue; rb->queue_init(stream_mgr.q, false); - rb->queue_enable_queue_send(stream_mgr.q, &stream_mgr_queue_send); /* sets audiosize and returns buffer pointer */ mem = rb->plugin_get_audio_buffer(&memsize); @@ -1028,6 +1027,9 @@ int stream_init(void) stream_mgr_thread_stack, sizeof(stream_mgr_thread_stack), 0, "mpgstream_mgr" IF_PRIO(, PRIORITY_SYSTEM) IF_COP(, CPU)); + rb->queue_enable_queue_send(stream_mgr.q, &stream_mgr_queue_send, + stream_mgr.thread); + if (stream_mgr.thread == NULL) { rb->splash(HZ, "Could not create stream manager thread!"); diff --git a/apps/plugins/mpegplayer/video_thread.c b/apps/plugins/mpegplayer/video_thread.c index 6508d28d1d..d16eb771b0 100644 --- a/apps/plugins/mpegplayer/video_thread.c +++ b/apps/plugins/mpegplayer/video_thread.c @@ -955,7 +955,7 @@ static void video_thread(void) else { /* Just a little left - spin and be accurate */ - rb->priority_yield(); + rb->yield(); if (str_have_msg(&video_str)) goto message_wait; } @@ -998,13 +998,15 @@ bool video_thread_init(void) video_str.hdr.q = &video_str_queue; rb->queue_init(video_str.hdr.q, false); - rb->queue_enable_queue_send(video_str.hdr.q, &video_str_queue_send); /* We put the video thread on another processor for multi-core targets. */ video_str.thread = rb->create_thread( video_thread, video_stack, VIDEO_STACKSIZE, 0, "mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK) IF_COP(, COP)); + rb->queue_enable_queue_send(video_str.hdr.q, &video_str_queue_send, + video_str.thread); + if (video_str.thread == NULL) return false; diff --git a/apps/voice_thread.c b/apps/voice_thread.c index 7bf52d4d0d..6e70f43cc5 100644 --- a/apps/voice_thread.c +++ b/apps/voice_thread.c @@ -424,12 +424,14 @@ void voice_thread_init(void) { logf("Starting voice thread"); queue_init(&voice_queue, false); - queue_enable_queue_send(&voice_queue, &voice_queue_sender_list); mutex_init(&voice_mutex); event_init(&voice_event, STATE_SIGNALED | EVENT_MANUAL); voice_thread_p = create_thread(voice_thread, voice_stack, sizeof(voice_stack), CREATE_THREAD_FROZEN, voice_thread_name IF_PRIO(, PRIORITY_PLAYBACK) IF_COP(, CPU)); + + queue_enable_queue_send(&voice_queue, &voice_queue_sender_list, + voice_thread_p); } /* voice_thread_init */ /* Unfreeze the voice thread */ |