[Tinyos-beta-commits] CVS: tinyos-1.x/beta/teps/txt tep108.txt, NONE, 1.1

David Gay idgay at users.sourceforge.net
Wed Mar 30 16:59:45 PST 2005


Update of /cvsroot/tinyos/tinyos-1.x/beta/teps/txt
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23839

Added Files:
	tep108.txt 
Log Message:
arbitration


--- NEW FILE: tep108.txt ---
============================
Resource Arbitration
============================

:TEP: 108
:Group: Core Working Group 
:Type: Documentary
:Status: Draft
:TinyOS-Version: 2.x
:Author: David Gay

:Draft-Created: 28-Mar-2005
:Draft-Version: $Revision: 1.1 $
:Draft-Modified: $Date: 2005/03/31 00:59:43 $
:Draft-Discuss: TinyOS Developer List <tinyos-devel at mail.millennium.berkeley.edu>

.. Note::

   This memo documents a part of TinyOS for the TinyOS Community, and
   requests discussion and suggestions for improvements.  Distribution
   of this memo is unlimited. This memo is in full compliance with
   TEP 1.

Abstract
====================================================================

This memo documents the general resource sharing mechanisms for TinyOS
2.x. These mechanisms are used to allow multiple software components to
arbitrate the use of both hardware buses, software components, etc.


1. Introduction
====================================================================

Components that wish to use a shared resource, such as a hardware bus,
memory or the services offered by another component need a way to arbitrate
use of these resources. 

In TinyOS 1.x, this arbitration was performed on a first-come, first-served
basis by having requests for, e.g., a service X return FAIL if it was
currently in use. Users of X could monitor service completion events if
they wished to retry a failed request. This approach has several drawbacks:

- If you need to make several requests of X, you have to handle the
  possibility of failure at any stage. This complicates implementations by
  adding extra internal states.
- You have no control over timing of a sequence of operations. This is a
  problem for, e.g., timing-sensitive use of an A/D converter.
- If a hardware resource supports reservation, you cannot express this
  via this software interface. For instance, I2C buses have a concept of
  "repeated start" when doing multiple bus transactions, but it was not
  clear how to use this in TinyOS 1.x's I2C abstraction.
- Most TinyOS 1.x services did not provide a very convenient way of 
  monitoring X's availability for the purpose of retries, nor very
  clear documentation of which requests could happen simultaneously.

In light of all these problems, TinyOS 2.x introduces standard resource
reservation mechanisms for use by components providing access to shared
resources.

2. Resource sharing in TinyOS 2.x
====================================================================

A single approach to resource sharing is not appropriate for all
circumstances. For instance, requiring resource reservation allows programs
to have better timing guarantees for access to an A/D converter. But if
a program does not need precise timing guarantees (e.g., when measuring
temperature in a biological monitoring application), this extra resource
reservation step complicates code. 

Thus, TinyOS services should offer resource sharing mechanisms appropriate
to their goals and level of abstraction. However, to preserve simplicity
and consistency there should only be a few different resource sharing
approaches, which we outline here.

- Resource reservation: the service must be reserved before use, via the
standard Resource interface. This approach is described in Section 3.
Because many services will have similar approaches to resource sharing
(e.g., round-robin, or priority-based), TinyOS includes standard arbiters
implementing various resource sharing policies. These arbiters are
described in Section 4.

- Request queuing: requests from different clients are queued and handled
in some (service-dependent) order. This approach is described in Section 5.

- Resource virtualisation: the service is virtualised so as to support an
arbitrary number of clients - a typical example is the Timer service. From
a programming perspective, this behaves similarly to resource queuing and
is therefore also described in Section 5.

Note that request queuing and resource virtualisation may need to store
significant amounts of per-client state. We expect that lower-level
services will use the resource reservation approach, while higher level
ones will prefer queuing or virtualisation. These higher-level services
will typically be built on top of the lower-level, resource-reservation
based services.

3. Resource Reservation Interface
====================================================================

interface Resource {
  /**
   * Request access to a shared resource. You must call release()
   * when you are done with it.
   * @return SUCCESS You have the resource.
   *         EBUSY The resource is busy. The granted() event will
   *               be signaled when you have the resource.
   */
  command error_t request();

  /**
   * You have received access to this resource.
   */
  event void granted();

  /**
   * Release a shared resource you previously acquired.
   */
  command void release();

  /**
   * Some other component has requested this resource. You might
   * want to consider releasing it.
   */
  event void requested();
}

The Resource interface is offered as a parameterised interface by
services which wish to provide access to a shared resource. The
interface's parameter represents client ids, which clients can obtain
via the special unique() function. For instance, the I2C service might
look like this:

#define I2C_RESOURCE "I2C.Resource"
configuration I2CPacketC {
  provides {
    /**
     * For reserving the I2C bus. 'id' is the client id, obtained
     * via unique(I2C_RESOURCE)
     */
    interface Resource[uint8_t id];

    /**
     * Actual I2C packet interface. 'busId' is the I2C
     * bus identifer of the device you wish to use.
     */
    interface I2CPacket[uint8_t busId];
  }
} ...

Clients of the I2C service would use it as follows:
module I2CUserM {
  uses interface Resource as I2CResource;
  uses interface I2CPacket;
} ...

configuration I2CUserC { }
implementation {
  components I2CUserM, I2CPacketC;

  I2CUserM.I2CResource -> I2CPacketC.Resource[unique(I2C_RESOURCE)];
  I2CUserM.I2CPacket -> I2CPacket.I2CPacket[0x73]; // using I2C device 0x73
}

4. Standard arbiters
====================================================================

Each service could provide its own implementation of the Resource
interface, but this would be a waste of programmer effort and would lead to
inconsistent resource sharing policies across services. Instead, TinyOS
includes a number of standard resource arbiters, in the form of generic
components, which implement the Resource interface. All of these arbiters
also provide a ResourceUser interface which can be interrogated to find the
current set of resource allocation:

interface ResourceUser {
  /**
   * Check whether resource is allocated.
   * @returns TRUE if the resource is currently allocated, FALSE otherwise.
   */
  command bool inUse();

  /**
   * Return id of client currently using the resource. Meaningless if
   * inUse() returns FALSE.
   */
  command uint8_t user();
}

ResourceUser can be used by the service implementation, e.g., to refuse
requests when it is not allocated. Or to allow implicit per-request
resource allocation in the style of TinyOS 1.x.

The StandardArbiter provides round-robin arbitration:
generic component StandardArbiter {
  provides interface Resource[uin8_t id];
  provides interface ResourceUser;
}

[[There will be other arbiters here, I presume. For instance, priority-based.
  Or for services which support >1 outstanding request.]]

5. Request queuing and resource virtualisation
====================================================================

A service which is queued or provides virtualisation is implemented by
parameterising the service interface (in contrast, the resource reservation
approach parameterises the Resource interface). As with Resource, each
client obtains an id via unique(). The service must support one outstanding
request for each unique id; a second request (before completion of the
first) on the same instance of a parameterised interface returns EBUSY.

As an example, the Timer services looks as follows:

#define TIMER_SERVICE "TimerC"
configuration TimerC {
  provides interface Timer<TMilli>[uint8_t id];
  provides interface Timer<TM32khz>[uint8_t id];
} ...

and clients use it as follows:
module TimerUserM {
  uses interface Timer<TMilli> as MyTimer;
} ...

configuration TimerUserC { }
implementation {
  components TimerUserM, TimerC;

  TimerUserM.MyTimer -> TimerC.Timer[unique(TIMER_SERVICE)];
}

The difference between queuing of requests and virtualisation is only
in the internal implementation of a service, and is thus beyond the
scope of this document.


6. Author's Address
====================================================================

| David Gay
| 2150 Shattuck Ave, Suite 1300
| Intel Research
| Berkeley, CA 94704
|
| phone - +1 510 495 3055
|
| email - david.e.gay at intel.com




More information about the Tinyos-beta-commits mailing list