summaryrefslogtreecommitdiffstats
path: root/firmware/kernel.c
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2011-03-02 08:49:38 +0000
committerMichael Sevakis <jethead71@rockbox.org>2011-03-02 08:49:38 +0000
commit12375d1d3aa41f7d277a9af584c7b810b636ec95 (patch)
treefc9ce8029a6910a8dac71b3bf60c71155a01eea4 /firmware/kernel.c
parent05e180a1308a095d51d51d0e047fcd44425ea88f (diff)
downloadrockbox-12375d1d3aa41f7d277a9af584c7b810b636ec95.tar.gz
rockbox-12375d1d3aa41f7d277a9af584c7b810b636ec95.zip
Merge functionality of wakeups and semaphores-- fewer APIs and object types. semaphore_wait takes a timeout now so codecs and plugins have to be made incompatible. Don't make semaphores for targets not using them.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29492 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/kernel.c')
-rw-r--r--firmware/kernel.c166
1 files changed, 67 insertions, 99 deletions
diff --git a/firmware/kernel.c b/firmware/kernel.c
index 588bbd2a75..a8718ebf34 100644
--- a/firmware/kernel.c
+++ b/firmware/kernel.c
@@ -978,6 +978,9 @@ void mutex_unlock(struct mutex *m)
* Simple semaphore functions ;)
****************************************************************************/
#ifdef HAVE_SEMAPHORE_OBJECTS
+/* Initialize the semaphore object.
+ * max = maximum up count the semaphore may assume (max >= 1)
+ * start = initial count of semaphore (0 <= count <= max) */
void semaphore_init(struct semaphore *s, int max, int start)
{
KERNEL_ASSERT(max > 0 && start >= 0 && start <= max,
@@ -988,132 +991,97 @@ void semaphore_init(struct semaphore *s, int max, int start)
corelock_init(&s->cl);
}
-void semaphore_wait(struct semaphore *s)
+/* Down the semaphore's count or wait for 'timeout' ticks for it to go up if
+ * it is already 0. 'timeout' as TIMEOUT_NOBLOCK (0) will not block and may
+ * safely be used in an ISR. */
+int semaphore_wait(struct semaphore *s, int timeout)
{
- struct thread_entry *current;
+ int ret;
+ int oldlevel;
+ int count;
+ oldlevel = disable_irq_save();
corelock_lock(&s->cl);
- if(LIKELY(--s->count >= 0))
+ count = s->count;
+
+ if(LIKELY(count > 0))
{
- /* wait satisfied */
- corelock_unlock(&s->cl);
- return;
+ /* count is not zero; down it */
+ s->count = count - 1;
+ ret = OBJ_WAIT_SUCCEEDED;
+ }
+ else if(timeout == 0)
+ {
+ /* just polling it */
+ ret = OBJ_WAIT_TIMEDOUT;
}
+ else
+ {
+ /* too many waits - block until count is upped... */
+ struct thread_entry * current = thread_id_entry(THREAD_ID_CURRENT);
+ IF_COP( current->obj_cl = &s->cl; )
+ current->bqp = &s->queue;
+ /* return value will be OBJ_WAIT_SUCCEEDED after wait if wake was
+ * explicit in semaphore_release */
+ current->retval = OBJ_WAIT_TIMEDOUT;
+
+ if(timeout > 0)
+ block_thread_w_tmo(current, timeout); /* ...or timed out... */
+ else
+ block_thread(current); /* -timeout = infinite */
- /* too many waits - block until dequeued... */
- current = thread_id_entry(THREAD_ID_CURRENT);
+ corelock_unlock(&s->cl);
- IF_COP( current->obj_cl = &s->cl; )
- current->bqp = &s->queue;
+ /* ...and turn control over to next thread */
+ switch_thread();
- disable_irq();
- block_thread(current);
+ return current->retval;
+ }
corelock_unlock(&s->cl);
+ restore_irq(oldlevel);
- /* ...and turn control over to next thread */
- switch_thread();
+ return ret;
}
+/* Up the semaphore's count and release any thread waiting at the head of the
+ * queue. The count is saturated to the value of the 'max' parameter specified
+ * in 'semaphore_init'. */
void semaphore_release(struct semaphore *s)
{
IF_PRIO( unsigned int result = THREAD_NONE; )
+ int oldlevel;
+ oldlevel = disable_irq_save();
corelock_lock(&s->cl);
- if(s->count < s->max && ++s->count <= 0)
+ if(LIKELY(s->queue != NULL))
{
- /* there should be threads in this queue */
- KERNEL_ASSERT(s->queue != NULL, "semaphore->wakeup\n");
- /* a thread was queued - wake it up */
- int oldlevel = disable_irq_save();
+ /* a thread was queued - wake it up and keep count at 0 */
+ KERNEL_ASSERT(s->count == 0,
+ "semaphore_release->threads queued but count=%d!\n", s->count);
+ s->queue->retval = OBJ_WAIT_SUCCEEDED; /* indicate explicit wake */
IF_PRIO( result = ) wakeup_thread(&s->queue);
- restore_irq(oldlevel);
+ }
+ else
+ {
+ int count = s->count;
+ if(count < s->max)
+ {
+ /* nothing waiting - up it */
+ s->count = count + 1;
+ }
}
corelock_unlock(&s->cl);
+ restore_irq(oldlevel);
-#ifdef HAVE_PRIORITY_SCHEDULING
- if(result & THREAD_SWITCH)
+#if defined(HAVE_PRIORITY_SCHEDULING) && defined(irq_enabled_checkval)
+ /* No thread switch if IRQ disabled - it's probably called via ISR.
+ * switch_thread would as well enable them anyway. */
+ if((result & THREAD_SWITCH) && irq_enabled_checkval(oldlevel))
switch_thread();
#endif
}
#endif /* HAVE_SEMAPHORE_OBJECTS */
-
-#ifdef HAVE_WAKEUP_OBJECTS
-/****************************************************************************
- * Lightweight IRQ-compatible wakeup object
- */
-
-/* Initialize the wakeup object */
-void wakeup_init(struct wakeup *w)
-{
- w->queue = NULL;
- w->signalled = false;
- IF_COP( corelock_init(&w->cl); )
-}
-
-/* Wait for a signal blocking indefinitely or for a specified period */
-int wakeup_wait(struct wakeup *w, int timeout)
-{
- int ret = OBJ_WAIT_SUCCEEDED; /* Presume success */
- int oldlevel = disable_irq_save();
-
- corelock_lock(&w->cl);
-
- if(LIKELY(!w->signalled && timeout != TIMEOUT_NOBLOCK))
- {
- struct thread_entry * current = thread_id_entry(THREAD_ID_CURRENT);
-
- IF_COP( current->obj_cl = &w->cl; )
- current->bqp = &w->queue;
-
- if (timeout != TIMEOUT_BLOCK)
- block_thread_w_tmo(current, timeout);
- else
- block_thread(current);
-
- corelock_unlock(&w->cl);
- switch_thread();
-
- oldlevel = disable_irq_save();
- corelock_lock(&w->cl);
- }
-
- if(UNLIKELY(!w->signalled))
- {
- /* Timed-out or failed */
- ret = (timeout != TIMEOUT_BLOCK) ?
- OBJ_WAIT_TIMEDOUT : OBJ_WAIT_FAILED;
- }
-
- w->signalled = false; /* Reset */
-
- corelock_unlock(&w->cl);
- restore_irq(oldlevel);
-
- return ret;
-}
-
-/* Signal the thread waiting or leave the signal if the thread hasn't
- * waited yet.
- *
- * returns THREAD_NONE or THREAD_OK
- */
-int wakeup_signal(struct wakeup *w)
-{
- int oldlevel = disable_irq_save();
- int ret;
-
- corelock_lock(&w->cl);
-
- w->signalled = true;
- ret = wakeup_thread(&w->queue);
-
- corelock_unlock(&w->cl);
- restore_irq(oldlevel);
-
- return ret;
-}
-#endif /* HAVE_WAKEUP_OBJECTS */