summaryrefslogtreecommitdiffstats
path: root/firmware
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2008-03-30 04:59:51 +0000
committerMichael Sevakis <jethead71@rockbox.org>2008-03-30 04:59:51 +0000
commitbc192c953eb2fe80cac471ea4601c27e23512440 (patch)
tree42b17a28635526d32560e14875865a88b2a6dac8 /firmware
parent8a6fd3ff4e63c81d7d50af535791318481280f95 (diff)
downloadrockbox-bc192c953eb2fe80cac471ea4601c27e23512440.tar.gz
rockbox-bc192c953eb2fe80cac471ea4601c27e23512440.tar.bz2
rockbox-bc192c953eb2fe80cac471ea4601c27e23512440.zip
Add a lightweight wakeup object for fast processors.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16885 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r--firmware/export/config.h4
-rw-r--r--firmware/export/kernel.h23
-rw-r--r--firmware/kernel.c78
3 files changed, 105 insertions, 0 deletions
diff --git a/firmware/export/config.h b/firmware/export/config.h
index 1a288dd590..cd98fc9dca 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -335,6 +335,10 @@
#endif /* SIMULATOR */
#define HAVE_SEMAPHORE_OBJECTS
#define HAVE_EVENT_OBJECTS
+
+#if defined (TOSHIBA_GIGABEAT_F) || defined (TOSHIBA_GIGABEAT_S)
+#define HAVE_WAKEUP_OBJECTS
+#endif
#endif
/* define for all cpus from SH family */
diff --git a/firmware/export/kernel.h b/firmware/export/kernel.h
index 78403c8b7d..337f249dfe 100644
--- a/firmware/export/kernel.h
+++ b/firmware/export/kernel.h
@@ -78,6 +78,11 @@
#define IS_SYSEVENT(ev) ((ev & SYS_EVENT) == SYS_EVENT)
+#ifndef TIMEOUT_BLOCK
+#define TIMEOUT_BLOCK -1
+#define TIMEOUT_NOBLOCK 0
+#endif
+
struct queue_event
{
long id;
@@ -178,6 +183,17 @@ struct event
};
#endif
+
+#ifdef HAVE_WAKEUP_OBJECTS
+struct wakeup
+{
+ struct thread_entry *queue; /* waiter list */
+ unsigned char signalled; /* signalled status */
+ IF_COP( struct corelock cl; ) /* multiprocessor sync */
+};
+#endif
+
+
/* global tick variable */
#if defined(CPU_PP) && defined(BOOTLOADER)
/* We don't enable interrupts in the iPod bootloader, so we need to fake
@@ -225,6 +241,7 @@ void timeout_cancel(struct timeout *tmo);
#define STATE_SIGNALED 1
#define WAIT_TIMEDOUT (-1)
+#define WAIT_FAILED 0
#define WAIT_SUCCEEDED 1
extern void queue_init(struct event_queue *q, bool register_queue);
@@ -274,4 +291,10 @@ extern void event_wait(struct event *e, unsigned int for_state);
extern void event_set_state(struct event *e, unsigned int state);
#endif /* HAVE_EVENT_OBJECTS */
+#ifdef HAVE_WAKEUP_OBJECTS
+extern void wakeup_init(struct wakeup *w);
+extern int wakeup_wait(struct wakeup *w, int timeout);
+extern int wakeup_signal(struct wakeup *w);
+#endif /* HAVE_WAKEUP_OBJECTS */
+
#endif /* _KERNEL_H_ */
diff --git a/firmware/kernel.c b/firmware/kernel.c
index 184d29fe93..439aea584a 100644
--- a/firmware/kernel.c
+++ b/firmware/kernel.c
@@ -1368,3 +1368,81 @@ void event_set_state(struct event *e, unsigned int state)
#endif
}
#endif /* HAVE_EVENT_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 = 0;
+ 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 = WAIT_SUCCEEDED; /* Presume success */
+ int oldlevel = disable_irq_save();
+
+ corelock_lock(&w->cl);
+
+ if(w->signalled == 0 && timeout != TIMEOUT_NOBLOCK)
+ {
+ struct thread_entry * current = cores[CURRENT_CORE].running;
+
+ 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(w->signalled == 0)
+ {
+ /* Timed-out or failed */
+ ret = (timeout != TIMEOUT_BLOCK) ? WAIT_TIMEDOUT : WAIT_FAILED;
+ }
+
+ w->signalled = 0; /* 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 = 1;
+ ret = wakeup_thread(&w->queue);
+
+ corelock_unlock(&w->cl);
+ restore_irq(oldlevel);
+
+ return ret;
+}
+#endif /* HAVE_WAKEUP_OBJECTS */
+