forked from len0rd/rockbox
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
This commit is contained in:
parent
8b40769554
commit
6d87513aa2
1 changed files with 26 additions and 4 deletions
|
@ -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 */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue