Add logic to drop the priority of the page fill task
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2857 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
8d933821e4
commit
273f1971d4
|
@ -160,7 +160,7 @@
|
|||
<dl>
|
||||
<dt><code>g_waitingforfill</code></dt>
|
||||
<dd>An OS list that is used to hold the TCBs of tasks that are waiting for a page fill.</dd>
|
||||
<dt><code>g_pendingfilltcb</code></dt>
|
||||
<dt><code>g_pftcb</code></dt>
|
||||
<dd>A variable that holds a reference to the TCB of the thread that is currently be re-filled.</dd>
|
||||
<dt><code>g_pgworker</code></dt>
|
||||
<dd>The <i>process</i> ID of of the thread that will perform the page fills.</dd>
|
||||
|
@ -307,8 +307,8 @@
|
|||
</p>
|
||||
|
||||
<p>
|
||||
The page fill worker thread will maintain a static variable called <code>_TCB *g_pendingfilltcb</code>.
|
||||
If no fill is in progress, <code>g_pendingfilltcb</code> will be NULL.
|
||||
The page fill worker thread will maintain a static variable called <code>_TCB *g_pftcb</code>.
|
||||
If no fill is in progress, <code>g_pftcb</code> will be NULL.
|
||||
Otherwise, it will point to the TCB of the task which is receiving the fill that is in progess.
|
||||
</p>
|
||||
<ul><small>
|
||||
|
@ -319,7 +319,7 @@
|
|||
</small></ul>
|
||||
|
||||
<p>
|
||||
When awakened from <code>pg_miss()</code>, no fill will be in progress and <code>g_pendingfilltcb</code> will be NULL.
|
||||
When awakened from <code>pg_miss()</code>, no fill will be in progress and <code>g_pftcb</code> will be NULL.
|
||||
In this case, the page fill worker thread will call <code>pg_startfill()</code>.
|
||||
That function will perform the following operations:
|
||||
<ul>
|
||||
|
@ -387,10 +387,10 @@
|
|||
In this non-blocking case, the callback <code>pg_callback()</code> will perform the following operations when it is notified that the fill has completed:
|
||||
<ul>
|
||||
<li>
|
||||
Verify that <code>g_pendingfilltcb</code> is non-NULL.
|
||||
Verify that <code>g_pftcb</code> is non-NULL.
|
||||
</li>
|
||||
<li>
|
||||
Find the higher priority between the task waiting for the fill to complete in <code>g_pendingfilltcb</code> and the task waiting at the head of the <code>g_waitingforfill</code> list.
|
||||
Find the higher priority between the task waiting for the fill to complete in <code>g_pftcb</code> and the task waiting at the head of the <code>g_waitingforfill</code> list.
|
||||
That will be the priority of he highest priority task waiting for a fill.
|
||||
</li>
|
||||
<li>
|
||||
|
@ -409,20 +409,20 @@
|
|||
<a name="TaskResumption"><h2>Task Resumption</h2></a>
|
||||
|
||||
<p>
|
||||
For the non-blocking <code>up_fillpage()</code>, the page fill worker thread will detect that the page fill is complete when it is awakened with <code>g_pendingfilltcb</code> non-NULL and fill completion status from <code>pg_callback</code>.
|
||||
For the non-blocking <code>up_fillpage()</code>, the page fill worker thread will detect that the page fill is complete when it is awakened with <code>g_pftcb</code> non-NULL and fill completion status from <code>pg_callback</code>.
|
||||
In the non-blocking case, the page fill worker thread will know that the page fill is complete when <code>up_fillpage()</code> returns.
|
||||
</p>
|
||||
<p>
|
||||
In this either, the page fill worker thread will:
|
||||
<ul>
|
||||
<li>
|
||||
Verify consistency of state information and <code>g_pendingfilltcb</code>.
|
||||
Verify consistency of state information and <code>g_pftcb</code>.
|
||||
</li>
|
||||
<li>
|
||||
Verify that the page fill completed successfully, and if so,
|
||||
</li>
|
||||
<li>
|
||||
Call <code>up_unblocktask(g_pendingfilltcb)</code> to make the task that just received the fill ready-to-run.
|
||||
Call <code>up_unblocktask(g_pftcb)</code> to make the task that just received the fill ready-to-run.
|
||||
</li>
|
||||
<li>
|
||||
Check if the <code>g_waitingforfill</code> list is empty.
|
||||
|
@ -432,10 +432,10 @@
|
|||
Remove the highest priority task waiting for a page fill from <code>g_waitingforfill</code>,
|
||||
</li>
|
||||
<li>
|
||||
Save the task's TCB in <code>g_pendingfilltcb</code>,
|
||||
Save the task's TCB in <code>g_pftcb</code>,
|
||||
</li>
|
||||
<li>
|
||||
If the priority of the thread in <code>g_pendingfilltcb</code>, is higher in priority than the default priority of the page fill worker thread, then set the priority of the page fill worker thread to that priority.
|
||||
If the priority of the thread in <code>g_pftcb</code>, is higher in priority than the default priority of the page fill worker thread, then set the priority of the page fill worker thread to that priority.
|
||||
</li>
|
||||
<li>
|
||||
Call <code>pg_startfill()</code> which will start the next fill (as described above).
|
||||
|
@ -446,7 +446,7 @@
|
|||
Otherwise,
|
||||
<ul>
|
||||
<li>
|
||||
Set <code>g_pendingfilltcb</code> to NULL.
|
||||
Set <code>g_pftcb</code> to NULL.
|
||||
</li>
|
||||
<li>
|
||||
Restore the default priority of the page fill worker thread.
|
||||
|
|
|
@ -87,10 +87,10 @@
|
|||
|
||||
extern pid_t g_pgworker;
|
||||
|
||||
/* The page fill worker thread maintains a static variable called
|
||||
* g_pendingfilltcb. If no fill is in progress, g_pendingfilltcb will be NULL.
|
||||
* Otherwise, g_pendingfile will point to the TCB of the task which is
|
||||
* receiving the fill that is in progess.
|
||||
/* The page fill worker thread maintains a static variable called g_pftcb.
|
||||
* If no page fill is in progress, g_pftcb will be NULL. Otherwise, g_pftcb
|
||||
* will point to the TCB of the task which is receiving the fill that is
|
||||
* in progess.
|
||||
*
|
||||
* NOTE: I think that this is the only state in which a TCB does not reside
|
||||
* in some list. Here is it in limbo, outside of the normally queuing while
|
||||
|
@ -98,7 +98,7 @@ extern pid_t g_pgworker;
|
|||
* TSTATE_TASK_INVALID.
|
||||
*/
|
||||
|
||||
extern FAR _TCB *g_pendingfilltcb;
|
||||
extern FAR _TCB *g_pftcb;
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
|
|
|
@ -166,7 +166,7 @@ void pg_miss(void)
|
|||
* thread to start working on the queued page fill requests.
|
||||
*/
|
||||
|
||||
if (!g_pendingfilltcb)
|
||||
if (!g_pftcb)
|
||||
{
|
||||
kill(g_pgworker, SIGWORK);
|
||||
}
|
||||
|
|
|
@ -82,8 +82,8 @@
|
|||
pid_t g_pgworker;
|
||||
|
||||
/* The page fill worker thread maintains a static variable called
|
||||
* g_pendingfilltcb. If no fill is in progress, g_pendingfilltcb will be NULL.
|
||||
* Otherwise, g_pendingfile will point to the TCB of the task which is
|
||||
* g_pftcb. If no fill is in progress, g_pftcb will be NULL.
|
||||
* Otherwise, g_pftcb will point to the TCB of the task which is
|
||||
* receiving the fill that is in progess.
|
||||
*
|
||||
* NOTE: I think that this is the only state in which a TCB does not reside
|
||||
|
@ -92,7 +92,7 @@ pid_t g_pgworker;
|
|||
* TSTATE_TASK_INVALID.
|
||||
*/
|
||||
|
||||
FAR _TCB *g_pendingfilltcb;
|
||||
FAR _TCB *g_pftcb;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Variables
|
||||
|
@ -132,9 +132,9 @@ status uint32_t g_starttime;
|
|||
*
|
||||
* When pg_callback() is called, it will perform the following operations:
|
||||
*
|
||||
* - Verify that g_pendingfilltcb is non-NULL.
|
||||
* - Verify that g_pftcb is non-NULL.
|
||||
* - Find the higher priority between the task waiting for the fill to
|
||||
* complete in g_pendingfilltcb and the task waiting at the head of the
|
||||
* complete in g_pftcb and the task waiting at the head of the
|
||||
* g_waitingforfill list. That will be the priority of he highest priority
|
||||
* task waiting for a fill.
|
||||
* - If this higher priority is higher than current page fill worker thread,
|
||||
|
@ -158,20 +158,20 @@ status uint32_t g_starttime;
|
|||
#ifndef CONFIG_PAGING_BLOCKINGFILL
|
||||
static void pg_callback(FAR _TCB *tcb, int result)
|
||||
{
|
||||
/* Verify that g_pendingfilltcb is non-NULL */
|
||||
/* Verify that g_pftcb is non-NULL */
|
||||
|
||||
if (g_pendingfilltcb)
|
||||
if (g_pftcb)
|
||||
{
|
||||
FAR _TCB *htcb = (FAR _TCB *)g_waitingforfill.head;
|
||||
FAR _TCB *wtcb = sched_gettcb(g_pgworker);
|
||||
|
||||
/* Find the higher priority between the task waiting for the fill to
|
||||
* complete in g_pendingfilltcb and the task waiting at the head of the
|
||||
* complete in g_pftcb and the task waiting at the head of the
|
||||
* g_waitingforfill list. That will be the priority of he highest
|
||||
* priority task waiting for a fill.
|
||||
*/
|
||||
|
||||
int priority = g_pendingfilltcb->sched_priority;
|
||||
int priority = g_pftcb->sched_priority;
|
||||
if (htcb && priority < htcb->sched_priority)
|
||||
{
|
||||
priority = htcb->sched_priority;
|
||||
|
@ -218,14 +218,14 @@ static void pg_callback(FAR _TCB *tcb, int result)
|
|||
* g_waitingforfill task list becomes empty.
|
||||
*
|
||||
* The result (NULL or a TCB pointer) will be returned in the global
|
||||
* variable, g_pendingfilltcb.
|
||||
* variable, g_pftcb.
|
||||
*
|
||||
* 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
|
||||
* pg_dequeue() 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).
|
||||
*
|
||||
|
@ -245,8 +245,8 @@ static inline bool pg_dequeue(void)
|
|||
{
|
||||
/* 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)
|
||||
g_pftcb = (FAR _TCB *)dq_remfirst((dq_queue_t*)&g_waitingforfill);
|
||||
if (g_pftcb != NULL)
|
||||
{
|
||||
/* Call the architecture-specific function up_checkmapping() to see if
|
||||
* the page fill still needs to be performed. In certain conditions,
|
||||
|
@ -255,10 +255,47 @@ static inline bool pg_dequeue(void)
|
|||
* simply be restarted.
|
||||
*/
|
||||
|
||||
if (!up_checkmapping(g_pendingfilltcb))
|
||||
if (!up_checkmapping(g_pftcb))
|
||||
{
|
||||
/* This page needs to be filled. Return with g_pendingfilltcb
|
||||
* holding the pointer to the TCB associated with task.
|
||||
/* This page needs to be filled. pg_miss bumps up
|
||||
* the priority of the page fill worker thread as each
|
||||
* TCB is added to the g_waitingforfill list. So we
|
||||
* may need to also drop the priority of the worker
|
||||
* thread as the next TCB comes off of the list.
|
||||
*
|
||||
* If wtcb->sched_priority > CONFIG_PAGING_DEFPRIO,
|
||||
* then the page fill worker thread is executing at
|
||||
* an elevated priority that may be reduced.
|
||||
*
|
||||
* If wtcb->sched_priority > g_pftcb->sched_priority
|
||||
* then the page fill worker thread is executing at
|
||||
* a higher priority than is appropriate for this
|
||||
* fill (this priority can get re-boosted by pg_miss()
|
||||
* if a new higher priority fill is required).
|
||||
*/
|
||||
|
||||
FAR _TCB *wtcb = (FAR _TCB *)g_readytorun.head;
|
||||
if (wtcb->sched_priority > CONFIG_PAGING_DEFPRIO &&
|
||||
wtcb->sched_priority > g_pftcb->sched_priority)
|
||||
{
|
||||
/* Don't reduce the priority of the page fill
|
||||
* worker thread lower than the configured
|
||||
* minimum.
|
||||
*/
|
||||
|
||||
int priority = g_pftcb->sched_priority;
|
||||
if (priority < CONFIG_PAGING_DEFPRIO)
|
||||
{
|
||||
priority = CONFIG_PAGING_DEFPRIO;
|
||||
}
|
||||
|
||||
/* Reduce the priority of the page fill worker thread */
|
||||
|
||||
sched_setpriority(wtcb, priority);
|
||||
}
|
||||
|
||||
/* Return with g_pftcb holding the pointer to
|
||||
* the TCB associated with task that requires the page fill.
|
||||
*/
|
||||
|
||||
return true;
|
||||
|
@ -268,10 +305,10 @@ static inline bool pg_dequeue(void)
|
|||
* virtual address space -- just restart it.
|
||||
*/
|
||||
|
||||
up_unblock_task(g_pendingfilltcb);
|
||||
up_unblock_task(g_pftcb);
|
||||
}
|
||||
}
|
||||
while (g_pendingfilltcb != NULL);
|
||||
while (g_pftcb != NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -323,7 +360,7 @@ static inline bool pg_startfill(void)
|
|||
* a page in-use, un-map it, and make it available.
|
||||
*/
|
||||
|
||||
result = up_allocpage(g_pendingfilltcb, &vpage);
|
||||
result = up_allocpage(g_pftcb, &vpage);
|
||||
DEBUGASSERT(result == OK);
|
||||
|
||||
/* Start the fill. The exact way that the fill is started depends upon
|
||||
|
@ -339,7 +376,7 @@ static inline bool pg_startfill(void)
|
|||
* status of the fill will be provided by return value from up_fillpage().
|
||||
*/
|
||||
|
||||
result = up_fillpage(g_pendingfilltcb, vpage);
|
||||
result = up_fillpage(g_pftcb, vpage);
|
||||
DEBUGASSERT(result == OK);
|
||||
#else
|
||||
/* If CONFIG_PAGING_BLOCKINGFILL is defined, then up_fillpage is non-blocking
|
||||
|
@ -351,7 +388,7 @@ static inline bool pg_startfill(void)
|
|||
* This callback will probably from interrupt level.
|
||||
*/
|
||||
|
||||
result = up_fillpage(g_pendingfilltcb, vpage, pg_callback);
|
||||
result = up_fillpage(g_pftcb, vpage, pg_callback);
|
||||
DEBUGASSERT(result == OK);
|
||||
|
||||
/* Save the time that the fill was started. These will be used to check for
|
||||
|
@ -387,7 +424,7 @@ static inline bool pg_startfill(void)
|
|||
*
|
||||
* This functin will perform the following operations:
|
||||
*
|
||||
* - Set g_pendingfilltcb to NULL.
|
||||
* - Set g_pftcb to NULL.
|
||||
* - Restore the default priority of the page fill worker thread.
|
||||
*
|
||||
* Input parameters:
|
||||
|
@ -405,7 +442,7 @@ static inline bool pg_startfill(void)
|
|||
static inline void pg_alldone(void)
|
||||
{
|
||||
FAR _TCB *wtcb = (FAR _TCB *)g_readytorun.head;
|
||||
g_pendingfilltcb = NULL;
|
||||
g_pftcb = NULL;
|
||||
sched_setpriority(wtcb, CONFIG_PAGING_DEFPRIO);
|
||||
}
|
||||
|
||||
|
@ -436,11 +473,11 @@ static inline void pg_alldone(void)
|
|||
|
||||
static inline void pg_fillcomplete(void)
|
||||
{
|
||||
/* Call up_unblocktask(g_pendingfilltcb) to make the task that just
|
||||
/* Call up_unblocktask(g_pftcb) to make the task that just
|
||||
* received the fill ready-to-run.
|
||||
*/
|
||||
|
||||
up_unblock_task(g_pendingfilltcb);
|
||||
up_unblock_task(g_pftcb);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -510,11 +547,11 @@ int pg_worker(int argc, char *argv[])
|
|||
|
||||
#ifdef CONFIG_PAGING_BLOCKINGFILL
|
||||
/* For the non-blocking up_fillpage(), the page fill worker thread will detect
|
||||
* that the page fill is complete when it is awakened with g_pendingfilltcb non-NULL
|
||||
* that the page fill is complete when it is awakened with g_pftcb non-NULL
|
||||
* and fill completion status from pg_callback.
|
||||
*/
|
||||
|
||||
if (g_pendingfilltcb != NULL)
|
||||
if (g_pftcb != NULL)
|
||||
{
|
||||
/* If it is a real page fill completion event, then the result of the page
|
||||
* fill will be in g_fillresult and will not be equal to -EBUSY.
|
||||
|
@ -530,7 +567,7 @@ int pg_worker(int argc, char *argv[])
|
|||
* task that was blocked waiting for this page fill.
|
||||
*/
|
||||
|
||||
up_unblock_task(g_pendingfilltcb);;
|
||||
up_unblock_task(g_pftcb);;
|
||||
|
||||
/* Yes .. Start the next asynchronous fill. Check the return
|
||||
* value to see a fill was actually started (false means that
|
||||
|
@ -563,14 +600,14 @@ int pg_worker(int argc, char *argv[])
|
|||
|
||||
/* Otherwise, this might be a page fill initiation event. When
|
||||
* awakened from pg_miss(), no fill will be in progress and
|
||||
* g_pendingfilltcb will be NULL.
|
||||
* g_pftcb will be NULL.
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
/* Are there tasks blocked and waiting for a fill? If so,
|
||||
* pg_startfill() will start the asynchronous fill (and set
|
||||
* g_pendingfilltcb).
|
||||
* g_pftcb).
|
||||
*/
|
||||
|
||||
(void)pg_startfill();
|
||||
|
@ -601,7 +638,7 @@ int pg_worker(int argc, char *argv[])
|
|||
* returns true.
|
||||
*/
|
||||
|
||||
up_unblock_task(g_pendingfilltcb);;
|
||||
up_unblock_task(g_pftcb);;
|
||||
}
|
||||
|
||||
/* All queued fills have been processed */
|
||||
|
|
Loading…
Reference in New Issue