/** * \file * * * \brief Internal scheduler structures and definitions for processes. * * \author Bernie Innocenti */ #ifndef KERN_PROC_P_H #define KERN_PROC_P_H #include "cfg/cfg_proc.h" #include "cfg/cfg_monitor.h" #include #include /* for cpu_stack_t */ #include // IRQ_ASSERT_DISABLED() #include // struct Process #ifndef asm_switch_context /** * CPU dependent context switching routines. * * Saving and restoring the context on the stack is done by a CPU-dependent * support routine which usually needs to be written in assembly. */ EXTERN_C void asm_switch_context(cpu_stack_t **new_sp, cpu_stack_t **save_sp); #endif /** * \name Flags for Process.flags. * \{ */ #define PF_FREESTACK BV(0) /**< Free the stack when process dies */ /*\}*/ /** Track running processes. */ extern REGISTER Process *current_process; /** * Track ready processes. * * Access to this list must be performed with interrupts disabled */ extern REGISTER List proc_ready_list; #if CONFIG_KERN_PRI # if CONFIG_KERN_PRI_INHERIT #define __prio_orig(proc) (proc->orig_pri) #define __prio_inh(proc) (LIST_EMPTY(&(proc)->inh_list) ? INT_MIN : \ ((PriNode *)LIST_HEAD(&proc->inh_list))->pri) #define __prio_proc(proc) (__prio_inh(proc) > __prio_orig(proc) ? \ __prio_inh(proc) : __prio_orig(proc)) # endif #define prio_next() (LIST_EMPTY(&proc_ready_list) ? INT_MIN : \ ((PriNode *)LIST_HEAD(&proc_ready_list))->pri) #define prio_proc(proc) (proc->link.pri) #define prio_curr() prio_proc(current_process) #define SCHED_ENQUEUE_INTERNAL(proc) \ LIST_ENQUEUE(&proc_ready_list, &(proc)->link) #define SCHED_ENQUEUE_HEAD_INTERNAL(proc) \ LIST_ENQUEUE_HEAD(&proc_ready_list, &(proc)->link) #else #define prio_next() 0 #define prio_proc(proc) 0 #define prio_curr() 0 #define SCHED_ENQUEUE_INTERNAL(proc) ADDTAIL(&proc_ready_list, &(proc)->link) #define SCHED_ENQUEUE_HEAD_INTERNAL(proc) ADDHEAD(&proc_ready_list, &(proc)->link) #endif /** * Enqueue a process 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 Access to the scheduler ready list must be performed with * interrupts disabled. */ #define SCHED_ENQUEUE(proc) do { \ IRQ_ASSERT_DISABLED(); \ LIST_ASSERT_VALID(&proc_ready_list); \ SCHED_ENQUEUE_INTERNAL(proc); \ } while (0) #define SCHED_ENQUEUE_HEAD(proc) do { \ IRQ_ASSERT_DISABLED(); \ LIST_ASSERT_VALID(&proc_ready_list); \ SCHED_ENQUEUE_HEAD_INTERNAL(proc); \ } while (0) #if CONFIG_KERN_PRI /** * Changes the priority of an already enqueued process. * * Searches and removes the process from the ready list, then uses LIST_ENQUEUE(() * to insert again to fix priority. * * No action is performed for processes that aren't in the ready list, eg. in semaphore queues. * * \note Performance could be improved with a different implementation of priority list. */ INLINE void sched_reenqueue(struct Process *proc) { IRQ_ASSERT_DISABLED(); LIST_ASSERT_VALID(&proc_ready_list); Node *n; PriNode *pos = NULL; FOREACH_NODE(n, &proc_ready_list) { if (n == &proc->link.link) { pos = (PriNode *)n; break; } } // only remove and enqueue again if process is already in the ready list // otherwise leave it alone if (pos) { REMOVE(&proc->link.link); LIST_ENQUEUE(&proc_ready_list, &proc->link); } } #endif //CONFIG_KERN_PRI /* Process trampoline */ void proc_entry(void); /* Schedule another process *without* adding the current one to the ready list. */ void proc_switch(void); /* Immediately schedule a particular process bypassing the scheduler. */ void proc_wakeup(Process *proc); /* Initialize a scheduler class. */ void proc_schedInit(void); #if CONFIG_KERN_MONITOR /** Initialize the monitor */ void monitor_init(void); /** Register a process into the monitor */ void monitor_add(Process *proc, const char *name); /** Unregister a process from the monitor */ void monitor_remove(Process *proc); /** Rename a process */ void monitor_rename(Process *proc, const char *name); #endif /* CONFIG_KERN_MONITOR */ /* * Quantum related macros are used in the * timer module and must be empty when * kernel is disabled. */ #if (CONFIG_KERN && CONFIG_KERN_PREEMPT) INLINE int preempt_quantum(void) { extern int _proc_quantum; return _proc_quantum; } INLINE void proc_decQuantum(void) { extern int _proc_quantum; if (_proc_quantum > 0) _proc_quantum--; } INLINE void preempt_reset_quantum(void) { extern int _proc_quantum; _proc_quantum = CONFIG_KERN_QUANTUM; } #else /* !(CONFIG_KERN && CONFIG_KERN_PREEMPT) */ INLINE int preempt_quantum(void) { return 0; } INLINE void proc_decQuantum(void) { } INLINE void preempt_reset_quantum(void) { } #endif /* (CONFIG_KERN && CONFIG_KERN_PREEMPT) */ #endif /* KERN_PROC_P_H */