From 6d87513aa2365a3b63fd71ecafb4f41363f256fe Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Fri, 23 Mar 2007 01:00:13 +0000 Subject: [PATCH] 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 --- firmware/kernel.c | 30 ++++++++++++++++++++++++++---- 1 file 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 */