On-Demand Paging>>> Under Construction <<<Last Updated: August 12, 2010 |
Table of Contents |
|
||
|
||
|
||
|
||
|
||
|
Terminolgy |
g_waitingforfill
g_pendingfill
g_pgworker
pg_callback()
pg_miss()
TCB
Initialization |
The following declarations will be added.
g_waitingforfill
.
A doubly linked list that will be used to implement a prioritized list of the TCBs of tasks that are waiting for a page fill.
g_pgworker
.
The process ID of of the thread that will perform the page fills
During OS initialization in sched/os_start.c
, the following steps
will be performed:
g_waitingforfill
queue will be initialized.
pid
of the page will worker thread will be saved in g_pgworker
.
Note that we need a special worker thread to perform fills;
we cannot use the "generic" worker thread facility because we cannot be
assured that all actions called by that worker thread will always be resident in memory.
Declarations for g_waitingforfill
, g_pgworker
, and other
internal, private definitions will be provided in sched/pg_internal.h
.
All public definitions that should be used by the chip-specific code will be available
in include/nuttx/page.h
and include/nuttx/arch.h
.
Page Faults |
Page fault exception handling.
Page fault handling is performed by the function pg_miss()
.
This function is called from architecture-specific memory segmentation
fault handling logic. This function will perform the following
operations:
up_block_task()
to block the task at the head of the ready-to-run list.
This should cause an interrupt level context switch to the next highest priority task.
The blocked task will be marked with state TSTATE_WAIT_PAGEFILL
and will be retained in the g_waitingforfill
prioritized task list.
g_waitingforfill
list.
If the priority of that task is higher than the current priority of the page fill worker thread, then boost the priority of the page fill worker thread to that priority.
When signaled from pg_miss()
, the page fill worker thread will be awakenend and will initiate the fill operation.
Input Parameters. None -- The head of the ready-to-run list is assumed to be that task that caused the exception. The current task context should already be saved in the TCB of that task. No additional inputs are required.
Assumptions.
pg_miss()
must be "locked" in memory.
Calling pg_miss()
cannot cause a nested page fault.
Locking code in Memory. One way to accomplish this would be a two phase link:
.text
and .rodata
sections of this partial link should be collected into a single section.
Fill Initiation |
The page fill worker thread will be awakened on one of two conditions:
pg_miss()
, the page fill worker thread will be awakenend (see above), or
pg_fillcomplete()
after completing last fill (see below).
The page fill worker thread will maintain a static variable called _TCB *g_pendingfill
.
If not fill is in progress, g_pendingfill
will be NULL.
Otherwise, will point to the TCB of the task which is receiving the fill that is in progess.
When awakened from pg_miss()
, no fill will be in progress and g_pendingfill
will be NULL.
In this case, the page fill worker thread will call pg_startfill()
.
That function will perform the following operations:
up_allocpage(vaddr, &page)
.
This chip-specific function will set aside page in memory and map to virtual address (vaddr).
If all pages available pages are in-use (the typical case),
this function will select a page in-use, un-map it, and make it available.
up_fillpage(page, pg_callback)
.
This will start asynchronous page fill.
The page fill worker thread will provide a callback function, pg_callback
,
that will be called when the page fill is finished (or an error occurs).
This callback will probably from interrupt level.
While the fill is in progress, other tasks may execute.
If another page fault occurs during this time, the faulting task will be blocked and its TCB will be added (in priority order) to g_waitingforfill
.
But no action will be taken until the current page fill completes.
NOTE: The IDLE task must also be fully locked in memory.
The IDLE task cannot be blocked.
It the case where all tasks are blocked waiting for a page fill, the IDLE task must still be available to run.
The chip-specific functions, up_allocpage(vaddr, &page)
and up_fillpage(page, pg_callback)
will be prototyped in include/nuttx/arch.h
Fill Complete |
When the chip-specific driver completes the page fill, it will call the pg_callback()
that was provided to up_fillpage
.
pg_callback()
will probably be called from driver interrupt-level logic.
The driver ill provide the result of the fill as an argument.
NOTE: pg_callback()
must also be locked in memory.
When pg_callback()
is called, it will perform the following operations:
g_pendingfill
is non-NULL.
g_pendingfill
is higher than page fill worker thread, boost work thread to that level.
Task Resumption |
When the page fill worker thread is awakened and g_pendingfill
is non-NULL (and other state variables are in concurrence),
the page fill thread will know that is was awakened because of a page fill completion event.
In this case, the page fill worker thread will:
g_pendingfill
.
up_unblocktask(g_pendingfill)
to make the task that just received the fill ready-to-run.
g_waitingforfill
list is empty.
If not:
g_waitingforfill
,
g_pendingfill
,
g_pendingfill
, 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.
pg_startfill()
which will start the next fill (as described above).
g_pendingfill
to NULL.