summaryrefslogtreecommitdiff
path: root/nuttx
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2010-08-15 16:23:18 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2010-08-15 16:23:18 +0000
commitaa8fe0d6cf94a297fd0e7c8a6ab1ddb315fda57e (patch)
treec4b6ec2ea5886dc9ce638d1981146ec1cb363006 /nuttx
parentb2769ae6a5785363554e9c77953eed7bf8a9e1f9 (diff)
downloadpx4-nuttx-aa8fe0d6cf94a297fd0e7c8a6ab1ddb315fda57e.tar.gz
px4-nuttx-aa8fe0d6cf94a297fd0e7c8a6ab1ddb315fda57e.tar.bz2
px4-nuttx-aa8fe0d6cf94a297fd0e7c8a6ab1ddb315fda57e.zip
Minor design improvements
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2856 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx')
-rwxr-xr-xnuttx/include/nuttx/page.h12
-rwxr-xr-xnuttx/sched/pg_worker.c175
2 files changed, 130 insertions, 57 deletions
diff --git a/nuttx/include/nuttx/page.h b/nuttx/include/nuttx/page.h
index 147a3b6c8..fc8ec989d 100755
--- a/nuttx/include/nuttx/page.h
+++ b/nuttx/include/nuttx/page.h
@@ -43,10 +43,7 @@
#include <nuttx/config.h>
-#include <sys/types.h>
-#include <stdint.h>
#include <stdbool.h>
-#include <nuttx/wqueue.h>
#ifdef CONFIG_PAGING
@@ -165,10 +162,9 @@ EXTERN void pg_miss(void);
* to be performed or not.
*
* Returned Value:
- * This function will return zero (OK) if the mapping is in place and
- * the negated errn ENXIO if the mapping is still needed. Other errors
- * may also be returned but these will be interpreted as fatal error
- * conditions.
+ * This function will return true if the mapping is in place and false
+ * if the mapping is still needed. Errors encountered should be
+ * interpreted as fatal.
*
* Assumptions:
* - This function is called from the normal tasking context (but with
@@ -178,7 +174,7 @@ EXTERN void pg_miss(void);
*
****************************************************************************/
-EXTERN int up_checkmapping(FAR _TCB *tcb);
+EXTERN bool up_checkmapping(FAR _TCB *tcb);
/****************************************************************************
* Name: up_allocpage()
diff --git a/nuttx/sched/pg_worker.c b/nuttx/sched/pg_worker.c
index 51975b05a..6c20111ac 100755
--- a/nuttx/sched/pg_worker.c
+++ b/nuttx/sched/pg_worker.c
@@ -41,6 +41,7 @@
#include <nuttx/config.h>
#include <stdint.h>
+#include <stdbool.h>
#include <unistd.h>
#include <queue.h>
#include <assert.h>
@@ -203,13 +204,85 @@ static void pg_callback(FAR _TCB *tcb, int result)
#endif
/****************************************************************************
+ * Name: pg_dequeue
+ *
+ * Description:
+ * Dequeue the next, highest priority TCB from the g_waitingforfill task
+ * list. Call up_checkmapping() see if the still needs to be performed
+ * for that task. In certain conditions, the page fault may occur on
+ * several threads for the same page and be queued multiple times. In this
+ * corner case, the blocked task will simply be restarted.
+ *
+ * This function will continue to examine g_waitingforfill until either
+ * (1) a task is found that still needs the page fill, or (2) the
+ * g_waitingforfill task list becomes empty.
+ *
+ * The result (NULL or a TCB pointer) will be returned in the global
+ * variable, g_pendingfilltcb.
+ *
+ * Input parameters:
+ * None
+ *
+ * Returned Value:
+ * If there are no further queue page fill operations to be performed,
+ * pg_startfill() will return false. Otherwise, it will return
+ * true to that the full is in process (any errors will result in
+ * assertions and this function will not return).
+ *
+ * Assumptions:
+ * Executing in the context of the page fill worker thread with all
+ * interrupts disabled.
+ *
+ ****************************************************************************/
+
+static inline bool pg_dequeue(void)
+{
+ /* Loop until either (1) the TCB of a task that requires a fill is found, OR
+ * (2) the g_watingforfill list becomes empty.
+ */
+
+ do
+ {
+ /* Remove the TCB from the head of the list (if any) */
+
+ g_pendingfilltcb = (FAR _TCB *)dq_remfirst((dq_queue_t*)&g_waitingforfill);
+ if (g_pendingfilltcb != NULL)
+ {
+ /* Call the architecture-specific function up_checkmapping() to see if
+ * the page fill still needs to be performed. In certain conditions,
+ * the page fault may occur on several threads for the same page and
+ * be queues multiple times. In this corner case, the blocked task will
+ * simply be restarted.
+ */
+
+ if (!up_checkmapping(g_pendingfilltcb))
+ {
+ /* This page needs to be filled. Return with g_pendingfilltcb
+ * holding the pointer to the TCB associated with task.
+ */
+
+ return true;
+ }
+
+ /* The page need by this task has already been mapped into the
+ * virtual address space -- just restart it.
+ */
+
+ up_unblock_task(g_pendingfilltcb);
+ }
+ }
+ while (g_pendingfilltcb != NULL);
+ return false;
+}
+
+/****************************************************************************
* Name: pg_startfill
*
* Description:
* Start a page fill operation on the thread whose TCB is at the head of
- * of the g_waitingforfill task list. That is a prioritized list so that will
- * be the highest priority task waiting for a page fill (in the event that
- * are multiple tasks waiting for a page fill).
+ * of the g_waitingforfill task list. That is a prioritized list so that
+ * will be the highest priority task waiting for a page fill (in the event
+ * that are multiple tasks waiting for a page fill).
*
* This function may be called either (1) when the page fill worker thread
* is notified that there is a new page fill TCB in the g_waitingforfill
@@ -220,7 +293,10 @@ static void pg_callback(FAR _TCB *tcb, int result)
* None
*
* Returned Value:
- * None
+ * If there are no further queue page fill operations to be performed,
+ * pg_startfill() will return false. Otherwise, it will return
+ * true to that the full is in process (any errors will result in
+ * assertions and this function will not return).
*
* Assumptions:
* Executing in the context of the page fill worker thread with all
@@ -228,30 +304,19 @@ static void pg_callback(FAR _TCB *tcb, int result)
*
****************************************************************************/
-static inline void pg_startfill(void)
+static inline bool pg_startfill(void)
{
FAR void *vpage;
int result;
- /* Remove the TCB at the head of the g_waitfor fill list */
+ /* Remove the TCB at the head of the g_waitfor fill list and check if there
+ * is any task waiting for a page fill. pg_dequeue will handle this (plus
+ * some cornercases) and will true if the next page TCB was successfully
+ * dequeued.
+ */
- g_pendingfilltcb = (FAR _TCB *)dq_remfirst((dq_queue_t*)&g_waitingforfill);
- if (g_pendingfilltcb != NULL)
+ if (pg_dequeue())
{
- /* Call the architecture-specific function up_checkmapping() to see if the
- * page fill still needs to be performed. In certain conditions, the page
- * fault may occur on several threads and be queued multiple times. In this
- * corner case, the blocked task will simply be restarted.
- */
-
- result = up_checkmapping(g_pendingfilltcb);
- if (result == OK)
- {
- up_unblock_task(g_pendingfilltcb);
- g_pendingfilltcb = NULL;
- return;
- }
-
/* Call up_allocpage(tcb, &vpage). This architecture-specific function will
* set aside page in memory and map to virtual address (vpage). If all
* available pages are in-use (the typical case), this function will select
@@ -308,7 +373,9 @@ static inline void pg_startfill(void)
* task must still be available to run.
*/
#endif /* CONFIG_PAGING_BLOCKINGFILL */
+ return true;
}
+ return false;
}
/****************************************************************************
@@ -390,7 +457,7 @@ static inline void pg_fillcomplete(void)
* The page fill worker thread will be awakened on one of three conditions:
* - When signaled by pg_miss(), the page fill worker thread will be
* awakenend, or
- * - if CONFIG_PAGING_BLOCKINGFILL is not defined, from pg_fillcomplete()
+ * - if CONFIG_PAGING_BLOCKINGFILL is not defined, from pg_callback()
* after completing a page fill.
* - A configurable timeout with no activity.
*
@@ -459,21 +526,23 @@ int pg_worker(int argc, char *argv[])
ASSERT(g_fillresult == OK);
- /* Handle the page fill complete event */
+ /* Handle the successful page fill complete event by restarting the
+ * task that was blocked waiting for this page fill.
+ */
- pg_fillcomplete();
+ up_unblock_task(g_pendingfilltcb);;
- /* Check if there are are more pending page fills */
+ /* Yes .. Start the next asynchronous fill. Check the return
+ * value to see a fill was actually started (false means that
+ * no fill was started).
+ */
- if (g_waitingforfill.head != NULL)
+ if (!pg_startfill())
{
- /* Yes .. Start the next asynchronous fill */
-
- pg_startfill();
- }
- else
- {
- /* Otherwise, there is nothing more to do */
+ /* No fill was started. This can mean only that all queued
+ * page fill actions have and been completed and there is
+ * nothing more to do.
+ */
pg_alldone();
}
@@ -499,32 +568,40 @@ int pg_worker(int argc, char *argv[])
else
{
- /* Are there tasks blocked and waiting for a fill? */
-
- if (g_waitingforfill.head != NULL)
- {
- /* Yes .. Start the asynchronous fill */
+ /* Are there tasks blocked and waiting for a fill? If so,
+ * pg_startfill() will start the asynchronous fill (and set
+ * g_pendingfilltcb).
+ */
- pg_startfill();
- }
+ (void)pg_startfill();
}
#else
/* Are there tasks blocked and waiting for a fill? Loop until all
- * pending fills have been processed
+ * pending fills have been processed.
*/
- while (g_waitingforfill.head != NULL)
+ for (;;)
{
- /* Yes .. Start the fill and block until the fill completes */
+ /* Yes .. Start the fill and block until the fill completes.
+ * Check the return value to see a fill was actually performed.
+ * (false means that no fill was perforemd).
+ */
- pg_startfill();
+ if (!pg_startfill())
+ {
+ /* Break out of the loop -- there is nothing more to do */
+
+ break;
+ }
- /* Handle the page fill complete event. In the non-blocking case,
- * the page fill worker thread will know that the page fill is
- * complete when pg_startfill() returns.
+ /* Handle the page fill complete event by restarting the
+ * task that was blocked waiting for this page fill. In the
+ * non-blocking fill case, the page fill worker thread will
+ * know that the page fill is complete when pg_startfill()
+ * returns true.
*/
- pg_fillcomplete();
+ up_unblock_task(g_pendingfilltcb);;
}
/* All queued fills have been processed */