|
|
System scheduler. More...
Defines | |
#define | os_preempt_enable() os_preempt_enable_common( 0 ) |
The macro enables preemption outside of the ISR. | |
#define | os_preempt_enable_intr() DOC_HIDDEN |
The macro enables preemption in ISR. | |
#define | OS_DINT_SAVE(flags) DOC_HIDDEN |
The macro saves state of interrupts and disables them. | |
#define | OS_INT_RESTORE(flags) DOC_HIDDEN |
The macro restores state of interrupts. | |
Functions | |
unsigned char | os_preempt_disable (void) |
The function disables preemption. | |
os_result_t | os_scheduler_run (void) |
Starts scheduler. | |
os_result_t | os_schedule (void) |
The function makes context switch. |
System scheduler.
The scheduler is central controller of CPU time. It is responsible for decision which thread should be running. In DioneOS the scheduler works according to the "highest priority" rule. It means that the thread is executed as long as it has the highest priority in a set of ready threads. The thread may be preempted if it calls one of the waiting function (e.g. os_sema_wait()). The preemption will also happen when other thread with higher priority change the state to ready. Note that the last option may occur in any time of thread execution. Consider following examples:
1. hardware interrupt triggers ISR, where semaphore is released (os_sema_post_intr()). Thread that was waiting on the semaphore become ready.
2. higher priority thread has been waiting for specific period because of explicit call os_sleep() or by expiration a timeout in os_sema_wait_timeouted()
When the CPU is switched from one thread to another the system saves thread context, so it will be restored when the thread become ready next time. During the context switch of all important registers are saved:
1. PC - current execution point,
2. SP - stack pointer; each thread uses its stack for execution,
3. SR - status register containing processor flags,
4. Rn..Rk - universal processor registers.
Notes a. msp430: R4..R15. All registers (except SP) are saved as 20-bits wide, so system can handle large code model (usage of the FLASH memory above 64KB is supported).
b. avr: R0..R31. Data access to the FLASH memory above 64KB is not supported yet, RAMPZ is not saved. Note that none of other processor registers are saved.
When you do some important sequence of operations in the thread and it must not be preempted you can use os_preempt_disable(), os_preempt_enable(). These functions control preemption and stop scheduler from switching the context. If the context should be switched it is deferred to os_preempt_enable(). In such section of the code functions that could wait are not allowed. This constraint is natural: if the call had happened, the system would have locked.
Disabling preemption does not affect global interrupt flag, so hardware interrupts can still cause run of ISR inside the section. When total protection from interrupting the execution is required use OS_DINT_SAVE() and OS_INT_RESTORE(). This guaranties that interrupts are disabled in between. It is useful when you need to guard an access to common data for threads and ISR. It also applies when atomic operations are performed from these two types of context.
Use interrupt control with care, do not disable interrupts for too long, because it affects interrupts latency and timer accuracy.
In order to start scheduler call os_scheduler_run(). This function should not return to caller when multithreading has been started but when you forgot to create threads before that it returns with OS_ERROR code.
The scheduler requires that there is always idle thread, that is never waiting. The idle thread should have the lowest priority (represented by highest number). When the others change to waiting state the CPU executes the code from the idle thread. This idle thread can be used to determine what is the load of the system and temporal characteristic of free run of the system.
#define OS_DINT_SAVE | ( | flags | ) | DOC_HIDDEN |
The macro saves state of interrupts and disables them.
Use on the beginning of critical sections. No ISR or preemption happen after that.
[out] | flags | unsigned short variable for storage status register that contains GIE. |
#define OS_INT_RESTORE | ( | flags | ) | DOC_HIDDEN |
The macro restores state of interrupts.
State of interrupts before call of corresponding OS_DINT_SAVE() is restored.
[in] | flags | variable where status of interrupts was stored. |
#define os_preempt_enable | ( | ) | os_preempt_enable_common( 0 ) |
The macro enables preemption outside of the ISR.
Because preemption control cannot be nested, first call of this function enables preemption.
#define os_preempt_enable_intr | ( | ) | DOC_HIDDEN |
The macro enables preemption in ISR.
Because preemption control cannot be nested, first call of this function enables preemption. Preemption will be enabled at the exit point of ISR.
unsigned char os_preempt_disable | ( | void | ) |
The function disables preemption.
Switching off preemption guaranties that context will be not switched to another thread, even if some waiting object is released and higher priority thread should be scheduled. It will be deferred to call os_preempt_enable(). Calls of os_preempt_disable() cannot be nested. Interrupt state is not affected. Preemption can be disabled but interrupts may still be enabled.
os_result_t os_schedule | ( | void | ) |
The function makes context switch.
It is not required to call the function, it is done in many points of the system and provides doing that when it is required.
The function switches to the higest priority thread in ready thread list. Its source code is in scheduler_a.asm
os_result_t os_scheduler_run | ( | void | ) |
Starts scheduler.
Thread with the highest priority will be started.
Threads should be created before calling this function.