Sie sind auf Seite 1von 125

Real Time Operating System

VxWorks
VxWorks
 VxWorks is a commercial hard real time operating system
developed by wind river systems.
 The main idea: use monolithic kernel to schedule user
tasks according to user defined priorities. Maximize kernel
timing predictability.
 Gives the users maximal control.
VxWorks
 A dedicated real time system, not intended as a general
purpose OS.
 lacks many modern os features that interfere with real time
performance (flat memory model, no paging).
VxWorks
 Scheduling is done using a preemptive priority driven
approach, priorities are chosen arbitrarily by the user (0-255).
 Priorities can be changed by the user at runtime but this is
discouraged.
 A user can lock a task so that it can‟t be preempted even by
higher priority tasks or interrupts.
 This allows the use of the fixed priority response time analysis
to check schedulability offline.
VxWorks
 Is resource sharingaware and has a priority inheritance
built in.
 Optimizations in implementation of the context switch
and the return from interrupts.
 The kernel never disables NMI (non-maskable interrupts)
so they are always available to the user.
VxWorks - limitations
 Lacks many modern OS features.
 Guaranteeing the deadlines is the responsibility of the user
at design time.
 Doesn‟t support most modern applications and APIs (only
a small subset of POSIX).
 Despite the flat memory model dynamic memory
allocation still cases memory fragmenting, which increases
timing unpredictability.
Tornado: An Embedded System Development Tool
Tornado
An IDE to develop real-time and embedded
applications with minimal intrusion on the target
system.
Tornado comprises:
 VxWorks, a high-performance real-time operating system.
 Application-building tools (compilers and associated
programs).
 IDE for
 managing projects,
 host-target communication,
 running, debugging, and monitoring VxWorks applications.
The Tornado IDE
 An integrated source-code editor.
 A project management facility.
 Integrated C and C++ compiler and linker.
 The browser, a visual monitoring tool for target system.
 CrossWind, a source-level debugger.
 WindSh, C and Tcl command shell that controls the target.
 VxWorks target simulator VxSim.
 WindView software logic analyzer for the target simulator.
Overview of Tornado IDE

Host System Target System

Shell Tornado IDE


Applications
Editor Debugger
Target
Server
Project Browser
VxWorks

WindView Target Target


Agent Agent
VxWorks
Target
Simulator
The Tornado shell (WindSh)
 Allows you to download application modules.
 Invoke both VxWorks and application module subroutines.
 Can be used for interactive exploration of the VxWorks
operating system and applications.
 WindSh can interpret most C language expressions.
 A Tcl interpreter is also included.
Shell Built-in Commands
WindSh provides common commands needed for development:
 sp Create a task with default options.
 td  Delete a task.
 s/c  Step/continue a task.
 i/ti  Give (detailed) task information.
 w/tw  Show which objects are tasks waiting for.
 ld/unld  Load/unload a module.
Debugger ( Cross-Wind )
 Setting breakpoints and controlling program execution.
 Program listings and data-inspection windows.
 Command-line interface extendable by Tcl scripting.
Browser
 The main browser window can be used to monitor-
 active system and application tasks
 memory consumption
 summary of the current target memory use
 The displays are snapshots and can be configured to
update interactively, or the automatically at a specified
interval.
Browser Display Includes:
• Detailed task information
• Semaphores
• Message queues
• Memory partitions
• Watchdog timers
• Stack usage by all tasks on the target
• Target CPU usage by task
• Object-module structure and symbols
• Interrupt vectors
Browser Display
Wind-View
 Wind-view is a software „logic analyzer‟ or „run-time analyzer‟ for
your multitasking application.
 A high precision graphical view of events, tasks, and interrupts in
your application, shown across time.
 Helps diagnose race conditions
Wind-view
Task States
Multitasking Kernel
 The Wind kernel is that part of VxWorks which directly
manages tasks.
 Allocates the CPU to tasks according to the VxWorks
scheduling algorithm.
 Uses Task Control Blocks (TCBs) to keep track of tasks.
 One per task
 Declared as WIND_TCB data structure in taskLib.h
 OS control information e.g. state, task priority, delay timer,
breakpoint list, error status, I/O redirections, etc.
 CPU Context Information e.g. PC, SP, CPU registers, FPU registers
Kernel Operation
Context Switch
 When one task stops executing and a new task starts, a context switch
or reschedule has occurred.
 To schedule a new task to run, the kernel must:
1. Save context of currently executing task into its TCB.
2. Restore context of next task to execute from its TCB.
 Complete context switch must be very fast.
Priority Scheduling
 The highest priority task ready to run (not pended or delayed) is
allocated the CPU.
 Rescheduling can occur at any time as a result of:
- Kernel calls
- Interrupts (e.g., system clock tick)
 The context switch is not delayed until the next system clock tick.
 Reschedules do not occur merely because a task has been
executing for a long time.
 When an interrupt causes a reschedule, it is because the interrupt
service routine called a kernel function. A special case of this is
the processing of timeouts and delays which occurs on every
system clock tick interrupt.
Priority Based Preemption
Priority Based Preemption
 Equal priority tasks won‟t preempt each other (by default)
 Priority Rescheduling occurs if
- The currently running task pends or delays.
- A task of higher priority becomes ready.
 When a task of higher priority takes the CPU away from the
current task, it is preempting that running task.
 If task B never blocks or pends, then task C will never run.
Task TArrival TExecute Priority
Example T1 0 5 3
T2 1 3 2
T3 2 8 1
Real-Time Multitasking
functions
(VxWorks)
Creating a Task
 int taskSpawn (name, priority, options, stackSize, entryPt,
arg1, ..., arg10)
- name Task name
- priority Task priority 0-255.
- options Task options
e.g. VX_UNBREAKABLE.
- stackSize Size of stack to be allocated in bytes.
- entryPt Address of code to start executing
(initial PC).
- arg1,.., arg10 Up to 10 arguments to entry-point
routine.
Creating a Task
 Returns a task id or ERROR if unsuccessful.
Example:
newTid = taskSpawn (“tMyTask”, 150, 0, 20000, myRoutine,
arg1, arg2, 0, 0, 0, 0, 0, 0, 0, 0)
int taskSpawn (name, priority, options,
Task ID’s stackSize, entryPt, arg1, ..., arg10)

 Assigned by kernel when task is created.


 Unique to each task.
 Efficient 32-bit handle for task.
 May be reused after task exits.
 A task id of zero refers to task making call (self).
 Relevant taskLib routines

taskIdSelf( ) Get ID of calling task.


taskIdListGet( ) Fill array with ID‟s of all existing tasks.
taskIdVerify( ) Verify a task ID is valid.
Task Names
 Provided for human convenience.
 Typically used only from the shell (during development).
 Within programs, use task Ids.
• Relevant taskLib routines:
taskName( ) - Get name from tid.
- takes task id as argument and returns name of the task

taskNameToId( ) - Get tid from task name.


- takes name of the task argument and returns task Id

int taskSpawn (name, priority, options, stackSize, entryPt,


arg1, ..., arg10)
Task Priorities

 Range from 0 (highest) to 255 (lowest).


 One can manipulate priorities dynamically with:
taskPriorityGet (tid, &priority)
taskPrioritySet (tid, priority)
 Doing so may make your application‟s behavior more
difficult to analyze.

int taskSpawn (name, priority, options, stackSize, entryPt,


arg1, ..., arg10)
Task Stacks
 Allocated from system memory pool when task is created.
 Fixed size after creation.
 The kernel reserves some space from the stack, making the
stack space actually available slightly less than the stack space
requested.
 Exceeding stack size (“stack crash”) causes unpredictable
system behavior.

int taskSpawn (name, priority, options, stackSize, entryPt,


arg1, ..., arg10)
Task Options
 VX_FP_TASK Add floating point
support.
 VX_NO_STACK_FILL Don’t fill stack with 0’s.
 VX_UNBREAKABLE Disable breakpoints.
 VX_DEALLOC_STACK Deallocate stack and TCB when
task exits (automatically set for
you).
 Use taskOptionsGet( ) to inquire about a tasks options.
 Use taskOptionsSet( ) to set and unset

int taskSpawn (name, priority, options, stackSize, entryPt,


arg1, ..., arg10)
Task Deletion
 taskDelete (tid)
Deletes the specified task.
Deallocates the TCB and stack.

 exit (code)
Equivalent to a taskDelete( ) of self.
code parameter is stored in the TCB field exitCode.
TCB may be examined for post-mortem debugging
Task Restart

 Task is terminated and re-spawned with original arguments


and tid.
 Usually used for error recovery.
 If a task tries to restart itself, the work of doing this is
actually handled by a new task of priority 0 named tRestart
which is spawned for just this purpose. The tRestart task
terminates after restarting the original task.
Task Suspend/Resume
 taskSuspend (tid)
Makes task ineligible to execute.
Can be added to pended or delayed state.
It is safest to have a task suspend itself.

 taskResume (tid)
Removes suspension.

Note:
Usually taskSuspend() and taskResume() are used for debugging
and development purposes.
Task Delay
 taskDelay (ticks)
To delay a task for a specified number of system clock ticks:
Dealing with Tornado
Creating the Task
# include <vxWorks.h>
#include < stdio.h>
int main ()
{
printf (“Welcome To Tornado World from main()…\n”);
return 0;
}
#include <stdio.h>
#include<VxWorks.h>
int fun();
int main()
{
printf(“\n This is my First VxWorks Program……\n”);
fun();
printf(“I am in MAIN after Function Calling…\n”);
return 0;
}
int fun()
{
Printf(“\n I am in Function Now…….\n”);
}
Example for taskSpawn()
# include <vxWorks.h>
#include < stdio.h>
void fun();
int tid1;
int main ()
{
printf(“\n This is my First VxWorks Program……\n”);
tid1=taskSpawn("task1",110,0,2000,fun,0,0,0,0,0,0,0,0,0,0);
printf(“I am in MAIN after Task Spawn…\n”);
return 0;
}
void fun();
{
printf (“Welcome To Tornado from Task – fun1\n”);
}
Example for taskSpawn()
#include"VxWorks.h"
#include"stdio.h"
#include"taskLib.h"
void fun1(int,int);
void fun2(int,int);
int tid1,tid2;
void f(void)
{
tid1=taskSpawn("task1",100,0,2000,fun1,10,200,0,0,0,0,0,0,0,0);
tid2=taskSpawn("task2",90,0,2000,fun2,20,100,0,0,0,0,0,0,0,0);
}

void fun1(int i,int j)


{
printf ("this is function1 %d, %d\n",i,j);
}

void fun2(int a, int b)


{
printf("this is function2 %d,%d\n",a,b);
}
Multi tasking
#include < vxWorks.h> Void myApp1()

#include <stdio.h> {

#include <taskLib.h> printf(“I am in task %d\n”,taskIdSelf());

# define COUNT 10 }

Void rootApp()
{
int i, taskid;
Printf(“I am in myApp…\n”);
for (i=0;i<COUNT;i++)

taskid=taskSpawn(“tmyApp1”,90,0x100,2000,(FUNCPTR)myApp1,0,0,0,0,0,0,0,0,0);
return 0;
}
Program to validate state of task
int rootApp()
#include <stdio.h> {
#include <vxWorks.h> printf (“I am in rootApp..\n”);
#include <taskLib.h> tid1=taskSpawn(“tmyApp1”,101,0,2000,
(FUNCPTR)myApp1,1,0,0,0,0,0,0,0,0,0);
#include <string.h>
tid1=taskSpawn(“tmyApp2”,102,0,2000,
(FUNCPTR)myApp2,1,0,0,0,0,0,0,0,0,0);
int myApp1(); return 0;
int myApp2(); }
int tid1, tid2; int myApp1(int k, int j)

int id1,id2; {
printf(“I am in myApp1..\n”);
taskSuspend(0);
STATUS ret;
If((ret=taskStatusString(tid1, status))==-1)
Char * status;
printf(“\n Retruns ERROR…\n”);
printf(“status of task = %s\n”,status);
printf(“\n I am in myApp1 after suspension\n”);
return 0;
}
Program to validate state of task
int myApp2(int k, int j)
{
printf (“I am in myApp2..\n”);
status =malloc (20);
If((ret=taskStatusString(tid1, status))==-1)
printf(“\n myApp1 Retruns ERROR…\n”);
printf(“status of task myApp1 = %s\n”,status);
takResume(tid1);
return 0;

}
Program for taskSafe / taskUnsafe():
int rootApp()
{
#include <stdio.h>
printf (“I am in rootApp..\n”);
#include <vxWorks.h>
s = (char *) malloc (10);
#include <taskLib.h> tid1=taskSpawn(“tmyApp1”,101,0,2000,
(FUNCPTR)myApp1,1,0,0,0,0,0,0,0,0,0);
#include <string.h>
tid1=taskSpawn(“tmyApp2”,102,0,2000,
(FUNCPTR)myApp2,1,0,0,0,0,0,0,0,0,0);
int myApp1(int, int ); return 0;
}
int myApp2(int, int );
int myApp1(int k, int j)
int tid1, tid2;
{
int id1,id2; char *st = (char *) malloc (20);
taskSafe();
taskDelay(10);
Char * s;
printf(“\n I am in myApp1 \n”);
taskStatusString(tid1, st)
printf(“status of task = %s\n”,st);
taskUnsafe();
printf(“AFTER UNSAFE…\n”);
return 0;
}
Program for taskSafe /
taskUnsafe():
int myApp2(int k, int j)
{
printf (“I am in myApp2..\n”);
taskDelete(tid1);
printf(“I am in myApp2 after DELETION..\n”);
return 0;

}
taskbrowser void fun1(int i,int j)
{
#include"VxWorks.h" while(1)
#include"stdio.h" {
#include"taskLib.h" printf("this is function1 %d,%d\n",i,j);
taskDelay(100);
void fun1(int,int);
printf("value of y is %d \n",y);
void fun2(int,int);
}
int tid1,tid2,y=10;
}

void f(void)
void fun2(int a,int b)
{ {
tid1=taskSpawn("task1",90,0x100,2000,(FUNCP while(1)
TR)fun1,10,20,0,0,0,0,0,0,0,0); {
tid2=taskSpawn("task2",100,0x100,2000,(FUNC
printf("this is function2 %d,%d\n",a,b);
PTR)fun2,20,60,0,0,0,0,0,0,0,0);
taskDelay(100);
} printf("value of y is %d \n",y);
}
}
taskidverify
#include"VxWorks.h" void fun1(int i,int j)
#include"stdio.h" {
#include"taskLib.h" int k;
void fun1(int,int); printf("this is function1 %d%d\n",i,j);
void fun2(int,int); k=taskIdSelf();
int tid1,tid2,p; printf("task1 id is %d\n",k);
void f(void) p=taskIdVerify(tid1);
{ printf("task id is verified in task1
tid1=taskSpawn("task1",100,0x100,2000,f %d\n",p);
un1,10,200,0,0,0,0,0,0,0,0); }
tid2=taskSpawn("task2",90,0x100,2000,fu
n2,20,100,0,0,0,0,0,0,0,0); void fun2(int a,int b)
p=taskIdVerify(tid1); {
printf("task id is verified in f %d",p); printf("this is function2 %d,%d\n",a,b);
} }
Inter task Synchronization
SEMAPHORES
Binary Semaphores
SEM_ID semBCreate (options, initialState)
options Specify queue type (SEM_Q_PRIORITY or
SEM_Q_FIFO) for tasks pended on this
semaphore.
initialState Initialize semaphore to be available
(SEM_FULL) or unavailable (SEM_EMPTY).
 Semaphores used for synchronization are typically
initialized to SEM_EMPTY (event has not occurred).
 Returns a SEM_ID, or NULL on error.
 Symbolic constants defined in semLib.h.
Taking a Semaphore
STATUS semTake (semId, timeout)
semId The SEM_ID returned from semBCreate( ).
timeout Maximum time to wait for semaphore.
 Value can be clock ticks, WAIT_FOREVER, or NO_WAIT.
 Can pend the task until either
- Semaphore is given or
- Timeout expires.
- Semaphore left unavailable.
 Returns OK if successful, ERROR on timeout (or invalid semId).
Giving a Semaphore
STATUS semGive (semId)
 Unblocks a task waiting for semId.
 If no task is waiting, makes semId available.
 Returns OK, or ERROR if semId is invalid.
Synchronizing Multiple Tasks
STATUS semFlush (semId)
 Unblocks all tasks waiting for semaphore.
 Does not affect the state of a semaphore.
 Useful for synchronizing actions of multiple tasks.
Example void c(void)
{
#include"VxWorks.h"
semTake(semBinary,WAIT_FOREVER);
#include"taskLib.h"
printf("\n task 1 has taken sem\n");
#include"semLib.h"
printf(“UNIVERSITY\n");
#include"stdio.h"
semGive(semBinary);
void c(void);
printf(" task 1 released sem\n");
void b(void);
}
SEM_ID semBinary;
void b(void)
void f()
{
{
semTake(semBinary,WAIT_FOREVER);
semBinary=semBCreate(SEM_Q_FIFO,SE
M_FULL); printf(" \ntask 2 has taken sem\n");
taskSpawn("task1",90,0,2000,(FUNCPTR)c, printf(“VIT\n");
0,0,0,0,0,0,0,0,0,0); taskDly(2000);
taskSpawn("task2",80,0,2000,(FUNCPTR)b, semGive(semBinary);
0,0,0,0,0,0,0,0,0,0); printf(" task2 released sem\n");
} }
Example void c(void)
{
#include"VxWorks.h" Int i;
#include"taskLib.h" for (i=0;i<COUNT;i++)
#include"semLib.h" {
#include"stdio.h“ semTake(semid1,WAIT_FOREVER);
# define COUNT 10 printf("\n I am in C and
global=%d….\n“,++global);
void c(void); semGive(semid1);
void b(void); }
SEM_ID semid1; }
int global=0; void b(void)
{
void f() Int i;
{ for (i=0;i<COUNT;I++)
int tid1, tid2; {
printf(“I am in Main…\n”); semTake(semid1,WAIT_FOREVER);
semid1=semBCreate(SEM_Q_FIFO,SEM_FULL); printf("\n I am in C and
global=%d….\n“,--global);
tid1=taskSpawn("task1",90,0,2000,(FUNCPTR)c,0,0,0,0,
0,0,0,0,0,0); semGive(semid1);
tid2=taskSpawn("task2",80,0,2000,(FUNCPTR)b,0,0,0,0, }
0,0,0,0,0,0);
}
}
Example int rootApp()
{
#include <taskLib.h> printf("*****************************\n");
#include<semLib.h> printf("I am in rootApp....\n");
semid1=semBCreate(SEM_Q_PRIORITY,SEM_EMPTY);
int tid1, tid2,tid3,tid4; semid2=semBCreate(SEM_Q_PRIORITY,SEM_EMPTY);
SEM_ID semid1,semid2,semid3; semid3=semBCreate(SEM_Q_PRIORITY,SEM_EMPTY);
tid1=taskSpawn("tmyApp1",101,0,2000,(FUNCPTR)myApp
int myApp1(); 1,0,0,0,0,0,0,0,0,0,0);
int myApp2(); tid2=taskSpawn("tmyApp2",101,0,2000,(FUNCPTR)myApp
int myApp3(); 2,0,0,0,0,0,0,0,0,0,0);
int myApp4(); tid3=taskSpawn("tmyApp3",101,0,2000,(FUNCPTR)myApp
3,0,0,0,0,0,0,0,0,0,0);
tid4=taskSpawn("tmyApp4",101,0,2000,(FUNCPTR)myApp
4,0,0,0,0,0,0,0,0,0,0);
return 0;
}
Example
int myApp3()
int myApp1()
{
{
semTake(semid3,WAIT_FOREVER);
semTake(semid1,WAIT_FOREVER);
printf(“3\t");
printf(“1\t");
semGive(semid2);
return 0;
return 0;
}
}

int myApp2()
int myApp4()
{
{
semTake(semid2,WAIT_FOREVER);
printf(“2\t");
printf(“4\t");
semGive(semid1);
semGive(semid3);
return 0;
return 0;
}
}
Example
Re-modify the above code to get the following output:
(i) 3421
(ii) 1234
(iii) 4123
Example
Create a Single Binary semaphore for printing
Create 5 tasks
4 tasks try to get and release the semaphore for PRINT
semBCreate(SEM_Q_PRIORITY, SEM_EMPTY)
semTake(semid1, WAIT_FOREVER)
semGive(semid1)
5th task for semaphore flush
semFlush(semid1)
Examine the output in the tornado IDE.
Count semaphore
SEM_ID semCCreate (options, initialState)
options : Specify queue type (SEM_Q_PRIORITY
or SEM_Q_FIFO) for tasks pended on
this semaphore.
initialState : Initial count
 Returns a SEM_ID, or NULL on error.
 When a task takes a counting semaphore, using semTake( ), subsequent
action depends on the state of the count:
◦ if the count is non-zero, it is decremented and the calling task continues
executing.
◦ If the count is zero, the task will be blocked, pending the availability of
the semaphore.
◦ If a timeout is specified and the timeout expires, the pended task will be
removed from the queue of pended tasks and enter the ready state with an
ERROR status.
◦ A pended task is ineligible for CPU allocation. Any number of tasks may
be pended simultaneously on the same counting semaphore.
 When a task gives a semaphore, using semGive( ), the next available task in
the pend queue is unblocked
SemCCreate
#include"vxWorks.h" int rootApp()
#include"stdio.h" {
#include"semaphore.h" printf("\n*********************************\n");
#include"taskLib.h" printf("I am in rootApp Now......\n");
semid1=semCCreate(SEM_Q_PRIORITY,1);
int myApp1(); tid1=taskSpawn("tmyApp1",200,0,2000,(FUNCPTR)myA
int myApp2(); pp1,0,0,0,0,0,0,0,0,0,0);
int myApp3(); tid2=taskSpawn("tmyApp2",150,0,2000,(FUNCPTR)myA
pp2,0,0,0,0,0,0,0,0,0,0);
int myApp4();
tid3=taskSpawn("tmyApp3",100,0,2000,(FUNCPTR)myA
int myApp5(); pp3,0,0,0,0,0,0,0,0,0,0);
tid4=taskSpawn("tmyApp4",50,0,2000,(FUNCPTR)myAp
SEM_ID semid1; p4,0,0,0,0,0,0,0,0,0,0);
int tid1, tid2,tid3,tid4,tid5; tid5=taskSpawn("tmyApp5",60,0,2000,(FUNCPTR)myAp
p5,0,0,0,0,0,0,0,0,0,0);
return 0;
}
int myApp3()
{
SemCCreate semTake(semid1,WAIT_FOREVER);
printf("I am in myApp3.....\n");
semGive(semid1);
int myApp1() return 0;
{ }
int myApp4()
semTake(semid1,WAIT_FOREVER); {
printf("I am in myApp1.....\n"); semTake(semid1,WAIT_FOREVER);

semGive(semid1); printf("I am in myApp4.....\n");


semGive(semid1);
return 0;
return 0;
}
}
int myApp2()
int myApp5()
{
{
semTake(semid1,WAIT_FOREVER);
semTake(semid1,WAIT_FOREVER);
printf("I am in myApp2.....\n");
printf("I am in myApp5.....\n");
semGive(semid1);
semGive(semid1);
return 0; return 0;
} }
Mutex
 semMCreate(options )
Semaphore options include the following:
 SEM_Q_PRIORITY (0x1)
◦ Queue pended tasks on the basis of their priority.
 SEM_Q_FIFO (0x0)
◦ Queue pended tasks on a first-in-first-out basis.
 SEM_INVERSION_SAFE (0x8)
◦ Enables priority inversion. With this option, the task owning the
semaphore will execute at the highest priority of the tasks pended
on the semaphore, if it is higher than its current priority. This option
must be accompanied by the SEM_Q_PRIORITY queuing mode.
returns semaphore ID, or NULL if memory cannot be allocated
int rootApp()
{
SemMCreate printf("\n*********************************\n");
printf("I am in rootApp Now......\n");
semid1=semMCreate(SEM_Q_PRIORITY);
#include"vxWorks.h" tid1=taskSpawn("tmyApp1",50,0,2000,(FUNCPTR)myApp1,0,0,0,0,
0,0,0,0,0,0);
#include"stdio.h"
tid2=taskSpawn("tmyApp2",50,0,2000,(FUNCPTR)myApp2,0,0,0,0,
#include"semaphore.h"
0,0,0,0,0,0);
#include"taskLib.h" tid3=taskSpawn("tmyApp3",50,0,2000,(FUNCPTR)myApp3,0,0,0,0,
0,0,0,0,0,0);
int myApp1(); tid4=taskSpawn("tmyApp4",50,0,2000,(FUNCPTR)myApp4,0,0,0,0,
0,0,0,0,0,0);
int myApp2();
return 0;
int myApp3();
}
int myApp4();

SEM_ID semid1;
int tid1, tid2,tid3,tid4;
int myApp2()
SemMCreate {
semTake(semid1,WAIT_FOREVER);
printf("I am in myApp2.....\n");

int myApp1() semGive(semid1);


return 0;
{
}
semTake(semid1,WAIT_FOREVER);
int myApp3()
printf("I am in myApp1.....\n");
{
taskDelay(10); semTake(semid1,WAIT_FOREVER);
printf("I am in myApp1 - After printf("I am in myApp3.....\n");
Delay.....\n"); semGive(semid1);
semGive(semid1); return 0;
return 0; }
} int myApp4()
{
printf("I am in myApp4.....\n");
return 0;
}
Ownership Property of Mutex
Semaphore
/* Ownership Property of Mutex int rootApp()
Semaphore */ {
printf("\n*********************************\n");
#include"vxWorks.h" printf("I am in rootApp Now......\n");
#include"stdio.h" semid1=semMCreate(SEM_Q_PRIORITY);

#include"semaphore.h" tid1=taskSpawn("tmyApp1",50,0,2000,(FUNCPTR)myA
pp1,0,0,0,0,0,0,0,0,0,0);
#include"taskLib.h"
tid2=taskSpawn("tmyApp2",50,0,2000,(FUNCPTR)myA
pp2,0,0,0,0,0,0,0,0,0,0);
int myApp1();
int myApp2(); return 0;
}
SEM_ID semid1;
int tid1, tid2;
Ownership Property of Mutex
Semaphore
int myApp2()
int myApp1()
{
{
int k;
k=semGive(semid1);
int k; printf("The Return value = %d\n",k);
k=semTake(semid1,WAIT_FOREVE
R);
return 0;
printf("I am in myApp1.....\n"); }
printf("The Return Value of SemTake
= %d\n",k);
taskDelay(10);
printf("I am in myApp1 - After
Delay.....\n");

return 0;
}
/* Recursive function of Mutex
Semaphore */
/* Recursive function of Mutex int rootApp()
Semaphore */ {
printf("\n*********************************\n");
#include"vxWorks.h" printf("I am in rootApp Now......\n");
#include"stdio.h" semid1=semMCreate(SEM_Q_PRIORITY);

#include"semaphore.h" tid1=taskSpawn("tmyApp1",50,0,2000,(FUNCPTR)myA
pp1,0,0,0,0,0,0,0,0,0,0);
#include"taskLib.h"

int myApp1(); return 0;


int recFun(); }

SEM_ID semid1;
int tid1;
/* Recursive function of Mutex
Semaphore */
int recFun()
int myApp1()
{
{

semTake(semid1,WAIT_FOREVER);
printf("I am in recFun...\n");
semTake(semid1,WAIT_FOREVER); semGive(semid1);
printf("I am in myApp1.....\n"); return 0;
recFun(); }

printf("I am in myApp1 - After


Calling recFun.....\n");
semGive(semid1);
return 0;
}
Dead-Lock
/* DeadLcok Using Mutex int rootApp()
Semaphore */ {
printf("\n*********************************\n");
#include"vxWorks.h" printf("I am in rootApp Now......\n");
#include"stdio.h" semid1=semMCreate(SEM_Q_PRIORITY);
#include"semaphore.h" semid2=semMCreate(SEM_Q_PRIORITY);
#include"taskLib.h" tid1=taskSpawn("tmyApp1",50,0,2000,(FUNCPTR)my
App1,0,0,0,0,0,0,0,0,0,0);
int myApp1(); tid2=taskSpawn("tmyApp2",50,0,2000,(FUNCPTR)my
int myApp2(); App2,0,0,0,0,0,0,0,0,0,0);
return 0;
}
SEM_ID semid1,semid2;
int tid1, tid2;
Dead-Lock
int myApp1() int myApp2()
{ {
semTake(semid2,WAIT_FOREVER);
semTake(semid1,WAIT_FOREVER); printf("myApp2 having semid2
printf("myApp1 having semid1 now......\n");
now......\n"); taskDelay(10);
taskDelay(10); semTake(semid1,WAIT_FOREVER);
semTake(semid2,WAIT_FOREVER); printf("myApp1 try to get semid1
printf("myApp1 try to get semid1 now......\n");
now......\n");
semGive(semid2);
semGive(semid1); semGive(semid2);
semGive(semid2); return 0;
return 0; }
}
SemMcreate
#include"stdio.h" void k()
#include"VxWorks.h" {
semId=semMCreate(SEM_Q_FIFO);
#include"taskLib.h" taskId1=taskSpawn("TASK1",50,0x100,2400,(FUNC
void c(void); PTR)a,0,0,0,0,0,0,0,0,0,0);
void a(void); taskId2=taskSpawn("TASK2",60,0x100,2400,(FUNC
PTR)b,0,0,0,0,0,0,0,0,0,0);
void b(void);
int taskId1,taskId2,taskId3; }
SEM_ID semId; void a(void)
{

semTake(semId,WAIT_FOREVER);
printf("\nTASK A\n");
taskId3=taskSpawn("TASK3",20,0x100,2400,(FUNC
PTR)c,0,0,0,0,0,0,0,0,0,0);
printf("TASK A after function\n");
semGive(semId);
}
SemMcreate
void b(void)
{

semTake(semId,WAIT_FOREVER);
printf("\nTASK B\n");
semGive(semId);
}

void c(void)
{
semTake(semId,WAIT_FOREVER);
printf("\nTASK C\n");
semGive(semId);
}
SemMcreate
#include"stdio.h" void a(void)
#include"VxWorks.h" {
semTake(semId,WAIT_FOREVER);
#include"taskLib.h" printf("\nTASK A\n");
void a(void); b();
void b(void); printf("TASK A after function\n");
semGive(semId);
int taskId1,taskId2;
}
SEM_ID semId;
void b(void)
{
void k()
semTake(semId,WAIT_FOREVER);
{ printf("\nTASK B\n");
semId=semBCreate(SEM_Q_FIFO,1); semGive(semId);
}
taskId1=taskSpawn("TASK1",50,0x100,2400,(FU
NCPTR)a,0,0,0,0,0,0,0,0,0,0);
taskId2=taskSpawn("TASK2",60,0x100,2400,(FU
NCPTR)b,0,0,0,0,0,0,0,0,0,0);
}
Intertask Communication
Inter task communication
 Two mechanisms are provided by RTOS for task communication:
 Message queues /Shared Memory
 Signals/ Events
 In addition, we will discuss the following mechanisms that can be
used in specific situation (not recommended)
 Function calls
 Accessing of variables
 Message queues/shared memory are used to pass the data, while
signals/events are used to signal other tasks.

86
Message queues
 Message queues are FIFO structure.
 Acts as a buffer between two tasks.
 A task need not consume the data passed by another immediately.

1
2
3

87
Message queues …..
 To use a message queue, the first step is to create one.
 Creation of a queue returns a queue ID.
 If any task wants to post some message to a task, it should use its
queue ID.
qid = queue_create (“MyQueue”, QUEUE_OPTION)
 Each queue can be usually configured as fixed size/ variable size.
 Most of RTOS will provide at least fixed size entries.

88
FIFO / Priority Queues
 Normally queues are FIFO.
 But priority options can also be used if multiple tasks are blocking
on a single queue and a message is posted in the queue.
 The queue can be configured to deliver a task that blocked the
queue first or the task that has higher priority.

3 3
10 4
10

89
Using queues

T1 T2

Q1 Q2

T3

Q3

90
Using queues ….
 It is a good practice to associate a queue with a task.
 The queue can be addressed through its unique mail id.
 Whenever a message needs to be posted to a task, it should
be posted to the corresponding queue.
 When we create multiple queues for the same task, we might
end up blocking inappropriately.
 For ex. Consider a case where there are 2 queues Q1 and Q2
associated with a task TA.
// Task A Code
queue_recieve (qid_1, pmessage1);
queue_recieve (qid_2, pmessage2);

 Let us assume Q1 is empty and the task A is blocked on it.


 Meanwhile if some message is posted in Q2, it will remain
unattended till some message is posted in Q1.
91
In VxWorks
Message Queues
 Used for inter task communication within one CPU.

 FIFO buffer of variable length messages.

 Message queues are normally FIFO; however, the msgQSend( )


function does allow an urgent message to be placed at the front,
rather than the rear, of the queue, enabling LIFO operation also.
Creating a Message Queue
 MSG_Q_ID msgQCreate (maxMsgs, maxMsgLength,
options)
maxMsgs Maximum number of messages
on the queue.
maxMsgLength Maximum size in bytes of a
message on the queue.
options Queue type for pended tasks
(MSG_Q_FIFO or
MSG_Q_PRIORITY).
 Returns an id used to reference this message queue or
NULL on error.
Sending Messages
 STATUS msgQSend (msgQId, buffer, nBytes, timeout,
priority)
msgQId MSG_Q_ID returned by msgQCreate( ).
buffer Address of data to put on queue.
nBytes Number of bytes to put on queue.
timeout Maximum time to wait (if queue is full).
Values can be tick count, WAIT_FOREVER
or NO_WAIT.
priority ”Priority“ of message to put on queue.
If MSG_PRI_URGENT, message put at
head of queue; if MSG_PRI_NORMAL,
message put at end of queue.
Sending Messages
 When queue is full, sending task blocks (until timeout).
 Use timeout of NO_WAIT for sending from interrupt
level.
 Symbolic constants defined in msgQLib.h.
 Returns OK on success, or ERROR on timeout,
invalid msgQId, or attempt to write more bytes than
maximum message size.
Message Sending Examples
status = msgQSend (msgQId, buf, sizeof(buf), WAIT_FOREVER,
MSG_PRI_NORMAL);

 status = msgQSend (msgQId, buf, sizeof(buf), NO_WAIT,


MSG_PRI_URGENT);
Receiving Messages
 int msgQReceive (msgQId, buffer, maxNBytes,
timeout)
msgQId Returned from msgQCreate( ).
buffer Address to store message.
maxNBytes Maximum size of message to
read from queue.
timeout Maximum time to wait (if no
messages available). Values can
be clock ticks,
WAIT_FOREVER, or NO_WAIT.
Receiving Messages
 Returns number of bytes read on success, ERROR on
timeout or invalid msgQId.
 Unread bytes in a message are lost.
 If queue is empty, receiving task pends (until timeout expires).
 Pended tasks wait in FIFO or priority order (specified in
msgQCreate( )).
 msgQReceive( ) returns at most the number of bytes in the first
message.
Deleting a Message Queue.

 STATUS msgQDelete (msgQId)


Deletes message queue.
Tasks pended on queue will be unpended; their msgQSend( )
or msgQReceive( ) calls return error.
example
#include"VxWorks.h"
#include"msgQLib.h"
#include"stdio.h"
#include"taskLib.h"
void a(void);
void b(void);
MSG_Q_ID mesgQueueId1;
void f()
{
mesgQueueId1=msgQCreate(100,50,MSG_Q_FIFO);
taskSpawn("task1",70,0x100,2000,(FUNCPTR)a,0,0,0,0,0,0,0,0,0,0);
taskSpawn("task2",80,0x100,2000,(FUNCPTR)b,0,0,0,0,0,0,0,0,0,0);
}
void a(void)
{
char msgBuf1[6]=“VIT";
char msgBuf2[10]=“UNIVERSITY";
msgQSend(mesgQueueId1,msgBuf1,6,WAIT_FOREVER,MSG_PRI_NORMAL);
msgQSend(mesgQueueId1,msgBuf2,10,WAIT_FOREVER,MSG_PRI_NORMAL);
printf("\nMessages are sent to message queue from task1\n");
}

void b(void)
{
char msgBuf3[6]={0};
char msgBuf4[10]={0};
msgQReceive(mesgQueueId1,msgBuf3,6,WAIT_FOREVER);
msgQReceive(mesgQueueId1,msgBuf4,10,WAIT_FOREVER);
printf("\nfirst messages from msg queue is %s\n",msgBuf3);
printf("\nsecond Message received received from message queue %s\n",msgBuf4);
}
example
#include"VxWorks.h"
#include"msgQLib.h"
#include"stdio.h"
#include"taskLib.h"
void a(void);
void b(void);
MSG_Q_ID mesgQueueId1;
char msgBuf1[8];
void f()
{
mesgQueueId1=msgQCreate(4,50,0x00);
taskSpawn("task1",70,0x100,2000,(FUNCPTR)a,0,0,0,0,0,0,0,0,0,0);
taskSpawn("task2",80,0x100,2000,(FUNCPTR)b,0,0,0,0,0,0,0,0,0,0);

}
example
void a(void)
{
char msgBuf1[8]=“Embedded";
char msgBuf2[8]=“Systems";
msgQSend(mesgQueueId1,msgBuf1,50,WAIT_FOREVER,MSG_PRI_NORMAL);
msgQSend(mesgQueueId1,msgBuf2,50,WAIT_FOREVER,MSG_PRI_URGENT);
printf("\nMessages are send to tasks from task1\n");
}
void b(void)
{
msgQReceive(mesgQueueId1,msgBuf1,50,WAIT_FOREVER);
printf("\n%s\n",msgBuf1);
msgQReceive(mesgQueueId1,msgBuf1,50,WAIT_FOREVER);
printf("\n%s\n",msgBuf1);
printf("\nMessage is received in task2\n");
}
SHARED MEMORY
Shared Memory
 Two or more tasks can exchange information by reading and writing
the same area in memory.
 Data exchange  takes place with zero copying  because buffer is
just one deep.
 For the rest any policy can be implemented on the top of shared
memory.
 DMA area is very popular for the usage of shared memory.
 Limit  availability of RAM memory.
 Shared memory must be reserved from OS and locked into RAM.
 Handshaking protocol is used among the tasks  to know the
freshness of data in shared memory.
 Common approach  use counter  to indicates how many writes
have already take place.
Shared Memory
 Shared memory has the properties of a so called block device.
 Programs can access that arbitrary blocks on the device in any
sequence.
 Character devices can access the data in a specified linear sequence 
FIFO.
 Its mediator policy:
◦ Loss free
◦ Non blocking
◦ Many to many /One to one
◦ Buffered.
 Some FIFO support blocking for synchronization at the reader‟s end  so
readers can woken up as soon as new data has arrived.  have task
queue in which blocked tasks can wait.
In VxWorks
Inter task communication
 It permits independent tasks to coordinate their actions.
 VxWorks provide rich set of inter task communication mechanisms:
◦ Shared memory  for simple sharing of data.
◦ Semaphores  for basic mutual exclusions and synchronization.
◦ Msg Queue/pipe  for inter task message passing within a CPU.
◦ Sockets / RPC  for network-transparent inter task
communication.
◦ Signals for exception handling
 VxMP  provides intertask communications over the back plane for
task running on different CPUs.
 This includes  shared semaphore, shared message queues, shared
memory, shared name database.
memPartCreate( )
PART_ID memPartCreate(char * pPool, unsigned poolSize ) -
create a memory partition
pPool is the global address of shared memory dedicated to the partition
poolSize is the size in bytes of shared memory dedicated to the partition
DESCRIPTION
 This routine creates a new memory partition containing a specified memory
pool.
 It returns a partition ID, which can then be passed to other routines to
manage the partition (i.e., to allocate and free memory blocks in the partition).
RETURNS
The partition ID, or NULL if there is insufficient memory
memPartAlloc( )
memPartAlloc(PART_ID partId,unsigned nBytes ) -
allocate a block of memory from a partition
partId: memory partition to allocate from
nBytes: number of bytes to allocate
DESCRIPTION
 This routine allocates a block of memory from a specified
partition.
 The size of the block will be equal to or greater than nBytes.
RETURNS
pointer, or ERROR if the block is invalid.
memPartFree( )
memPartFree(PART_ID partId, char * pBlock ) - free a block of
memory in a partition
partId: memory partition to add block to
pBlock : pointer to block of memory to free

DESCRIPTION
 This routine returns to a partition's free memory list a block of memory previously
allocated with memPartAlloc( ).

RETURNS
OK, or ERROR if the block is invalid.
memPartAddToPool( )
memPartAddToPool(PART_ID partId, char * pPool, unsigned
poolSize ) - add memory to a memory partition.
partId: partition to initialize
pPool pointer to memory block
poolSize block size in bytes
DESCRIPTION
 This routine adds memory to a specified memory partition already
created with memPartCreate( ). The memory added need not be
contiguous with memory previously assigned to the partition.
RETURNS
OK or ERROR.
Example
#include"VxWorks.h"
#include"MemLib.h"
#include"stdio.h"
#include"taskLib.h"
#include"string.h"
void a(void);
void b(void);
PART_ID Id1;
char *p1;
void f()
{
unsigned int size=80;
void *p;
p=(void *)malloc(100);
Id1=memPartCreate((char *)p,size);
taskSpawn("task1",70,0,2000,(FUNCPTR)a,0,0,0,0,0,0,0,0,0,0);
taskSpawn("task2",80,0,2000,(FUNCPTR)b,0,0,0,0,0,0,0,0,0,0);
}
Example
void a(void)
{
p1=(char *)memPartAlloc(Id1,50);
strcpy(p1,"be proud to be indian");
printf("TASK1 writes \n");
}

void b(void)
{
printf("read data is %s \n",p1);
memPartFree(Id1,(void *)p1);
printf("TASK2 reads \n");
}
SIGNALS
Signals
Signals
 A signal is the software analog of an interrupt:
 A signal sent to a task indicates some asynchronous event has occurred.
 There are 31 unique signals, each representing a different event.
 A task can attach a signal handler to take appropriate action when the
signal is received.
 Upon completion of signal handling, normal task execution is resumed
(unless the signal corresponds to an exception).
UNIX vs. VxWorks Signals
 Signal is ignored if no handler is installed.
 Can install a handler to catch SIGKILL.
 No SIGCHLD, SIGPIPE, or SIGURG.
 Automatic function restarting
 Automatic function restarting describes behavior for a task which catches
a signal while on the pend queue:
1. Task receives a signal while pended.
2. Task is removed from pend queue and made ready to run.
3. When the task is the highest priority task on the Ready queue, it runs its
signal handler for the signal it caught.
4. After running its signal handler, the task is returned to the pended state,
with its originally specified timeout.
UNIX vs. VxWorks Signals
Caveats
 Signals are not recommended for general inter task communication.
A signal:
◦ May be handled at too high priority if it arrives during a priority
inheritance.
◦ Disrupts a task‟s normal execution order. (It is better to create two
tasks than to multiplex processing in one task via signals.)
◦ Can cause reentrancy problems between a task running its signal
handler and the same task running its normal code.
◦ Can be used to tell a task to shut itself down.
Registering a Signal Handler
To register a signal handler:
signal (signo, handler)
 signo Signal number.
 handler Routine to invoke when signal arrives (or
SIG_IGN to ignore signal).
 Returns the previously installed signal handler, or
SIG_ERR.
kill
 Kill(int TASKID,INT SIGNO)
Kill function is used send any signal any task
Arguments
TASKID : ID of the task to which signal is to be sent
SIGNO : SIGNAL number to be sent
Signals and Exceptions
 Hardware exceptions include bus error, address error, divide by
zero, floating point overflow, etc..
 Some signals correspond to exceptions (e.g., SIGSEGV
corresponds to a bus error on a 68k; SIGFPE corresponds to
various arithmetical exceptions).
Signals and Exceptions
 When an executing task generates an exception:
 If the task has a signal handler installed to deal with that
exception, VxWorks will raise the signal to that task.
 If the task has no signal handler installed for that exception,
VxWorks will suspend the task and log an error message to the
console.
Signals and Exceptions
 If an exception signal handler returns:
The offending task will be suspended.
A message will be logged to the console.

 Exception signal handlers typically call:


exit( ) to terminate the task, or
taskRestart( ) to restart the task, or
longjmp( ) to resume execution at location saved by setjmp(
).
Example
#include<stdio.h> int rootApp()
#include<vxWorks.h> {
#include<sigLib.h> printf("****VIT **********\n");
#include<taskLib.h> printf("I am in rootApp now....\n");
void sig_Handle(int signo); signal(SIGINT,sig_Handle);
/* A Simple Program for SIGNAL */ raise(SIGINT);
void sig_Handle(int signo) printf("Back to rootAoo now...\n");
{ return 0;
printf("I am in Signal Handler ----\n"); }
}
Example
/* includes */
#include "vxWorks.h"
#include "sigLib.h"
#include "taskLib.h"
#include "stdio.h"

/* function prototypes */
void catchSIGINT(int);
void sigCatcher(void);

/* globals */
#define NO_OPTIONS 0
#define ITER1 100
#define LONG_TIME 1000000
#define HIGHPRIORITY 100
#define LOWPRIORITY 101
int ownId;
Example
void sigGenerator(void) /* task to generate the SIGINT signal */
{
int i, j, taskId;
STATUS taskAlive;
if((taskId = taskSpawn("signal",100,0x100,20000,(FUNCPTR)sigCatcher,0,0,0,0,0,0,0,
0,0,0)) == ERROR)
printf("taskSpawn sigCatcher failed\n");
ownId = taskIdSelf(); /* get sigGenerator's task id */
taskDelay(30); /* allow time to get sigCatcher to run */
for (i=0; i < ITER1; i++)
{
if ((taskAlive = taskIdVerify(taskId)) == OK)
{
printf("+++++++++++++++++++++++++++++++SIGINT sinal generated\n");
kill(taskId, SIGINT); /* generate signal */
taskPrioritySet(ownId,LOWPRIORITY);
}
break;
}
printf("\n***************sigGenerator Exited***************\n");
}
void sigCatcher(void) /* task to handle the SIGINT signal */
{
struct sigaction newAction;
int i, j;
newAction.sa_handler = catchSIGINT; /* set the new handler */
sigemptyset(&newAction.sa_mask); /* no other signals blocked */
newAction.sa_flags = NO_OPTIONS; /* no special options */
if(sigaction(SIGINT, &newAction, NULL) == -1)
printf("Could not install signal handler\n");

for (i=0; i < ITER1; i++)


{
for (j=0; j < LONG_TIME; j++);
printf("Normal processing in sigCatcher\n");
}
printf("\n+++++++++++++++sigCatcher Exited+++++++++++++++\n");
}
void catchSIGINT(int signal) /* signal handler code */
{
printf("-------------------------------SIGINT signal caught\n");
taskPrioritySet(ownId,HIGHPRIORITY);
}

Das könnte Ihnen auch gefallen