diff --git a/include/nuttx/page.h b/include/nuttx/page.h new file mode 100755 index 0000000000..33d2daf940 --- /dev/null +++ b/include/nuttx/page.h @@ -0,0 +1,150 @@ +/**************************************************************************** + * include/nuttx/page.h + * This file defines interfaces used to support NuttX On-Demand Paging. + * + * Copyright (C) 2010 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __NUTTX_PAGE_H +#define __NUTTX_PAGE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#ifdef CONFIG_PAGING + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pg_miss + * + * Description: + * This function is called from architecture-specific memory segmentaion + * fault handling logic. This function will perform the following + * operations: + * + * 1) Sanity checking. + * - ASSERT if the currently executing task is the page fill worker + * thread. The page fill worker thread is how the the page fault + * is resolved and all logic associated with the page fill worker + * must be "locked" and always present in memory. + * 2) Block the currently executing task. + * - Call 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. + * 3) Boost the page fill worker thread priority. + * - Check the priority of the task at the head of the 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. + * 4) Signal the page fill worker thread. + * - Is there a page fill pending? If not then signal the worker + * thread to start working on the queued page fill requests. + * + * Input Parameters: + * None - The head of the ready-to-run list is assumed to be task that + * caused the exception. + * + * Returned Value: + * None - Either this function function succeeds or an assertion occurs. + * + * Assumptions: + * - It is assumed that this function is called from the level of an + * exception handler and that all interrupts are disabled. + * - It is assumed that currently executing task (the one at the head of + * the ready-to-run list) is the one that cause the fault. This will + * always be true unless the page fault occurred in an interrupt handler. + * Interrupt handling logic must always be present and "locked" into + * memory. + * - The chip-specific page fault exception handler has already verified + * that the exception did not occur from interrupt/exception handling + * logic. + * - As mentioned above, the task causing the page fault must not be the + * the page fill worker thread because that is the only way to complete + * the page fill. + * + * NOTES: + * 1. One way to accomplish this would be a two pass link phase: + * - In the first phase, create a partially linked objected containing + * all interrupt/exception handling logic, the page fill worker thread + * plus all parts of the IDLE thread (which must always be available + * for execution). + * - All of the .text and .rodata sections of this partial link should + * be collected into a single section. + * - The second link would link the partially linked object along with + * the remaining object to produce the final binary. The linker + * script should position the "special" section so that it lies + * in a reserved, "non-swappable" region. + * + ****************************************************************************/ + +EXTERN void pg_miss(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY */ +#endif /* CONFIG_PAGING */ +#endif /* __NUTTX_PAGE_H */ diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index 2667999d86..169072174d 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -1,7 +1,7 @@ /******************************************************************************** * nuttx/sched.h * - * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2010 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -87,21 +87,23 @@ enum tstate_e { TSTATE_TASK_INVALID = 0, /* INVALID - The TCB is uninitialized */ - TSTATE_TASK_PENDING = 1, /* READY_TO_RUN - Pending preemption unlock */ - TSTATE_TASK_READYTORUN = 2, /* READY-TO-RUN - But not running */ - TSTATE_TASK_RUNNING = 3, /* READY_TO_RUN - And running */ + TSTATE_TASK_PENDING, /* READY_TO_RUN - Pending preemption unlock */ + TSTATE_TASK_READYTORUN, /* READY-TO-RUN - But not running */ + TSTATE_TASK_RUNNING, /* READY_TO_RUN - And running */ - TSTATE_TASK_INACTIVE = 4, /* BLOCKED - Initialized but not yet activated */ - TSTATE_WAIT_SEM = 5 /* BLOCKED - Waiting for a semaphore */ + TSTATE_TASK_INACTIVE, /* BLOCKED - Initialized but not yet activated */ + TSTATE_WAIT_SEM, /* BLOCKED - Waiting for a semaphore */ #ifndef CONFIG_DISABLE_SIGNALS - , - TSTATE_WAIT_SIG = 6 /* BLOCKED - Waiting for a signal */ + TSTATE_WAIT_SIG, /* BLOCKED - Waiting for a signal */ #endif #ifndef CONFIG_DISABLE_MQUEUE - , TSTATE_WAIT_MQNOTEMPTY, /* BLOCKED - Waiting for a MQ to become not empty. */ - TSTATE_WAIT_MQNOTFULL /* BLOCKED - Waiting for a MQ to become not full. */ + TSTATE_WAIT_MQNOTFULL. /* BLOCKED - Waiting for a MQ to become not full. */ #endif +#ifdef CONFIG_PAGING + TSTATE_WAIT_PAGEFILL, /* BLOCKED - Waiting for page fill */ +#endif + NUM_TASK_STATES /* Must be last */ }; typedef enum tstate_e tstate_t; @@ -110,22 +112,7 @@ typedef enum tstate_e tstate_t; #define FIRST_READY_TO_RUN_STATE TSTATE_TASK_READYTORUN #define LAST_READY_TO_RUN_STATE TSTATE_TASK_RUNNING #define FIRST_BLOCKED_STATE TSTATE_TASK_INACTIVE -#ifndef CONFIG_DISABLE_MQUEUE -# define LAST_BLOCKED_STATE TSTATE_WAIT_MQNOTFULL -# ifndef CONFIG_DISABLE_SIGNALS -# define NUM_TASK_STATES 9 -# else -# define NUM_TASK_STATES 8 -# endif -#else -# ifndef CONFIG_DISABLE_SIGNALS -# define LAST_BLOCKED_STATE TSTATE_WAIT_SIG -# define NUM_TASK_STATES 7 -# else -# define LAST_BLOCKED_STATE TSTATE_WAIT_SEM -# define NUM_TASK_STATES 6 -# endif -#endif +#define LAST_BLOCKED_STATE (NUM_TASK_STATES-1) /* The following is the form of a thread start-up function */ diff --git a/include/signal.h b/include/signal.h index 40fb3cbf03..59bf891e84 100644 --- a/include/signal.h +++ b/include/signal.h @@ -96,7 +96,9 @@ #endif #endif -#ifdef CONFIG_SCHED_WORKQUEUE +/* SIGWORK is used to wake up various internal, NuttX worker thread */ + +#if defined(CONFIG_SCHED_WORKQUEUE) || defined(CONFIG_PAGING) #ifndef CONFIG_SIG_SIGWORK #define SIGWORK 4 /* Used to wake up the work queue */ #else diff --git a/sched/Makefile b/sched/Makefile index ec9923e1cd..40392504c7 100644 --- a/sched/Makefile +++ b/sched/Makefile @@ -139,10 +139,15 @@ ifeq ($(CONFIG_SCHED_WORKQUEUE),y) WORK_SRCS = work_thread.c work_queue.c work_cancel.c endif +ifeq ($(CONFIG_PAGING),y) +PGFILL_SRCS = pg_miss.c +endif + IRQ_SRCS = irq_initialize.c irq_attach.c irq_dispatch.c irq_unexpectedisr.c CSRCS = $(MISC_SRCS) $(TSK_SRCS) $(SCHED_SRCS) $(WDOG_SRCS) $(TIME_SRCS) \ - $(SEM_SRCS) $(TIMER_SRCS) $(WORK_SRCS) $(IRQ_SRCS) + $(SEM_SRCS) $(TIMER_SRCS) $(WORK_SRCS) $(PGFILL_SRCS) $(IRQ_SRCS) + ifneq ($(CONFIG_DISABLE_CLOCK),y) CSRCS += $(CLOCK_SRCS) endif diff --git a/sched/os_start.c b/sched/os_start.c index 78b1c79973..ac52c4d664 100644 --- a/sched/os_start.c +++ b/sched/os_start.c @@ -130,6 +130,12 @@ volatile dq_queue_t g_waitingformqnotempty; volatile dq_queue_t g_waitingformqnotfull; #endif +/* This is the list of all tasks that are blocking waiting for a page fill */ + +#ifdef CONFIG_PAGING +volatile dq_queue_t g_waitingforfill; +#endif + /* This the list of all tasks that have been initialized, but not yet * activated. NOTE: This is the only list that is not prioritized. */ @@ -166,6 +172,12 @@ pidhash_t g_pidhash[CONFIG_MAX_TASKS]; pid_t g_worker; #endif +/* The task ID of the page fill worker thread */ + +#ifdef CONFIG_PAGING +pid_t g_pgworker; +#endif + /* This is a table of task lists. This table is indexed by * the task state enumeration type (tstate_t) and provides * a pointer to the associated static task list (if there @@ -188,6 +200,9 @@ const tasklist_t g_tasklisttable[NUM_TASK_STATES] = { &g_waitingformqnotempty, true }, /* TSTATE_WAIT_MQNOTEMPTY */ { &g_waitingformqnotfull, true } /* TSTATE_WAIT_MQNOTFULL */ #endif +#ifdef CONFIG_PAGING + { &g_waitingforfill, true } /* TSTATE_WAIT_PAGEFILL */ +#endif }; /**************************************************************************** @@ -239,6 +254,9 @@ void os_start(void) #ifndef CONFIG_DISABLE_MQUEUE dq_init(&g_waitingformqnotfull); dq_init(&g_waitingformqnotempty); +#endif +#ifdef CONFIG_PAGING + dq_init(&g_waitingforfill); #endif dq_init(&g_inactivetasks); sq_init(&g_delayeddeallocations); diff --git a/sched/pg_internal.h b/sched/pg_internal.h new file mode 100755 index 0000000000..5a22daad10 --- /dev/null +++ b/sched/pg_internal.h @@ -0,0 +1,107 @@ +/**************************************************************************** + * sched/pg_internal.h + * + * Copyright (C) 2010 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __SCHED_PG_INTERNAL_H +#define __SCHED_PG_INTERNAL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#ifdef CONFIG_PAGING + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#ifndef CONFIG_PAGING_WORKPRIORITY +# define CONFIG_PAGING_WORKPRIORITY 50 +#endif + +#ifndef CONFIG_PAGING_WORKSTACKSIZE +# define CONFIG_PAGING_WORKSTACKSIZE CONFIG_IDLETHREAD_STACKSIZE +#endif + +#ifdef CONFIG_DISABLE_SIGNALS +# warning "Page fill support requires signals" +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY + +/* If is the PID of the page fill worker thread */ + +extern pid_t g_pgworker; + +/* If non-NULL, this points to the TCB of the task currently being filled */ + +extern FAR _TCB *g_filltcb; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: pg_worker + * + * Description: + * This is the entry point of the worker thread that performs the actual + * page file. + * + * Input parameters: + * argc, argv (not used) + * + * Returned Value: + * Does not return + * + ****************************************************************************/ + +extern int pg_worker(int argc, char *argv[]); + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_PAGING */ +#endif /* __SCHED_PG_INTERNAL_H */ diff --git a/sched/pg_miss.c b/sched/pg_miss.c new file mode 100644 index 0000000000..54170f8c51 --- /dev/null +++ b/sched/pg_miss.c @@ -0,0 +1,175 @@ +/**************************************************************************** + * sched/pg_miss.c + * + * Copyright (C) 2010 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include + +#ifdef CONFIG_PAGING + +#include "os_internal.h" +#include "pg_internal.h" + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pg_miss + * + * Description: + * This function is called from architecture-specific memory segmentaion + * fault handling logic. This function will perform the following + * operations: + * + * 1) Sanity checking. + * - ASSERT if the currently executing task is the page fill worker + * thread. The page fill worker thread is how the the page fault + * is resolved and all logic associated with the page fill worker + * must be "locked" and always present in memory. + * - ASSERT if an interrupt was executing at the time of the exception. + * 2) Block the currently executing task. + * - Call 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. + * 3) Boost the page fill worker thread priority. + * - Check the priority of the task at the head of the 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. + * 4) Signal the page fill worker thread. + * - Is there a page fill pending? If not then signal the worker + * thread to start working on the queued page fill requests. + * + * Input Parameters: + * None - The head of the ready-to-run list is assumed to be task that + * caused the exception. + * + * Returned Value: + * None - Either this function function succeeds or an assertion occurs. + * + * Assumptions: + * - It is assumed that this function is called from the level of an + * exception handler and that all interrupts are disabled. + * - It is assumed that currently executing task (the one at the head of + * the ready-to-run list) is the one that cause the fault. This will + * always be true unless the page fault occurred in an interrupt handler. + * Interrupt handling logic must always be present and "locked" into + * memory. + * - As mentioned above, the task causing the page fault must not be the + * the page fill worker thread because that is the only way to complete + * the page fill. + * + * NOTES: + * 1. One way to accomplish this would be a two pass link phase: + * - In the first phase, create a partially linked objected containing + * all interrupt/exception handling logic, the page fill worker thread + * plus all parts of the IDLE thread (which must always be available + * for execution). + * - All of the .text and .rodata sections of this partial link should + * be collected into a single section. + * - The second link would link the partially linked object along with + * the remaining object to produce the final binary. The linker + * script should position the "special" section so that it lies + * in a reserved, "non-swappable" region. + * + ****************************************************************************/ + +void pg_miss(void) +{ + FAR _TCB *ftcb = (FAR _TCB*)g_readytorun.head; + FAR _TCB *wtcb; + + /* Sanity checking + * + * ASSERT if the currently executing task is the page fill worker thread. + * The page fill worker thread is how the the page fault is resolved and + * all logic associated with the page fill worker must be "locked" and + * always present in memory. + */ + + DEBUGASSERT(g_pgworker != ftcb->pid); + + /* Block the currently executing task + * - Call 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. + */ + + up_block_task(ftcb, TSTATE_WAIT_PAGEFILL); + + /* Boost the page fill worker thread priority. + * - Check the priority of the task at the head of the 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. + */ + + wtcb = sched_gettcb(g_pgworker); + DEBUGASSERT(wtcb != NULL); + + if (wtcb->sched_priority < ftcb->sched_priority) + { + /* Reprioritize the page fill worker thread */ + + sched_setpriority(wtcb, ftcb->sched_priority); + } + + /* Signal the page fill worker thread. + * - Is there a page fill pending? If not then signal the worker + * thread to start working on the queued page fill requests. + */ + + if (!g_filltcb) + { + kill(g_pgworker, SIGWORK); + } +} + +#endif /* CONFIG_PAGING */