# Lecture 21 - Anthropomorphic Programming

## Public Service Annoucements

1. Train Control I demo on Friday, 3 July.
2. The exam has three start times.
• 20.30, August 4
• 09.30, August 5
• 20.30, August 5
The end times are 26.5 hours after the start time.
Answers to questions asked from 20.30, 4 August to 22.00, 4 August will be answered on the newsgroup, whether they arrive by e-mail or on the newsgroup.
3. PDF on Acceleration Mathematics.

# Calibration I

## 4. Calibrating Acceleration and Deceleration: Doing Better

There are three models of interest.

1. Abrupt change of velocity.
• At some time, ta, during the acceration the model changes the velocity from v0 to v1.
• To go the same distance as the other models we require ta = (t0 + t1) / 2.
2. Constant acceleration.
• Velocity increases linearly as long at acceleration continues.
• Model 1 falls behind this model, then catches up.
• Maximum distance Model 1 lags model 2 is at (t1 + t2) / 2.
• maximum lag is (v1 - v0)(t1 - t0) / 8
3. Zero acceleration at the end points: finite jerk.
• Velocity increases as a cubic.
• Distance travelled increases quartically.
• Model 2 falls behind this model, then catches up.
• Maximum distance behind at (t0 + t1) / 2.
• Maximum distance model 2 falls behind is (v1 - v0)(t1 - t0) / 32

# 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
• capabilities
• emotions
• Why not programs?
• apply them to intertask relationships

• 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

Why do servers need attendant tasks?

• What happens if a server calls AwaitEvent?

## 1. Proprietor with a Notifier

Proprietor `owns' a service, which usually means a resource.

• Think of the owner at the counter of an old-fashioned store
• `store' means where things are stored;
• a proprietor is a store-keeper;
• The goods are behind the counter and only the proprietor can access them.
• Clients come to the front and are processed one by one.
• Comment. The modern `store' is considered by many to be the most important innovation of the 20th century. (Yes, including the transistor, the computer, quantum mechanics, antibiotics, etc.) A whole lot of work that was previously done by store personnel is now done by the client. This is possible only because extensive codes of conduct have been internalized by clients. (That is, a large collection of new behaviour norms have been created and propagated.)
• Somebody has to sit out back waiting for the truck and bringing it to the proprietor

#### Notifier Code for a UART

• Initialize
```      Receive( &serverTid, eventId );
```
• Work
```      FOREVER {
data = AwaitEvent( eventid );
switch( data.event-type ) {
case RCV_INT:
Send( serverTid, {NOT_RCV, data.byte}, ... );
break;
case XMT_INT:
Send( serverTid, {NOT_XMIT}, byte );  // byte is to be transmitted
store( UART..., byte )
break;
}
}
```

#### Proprietor Code for a UART

• Initialize
```      // 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.
```
• Work
```      FOREVER {
requesterTid = Receive( request, {request-type, data} );
switch ( request-type ) {
case NOT_RCV:
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:
enqueue ( xmitfifo, data );
if ( ! empty( xmitQ ) )
Reply( dequeue( xmitQ ), dequeue( xmitfifo ) );
break;
}
}
```

#### Notes

1. Notifier is usually of higher priority than server
• Notice the early reply in the proprietor
2. We assume that interrupts get turned on and/or off in the kernel?
3. We hope that the code
• exhibits duality explicitly
• is easy to break into parts
• is easy to extend

## 2. Using a Courier

Simplest is best

#### Transmit Notifier Code

• Initialize
```      Receive( &courierTid, ... );
```
• Work
```      FOREVER {
store( UART..., byte )
data = AwaitEvent( eventid );
}
```

#### Transmit Courier Code

• Initialize
```      Receive( &serverTid, notifierTid );
Send( notifierTid, ... );
```
• Work
```FOREVER {
Send( notifierTid, {data} );
Send( serverTid, {req}, {data} );
}```

#### Transmit Proprietor Code

• Initialize
```// 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.
```
• Work
```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:
enqueue ( xmitFifo, data );
if ( ! empty( xmitQ ) ) Reply( dequeue( xmitQ ), dequeue( xmitFifo ) );
break;
default:
ASSERT( "..." );
}
}```

#### Notes

This gets you through a bottleneck where at most than two events come too fast.

Remember that all the calls provide error returns. You can/should use them for error recovery

• static error recovery: debugging
• dynamic error recovery: at run time

Another possible arrangement for task creation

• Server creates the courier
• Couier creates the notifier

Another possible arrangement for initialization

• Courier sends to its parentTid
• Notifier sends to its parentTid

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.

E.g., the decision to add a courier requires revision of code within the group, but not outside it.

## 3. The Warehouse

Add a warehouse between the courier and the notifier.

• In structure the warehouse is a typical server.
• The warehouse has only a single client, the courier, so its sendQ never has more than one member.
• The warehouse put together multiple inputs into a package, or break a package into multiple outputs.
• The sooner you package, and the later you unpackage, the fewer messages you need to pass.
• #### Initialization

The initialization given for the courier, above, generalizes to include the warehouse, essentially without change.

#### Forever

The notifier is now talking directly to a server and has the shape given above for the proprietor. The warehouse cannot talk directly to the proprietor because both are servers.

• A courier is inserted between them.
• If there is to be two way traffic between the proprietor and the warehouse two servers are needed.

#### Note

This structure clears up most problems when a burst of requests to the server would leave the notifier waiting in a long sendQ.

• Warehouse and proprietor share the work.
• Server's Tid is public; Warehouse's Tid is private.
• This is far from the only way to share the work. For example,
• The server could be guarded by a receptionist (assistant) who ensures that another client request occurs only when the previous request is complete. Then the warehouse is unnecessary.

Two issues:

1. Handles bottlenecks of all sizes.

Give a precise and quantitative definition of `bottleneck'.

2. Server could be buffered on the other side

Called a guard.

What this amounts to is that a server should be lean and hungry

• do as little as possible

## 4. Secretary, Receptionist

The warehouse guards the notifier from the effect of multiple clients on the server. Another method of guarding the notifier is to guard the proprietor so that its sendQ is always empty. The secretary/receptionist does so.

The secretary receives requests from many clients and forwards them one at a time to the proprietor. Because the secretary Receives it cannot Send. It communicates with the Proprietor using a Courier.

• The Courier Sends to the Secretary.
• The Secretary Replys the nest request to the Courier.
• The Courier Sends the request to the Proprietor.
• The Proprietor Replys the result to the Courier.
• The Courier Sends the result to the Secretary.
• The Secretary Replys the result to the Client.

Notes

1. When all the clients have been given service
• The Secretary is Send-blocked waiting for a Client.
• The Courier is Reply-blocked waiting for a request from the Secretary.
• The Proprietor is Send-blocked waiting for either data from the Notifier or for a request from the Courier.
• The Notifier is Event-blocked.
2. The Courier is almost always Reply-blocked. If it spends a significant amount of time Receive-blocked the system is overloaded.
3. If there is a temporary overload of Client requests, the Courier may sit for a while in the Secretary's SendQ while the Proprietor continues to interact with the Notifier.
4. If there is a permanent overload of requests you are in trouble.

Administrator is a proprietor who does no work but only assigns work to others

• Work orders are given to workers
• If Create is fast and you have a method for reclaiming resources you can Create and Destroy workers on demand.
• Otherwise workers are created at initialization and the administrator maintains a pool of free workers

Where do the workers come from?

• Static organizations hire a workforce of employees who are assigned tasks as they come up.
• And if they have run out of employees then you (the client) just have to wait.
• If the worker is waiting for some data to be available, which is the most common case, then
• a worker at the priority of the client does the waiting,
• the administrator goes on to supply workers to other clients,
• nobody loses
• Dynamic organizations hire workers after the need for work appears, and fire them when the work is done. These are called contract workers or consultants.
• Create (hire) a worker when they are needed, destroy (fire) them when they are no longer needed.
• No need to provide a pension, benefits and so on.
• Helpers hired (created) by the consultant should be fired (destroyed) with the consultant.
• The destroy primitive usually destroys all the children of the task being destroyed.
• Resources are returned to the system to prevent a population explosion of zombies in the workplace
• Semi-dynamic organizations are between static and dynamic.
• New workers are hired (created),
• but they are not fired.
• If two dynamic administrators exist in a system you may have to regulate the system globally in order to resolve a creation race between them.
• The type of independent agent system studied by Kate Larson handles such problems locally

Most workers prefer employee status to consultant status.

### Worker code

```  Send( administrator, nil, workOrder );
FOREVER {
workResult = doWork( workOrder );
}```

`doWork` might require further sends to servers or warehouses, which is harmless in this context.

What kind of work might a worker do?

• The most common type of worker does something like calculating a shortest route.
• Too long a calculation to put inside a server, but something that a client might request from a server.
• Updating a calibration might fall into the same category.
• You certainly want to do it, but it doesn't matter if you do it after more urgent things.
• The results that come back from workers will not preserve the order in which they are given.
• It might even do floating point calculation. Why?

#### Initialization

```Administrator( ) {
for ( i = 0; i < NUM_WORKERS; i++ ) worker[i] = Create( mypriority - 1, workerCode );

FOREVER {
switch( request.type ) {
case CLIENT:
enqueue( orderQ, {order = {client, request}} );
if ( !empty( employeeQ ) ) Reply( dequeue( employeeQ ) ), dequeue( orderQ ) );
break;
case WORKER:
enqueue( emploeeQ, requester);
if ( !empty( orderQ ) ) Reply( dequeue( employeeQ ), { dequeue( orderQ ) );
if ( request != nil ) { Reply( request.client, request.request );
break;
}
}```

Note: Tid of the client is included in the workorder to the administrator does not have to maintain and search a list of jobs being done. (Administrators are by nature lazy!)

1. As above, Administrator includes Tid of the client in the order.
2. Worker replies directly to client with result and to administrator with request for another order to process.

• Suppose that there is data required for processing each order.
• It would be maintained internally and added to the appropriate order before the order is despatched to the worker.
• Another model: the worker queries a detective.

## 6. The Detective

### Simple Events

The notifier is a task that waits on events.

• AwaitEvent is like Send

It has two features

• a simple, kernel-defined event that it waits on
• can only serve one master (`one' defined in terms of the kernel events)
• The notifier needs to pass on that the event has happened
• which it does using Send
```FOREVER {
AwaitEvent( eventId );
Send( server );
}```

You could call a notifier a detective,

• who looks around on your behalf,
• and let's you know when something you care about happens,
• but really it is a detective's worker, whom you employ directly.

### Complex Events

In an application there is likely to be lots of waiting on combinations of events.

• form the combinations using Boolean operators
• for example, Respond `okay' when this sensor is triggered or `time-out' when Delay returns.

We use the detective to discover that a complex event has occurred.

• How does the detective work?

#### Conjunction

Code could be

```FOREVER {
Send( part1 );
Send( part2 );
...
Send( master );
}```

#### Disjunction

Code above doesn't even pretend to work!

```FOREVER {
switch ( request.type ) {
case CLIENT:
case = {requester, request.event, request.delay} );
insert( caseDB, case );
if ( !empty( delayQ ) && !empty( irregularQ ) ) {
Reply( dequeue( delayQ ), case );
Reply( dequeue( irregularQ ), case );
}
case DELAY:
enqueue( delayQ, requester );
if ( case = pending( caseDB, nil ) && !empty( irregularQ ) ) {
Reply( dequeue( delayQ ), case );
Reply( dequeue( irregularQ ), case );
}
case = extract( caseDB, request.requester );
if ( case != nil ) Reply( case.requester, TIME_OUT );
break;
case CLUE:
enqueue( irregularQ, requester );
if ( ( case = pending( caseDB, nil )!=nil && !empty( delayQ ) ) {
Reply( dequeue( delayQ ), case );
Reply( dequeue( irregularQ ), case );
}
case = extract( caseDB, request.requester );
if ( case != nil ) Reply( case.requester, EVENT );
break;
}
}```

This is the code of a particular detective, one that notifies you which occurs first, a time-out or an event.

#### Not

We can say that an event has not happened yet.

Only at the end of the universe can we say that an event simply has not happened.

Time-outs are needed for NOT: how to do them is shown above.

Who is the client of the detective

1. Initiator of a normal action

## 7. Housekeeper

Housekeeper of the system who will detect, and possibly clean up pathologies.