We are supposed to support
int Get( int port )
and
int Put( int port, char c )
These are wrappers for sends to one or more serial servers.
| one server | two servers | four servers | ||||
| one
notifier |
likely queue
congestion in server |
likely queue
congestion in notifer |
||||
| two
notifiers |
one per channel?
one per direction? |
how should they
be paired? |
||||
| four
notifiers |
certain queue
congestion in server |
likely queue
congestion in server |
best performance,
most tasks |
Issues
Either
Or
We all, even most programmers (!), have effective intuitions about human relations
Tasks are independent entities
Why do servers need attendant tasks?
Proprietor `owns' a service, which usually means a resource.
Kernel is handling hardware in this example
Receive( &serverTid, eventId );
Reply( serverTid, ... );
FOREVER {
data = AwaitEvent( eventid ); // data includes event type and volatile data
switch( data.event-type ) {
case RCV_INT:
Send( serverTid, {NOT_RCV, data.byte}, ... );
break;
case XMT_INT:
// test transmitter, turn interrupt off and on?
Send( serverTid, {NOT_XMIT}, byte ); // byte is to be transmitted
store( UART..., byte )
break;
default:
ASSERT( "This never happens because our kernel is bug-free." );
}
// queues & fifos
notifierPid = Create( notifier ); //Should notifier code name be hard coded?
Send( notifierTid, MyTid( ), ... ); //On return notifier is known to be okay
RegisterAs( ); //On return requests can begin.
FOREVER {
requesterTid = Receive( request, {request-type, data} );
switch ( request-type ) {
case NOT_RCV:
Reply( requesterTid, ... );
enqueue( rcvfifo, data );
if ( ! empty( rcvQ ) ) Reply( dequeue( rcvQ ), dequeue( rcvfifo ) );
break;
case NOT_XMIT:
enqueue( xmitQ, requesterTid );
if ( ! empty( xmitfifo ) ) Reply( dequeue( xmitQ ), dequeue( xmitfifo ) );
break;
case CLIENT_RCV:
enqueue( rcvQ, requesterTid );
if ( !empty( rcvfifo ) Reply( dequeue( rcvQ ), dequeue( rcvfifo ) );
break;
case CLIENT_XMIT:
Reply( requesterTid, ... );
enqueue ( xmitfifo, data );
if ( ! empty( xmitQ ) ) Reply( dequeue( xmitQ ), dequeue( xmitfifo ) );
break;
default:
ASSERT( "Never executed because notifiers and clients are bug-free." )
}
}
Simplest is best
Receive( &courierTid, ... );
Reply( courierTid, ... );
FOREVER {
Receive( &courierTid, byte );
load( UART..., byte )
data = AwaitEvent( eventid );
Reply( courierTid, NOT_XMIT, );
}
Receive( &serverTid, notifierTid ); Send( notifierTid, ... ); Reply( serverTid );
FOREVER {
Send( notifierTid, {data} );
Send( serverTid, {req}, {data} );
}
// queues & fifos
notifierTid = Create( notifier );
courierTid = Create( courier );
Send( courierTid, notifierTid, ... ); // On return courier & notifier are known to be okay
RegisterAs( ); //On return client requests will begin.
FOREVER {
requesterTid = Receive( request, {request-type, data} );
switch ( request-type ) {
case NOT_XMIT:
enqueue( requesterTid, xmitQ )
if ( ! empty( xmitFifo ) ) Reply( dequeue( xmitQ ), dequeue( xmitFifo ) );
break;
case CLIENT_XMIT:
Reply( requesterTid, ... );
enqueue ( xmitFifo, data );
if ( ! empty( xmitQ ) ) Reply( dequeue( xmitQ ), dequeue( xmitFifo ) );
break;
default:
ASSERT( "..." );
}
}
This gets you through a bottleneck where no more than two events come too fast.
Remember that all the calls provide error returns. You can/should use them for error recovery
Another possible arrangement for task creation
Another possible arrangement for initialization
Distributed gating
I am showing you collections of tasks implemented together because sets of related tasks is a level of organization above the individual task.
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. Produce useful results by inserting
str pc, <magic location>
into your code, and with the assistance of a load map, finding out where you were in whose code when the problem occurred.
In single-threaded programs this is often the most useful tool.
What is the equivalent of a stack trace in a real-time multi-tasking environment?
Two basic questions to answer.
What does it do?
How do you get it started?
Breakpoint is a special case of a particular sort of tool that is very common.
Getting information closer to real-time.
Return to: