CS452 - Real-Time Programming - Fall 2011
Lecture 17 - Debugging, Anthropomorphic Programming
Public Service Annoucements
- Due date of kernel 4 (Friday, 28 October)
- Saturday November 5, 11.00 to 13.00. Open house for high school
students.
- Signatures of Getc( ) and Putc( )
Serial I/O
The implementations that follow are samples to show how bytes flow from
task to task. They are not the only, and probably not the best possible
implementations. They have been chosen because it is easy to see the byte
flow in them, or so I hope.
Implementation without FIFO, without Flow Control
Receive
There must be a FIFO receive buffer (probably circular) in the server, and
a queue for clients blocked on Getc( )
Interrupt
Kernel
- Check for EVENT_BLOCKED Notifier
- Read byte from UART
- Interrupt automatically cleared
- Ready Notifier, returning byte
Notifier
- Send byte to server
Server
- Receive byte from Notifier
- Reply to Notifier
- If client queued
else
- Put byte in receive buffer
Client Getc
Server
- If receive buffer not empty
- Reply first byte to client
else
Transmit
There is a FIFO transmit buffer (probably circular) in the server
Interrupt
Kernel
- Check for EVENT_BLOCKED Notifier
- Ready Notifier
Notifier
- Send to server for byte
- Write byte to UART
Server
- If no byte available, then
- wait for Client to do Putc( )
- Reply byte
Client Putc
Server
- If Notifier waiting
else
- Reply `done' to Client
Implementation without FIFO, with Flow Control
Receive
Same as above.
Transmit
There is a FIFO transmit buffer and a CTS state variable
Transmit Interrupt
Kernel
- Check for EVENT_BLOCKED Notifier
- Disable interrupt in ICU
- Ready Notifier
Notifier
- Send to server for byte
- Write byte to UART
- Enable interrupt in ICU
Server
- If buffer empty
- If !CTS
else
Client Putc
Server
- If Notifier waiting && CTS
else
CTS Interrupt
Kernel
- Check for EVENT_BLOCKED CTSNotifier
- Turn off interrupt in UART
- Ready CTSNotifier
CTSNotifier
- Send CTS toggle message to Server
Server
- Reply to CTSNotifier
- Toggle CTS
- Read UART modem status
- while( CTS != UART modem status CTS ) Read UART modem status
- If CTS &&Notifier waiting && buffer not empty
Debugging Real-time Programs
The most common set of debugging tools used by experienced programmers is
the oldest: printf, grep & stack trace.
- The power of these tools is greatly enhanced by strong conventions in
code formatting.
Debugging real-time programs, at its base, is just the same as any other
debugging, and just the same as empirical science.
- Gather data.
- Create a model that explains the data
- Test the model
- If the model is not correct, go to 1.
- Remember that the model is ALWAYS provisional: data collected later may
invalidate it, no matter how much data has confirmed it.
But real-time programs are harder to debug. Very few programs are entirely
free of critical races, which are the worst type of bug, lurking for weeks
months or years in seemingly correct code, the appearing when innocuous,
unconnected changes occur.
RedBoot
The memory contents are not wiped by reset. Some of the most difficult
errors can be detected only by using the contents of memory after a reset.
On some types of exceptions RedBoot will attempt to connect with gdb. In
such cases it writes a bunch of gibberish on the bottom of the monitor
screen. Among that gibberish is the address of the instruction that caused
the exception. Using the load map generated by the linker you can find
- the function that your application was running when the exception
occurred, and
- the assembly language instruction where the exception occurred.
It is usually pretty easy to figure out which line of C source was
responsible for the instruction.
Stack Trace
In single-threaded programs this is often the most useful tool.
- Anything that terminates execution abnormally prints the set of active
stack frames
- Minimal version
- name of calling function
- line number of call
- Extreme version
- values of arguments
- values of local variables
What is the equivalent of a stack trace in a real-time multi-tasking
environment?
- Most would say it is the set of tasks, and the run state of each.
- That information is available starting at the set of task descriptors,
but how do you get it in an understandable way?
Breakpoint
What does it do?
- snapshot of the system
- This means that computation, including respose to interrupts, must
stop, or it isn't a snapshot.
- provides interactive tools for examining kernel data structures, such
as
- task descriptors
- lists and queues
- stacks, including the program counter and local variables, of
individual tasks
- restart system immediately afterwards
- If you want to continue where processing stopped you must make
certain that all state is saved when you enter Beakpoint and restored
when you leave it. What about pending interrupts? You can't stop the
entire universe!
- Otherwise you can re-enter RedBoot.
How do you get it started?
- function call, which you insert in your code when compiling.
- The easiest and fastest form to implement.
- Having the call as part of ASSERT is common.
- Has to exit to RedBoot. (Jump to x00.)
- system call instead of function call, which respects the kernel/user
distinction.
- an exception triggered externally
- at initialization
- Set up the system so that the external event will generate an
exception
- E.g. attach a button to PDIO on the third connector, set up
ICU.
- at run-time
- Trigger the interrupt
- Switch to Breakpoint in the event handler
- Either exit to RedBoot,
- Or clean up pending interrupts and resume execution.
Breakpoint is a special case of a particular sort of tool that is very
common.
- condition occurs => information is made available
- breakpoint provides the information interactively (`interactively' =
`on the time scale of the user')
- it can stop the system completely. How?
- but it has limited ability to stop the real world
We need methods of getting information closer to real-time.
Anthropomorphic Programming
We all, even most programmers (!), have effective intuitions about human
relations
- We use them to `understand' pets, which means attributing to them
- goals
- knowledge
- capability
- emotions
- Why not programs?
- apply them to intertask relationships
Tasks are independent entities
- Understand them by thinking about them as if they have capabilities and
goals.
- When you are developing something like the train application you are
defining roles and relationships.
Return to: