diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2006-12-16 18:35:12 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2006-12-16 18:35:12 +0000 |
commit | 43c15921e42ad56f315ad2f54ce6fa52e02d3b41 (patch) | |
tree | 95d64629e7b34789fde0c36a77dad0678d0502ef /uisimulator | |
parent | 63a1cb52b43854848171334379f2ed9d4fe47837 (diff) | |
download | rockbox-43c15921e42ad56f315ad2f54ce6fa52e02d3b41.tar.gz rockbox-43c15921e42ad56f315ad2f54ce6fa52e02d3b41.zip |
Add queue_send synchronous message sending. Right now only for SWCODEC. Actual usage to be added to playback and recording shortly in upcoming commits.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11776 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'uisimulator')
-rw-r--r-- | uisimulator/sdl/kernel.c | 189 |
1 files changed, 178 insertions, 11 deletions
diff --git a/uisimulator/sdl/kernel.c b/uisimulator/sdl/kernel.c index f1eb095e7b..fa573a3cc9 100644 --- a/uisimulator/sdl/kernel.c +++ b/uisimulator/sdl/kernel.c @@ -18,6 +18,7 @@ ****************************************************************************/ #include <stdlib.h> +#include "memory.h" #include "uisdl.h" #include "kernel.h" #include "thread-sdl.h" @@ -32,13 +33,71 @@ int set_irq_level (int level) return (_lv = level); } +#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME +/* Moves waiting thread's descriptor to the current sender when a + message is dequeued */ +static void queue_fetch_sender(struct queue_sender_list *send, + unsigned int i) +{ + int old_level = set_irq_level(15<<4); + struct queue_sender **spp = &send->senders[i]; + + if(*spp) + { + send->curr_sender = *spp; + *spp = NULL; + } + + set_irq_level(old_level); +} + +/* Puts the specified return value in the waiting thread's return value + and wakes the thread - a sender should be confirmed to exist first */ +static void queue_release_sender(struct queue_sender **sender, void *retval) +{ + (*sender)->retval = retval; + *sender = NULL; +} + +/* Releases any waiting threads that are queued with queue_send - + reply with NULL */ +static void queue_release_all_senders(struct event_queue *q) +{ + if(q->send) + { + unsigned int i; + for(i = q->read; i != q->write; i++) + { + struct queue_sender **spp = + &q->send->senders[i & QUEUE_LENGTH_MASK]; + if(*spp) + { + queue_release_sender(spp, NULL); + } + } + } +} + +/* Enables queue_send on the specified queue - caller allocates the extra + data structure */ +void queue_enable_queue_send(struct event_queue *q, + struct queue_sender_list *send) +{ + q->send = send; + memset(send, 0, sizeof(*send)); +} +#endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */ + void queue_init(struct event_queue *q, bool register_queue) { (void)register_queue; - q->read = 0; - q->write = 0; + q->read = 0; + q->write = 0; q->thread = NULL; +#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME + q->send = NULL; /* No message sending by default */ +#endif } void queue_delete(struct event_queue *q) @@ -48,12 +107,23 @@ void queue_delete(struct event_queue *q) void queue_wait(struct event_queue *q, struct event *ev) { + unsigned int rd; + while(q->read == q->write) { switch_thread(true, NULL); } - *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK]; + rd = q->read++ & QUEUE_LENGTH_MASK; + *ev = q->events[rd]; + +#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME + if(q->send && q->send->senders[rd]) + { + /* Get data for a waiting thread if one */ + queue_fetch_sender(q->send, rd); + } +#endif } void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks) @@ -67,7 +137,16 @@ void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks) if(q->read != q->write) { - *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK]; + unsigned int rd = q->read++ & QUEUE_LENGTH_MASK; + *ev = q->events[rd]; + +#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME + if(q->send && q->send->senders[rd]) + { + /* Get data for a waiting thread if one */ + queue_fetch_sender(q->send, rd); + } +#endif } else { @@ -77,16 +156,81 @@ void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks) void queue_post(struct event_queue *q, long id, void *data) { - int wr; - int oldlevel; + int oldlevel = set_irq_level(15<<4); + unsigned int wr = q->write++ & QUEUE_LENGTH_MASK; + + q->events[wr].id = id; + q->events[wr].data = data; + +#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME + if(q->send) + { + struct queue_sender **spp = &q->send->senders[wr]; + + if(*spp) + { + /* overflow protect - unblock any thread waiting at this index */ + queue_release_sender(spp, NULL); + } + } +#endif - oldlevel = set_irq_level(15<<4); - wr = (q->write++) & QUEUE_LENGTH_MASK; + set_irq_level(oldlevel); +} - q->events[wr].id = id; +#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME +void * queue_send(struct event_queue *q, long id, void *data) +{ + int oldlevel = set_irq_level(15<<4); + unsigned int wr = q->write++ & QUEUE_LENGTH_MASK; + + q->events[wr].id = id; q->events[wr].data = data; + + if(q->send) + { + struct queue_sender **spp = &q->send->senders[wr]; + struct queue_sender sender; + + if(*spp) + { + /* overflow protect - unblock any thread waiting at this index */ + queue_release_sender(spp, NULL); + } + + *spp = &sender; + + set_irq_level(oldlevel); + while (*spp != NULL) + { + switch_thread(true, NULL); + } + + return sender.retval; + } + + /* Function as queue_post if sending is not enabled */ set_irq_level(oldlevel); + return NULL; +} + +#if 0 /* not used now but probably will be later */ +/* Query if the last message dequeued was added by queue_send or not */ +bool queue_in_queue_send(struct event_queue *q) +{ + return q->send && q->send->curr_sender; } +#endif + +/* Replies with retval to any dequeued message sent with queue_send */ +void queue_reply(struct event_queue *q, void *retval) +{ + if(q->send && q->send->curr_sender) + { + queue_release_sender(&q->send->curr_sender, retval); + } +} +#endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */ bool queue_empty(const struct event_queue* q) { @@ -96,6 +240,11 @@ bool queue_empty(const struct event_queue* q) void queue_clear(struct event_queue* q) { /* fixme: This is potentially unsafe in case we do interrupt-like processing */ +#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME + /* Release all thread waiting in the queue for a reply - + dequeued sent message will be handled by owning thread */ + queue_release_all_senders(q); +#endif q->read = 0; q->write = 0; } @@ -104,9 +253,27 @@ void queue_remove_from_head(struct event_queue *q, long id) { int oldlevel = set_irq_level(15<<4); - while (q->read != q->write && - q->events[(q->read) & QUEUE_LENGTH_MASK].id == id) + while(q->read != q->write) { + unsigned int rd = q->read & QUEUE_LENGTH_MASK; + + if(q->events[rd].id != id) + { + break; + } + +#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME + if(q->send) + { + struct queue_sender **spp = &q->send->senders[rd]; + + if(*spp) + { + /* Release any thread waiting on this message */ + queue_release_sender(spp, NULL); + } + } +#endif q->read++; } |