summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2007-03-23 01:00:13 +0000
committerMichael Sevakis <jethead71@rockbox.org>2007-03-23 01:00:13 +0000
commit6d87513aa2365a3b63fd71ecafb4f41363f256fe (patch)
tree567d7595e403bd917aaad40317a30d19366a4357 /firmware
parent8b4076955451df160593f7d3a345801015aec039 (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.c30
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 */