core/include/scheduler.h File Reference

System scheduler. More...


#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.


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.

Detailed Description

System scheduler.

Piotr Romaniuk, (c) ELESOFTROM
1.0 Jan 20, 2012

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 Documentation

#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.

In current implementation it is not atomic, so between store and disable operations interrupt may appear. Because of that ISR may be called or context switch happen. Nevertheless, when control returns to the thread the context is recovered and interrupt state as well. It is guaranteed that after execution of this macro interrupts are disabled and previous interrupt state is stored in a variable specified as argument.
Do not keep interrupts disabled for too long. It will affect interrupts latency and timers.
[out]flagsunsigned 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]flagsvariable 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.

Returns returns codes like os_schedule(), i.e. OS_STATUS_OK if success, may generate exception os_bug() when list of ready threads is empty.
#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.

returns always OS_STATUS_OK

Function Documentation

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.

Be careful, when preempt is disabled os_mutex_get() or os_sema_wait{timeouted}() will not block or generate exception os_bug (it depends on settings in configuration).
previous value of preemption state.
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_STATUS_OK when scheduling is correct OS_PREEMPT_DIS if preempt is disabled, immediate return without other tests it may be correct, e.g. os_sema_post() during preempt disabled os_bug(OS_BUG_EMPTY_RDY_LIST) - when list of ready threads is empty
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.

If scheduler is run, it should not return,
if returns (with OS_ERROR) it means that something went wrong e.g. no threads were defined