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,
|
static void queue_fetch_sender(struct queue_sender_list *send,
|
||||||
unsigned int i)
|
unsigned int i)
|
||||||
{
|
{
|
||||||
|
/* Disable interrupts to protect against collision in this slot */
|
||||||
int old_level = set_irq_level(HIGHEST_IRQ_LEVEL);
|
int old_level = set_irq_level(HIGHEST_IRQ_LEVEL);
|
||||||
struct thread_entry **spp = &send->senders[i];
|
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
|
/* 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,
|
static void queue_release_sender(struct thread_entry **sender,
|
||||||
intptr_t retval)
|
intptr_t retval)
|
||||||
{
|
{
|
||||||
(*sender)->retval = retval;
|
(*sender)->retval = retval;
|
||||||
wakeup_thread(sender);
|
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 -
|
/* 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)
|
static void queue_release_all_senders(struct event_queue *q)
|
||||||
{
|
{
|
||||||
if(q->send)
|
if(q->send)
|
||||||
|
@ -191,8 +206,10 @@ void queue_delete(struct event_queue *q)
|
||||||
#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
|
#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
|
||||||
/* Release waiting threads and reply to any dequeued message
|
/* Release waiting threads and reply to any dequeued message
|
||||||
waiting for one. */
|
waiting for one. */
|
||||||
|
int level = set_irq_level(HIGHEST_IRQ_LEVEL);
|
||||||
queue_release_all_senders(q);
|
queue_release_all_senders(q);
|
||||||
queue_reply(q, NULL);
|
queue_reply(q, NULL);
|
||||||
|
set_irq_level(level);
|
||||||
#endif
|
#endif
|
||||||
/* Move the following queues up in the list */
|
/* Move the following queues up in the list */
|
||||||
for(;i < num_queues-1;i++)
|
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)
|
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 */
|
#endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue