240 likes | 361 Views
Threading Abstractions for Embedded Operating Systems on Memory Constrained Devices. Andrew Barton-Sweeney September 21, 2006. Why Threading?. Many tasks running on a sensor node Short sensor sample and hardware drivers Communication and radio network Long data processing algorithms
E N D
Threading Abstractions for Embedded Operating Systems on Memory Constrained Devices Andrew Barton-Sweeney September 21, 2006
Why Threading? • Many tasks running on a sensor node • Short sensor sample and hardware drivers • Communication and radio network • Long data processing algorithms • Without threading or concurrency, a long-running task can block other tasks from running. • Ex. A compression algorithm may prevent the node from receiving critical messages from the radio network. • Solution: • The programmer can write only short routines that always run quickly. This is not always feasible for certain routines. • The programmer can explicitly breakup a routine in sections, and maintain a state-machine that runs the sections in a sequence. • Use threading: the programmers design the routine using the natural logic of the algorithm, and familiar control constructs such as infinite loops. The scheduler will handle multiple routines concurrently.
Overview • Threading and Scheduler Flavors • Preemptive Scheduling vs. Non-Preemptive Scheduling • Advantages and Disadvantages • Examples of Threading Abstractions • eCos and uCOS-II • Mantis • Contiki • TinyOS and TinyMOS • Protothreads
Non-Preemptive (Event-Driven) Scheduler • Support multiple threads of execution as different event handlers. • Task Threads may be started by an event. • Current Thread of Execution runs to completion, blocking other threads from running.
Preemptive Scheduler • Threads have priority levels. • Task Threads must be started by the program. • Higher priority threads cause a running lower priority threads to suspend execution and the processor runs the higher priority thread. (context switch) When the higher priority thread is finished, the lower priority thread resumes where it was interrupted.
Differences between Threading Models • Preemptive Scheduler • Stack (Memory) • Each thread requires a unique stack to store the procedure call sequence and automatic variables. • This is a large memory overhead. • Synchronization • Threads may execute concurrently and require synchronization to protect shared resources. • Introduces many potential run-time errors. Difficult to debug. Requires careful programming and use of the synchronization mechanisms, • Continuous Program Model • The algorithm of a thread is programmed in a logical sequence. The programmer does not concern with blocking other threads- the scheduler will handle this. • Overhead from context switching between threads. Requires a more complex scheduler, with latency to save the context of one thread and load the context of the next.
Differences between Threading Models • Non-preemeptive (Event-Driven) • Stack (Memory) • Requires a single stack. (stores automatic variable and call-trace of the programs execution). • Switching task threads causes the stack to unwind. (The calls made in the task thread are returned, and the stack is returned to the original caller of the event-handler task thread- ie. The scheduler) • Synchronization • A single task thread executes at any time without interruption by other tasks. No synchronization is needed between tasks. • Must protect resources used by the task thread only from interrupts. (Careful design of interrupt code can reduce concurrency issues by letting the interrupt schedule a new task thread to handle the interrupt’s activity) • Run-to-completion Model (State-Machine) • Task thread must be designed to execute quickly and return without blocking the processor for a long time. • A long algorithm must be broken into smaller pieces and the task must reschedule itself to run all pieces of the algorithm, allowing other tasks to run in between. A state machine is used to manage running the long algorithm.
eCos and uCOS-II • Scheduler • Multilevel Priorities • (Linked list, threads may share same priority level) • Bitmap Priorities • (Bitmap, threads have a unique priority level) • Conventional Threading • Traditional preemptive threading paradigm as in UNIX • Priority based Preemption. • Timeslicing with multilevel priorities. • Synchronization • Scheduler Lock • Mutex • Sempahore • Conditional Variable • Flags • Message Boxes
eCos Example • #include <cyg/kernel/kapi.h> • #define MONITOR_THREAD_STACK_SIZE ( 2048 / sizeof(int) ) • int monitor_thread_stack[ MONITOR_THEAD_STACK_SIZE ]; • cug_handle_t monitor_thread_handle; • cyg_thread monitor_thread_obj; • // • // Monitoring thread. • // • void monitor_thread( cyg_addrword_t index ) • { • unsigned long monitor_counter = 0; • // Infinite loop for monitor thread. • while ( 1 ) • { • // Delay for 1000 ticks. • cyg_thread_delay( 1000 ); • // Increment the counter. • monitor_counter++; • } • } • // • // Main starting point for the application. • // • void cyg_user_start( void ) • { • // Create the Monitor thread. • cyg_thread_create( • 12, • monitor_thread, • 0, • "Monitor Thread", • &monitor_thread_stack, • MONITOR_THREAD_STACK_SIZE, • &monitor_thread_handle, • &monitor_thread_obj ); • // Let thre thread run when the scheduler starts. • cyg_thread_resume( monitor_thread_handle ); • }
MantisOS • Scheduler • Power-aware (sleep when no active threads). • Preemptive time-slicing with priority levels. • Threading • Subset of POSIX threads: priority-based thread scheduling with round-robin semantics within a priority level. • Synchronization • Semaphores
Mantis OS Example • void start( void ){ • Packet data; • uint8_t i, size; • mos_enable_power_mgt(); • while( 1 ){ • size = flooding_recv( (char*)&data, 0x02 ); • if( size < 1) • mos_led_toggle( 0 ); • else{ • for( i=0; i<size; i++ ) • mos_uart_send(0, ((char*)&data[i] ); • mos_led_toggle( 2 ); • } • mos_thread_sleep( 32 ); • } • }
Contiki • Scheduler (Kernel) • Event-driven, non-preemptive • Threading • Optional Application layer library • An application task includes the threading library. The task creates an runs application threads when the task is run from the scheduler. • No priorities. Preemption is implemented through time-slicing. • Synchronization • Post and wait primitives allow a thread to signal to another thread. Concurrency issues are left to the programmer to provides application specific resource protections.
TinyOS and TinyMOS • TinyOS • Uses a scheduler in a single thread to run tasks on an event. A task runs to completion, blocking other tasks, until it returns to the scheduler. • TinyMOS • Gives preemptive threading features to TinyOS • Run the TinyOS scheduler as a single thread inside a master preemptive scheduler. • Tasks in the TinyOS scheduler can schedule threads to run in the master scheduler.
Protothreads Library • Application layer threading library. • A threading abstraction that provides preemptive threading-like features. • Allow a programmer to simulate concurrent processes in an event-driven operating system (non-preemptive). • A long running task can yield to others tasks, and resume operation at a later time.
Protothreads in C • The threading features are implemented as macros in C language, inserted into a routine. • The macros create automatically generate a switch statement, and state-machine. • The state-machine allows the routine to save its current state in the middle of operation and return to the caller (yield). • In the future, the routine is called again, and uses the saved state to resume at the last point of operation. • The state per protothread is only two bytes. • The programmer does not need to explicitly create the state machine. This greatly simplifies the design of the routine.
Advantages • Very small memory overhead per thread • No stack per thread • No latency for context switching • No preemption. The thread will run to completion until it explicitly yeilds. This prevents concurrency issues, since a protothread will never be interrupted. (except for hardware interrupts…) • Simplify the creation of the state-machine to break-up long-running routines.
Disadvantages • No preemption. The thread will run to completion until it explicitly yields. It is possible for a BAD routine to block a protothread and stall the entire system. • No automatic variables. They would require a separate stack. • All threads run in a single stack. • When a thread yields, the routine returns to the caller before another thread is run. This is called stack rewinding. Any automatic variables are lost. • The current implementation of Protothreads does not allow a routine to use switch statements.
Example: Radio Task using Event Driven Task • enum { • ON, • WAITING, • OFF • } state; • void radio_wake_eventhandler() { • switch( state ){ • case OFF: • if( timer_expired( &timer ) ) { • radio_on(); • state = ON; • timer_set( &timer, T_AWAKE ); • } • break; • case ON: • if( timer_expired( &timer ) ) { • timer_set( &timer, T_SLEEP ); • if( !communication_complete() ) { • state = WAITING; • } else { • radio_off(); • state = OFF; • } • } • break; • case WAITING: • if( communication_complete() • || timer_expired( &timer ) ) { • state = ON; • timer_set( &timer, T_AWAKE ); • } else { • radio_off(); • state = OFF; • } • break; • } • }
Example: Radio Task using Protothreads • PT_THREAD( radio_wake_thread( struct pt *pt )) { • PT_BEGIN( pt ); • while( 1 ) { • radio_on(); • timer_set( &timer, T_AWAKE ); • PT_WAIT_UNTIL( pt, timer_expired( &timer )); • timer_set( &timer, T_SLEEP ); • if( !communication_complete()) { • PT_WAIT_UNTIL( pt, communication_complete() • || timer_expired( &timer )); • } • if( !timer_expired( &timer )) { • radio_off(); • PT_WAIT_UNTIL( pt, timer_expired( &timer )); • } • } • PT_END( pt ); • }
Code Generated by Protothreads Library • void radio_wake_thread( struct pt *pt ) { • switch( pt->lc ) { • case 0: • while( 1 ) { • radio_on(); • timer_set( &timer, T_AWAKE ); • pt->lc = 8; • case 8: • if( !timer_expired( &timer )) { • return; • } • timer_set( &timer, T_SLEEP ); • if( !communication_complete() ) { • pc->lc = 13; • case 13: • if( !(communication_complete() || • timer_expired( &timer ))) { • return; • } • } • if( !timer_expired( &timer )) { • radio_off(); • pt->lc = 18; • case 18: • if( !timer_expired( &timer )) { • return; • } • } • } • } • }
Review of Threading Abstractions • Kernel Layer Preemptive Scheduler • Traditional preemptive threading, like UNIX • Kernel Layer Non-Preemptive Scheduler • Event-driven operating system • Application Layer Preemptive Scheduler • Application Layer Event-Driven Scheduler • Compile-time Generation of a State-Machine for a Concurrency Abstraction in a Non-preemptive Scheduler.
The State of the Art • eCos and uCOS-II • Traditional Preemptive Threading, like UNIX • Mantis • Subset of Traditional Preemptive Threading • Power-aware scheduler • Contiki • Application Layer Threading Library • Event-driven scheduler • TinyOS and SOS • Event-driven scheduler • No preemptive threading • TinyMOS • Master preemptive scheduler • Run TinyOS scheduler (event-driven) in a preemptive thread • Protothreads • Application layer library for Non-preemptive concurrency abstraction • Automatically generate state-machine to break up long sections of code. • Yield to other tasks, use state-machine to resume to last point of operation
Threading in SOS • A Protothreads Library is available for SOS. • Similar to Application Layer threads in Contiki. • Cannot use Protothreads in a module message handler! • The Protothreads State-Machine conflicts the message switch statement. • The message handler is an event scheduler! • Use Protothreads in a sub-routine! • Create a Protothread in a sub-routine. • Let a Module repeatedly call the sub-routine, until the Protothread is finished.
References • eCos • http://ecos.sourceware.org/ • uCOS-II • http://www.geocities.com/michaelanburaj/uCOS/index.html • Papers • http://www.ovro.caltech.edu/~dwh/ucos/project_AR1803.pdf#search=%22uCos%20paper%22 • http://micrium.com/downloads/appnotes/NS-CR16C-uCOS-II.pdf#search=%22explain%20ucos-ii%22 • Micrium – Commercial site • http://www.micrium.com/ • Mantis • http://mantis.cs.colorado.edu/index.php/tiki-pagehistory.php?page=HomePage&diff=83 • Contiki • http://www.sics.se/~adam/contiki/ • TinyOS • http://www.tinyos.net/ • TinyMOS • http://www.eecs.harvard.edu/emnets/papers/trumplerEmnets06.pdf#search=%22tinymos%22 • Protothreads • http://www.sics.se/~adam/pt/ • SOS • http://nesl.ee.ucla.edu/projects/sos-1.x/publications/