[Tinyos-beta-commits]
CVS: tinyos-1.x/beta/SystemCore/MementoMori/old
DFDTypes.h, NONE, 1.1 FailureDetector.nc, NONE,
1.1 FailureDetectorM.nc, NONE, 1.1 MonitoringBalancer.nc, NONE,
1.1 MonitoringBalancerM.nc, NONE, 1.1 MonitoringState.nc, NONE,
1.1 MonitoringStateM.nc, NONE, 1.1 NodeTimeout.nc, NONE,
1.1 NodeTimeoutM.nc, NONE, 1.1
Stan Rost
stanrost at users.sourceforge.net
Tue Sep 28 15:37:55 PDT 2004
Update of /cvsroot/tinyos/tinyos-1.x/beta/SystemCore/MementoMori/old
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv877/old
Added Files:
DFDTypes.h FailureDetector.nc FailureDetectorM.nc
MonitoringBalancer.nc MonitoringBalancerM.nc
MonitoringState.nc MonitoringStateM.nc NodeTimeout.nc
NodeTimeoutM.nc
Log Message:
- Added old code
--- NEW FILE: DFDTypes.h ---
#ifndef _SR_DFDTYPES__
#define _SR_DFDTYPES__
#include <VitalStats.h>
#include <TimeStamp.h>
// Important constants
enum {
// Max number of neighbors that a node can watch
MAX_WATCHED = 5,
// .. of them, how many nodes are "under evaluation"
// and may possible replace one of the permanent slots
MAX_CANDIDATES = 1,
// .. maximum number of nodes we expect to cover any
// given node
MAX_COVERAGE = 5
};
// Failure opinions
enum {
FOP_UNCERTAIN = 0,
FOP_ALIVE = 1,
FOP_TENTATIVELY_FAILED = 2,
FOP_FAILED = 3
};
typedef uint8_t FOpinion;
typedef struct {
// Node that we're tracking
uint16_t srcAddr;
// Coverage of this node (i.e. the number of
// monitors it thinks it has)
uint8_t coverage;
// Has this slot not been occupied
uint8_t free:1;
// Is this slot is used to evaluate
// the fitness of the node for being a monitoring target
uint8_t candidate:1;
// Failure status of the node
uint8_t status:2;
// The core state that this node shared
// with the previous heartbeat
VitalStats stats;
} MonitorRec;
typedef struct {
uint8_t len;
uint8_t addrHash[0];
} NodeList;
uint8_t addrHash(uint16_t addr) {
return (addr >> 8) ^ (addr & 0xFF);
}
void clearNList(NodeList *nl) {
nl->len = 0;
}
// Unique
void addNList(NodeList *nl, uint16_t addr, uint8_t maxLen) {
uint8_t i, myHash = addrHash(addr);
for (i = 0; i < nl->len; i++) {
if (nl->addrHash[i] == myHash)
return;
}
if (nl->len < maxLen) {
nl->addrHash[nl->len++] = myHash;
}
}
void delNList(NodeList *nl, uint16_t addr) {
uint8_t i, myHash = addrHash(addr);
for (i = 0; i < nl->len; i++) {
if (nl->addrHash[i] == myHash) {
memmove(&nl->addrHash[i],
&nl->addrHash[i+1],
(nl->len - 1) * sizeof(nl->addrHash[0]));
nl->len--;
break;
}
}
}
void copyNList(NodeList *tgt, NodeList *src, uint8_t maxLen) {
tgt->len = src->len;
memcpy(&tgt->addrHash[0],
&src->addrHash[0],
(src->len > maxLen ? maxLen : src->len) * sizeof(src->addrHash[0]));
}
typedef struct {
uint8_t idx;
} MonitorIterator;
// Node timeout types
enum {
NT_FAIL_DETECTOR = 0,
NT_MONITORED,
// Timeout for the nodes I monitor
// I stop monitoring these nodes when the node repeatedly
// excludes me from the list of its monitors
NT_MONITORING
// Timeout for the nodes monitoring me
// I stop counting the node as my monitor
// when the node monitoring me stops monitoring me for that long
};
#endif
--- NEW FILE: FailureDetector.nc ---
/**
*
* This interface exposes the capability
* to detect failures and test for local
* belief as to node liveness.
*
* @author Stan Rost
*
**/
includes DFDTypes;
interface FailureDetector {
/**
* Queries the status of a node
*
* @param addr Address of the node in question
*
* @result Returns one of
* {FOP_ALIVE, FOP_FAILED, FOP_UNCERTAIN}
**/
command FOpinion getOpinion(uint16_t addr);
/**
* ShareImpose the opinion of an external node
* regarding the status of this node.
*
* @param addr Monitoring target whose status is being claimed
* @param op The failure status opinion
*
* @returns FAIL if we are not responsible for monitoring addr
**/
command result_t imposeOpinion(uint16_t addr, FOpinion op);
/**
* Notifies a component that locally,
* our belief about a given node has changed
*
* @param addr The address of the node
* @param op The new opinion
*
**/
event void opinionChanged(uint16_t addr,
FOpinion oldOp,
FOpinion newOp);
/**
* Queries the preiod of failure detection
* for this node (in 1/1024th of a second).
*
* @param addr Address of the node
*
* @returns 0xFFFFFFFF if we do not watch over this node,
* the timeout period otherwise
**/
command uint32_t getTimeout(uint16_t addr);
/**
* Postpone the timeout of a given node
* by a given delay
*
* @param addr Address of the node
* @param delay Postpone by this much 1/1024th of a second
*
* @return Returns SUCCESS if such node was found, and its
* timer postponed
**/
command result_t postpone(uint16_t addr, uint32_t delay);
}
--- NEW FILE: FailureDetectorM.nc ---
includes DFDTypes;
module FailureDetectorM {
provides {
interface StdControl;
interface FailureDetector;
}
uses {
interface HeartBeatHandler;
interface MonitoringState;
interface NodeTimeout;
}
}
implementation {
MonitorRec *earliest = NULL;
//------------ StdControl -----------------
command result_t StdControl.init() {
return SUCCESS;
}
command result_t StdControl.start() {
return SUCCESS;
}
command result_t StdControl.stop() {
return SUCCESS;
}
//------------ MonitoringState ------------
event void MonitoringState.added(uint16_t addr) {
MonitorRec *mr = call MonitoringState.lookup(addr);
if (mr == NULL)
return;
mr->status = FOP_ALIVE;
call NodeTimeout.add(addr, NT_FAIL_DETECTOR,
call HeartBeatHandler.getPeriod());
}
event void MonitoringState.deleted(uint16_t addr) {
call NodeTimeout.remove(addr, NT_FAIL_DETECTOR);
}
//------------ FailureDetector ------------
/**
* Queries the status of a node
*
* @param addr Address of the node in question
*
* @result Returns one of
* {FOP_ALIVE, FOP_FAILED, FOP_UNCERTAIN}
**/
command FOpinion FailureDetector.getOpinion(uint16_t addr) {
MonitorRec *mr = call MonitoringState.lookup(addr);
if (mr == NULL)
return FOP_UNCERTAIN;
else
return (mr->status);
}
/**
* Share the opinion of an external node
* regarding the status of this node.
*
* @param src Source of the opinion
* @param addr Monitoring target whose status is being claimed
* @param op The failure status opinion
*
* @returns FAIL if we are not responsible for monitoring addr
**/
command result_t FailureDetector.imposeOpinion(uint16_t addr,
FOpinion op) {
MonitorRec *mr = call MonitoringState.lookup(addr);
if (mr == NULL)
return FAIL;
if (mr->status != op) {
signal FailureDetector.opinionChanged(addr,
mr->status,
op);
}
mr->status = op;
return SUCCESS;
}
/**
* Queries the preiod of failure detection
* for this node (in 1/1024th of a second).
*
* @param addr Address of the node
*
* @returns 0xFFFFFFFF if we do not watch over this node,
* the timeout period otherwise
**/
command uint32_t FailureDetector.getTimeout(uint16_t addr) {
MonitorRec *mr = call MonitoringState.lookup(addr);
if (mr == NULL)
return 0xFFFFFFFF;
else
return call NodeTimeout.getTimeout(addr, NT_FAIL_DETECTOR);
}
/**
* Postpone the timeout of a given node
* by a given delay
*
* @param addr Address of the node
* @param delay Postpone by this much 1/1024th of a second
**/
command result_t FailureDetector.postpone(uint16_t addr, uint32_t delay) {
MonitorRec *mr = call MonitoringState.lookup(addr);
if (mr == NULL)
return FAIL;
call NodeTimeout.postpone(addr, NT_FAIL_DETECTOR, delay);
}
//----------------- HeartBeatHandler --------------------------
event void HeartBeatHandler.receiveHeartBeat(uint16_t srcAddr,
VitalStats *vStats) {
MonitorRec *mr = call MonitoringState.lookup(srcAddr);
dbg(DBG_USR1, "GOT HEARTBEAT FROM %u\n", srcAddr);
if (mr == NULL) {
dbg(DBG_USR1, "Not my node: %u\n", srcAddr);
return;
}
// Copy the core state
// call VitalStats.copy(&wSlot[wIndex].stats, vStats);
call NodeTimeout.update(srcAddr, NT_FAIL_DETECTOR);
call HeartBeatHandler.getPeriod();
call FailureDetector.imposeOpinion(srcAddr,
FOP_ALIVE);
return;
}
/*
event void HeartBeatHandler.receivePacket(uint16_t srcAddr) {
MonitorRec *mr = call MonitoringState.lookup(addr);
if (mr == NULL) {
return;
}
call FailureDetector.postpone(srcAddr,
call FailureDetector.getTimeout(srcAddr));
call FailureDetector.imposeOpinion(srcAddr, FOP_ALIVE);
return;
}
*/
// ------- NodeTimeout ------------------------------------
event void NodeTimeout.timedOut(uint16_t addr, uint8_t type) {
if (type == NT_FAIL_DETECTOR) {
MonitorRec *mr = call MonitoringState.lookup(addr);
uint8_t oldStatus;
if (mr == NULL) {
dbg(DBG_USR1, "*** ERROR: NodeTimeout.timedOut could not find %u\n", addr);
return;
}
oldStatus = mr->status;
mr->status = FOP_TENTATIVELY_FAILED;
signal FailureDetector.opinionChanged(addr, oldStatus,
FOP_TENTATIVELY_FAILED);
}
}
event void NodeTimeout.timeoutReset(uint16_t addr, uint8_t type) {
if (type == NT_FAIL_DETECTOR) {
MonitorRec *mr = call MonitoringState.lookup(addr);
uint8_t oldStatus;
if (mr == NULL) {
dbg(DBG_USR1, "*** ERROR: NodeTimeout.timedOut could not find %u\n", addr);
return;
}
oldStatus = mr->status;
mr->status = FOP_ALIVE;
signal FailureDetector.opinionChanged(addr, oldStatus,
FOP_ALIVE);
}
}
}
--- NEW FILE: MonitoringBalancer.nc ---
/**
* This interface defines the interface
* of the monitoring balancer component, responsible
* for load-balancing coverage throughout the network.
*
* The responsibilities of a monitoring balancer
* include estimating the number of monitors,
* exposing the list of this node's monitors, etc
*
* @author Stan Rost
**/
interface MonitoringBalancer {
/**
* Prepares the estimation of monitors for the next round.
*
**/
command void resetMonitors();
/**
* Add a node to the roster of my monitors
**/
command void monitoredBy(uint16_t addr);
/**
* Export the list of monitors
**/
command void exportMonitorList(uint8_t *numMonEstimate,
NodeList *ml,
uint8_t maxLen);
/**
* Process incoming monitor list. Potentially stop
* covering this node if it does not include us
* in its list. Estimate the size of its cover set
*
**/
event void processMonitorList(uint16_t srcAddr,
uint8_t numMonEstimate,
NodeList *ml);
}
--- NEW FILE: MonitoringBalancerM.nc ---
component MonitoringBalancerM {
provides {
interface StdControl;
interface MonitoringBalancer;
interface HeartBeatHandler as HeartBeatHandlerExt;
}
uses {
interface HeartBeatHandler;
interface FailureDetector;
interface MonitoringState;
interface Time;
}
}
implementation {
// We are monitoring this many nodes
uint8_t numMonitored = 0;
// ...of them, this many are under evaluation
// to replace our monitoring targets
uint8_t numCandidates = 0;
uint16_t monitorsBuf[MAX_MONITOR_BUF];
uint8_t numMonEst = 0;
//------------ StdControl -----------------
command result_t StdControl.init() {
NodeList *ml = (NodeList *)monitorsBuf;
clearNList(ml);
return SUCCESS;
}
command result_t StdControl.start() {
return SUCCESS;
}
command result_t StdControl.stop() {
return SUCCESS;
}
//------------ MonitoringBalancer ---------
command void MonitoringBalancer.resetMonitors() {
}
command void MonitoringBalancer.monitoredBy(uint16_t addr) {
NodeList *ml = (NodeList *)monitorsBuf;
addNList(ml, addr, MAX_MONITOR_BUF - 1);
call NodeTimeout.add(addr, NT_MONITORED, 5 * ROLLCALL_PERIOD);
call NodeTimeout.update(addr, NT_MONITORED);
}
event void NodeTimout.timedOut(uint16_t addr, uint8_t type) {
if (type == NT_MONITORED) {
// The node that we think monitors
// us has excluded us from the list of nodes
// it monitors for a very long time
// Remove it from the list of our monitors
call NodeTimeout.remove(addr, NT_MONITORED);
delNList(ml, addr);
} else if (type == NT_MONITORING) {
// The node that we are monitoring
// cannot hear from us and thus overestimates
// Remove it from our list of nodes that
// we monitor
call NodeTimeout.remove(addr, NT_MONITORING);
call MonitoringState.del(addr);
}
}
event void NodeTimeout.timeoutReset(uint16_t addr, uint8_t type) {
}
command void MonitoringBalancer.exportMonitorList(uint8_t *numMonEstimate,
NodeList *ml,
uint8_t maxLen) {
NodeList *_ml = (NodeList *)monitorsBuf;
*numMonEstimate = ml->len;
copyNList(ml, _ml, maxLen);
}
command void MonitoringBalancer.processMonitorList(uint16_t srcAddr,
uint8_t numMonEstimate,
NodeList *nl) {
MonitorRec *mr = call MonitoringState.lookup(srcAddr);
if (mr != NULL && !mr->candidate) {
call NodeTimeout.add(srcAddr, NT_MONITORING, 5 * ROLLCALL_PERIOD);
{
// We are watching this node, but does it know
// that?
uint8_t i, myHash = addrHash(TOS_LOCAL_ADDRESS);
for (i = 0; i < nl->len; i++) {
if (nl->addrHash[i] == myHash) {
break;
}
}
if (i != nl->len) {
// This node knows we are monitoring it!
call NodeTimeout.update(srcAddr, NT_MONITORING);
}
}
mr->coverage = numMonEstimate;
}
}
//------------ MonitoringState ------------
event void MonitoringState.added(uint16_t addr) {
MonitoringRec *mr;
if ((mr = call MonitoringState.lookup(addr)) == NULL)
return;
// XXX: Should it be this?
mr->coverage = 0xFF;
}
event void MonitoringState.deleted(uint16_t addr) {
}
//----------------- HeartBeatHandler --------------------------
bool ripe(uint8_t i) {
return timeStampDiff(now, candiCache[i].startTime) >
CANDIDATE_PROBATION;
}
bool qualifies(uint8_t i) {
return candiCache[i].numHeartBeats > CANDIDATE_QUALIFY;
}
bool better(MonitorRec *mr1,
MonitorRec *mr2) {
return (call FailureDetector.getTimeout(mr1->srcAddr) <
call FailureDetector.getTimeout(mr2->srcAddr) &&
mr2->coverage != 0xFF && // Uninitialized
mr1->coverage <= m2->coverage);
}
// This part determines whether a new node should replace
// an old node in the watcher cache
event void HeartBeatHandler.receiveHeartBeat(uint16_t srcAddr,
VitalStats *vStats) {
MonitorRec *mr = call MonitoringState.lookup(srcAddr);
if (mr == NULL) {
// We are not currently tracking this node
// Should we add it to the cache of candidates?
if (numCandidates < MAX_CANDIDATES) {
// Add to the candidate cache
uint8_t i;
for (i = 0; i < MAX_CANDIDATES; i++) {
if (candiCache[i].mr == NULL &&
((candiCache[i].mr = mr =
call MonitoringState.add(srcAddr)) != NULL)) {
candiCache[i].numHeartBeats = 1;
curTimeStamp(candiCache[i].startTime);
mr->candidate = TRUE;
numCandidates++;
break;
}
}
}
} else if (mr->candidate) {
// We are tracking this node but it's a candidate
uint8_t i;
TimeStamp now;
for (i = 0; i < MAX_CANDIDATES; i++) {
if (candiCache[i].mr == mr) {
break;
}
}
if (i == MAX_CANDIDATES) {
dbg(DBG_USR1, "*** ERROR: Candidate not found in cache!!!\n");
return;
}
curTimeStamp(now);
// See if the candidate has graduated
if (ripe(i)) {
// Timed out, time to evaluate
if (qualifies(i)) {
// This candidate has qualified, add it to the
// system
if (numMonitored + numCandidates < MAX_WATCHED) {
// Just add, we have space
mr->candidate = FALSE;
numMonitored++;
candiCache[i].mr = NULL;
numCandidates--;
} else {
// Need to replace another in the cache
MonitorIterator mi;
MonitorRec *cur = NULL, *worst = NULL;
call MonitoringState.iterate(&mi);
while ((cur = call MonitoringState.next(&mi)) != NULL) {
if (!cur->candidate &&
(worst == NULL ||
better(worst, cur)))
worst = cur;
}
if (worst == NULL) {
dbg(DBG_USR1, "*** ERROR: Worst is NULL\n");
return;
}
if (better(mr, worst)) {
call MonitoringState.del(worst->srcAddr);
// numMonitored stays the same
candiCache[i].mr = NULL;
mr->candidate = FALSE;
numCandidates--;
}
}
} else {
// This candidate does not pass muster
call MonitoringState.del(candiCache[i].mr->srcAddr);
candiCache[i].mr = NULL;
numCandidates--;
}
}
}
// Pass-through to the failure detector
call HeartBeatHandlerExt.receiveHeartBeat(srcAddr,
vStats);
}
event void HeartBeatHandler.receivePacket(uint16_t srcAddr) {
call HeartBeatHandlerExt.receivePacket(srcAddr);
}
//----------------- FailureDetector ---------------------------
event void FailureDetector.opinionChanged(uint16_t addr,
FOpinion oldOp,
FOpionion newOp) {
}
}
--- NEW FILE: MonitoringState.nc ---
/**
* This interface exposes the shared monitoring state
*
* Synchronization is provided by the shared structure
* being accessed from task contexts.
**/
includes DFDTypes;
interface MonitoringState {
/**
* Looks up a monitoring record for the node
* addr.
*
* @param addr The address of the node
*
* @return NULL if we are not monitoring this node,
* pointer to the record if we are.
**/
command MonitorRec *lookup(uint16_t addr);
/**
*
* Adds a monitoring record for this node,
* sets up the data structures properly
*
* @param addr Address of the node to add
*
* @return NULL if there is no more space,
* pointer to the record if we added successfully
*
**/
command MonitorRec *add(uint16_t addr);
event void added(uint16_t addr);
/**
* Delete a given node from list of monitored
*
* @param addr Address of the node
*
* @return SUCCESS if the node was located and deleted.
**/
command result_t del(uint16_t addr);
event void deleted(uint16_t addr);
/**
* Check if I am monitoring a certain node
* at this time
*
* @param addr Node address
*
* @return TRUE if so.
**/
command bool amMonitoring(uint16_t addr);
/**
* Export the records and liveness opinions
* about the nodes which we monitor.
*
* @param wl Pointer to the list of watched nodes
* @param mask A bitmap where (bit at i == 1) => (node wl[i] is alive)
**/
command void exportWatched(NodeList *wl, uint32_t *mask);
/**
* Begins the iteration over the list of actively monitored
* nodes
*
* @param mi Pointer to the iterator
**/
command void iterate(MonitorIterator *mi);
/**
* Iterates to the next actively monitored
* node. All iteration must happen within
* the context of a single task to ensure
* correctness of the semantics of this call.
*
* @param mi Pointer to the iterator
*
* @return Returns NULL when no more records
* are available, or pointer to the next
* monitoring record
**/
command MonitorRec *next(MonitorIterator *mi);
}
--- NEW FILE: MonitoringStateM.nc ---
includes DFDTypes;
module MonitoringStateM {
provides {
interface StdControl;
interface MonitoringState;
}
/*
uses {
interface VitalStats;
}
*/
}
implementation {
// Watcher slots
// Total #=MAX_WATCHED slots
MonitorRec wSlot[MAX_WATCHED];
void printTable() {
uint8_t i;
dbg(DBG_USR1, "MonitoringState ------------------\n");
dbg(DBG_USR1, "==================================\n");
for (i = 0; i < MAX_WATCHED; i++) {
if (!wSlot[i].free) {
dbg(DBG_USR1,
"%u\tCov: %u\t%s\t%s\n",
wSlot[i].srcAddr,
wSlot[i].coverage,
(wSlot[i].free == TRUE ? "FREE" : "OCCD"),
(wSlot[i].candidate ? "CAND" : "FULL"),
(wSlot[i].status == FOP_UNCERTAIN ? "UNCR" :
(wSlot[i].status == FOP_ALIVE ? "ALIV" :
(wSlot[i].status == FOP_TENTATIVELY_FAILED ? "TFAIL" :
(wSlot[i].status == FOP_FAILED ? "FAIL" : "UNKN"))))
);
}
}
dbg(DBG_USR1, "\n");
}
//------------- StdControl ------------------------
command result_t StdControl.init() {
uint8_t i;
for (i = 0; i < MAX_WATCHED; i++) {
wSlot[i].free = TRUE;
}
return SUCCESS;
}
command result_t StdControl.start() {
return SUCCESS;
}
command result_t StdControl.stop() {
return SUCCESS;
}
//------------- MonitoringState -------------------
/**
* Looks up a monitoring record for the node
* addr.
*
* @param addr The address of the node
*
* @return NULL if we are not monitoring this node,
* pointer to the record if we are.
**/
command MonitorRec *MonitoringState.lookup(uint16_t addr) {
uint8_t i;
for (i = 0; i < MAX_WATCHED; i++) {
if (wSlot[i].srcAddr == addr &&
!wSlot[i].free) {
return &wSlot[i];
}
}
return NULL;
}
// Initialize a free, new spot
void fillMonitorSlot(uint8_t idx, uint16_t addr) {
wSlot[idx].srcAddr = addr;
// call VitalStats.init(&wSlot[idx].stats);
wSlot[idx].free = FALSE;
wSlot[idx].status = FOP_ALIVE;
wSlot[idx].candidate = FALSE;
wSlot[idx].coverage = 0xFF;
dbg(DBG_USR2, "Initialized %d\n");
}
/**
*
* Adds a monitoring record for this node,
* sets up the data structures properly
*
* @param addr Address of the node to add
*
* @return NULL if there is no more space,
* pointer to the record if we added successfully
*
**/
command MonitorRec *MonitoringState.add(uint16_t addr) {
uint8_t i,
firstFree = MAX_WATCHED;
dbg(DBG_USR2, "*** ADDTOWATCH\n");
// Find a free slot, ideally one whose hash matches src
for (i = 0; i < MAX_WATCHED; i++) {
if (firstFree == MAX_WATCHED &&
wSlot[i].free) {
firstFree = i;
}
}
if (firstFree == MAX_WATCHED)
return NULL;
else {
fillMonitorSlot(firstFree, addr);
printTable();
signal MonitoringState.added(addr);
return &wSlot[firstFree];
}
}
/**
* Delete a given node from list of monitored
*
* @param addr Address of the node
*
* @return SUCCESS if the node was located and deleted.
**/
command result_t MonitoringState.del(uint16_t addr) {
MonitorRec *result = call MonitoringState.lookup(addr);
if (result == NULL)
return FAIL;
result->free = TRUE;
signal MonitoringState.deleted(addr);
printTable();
return SUCCESS;
}
command bool MonitoringState.amMonitoring(uint16_t addr) {
return !(call MonitoringState.lookup(addr) == NULL);
}
/**
* Export the records and liveness opinions
* about the nodes which we monitor.
*
* @param wl Pointer to the list of watched nodes
* @param mask A bitmap where (bit at i == 1) => (node wl[i] is alive)
**/
command void MonitoringState.exportWatched(NodeList *wl,
uint32_t *mask) {
uint8_t i, _numWatched = 0;
for (i = 0; i < MAX_WATCHED; i++) {
if (!wSlot[i].free &&
!wSlot[i].candidate) {
wl->addrHash[_numWatched] = addrHash(wSlot[i].srcAddr);
if (wSlot[i].status == FOP_ALIVE)
(*mask) |= (1 << (_numWatched));
_numWatched++;
}
}
wl->len = _numWatched;
}
/**
* Begins the iteration over the list of actively monitored
* nodes
*
* @param mi Pointer to the iterator
**/
command void MonitoringState.iterate(MonitorIterator *mi) {
mi->idx = 0;
}
/**
* Iterates to the next actively monitored
* node. All iteration must happen within
* the context of a single task to ensure
* correctness of the semantics of this call.
*
* @param mi Pointer to the iterator
*
* @return Returns NULL when no more records
* are available, or pointer to the next
* monitoring record
**/
command MonitorRec *MonitoringState.next(MonitorIterator *mi) {
uint8_t i;
for (i = mi->idx; i < MAX_WATCHED; i++) {
if (!wSlot[i].free) {
mi->idx = i + 1;
return &wSlot[i];
}
}
return NULL;
}
//--------------- Helper funcs ------------------------
}
--- NEW FILE: NodeTimeout.nc ---
/**
* This interface allows to estimate the timeouts
* on various periodically recurring events signalled
* from packets from nearby nodes.
*
* @author Stan Rost
*
**/
interface NodeTimeout {
/**
* Add a new timeout estimator
*
* @param addr Address of the node
* @param type Type of the estimator
* @param initialTO The magnitude of the initial timeout
*
* @return Returns <code>FAIL</code> if out of space.
**/
command result_t add(uint16_t addr, uint8_t type, uint32_t initialTO);
/**
* Update the timeout estimator
* (driven by the node's event)
*
* @param addr Address of the node
* @param type Type of the estimator
*
* @return Returns <code>FAIL</code> if no estimator for this node.
**/
command result_t update(uint16_t addr, uint8_t type);
/**
* Postpone timeout by a time interval
*
* @param addr Address of the node
* @param type Type of the estimator
* @param delay Delay of postponement
**/
command result_t postpone(uint16_t addr, uint8_t type, uint32_t delay);
/**
* Remove the estimator
*
* @param addr Address of the node
* @param type Type of the estimator
**/
command result_t remove(uint16_t addr, uint8_t type);
/**
* Has this timeout estimator timed out?
*
* @param addr Address of the node
* @param type Type of the estimator
*
* @return Returns <code>FAIL</code> if no estimator for this node.
**/
command bool hasTimedOut(uint16_t addr, uint8_t type);
/**
* What is the timeout period for this estimator?
*
* @param addr Address of the node
* @param type Type of the estimator
*
* @return Returns <code>FAIL</code> if no estimator for this node.
**/
command uint32_t getTimeout(uint16_t addr, uint8_t type);
/**
* The estimator has timed out
*
* @param addr Address of the node
* @param type Type of the estimator
*
**/
event void timedOut(uint16_t addr, uint8_t type);
/**
* The estimator has been updated, and reinstated
*
* @param addr Address of the node
* @param type Type of the estimator
*
**/
event void timeoutReset(uint16_t addr, uint8_t type);
}
--- NEW FILE: NodeTimeoutM.nc ---
includes DFDTypes;
includes AM;
module NodeTimeoutM {
provides {
interface StdControl;
interface NodeTimeout;
}
uses {
interface Time;
interface TinyTimeInterval;
interface AbsoluteTimer;
interface TimeSetListener;
}
}
implementation {
// ------------- Local data ---------------------
typedef struct {
uint16_t addr;
uint8_t timedOut:1;
uint8_t type:7;
TimeStamp lastUpdate;
TimeStamp timeOut;
uint32_t avgInterval;
uint32_t varInterval;
} TimeoutStruct;
enum {
MAX_TIMEOUTS = MAX_WATCHED * 2 + MAX_COVERAGE
};
// There should be 2 timeout structs / monitoring target
// 1 timeout struct / my monitor
TimeoutStruct tOuts[MAX_TIMEOUTS];
TimeoutStruct *earliest = NULL;
void printTable() {
uint8_t i;
dbg(DBG_USR1, "Node timeout ---------------------\n");
dbg(DBG_USR1, "==================================\n");
for (i = 0; i < MAX_TIMEOUTS; i++) {
if (tOuts[i].addr != TOS_BCAST_ADDR) {
dbg(DBG_USR1, "%u\t%u\t%s\t%u\t%u\t%u\n",
tOuts[i].addr,
tOuts[i].type,
(tOuts[i].timedOut ? "TOUT" : "LIVE"),
tOuts[i].avgInterval,
tOuts[i].varInterval,
call NodeTimeout.getTimeout(tOuts[i].addr, tOuts[i].type));
}
}
dbg(DBG_USR1, "\n");
}
// ------------- StdControl ---------------------
command result_t StdControl.init() {
uint8_t i;
for (i = 0; i < MAX_TIMEOUTS; i++) {
tOuts[i].addr = TOS_BCAST_ADDR;
tOuts[i].type = 0x7F;
}
return SUCCESS;
}
command result_t StdControl.start() {
return SUCCESS;
}
command result_t StdControl.stop() {
return SUCCESS;
}
// ------------- NodeTimeout --------------------
TimeoutStruct *findTO(uint16_t addr, uint8_t type) {
uint8_t i;
for (i = 0; i < MAX_TIMEOUTS; i++) {
if (tOuts[i].type == type &&
tOuts[i].addr == addr)
return &tOuts[i];
}
return NULL;
}
void curTimeStamp(TimeStamp t) {
// Timestamp the message
tos_time_t now = call Time.get();
tos2timeStamp(now, t);
}
inline uint32_t timeoutEstimate(TimeoutStruct *tos) {
return tos->avgInterval +
(tos->varInterval << 2);
}
void calcTimeout(TimeoutStruct *tos) {
#define TIMER_INFLATE 10
timeStampCopy(tos->timeOut,
tos->lastUpdate);
timeStampAdd32(tos->timeOut,
2 * timeoutEstimate(tos));
timeStampAdd16(tos->timeOut,
TIMER_INFLATE);
}
// Is lastHeard(idx1) earlier than leastHeard(idx2)?
bool earlierThan(TimeoutStruct *r1,
TimeoutStruct *r2) {
return (timeStampCompare(r1->timeOut,
r2->timeOut) < 0);
}
void resetTimer() {
uint8_t i;
TimeoutStruct *cur, *winner = NULL;
for (i = 0; i < MAX_TIMEOUTS; i++) {
cur = &tOuts[i];
if (cur->addr != TOS_BCAST_ADDR &&
!cur->timedOut &&
(winner == NULL ||
earlierThan(cur, winner)))
winner = cur;
}
if (winner != NULL) {
call AbsoluteTimer.set(timeStamp2tos(winner->timeOut));
earliest = winner;
} else {
call AbsoluteTimer.cancel();
earliest = NULL;
}
}
void correctTimer(TimeoutStruct *tos) {
if (tos == earliest)
resetTimer();
else if ((earliest == NULL ||
earlierThan(tos, earliest))) {
call AbsoluteTimer.cancel();
call AbsoluteTimer.set(timeStamp2tos(tos->timeOut));
earliest = tos;
}
// Otherwise, no need to do anything
}
command result_t NodeTimeout.add(uint16_t addr, uint8_t type,
uint32_t initialTO) {
TimeoutStruct *res;
if (findTO(addr, type) != NULL)
return SUCCESS;
if ((res = findTO(TOS_BCAST_ADDR, 0x7F)) == NULL)
return FAIL;
res->addr = addr;
res->type = type;
res->timedOut = FALSE;
res->avgInterval = initialTO;
res->varInterval = 0;
curTimeStamp(res->lastUpdate);
calcTimeout(res);
correctTimer(res);
dbg(DBG_USR1, "NodeTimeout: ADD\n");
printTable();
return SUCCESS;
}
command result_t NodeTimeout.remove(uint16_t addr, uint8_t type) {
TimeoutStruct *res;
if ((res = findTO(addr, type)) == NULL)
return FAIL;
res->addr = TOS_BCAST_ADDR;
res->type = 0x7F;
if (res == earliest)
resetTimer();
dbg(DBG_USR1, "NodeTimeout: REMOVE\n");
printTable();
return SUCCESS;
}
command result_t NodeTimeout.update(uint16_t addr, uint8_t type) {
TimeoutStruct *res;
uint32_t diff, *a, *v;
TimeStamp ts;
dbg(DBG_USR1, "UPDATE CALLED\n");
if ((res = findTO(addr, type)) == NULL) {
dbg(DBG_USR1, "UPDATE: %u, %u not found\n", addr, type);
return FAIL;
}
curTimeStamp(ts);
diff = (uint32_t)timeStampDiff(ts,
res->lastUpdate);
a = &res->avgInterval;
v = &res->varInterval;
// The TCP-like timeout estimator
if (diff < *a &&
(*a - diff) > *v) {
// This is to negate the effects
// of an unexpectedly small diff
// due to, for example, time synchronization
*v = (31 * (*v) + (*a > diff ?
*a - diff :
diff - *a)) / 32;
} else {
*v = (3 * (*v) + (*a > diff ?
*a - diff :
diff - *a)) / 4;
}
*a = (7 * (*a) + diff) / 8;
if (res->timedOut) {
signal NodeTimeout.timeoutReset(res->addr, res->type);
res->timedOut = FALSE;
}
timeStampCopy(res->lastUpdate, ts);
calcTimeout(res);
correctTimer(res);
dbg(DBG_USR1, "NodeTimeout: UPDATE\n");
printTable();
return SUCCESS;
}
command result_t NodeTimeout.postpone(uint16_t addr, uint8_t type,
uint32_t delay) {
TimeoutStruct *res;
if ((res = findTO(addr, type)) == NULL)
return FALSE;
timeStampAdd32(res->timeOut, delay);
correctTimer(res);
}
command bool NodeTimeout.hasTimedOut(uint16_t addr, uint8_t type) {
TimeoutStruct *res;
if ((res = findTO(addr, type)) == NULL)
return FALSE;
return (res->timedOut != 0);
}
command uint32_t NodeTimeout.getTimeout(uint16_t addr, uint8_t type) {
TimeoutStruct *res;
if ((res = findTO(addr, type)) == NULL)
return 0xFFFFFFFF;
else
return timeoutEstimate(res);
}
// ----------- AbsoluteTimer -----------------------
event result_t AbsoluteTimer.fired() {
uint8_t i;
TimeStamp now, nowUpdated;
uint16_t tinyIntStart;
curTimeStamp(now);
call TinyTimeInterval.startNow(&tinyIntStart);
dbg(DBG_USR1, "AbsoluteTimer fired at\n");
timeStampPrint(now);
for (i = 0; i < MAX_TIMEOUTS; i++) {
if (tOuts[i].addr != TOS_BCAST_ADDR &&
!tOuts[i].timedOut) {
timeStampCopy(nowUpdated, now);
timeStampAdd16(nowUpdated,
call TinyTimeInterval.passedSince(&tinyIntStart));
if (timeStampCompare(now, tOuts[i].timeOut) >= 0) {
tOuts[i].timedOut = TRUE;
signal NodeTimeout.timedOut(tOuts[i].addr,
tOuts[i].type);
}
}
}
printTable();
resetTimer();
return SUCCESS;
}
// ------- TimeSetListener --------------------------
event void TimeSetListener.timeAdjusted(int64_t msTicks) {
if (earliest != NULL) {
uint8_t i;
for (i = 0; i < MAX_TIMEOUTS; i++) {
if (tOuts[i].addr != TOS_BCAST_ADDR) {
int64_t t;
t = timeStamp2ulint(tOuts[i].lastUpdate);
t += msTicks;
ulint2timeStamp((uint64_t)t, tOuts[i].lastUpdate);
}
}
// Only one node's timer needs to be corrected, really
correctTimer(earliest);
}
}
}
More information about the Tinyos-beta-commits
mailing list