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)
downloadrockbox-6d87513aa2365a3b63fd71ecafb4f41363f256fe.tar.gz
rockbox-6d87513aa2365a3b63fd71ecafb4f41363f256fe.zip
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)
100static void queue_fetch_sender(struct queue_sender_list *send, 100static void queue_fetch_sender(struct queue_sender_list *send,
101 unsigned int i) 101 unsigned int i)
102{ 102{
103 /* Disable interrupts to protect against collision in this slot */
103 int old_level = set_irq_level(HIGHEST_IRQ_LEVEL); 104 int old_level = set_irq_level(HIGHEST_IRQ_LEVEL);
104 struct thread_entry **spp = &send->senders[i]; 105 struct thread_entry **spp = &send->senders[i];
105 106
@@ -113,17 +114,31 @@ static void queue_fetch_sender(struct queue_sender_list *send,
113} 114}
114 115
115/* Puts the specified return value in the waiting thread's return value 116/* Puts the specified return value in the waiting thread's return value
116 and wakes the thread - a sender should be confirmed to exist first */ 117 * and wakes the thread.
118 * 1) A sender should be confirmed to exist before calling which makes it
119 * more efficent to reject the majority of cases that don't need this
120 called.
121 * 2) Requires interrupts disabled since queue overflows can cause posts
122 * from interrupt handlers to wake threads. Not doing so could cause
123 * an attempt at multiple wakes or other problems.
124 */
117static void queue_release_sender(struct thread_entry **sender, 125static void queue_release_sender(struct thread_entry **sender,
118 intptr_t retval) 126 intptr_t retval)
119{ 127{
120 (*sender)->retval = retval; 128 (*sender)->retval = retval;
121 wakeup_thread(sender); 129 wakeup_thread(sender);
122 *sender = NULL; 130#if 0
131 /* This should _never_ happen - there must never be multiple
132 threads in this list and it is a corrupt state */
133 if (*sender != NULL)
134 panicf("Queue: send slot ovf");
135#endif
123} 136}
124 137
125/* Releases any waiting threads that are queued with queue_send - 138/* Releases any waiting threads that are queued with queue_send -
126 reply with NULL */ 139 * reply with 0.
140 * Disable IRQs before calling since it uses queue_release_sender.
141 */
127static void queue_release_all_senders(struct event_queue *q) 142static void queue_release_all_senders(struct event_queue *q)
128{ 143{
129 if(q->send) 144 if(q->send)
@@ -191,8 +206,10 @@ void queue_delete(struct event_queue *q)
191#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME 206#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
192 /* Release waiting threads and reply to any dequeued message 207 /* Release waiting threads and reply to any dequeued message
193 waiting for one. */ 208 waiting for one. */
209 int level = set_irq_level(HIGHEST_IRQ_LEVEL);
194 queue_release_all_senders(q); 210 queue_release_all_senders(q);
195 queue_reply(q, NULL); 211 queue_reply(q, NULL);
212 set_irq_level(level);
196#endif 213#endif
197 /* Move the following queues up in the list */ 214 /* Move the following queues up in the list */
198 for(;i < num_queues-1;i++) 215 for(;i < num_queues-1;i++)
@@ -319,7 +336,12 @@ void queue_reply(struct event_queue *q, intptr_t retval)
319{ 336{
320 if(q->send && q->send->curr_sender) 337 if(q->send && q->send->curr_sender)
321 { 338 {
322 queue_release_sender(&q->send->curr_sender, retval); 339 int level = set_irq_level(HIGHEST_IRQ_LEVEL);
340 if(q->send->curr_sender)
341 {
342 queue_release_sender(&q->send->curr_sender, retval);
343 }
344 set_irq_level(level);
323 } 345 }
324} 346}
325#endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */ 347#endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */