diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2007-03-23 01:00:13 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2007-03-23 01:00:13 +0000 |
commit | 6d87513aa2365a3b63fd71ecafb4f41363f256fe (patch) | |
tree | 567d7595e403bd917aaad40317a30d19366a4357 /firmware | |
parent | 8b4076955451df160593f7d3a345801015aec039 (diff) |
In reponse to a report of a blocking violation, give sync queues a going over and catch any old, obscure leftover issues. A couple spots needed interrupt stopage where there could be confict if an IRQ post wakes a waiting thread because the queue is overflowing. There does appear to be an issue with wakeup_thread, interrupts and running list modification in general.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12895 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/kernel.c | 30 |
1 files changed, 26 insertions, 4 deletions
diff --git a/firmware/kernel.c b/firmware/kernel.c index cddaf41656..192728bdb2 100644 --- a/firmware/kernel.c +++ b/firmware/kernel.c @@ -100,6 +100,7 @@ void yield(void) static void queue_fetch_sender(struct queue_sender_list *send, unsigned int i) { + /* Disable interrupts to protect against collision in this slot */ int old_level = set_irq_level(HIGHEST_IRQ_LEVEL); struct thread_entry **spp = &send->senders[i]; @@ -113,17 +114,31 @@ static void queue_fetch_sender(struct queue_sender_list *send, } /* Puts the specified return value in the waiting thread's return value - and wakes the thread - a sender should be confirmed to exist first */ + * and wakes the thread. + * 1) A sender should be confirmed to exist before calling which makes it + * more efficent to reject the majority of cases that don't need this + called. + * 2) Requires interrupts disabled since queue overflows can cause posts + * from interrupt handlers to wake threads. Not doing so could cause + * an attempt at multiple wakes or other problems. + */ static void queue_release_sender(struct thread_entry **sender, intptr_t retval) { (*sender)->retval = retval; wakeup_thread(sender); - *sender = NULL; +#if 0 + /* This should _never_ happen - there must never be multiple + threads in this list and it is a corrupt state */ + if (*sender != NULL) + panicf("Queue: send slot ovf"); +#endif } /* Releases any waiting threads that are queued with queue_send - - reply with NULL */ + * reply with 0. + * Disable IRQs before calling since it uses queue_release_sender. + */ static void queue_release_all_senders(struct event_queue *q) { if(q->send) @@ -191,8 +206,10 @@ void queue_delete(struct event_queue *q) #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME /* Release waiting threads and reply to any dequeued message waiting for one. */ + int level = set_irq_level(HIGHEST_IRQ_LEVEL); queue_release_all_senders(q); queue_reply(q, NULL); + set_irq_level(level); #endif /* Move the following queues up in the list */ for(;i < num_queues-1;i++) @@ -319,7 +336,12 @@ void queue_reply(struct event_queue *q, intptr_t retval) { if(q->send && q->send->curr_sender) { - queue_release_sender(&q->send->curr_sender, retval); + int level = set_irq_level(HIGHEST_IRQ_LEVEL); + if(q->send->curr_sender) + { + queue_release_sender(&q->send->curr_sender, retval); + } + set_irq_level(level); } } #endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */ |