#ifndef CFG_KERN_H
#define CFG_KERN_H
-#include "cfg/cfg_arch.h" /* ARCH_EMUL */
+#include "cfg/cfg_timer.h" // CONFIG_TIMER_EVENTS
/**
* Enable the multithreading kernel.
/**
* \name Optional kernel features
- *
* \{
*/
/* Module/option Active Dependencies */
#define CONFIG_KERN_SCHED (1)
#define CONFIG_KERN_SIGNALS (1 && CONFIG_KERN_SCHED)
-#define CONFIG_KERN_TIMER (1)
#define CONFIG_KERN_IRQ (1)
#define CONFIG_KERN_HEAP (0)
#define CONFIG_KERN_SEMAPHORES (0 && CONFIG_KERN_SIGNALS)
#define CONFIG_KERN_MONITOR (1 && CONFIG_KERN_SCHED)
-#define CONFIG_KERN_PREEMPT (1 && CONFIG_KERN_SCHED && CONFIG_KERN_TIMER && CONFIG_KERN_IRQ)
+#define CONFIG_KERN_PREEMPT (1 && CONFIG_KERN_SCHED && CONFIG_TIMER_EVENTS && CONFIG_KERN_IRQ)
+#define CONFIG_KERN_PRI (1 && CONFIG_KERN_PREEMPT)
/*\}*/
+
/* OBSOLETE */
#define CONFIG_KERN_PREEMPTIVE CONFIG_KERN_PREEMPT
/// [ms] Time sharing quantum (a prime number prevents interference effects)
-#define CONFIG_KERN_QUANTUM 50
+#define CONFIG_KERN_QUANTUM 47
/// Module logging level.
#define KERN_LOG_LEVEL LOG_LVL_ERR
/**
* \name Optional kernel features
- *
* \{
*/
/* Module/option Active Dependencies */
#define CONFIG_KERN_SCHED (0)
#define CONFIG_KERN_SIGNALS (0 && CONFIG_KERN_SCHED)
-#define CONFIG_KERN_TIMER (0)
#define CONFIG_KERN_IRQ (0)
#define CONFIG_KERN_HEAP (0)
#define CONFIG_KERN_SEMAPHORES (0 && CONFIG_KERN_SIGNALS)
#define CONFIG_KERN_MONITOR (0 && CONFIG_KERN_SCHED)
-#define CONFIG_KERN_PREEMPT (0 && CONFIG_KERN_SCHED && CONFIG_KERN_TIMER && CONFIG_KERN_IRQ)
+#define CONFIG_KERN_PREEMPT (0 && CONFIG_KERN_SCHED && CONFIG_TIMER_EVENTS && CONFIG_KERN_IRQ)
+#define CONFIG_KERN_PRI (0 && CINFIG_KERN_PREEMPT)
+/*\}*/
+
+// FIXME: move somewhere
+#define CONFIG_DEPEND(FEATURE, DEPENDENCIES) STATIC_ASSERT(!(FEATURE) || !!(DEPS))
+
+CONFIG_DEPEND(CONFIG_KERN_PRI, CONFIG_KERN_PREEMPT);
-/* EXPERIMENTAL */
/* OBSOLETE */
#define CONFIG_KERN_PREEMPTIVE CONFIG_KERN_PREEMPT
#define CPU_SAVED_REGS_CNT 1
#define CPU_STACK_GROWS_UPWARD 0
- #define CPU_SP_ON_EMPTY_SLOT 0
+ #define CPU_SP_ON_EMPTY_SLOT 1
#elif CPU_DSP56K
void idle_init(void)
{
- proc_new(idle, NULL, sizeof(idle_stack), idle_stack);
+ Process *idle_proc = proc_new(idle, NULL, sizeof(idle_stack), idle_stack);
+ proc_setPri(idle_proc, (int)~0);
}
#include <cfg/module.h>
#include <kern/proc_p.h>
+#include <kern/proc.h>
#include <cfg/cfg_kern.h>
if (old_process != CurrentProcess)
{
+ IRQ_DISABLE;
+
TRACEMSG("switching from %p:%s to %p:%s",
old_process, old_process ? old_process->monitor.name : "---",
- CurrentProcess, CurrentProcess->monitor.name);
+ CurrentProcess, proc_currentName());
if (old_process)
swapcontext(&old_process->context, &CurrentProcess->context);
else
setcontext(&CurrentProcess->context);
- // not reached
+ IRQ_ENABLE;
}
- //TRACEMSG("keeping %p:%s", CurrentProcess, CurrentProcess->monitor.name);
+ TRACEMSG("resuming %p:%s", CurrentProcess, CurrentProcess->monitor.name);
#endif // CONFIG_KERN_PREEMPT
}
if (!preempt_forbid_cnt)
{
IRQ_DISABLE;
+
+ #if CONFIG_KERN_PRI
+ Process *rival = (Process *)LIST_HEAD(&ProcReadyList);
+ if (rival && rival->link.pri >= CurrentProcess->link.pri)
+ {
+ #endif
+
TRACEMSG("preempting %p:%s", CurrentProcess, proc_currentName());
#if 0
SCHED_ENQUEUE(CurrentProcess);
proc_preempt();
#endif
+ #if CONFIG_KERN_PRI
+ }
+ #endif
+
IRQ_ENABLE;
}
#include <string.h> /* memset() */
+// FIXME: move somewhere
+#define CONFIG_DEPEND(FEATURE, DEPS) STATIC_ASSERT(!(FEATURE) || !!(DEPS))
+
+CONFIG_DEPEND(CONFIG_KERN_PRI, CONFIG_KERN_PREEMPT);
+
/*
* The scheduer tracks ready processes by enqueuing them in the
#if CONFIG_KERN_HEAP
proc->flags = 0;
#endif
+
+#if CONFIG_KERN_PRI
+ proc->link.pri = 0;
+#endif
}
MOD_DEFINE(proc);
#endif
}
+/**
+ * Change the scheduling priority of a process.
+ *
+ * Process piorities are signed ints, whereas a larger integer value means
+ * higher scheduling priority. The default priority for new processes is 0.
+ * The idle process runs with the lowest possible priority: INT_MIN.
+ *
+ * A process with a higher priority always preempts lower priority processes.
+ * Processes of equal priority share the CPU time according to a simple
+ * round-robin policy.
+ *
+ * As a general rule to maximize responsiveness, compute-bound processes
+ * should be assigned negative priorities and tight, interactive processes
+ * should be assigned positive priorities.
+ *
+ * To avoid interfering with system background activities such as input
+ * processing, application processes should remain within the range -10
+ * and +10.
+ */
+void proc_setPri(struct Process *proc, int pri)
+{
+ if (proc->link.pri == pri)
+ return;
+
+ proc->link.pri = pri;
+
+ if (proc != CurrentProcess)
+ {
+ //proc_forbid();
+ //TODO: re-enqueue process
+ //pric_permit();
+ }
+}
+
/**
* Terminate the current process
*/
const char *proc_name(struct Process *proc);
const char *proc_currentName(void);
+#if CONFIG_KERN_PRI
+void proc_setPri(struct Process *proc, int pri);
+#endif
+
/**
* Disable preemptive task switching.
*
typedef struct Process
{
+#if CONFIG_KERN_PRI
+ PriNode link; /**< Link Process into scheduler lists */
+#else
Node link; /**< Link Process into scheduler lists */
+#endif
cpustack_t *stack; /**< Per-process SP */
iptr_t user_data; /**< Custom data passed to the process */
*/
extern REGISTER List ProcReadyList;
-
-/**
- * Enqueue a task in the ready list.
- *
- * Always use this macro to instert a process in the ready list, as its
- * might vary to implement a different scheduling algorithms.
- *
- * \note This macro is *NOT* protected against the scheduler. Access to
- * this list must be performed with interrupts disabled.
- */
-#define SCHED_ENQUEUE(proc) do { \
- LIST_ASSERT_VALID(&ProcReadyList); \
- ADDTAIL(&ProcReadyList, &(proc)->link); \
- } while (0)
+#if CONFIG_KERN_PRI
+ /**
+ * Enqueue a task in the ready list.
+ *
+ * Always use this macro to instert a process in the ready list, as its
+ * might vary to implement a different scheduling algorithms.
+ *
+ * \note This macro is *NOT* protected against the scheduler. Access to
+ * this list must be performed with interrupts disabled.
+ */
+ #define SCHED_ENQUEUE(proc) do { \
+ LIST_ASSERT_VALID(&ProcReadyList); \
+ LIST_ENQUEUE(&ProcReadyList, &(proc)->link); \
+ } while (0)
+
+#else // !CONFIG_KERN_PRI
+
+ #define SCHED_ENQUEUE(proc) do { \
+ LIST_ASSERT_VALID(&ProcReadyList); \
+ ADDTAIL(&ProcReadyList, &(proc)->link); \
+ } while (0)
+
+#endif // !CONFIG_KERN_PRI
/** Schedule to another process *without* adding the current to the ready list. */
void proc_schedule(void);