rvtimermgr.c

来自「h.248协议源码」· C语言 代码 · 共 425 行

C
425
字号
#if (0)
******************************************************************************
Filename    :
Description :
******************************************************************************
                Copyright (c) 2001 RADVision Inc.
************************************************************************
NOTICE:
This document contains information that is proprietary to RADVision LTD.
No part of this publication may be reproduced in any form whatsoever 
without written prior approval by RADVision LTD..

RADVision LTD. reserves the right to revise this publication and make 
changes without obligation to notify any person of such revisions or 
changes.
******************************************************************************
$Revision:$
$Date:$
$Author: S. Cipolli$
******************************************************************************
#endif

#include <assert.h>
#include <limits.h>
#include "rvplatform.h"
#include "rvtypes.h"
#include "rvlog.h"
#include "rvtime.h"
#include "rvtimermgr.h"

#if defined(RV_IO_ANSI) && defined(RV_TIMERSTATS_ON)
#include <stdio.h>
#endif

void rvTimerPtrSwap(RvTimer** a, RvTimer** b) {
	size_t pos;
	RvTimer* t = *a;
	*a = *b;
	*b = t;
	pos = (*a)->pos;
	(*a)->pos = (*b)->pos;
	(*b)->pos = pos;
}

#define rvTimerMgrHeapDestruct(_h)			(rvPtrVectorDestruct(_h))
#define rvTimerMgrHeapAt(_h, _pos)			(*(RvTimer**)rvPtrVectorAt((_h), (_pos)))
#define rvTimerMgrHeapTop(_h)				(rvTimerMgrHeapAt((_h), 0))
#define rvTimerMgrHeapSize(_h)				(rvPtrVectorSize(_h))
#define rvTimerMgrHeapParent(_h, _pos)		(((_pos) - 1) / 2)
#define rvTimerMgrHeapLeftChild(_h, _pos)	(((_pos) * 2) + 1)
#define rvTimerMgrHeapRightChild(_h, _pos)	(((_pos) * 2) + 2)
#define rvTimerMgrHeapHasLeftChild(_h, _pos)\
  (rvTimerMgrHeapLeftChild((_h), (_pos)) < rvTimerMgrHeapSize(_h))
#define rvTimerMgrHeapHasRightChild(_h, _pos)\
  (rvTimerMgrHeapRightChild((_h), (_pos)) < rvTimerMgrHeapSize(_h))
#define rvTimerMgrHeapFirstLeaf(_h)			(rvTimerMgrHeapSize(_h) / 2)
#define rvTimerMgrHeapGetKey(_h, _pos)		(rvTimerMgrHeapAt((_h), (_pos))->absolute)
#define rvTimerMgrHeapSwap(_h, _a, _b)		\
  rvTimerPtrSwap((RvTimer**)rvPtrVectorAt((_h), (_a)), \
  (RvTimer**)rvPtrVectorAt((_h), (_b)))

static void rvTimerMgrHeapSift(RvTimerMgrHeap *h, size_t pos) {
	size_t firstLeaf;

	if (pos >= rvTimerMgrHeapSize(h))
		return;

	firstLeaf = rvTimerMgrHeapFirstLeaf(h);

	while (pos < firstLeaf)
	{
		size_t j = rvTimerMgrHeapLeftChild(h, pos);
		if ((j + 1) < rvTimerMgrHeapSize(h) &&	rvTimerMgrHeapGetKey(h, j+1) < rvTimerMgrHeapGetKey(h, j))
			++j;
		if (rvTimerMgrHeapGetKey(h, pos) <= rvTimerMgrHeapGetKey(h, j))
			return;
		rvTimerMgrHeapSwap(h, pos, j);
		pos = j;
	}
}

static RvTimerMgrHeap* rvTimerMgrHeapConstruct(RvTimerMgrHeap* h, RvAlloc* a) {
	rvPtrVectorConstruct(h, a);
	rvVectorReserve(RvVoidPtr)(h, 1024);
	return h;
}

static void rvTimerMgrHeapPush(RvTimerMgrHeap *h, RvTimer *t) {
	size_t pos = rvPtrVectorSize(h);
	rvPtrVectorPushBack(h, t);
	t->pos = pos;

	while (pos != 0) {
		size_t parent = rvTimerMgrHeapParent(h, pos);
		if (rvTimerMgrHeapGetKey(h, pos) >= rvTimerMgrHeapGetKey(h, parent))
			break;

		rvTimerMgrHeapSwap(h, pos, parent);
		pos = parent;
	}
}

static RvTimer* rvTimerMgrHeapPop(RvTimerMgrHeap* h) {
	RvTimer *t;

	assert(rvTimerMgrHeapSize(h) > 0);

	rvTimerMgrHeapSwap(h, 0, rvTimerMgrHeapSize(h) - 1);

	t = (RvTimer *)rvPtrVectorBack(h);
	assert(t->pos < rvTimerMgrHeapSize(h));

	t->pos = ~0; /* Mark as removed */
	rvPtrVectorPopBack(h);

	if (rvTimerMgrHeapSize(h) != 0)
		rvTimerMgrHeapSift(h, 0);

	return t;
}

static RvTimer *rvTimerMgrHeapRemoveAt(RvTimerMgrHeap *h, size_t pos) {
	RvTimer *t;

	assert((pos < rvTimerMgrHeapSize(h)) || (pos == (~0)));

	if (pos >= rvTimerMgrHeapSize(h)) 
		return NULL;

	rvTimerMgrHeapSwap(h, pos, rvTimerMgrHeapSize(h) - 1);

	t = (RvTimer *)rvPtrVectorBack(h);
	t->pos = ~0; /* Mark as removed */
	rvPtrVectorPopBack(h);

	while (pos != 0) {
		size_t parent = rvTimerMgrHeapParent(h, pos);

		if (rvTimerMgrHeapGetKey(h, pos) >= rvTimerMgrHeapGetKey(h, parent))
			break;

		rvTimerMgrHeapSwap(h, pos, parent);
		pos = parent;
	}

	if (rvTimerMgrHeapSize(h) != 0) 
		rvTimerMgrHeapSift(h, pos);

	return t;
}

#if 0
static RvBool rvTimerMgrHeapVerify(RvTimerMgrHeap *h, size_t pos) {

	/* If timer's pos is not where the timer actually is... fail */
	if (rvTimerMgrHeapAt(h, pos)->pos != pos) 
		return rvFalse;

	if (rvTimerMgrHeapHasLeftChild(h, pos)) {
		size_t left = rvTimerMgrHeapLeftChild(h, pos);
		RvTimer* leftTimer = rvTimerMgrHeapAt(h, left);
		
		/* If the timer's key is not in the right place in the heap... fail */
		if (rvTimerMgrHeapGetKey(h, pos) > rvTimerMgrHeapGetKey(h, left))
			return rvFalse;

		if (!rvTimerMgrHeapVerify(h, left))
			return rvFalse;
	}
		
	if (rvTimerMgrHeapHasRightChild(h, pos)) {		
		size_t right = rvTimerMgrHeapRightChild(h, pos);		
		RvTimer* rightTimer = rvTimerMgrHeapAt(h, right);
		
		/* If the timer's key is not in the right place in the heap... fail */
		if (rvTimerMgrHeapGetKey(h, pos) > rvTimerMgrHeapGetKey(h, right))
			return rvFalse;

		if (!rvTimerMgrHeapVerify(h, right))
			return rvFalse;
	}

	return rvTrue;
}

#endif

#if defined(RV_TIMERSTATS_ON)
static void rvTimerMgrCollectStats(RvTimerMgr* tm, RvTimer* t) {
	RvHrtime actual, delta;

	t->finished = rvTimeGetHrtime();
	actual = rvTimeHrSubtract(t->finished, t->started);
	delta = rvTimeHrSubtract(actual, t->absolute);
	tm->totalDelta = rvTimeHrAdd(tm->totalDelta, delta);
	tm->count++;

#if !defined(RV_IO_NONE)
	if (delta < 0)
		printf("Negative delta\n");
#if defined(RV_OS_WIN32)
	printf("Timer %p { abs=%I64d, actual=%I64d, delta=%I64d, avgDelta=%I64d }\n",
		   t, t->absolute, actual, delta, (tm->totalDelta / (RvHrtime)tm->count));
#else
	/* Using %lld does not currently work on embedded systems. */
	printf("Timer %p { abs=%lld, actual=%lld, delta=%lld, avgDelta=%lld }\n",
		   t, t->absolute, actual, delta, (tm->totalDelta / (RvHrtime)tm->count));
#endif
#endif

}
#endif

static void rvTimerMgrTrigger(RvTimer* e) {
	RvTimer* t;

	/* Trigger expired timers */
	while (e != 0) {

		/* Pop expired timer off list */
		t = e; 
		e = t->next;

		/* Trigger timer function */
		t->func(t, t->data);
	}
}

static void rvTimerMgrProcess(RvTimerMgr* tm) {
	RvHrtime currentTime;
	RvTimer* t;
	RvTimer* e = 0;

	rvMutexLock_(&tm->mutex);

	/* Get current */
	currentTime = rvTimeGetHrtime();

	/* Build list of expired timers */
	while (rvTimerMgrHeapSize(&tm->heap) != 0) {
		t = rvTimerMgrHeapTop(&tm->heap);
		if (t->absolute <= currentTime) {
			t->next = e;
			e = t;
			rvTimerMgrHeapPop(&tm->heap);
			t->state = RV_TIMER_STATE_DEAD;
		} else 
			break;
	}

	rvMutexUnlock_(&tm->mutex);

	/* Trigger expired timers */
	rvTimerMgrTrigger(e);
}

static void rvTimerMgrThread(RvThread_* th, void* data) {
	RvTimerMgr* tm = (RvTimerMgr*)data;
	rvLogEnter(&rvLog, "rvTimerMgrThread");

	while (tm->state == RV_TIMERMGRSTATE_ALIVE) {
		rvThreadSleep_(tm->period);
		rvTimerMgrProcess(tm);
	}

	rvLogLeave(&rvLog, "rvTimerMgrThread");
}

static void rvTimerMgrStartTimeBase(RvTimerMgr* tm) {
	rvThreadConstruct_(&tm->thread, "Timer Mgr", RV_PRIORITYVALUE_MAX,
	  RV_STACKSIZE_TIMERMGR, rvTimerMgrThread, tm);
	rvThreadStart_(&tm->thread);
}

static void rvTimerMgrAdd_(RvTimerMgr* tm, RvTimer* t, RvHrtime nanosec) {
	rvLogEnter(&rvLog, "rvTimerMgrAdd");
	
	/* Lazy initialization of time-base thread */
	if (tm->state == RV_TIMERMGRSTATE_UNBORN) {
		tm->state = RV_TIMERMGRSTATE_ALIVE;
		rvTimerMgrStartTimeBase(tm);
	}	

#if defined(RV_HACK_AVOIDDUPTIMERS)
	{
		size_t pos;
		if ((pos = rvTimerMgrFind(tm, t)) != ~0) {
			rvLogWarning(&rvLog, "rvTimerMgrAdd: Duplicate timer found. Old timer removed");
			rvTimerMgrHeapRemoveAt(&tm->heap, pos);
			t->state = RV_TIMER_STATE_DEAD;
		}
	}
#endif

	assert(t->state != RV_TIMER_STATE_ALIVE && t->pos == (~0));

	/* Mark as "alive" */
	t->state = RV_TIMER_STATE_ALIVE;
	t->absolute = nanosec;

	/* Assign a unique (non-zero) identifier to the timer */
	t->id = (++(tm->id)) ? tm->id : ++(tm->id);

	/* Add it to the heap */
	rvTimerMgrHeapPush(&tm->heap, t);

	rvLogLeave(&rvLog, "rvTimerMgrAdd_");
}

static RvBool rvTimerMgrRemove_(RvTimerMgr* tm, RvTimer* t) {
	RvBool r = rvFalse; 

	rvLogEnter(&rvLog, "rvTimerMgrRemove_");

	/* If timer was started ... stop it */
	if (t->state == RV_TIMER_STATE_ALIVE) {
		assert(t == rvTimerMgrHeapAt(&tm->heap, t->pos));
		if (rvTimerMgrHeapRemoveAt(&tm->heap, t->pos) != NULL) {
			t->state = RV_TIMER_STATE_DEAD;
			r = rvTrue;
		}
	}
	
	rvLogLeave(&rvLog, "rvTimerMgrRemove_");

	return r;
}

/* Useful for debugging timer problems */
static size_t rvTimerMgrFind_(RvTimerMgr* tm, RvTimer* t) {
	size_t pos;	
	for (pos = 0; pos < rvTimerMgrSize(tm); ++pos)
		if (rvTimerMgrHeapAt(&tm->heap, pos) == t)
			return pos;
	return ~0;
}

/* Public: */
RvTimerMgr* rvTimerMgrConstructA(RvTimerMgr* tm, unsigned int period, 
  RvAlloc* a) {
	rvLogEnter(&rvLog, "rvTimerMgrConstruct");

	/* Construct members */
	rvMutexConstruct_(&tm->mutex);
	rvTimerMgrHeapConstruct(&tm->heap, a);
	tm->id = 0;
	tm->period = period;
	tm->state = RV_TIMERMGRSTATE_UNBORN;

#if defined(RV_TIMERSTATS_ON)
	tm->totalDelta = (rvHrtime)0;
	tm->count = 0;
#endif	

	rvLogLeave(&rvLog, "rvTimerMgrConstruct");

	return tm;
}

void rvTimerMgrDestruct(RvTimerMgr* tm) {
	rvLogEnter(&rvLog, "rvTimerMgrDestruct");
	if (tm->state == RV_TIMERMGRSTATE_ALIVE) {
		tm->state = RV_TIMERMGRSTATE_DEAD;
		rvThreadDestruct_(&tm->thread); 
	}
	rvTimerMgrHeapDestruct(&tm->heap);
	rvMutexDestruct_(&tm->mutex);
	rvLogLeave(&rvLog, "rvTimerMgrDestruct");
}

size_t rvTimerMgrSize(const RvTimerMgr* tm) {
	return rvTimerMgrHeapSize(&tm->heap);
}

RvBool rvTimerMgrAdd(RvTimerMgr* tm, RvTimer* t) {
	RvBool r = rvTrue;
	rvLogEnter(&rvLog, "rvTimerMgrAdd");
	rvMutexLock_(&tm->mutex);
	if (t->state == RV_TIMER_STATE_UNBORN)
		rvTimerMgrAdd_(tm, t, rvTimeHrAdd(t->relative, rvTimeGetHrtime()));
	else
		r = rvFalse;
	rvMutexUnlock_(&tm->mutex);
	rvLogLeave(&rvLog, "rvTimerMgrAdd");
	return r;
}

RvBool rvTimerMgrRemove(RvTimerMgr* tm, RvTimer* t) {
	RvBool r;
	rvLogEnter(&rvLog, "rvTimerMgrRemove");
	rvMutexLock_(&tm->mutex);
	r = rvTimerMgrRemove_(tm, t);
	rvMutexUnlock_(&tm->mutex);	
	rvLogLeave(&rvLog, "rvTimerMgrRemove");
	return r;
}

RvBool rvTimerMgrReset(RvTimerMgr* tm, RvTimer* t, RvHrtime nanosec) {
	RvBool r;
	
	rvLogEnter(&rvLog, "rvTimerMgrReset");
	rvMutexLock_(&tm->mutex);

	/* Remove the timer is its already alive */
	r = rvTimerMgrRemove_(tm, t);

	/* Add the timer to the timer manager */
	t->relative = nanosec;
	rvTimerMgrAdd_(tm, t, rvTimeHrAdd(t->relative, rvTimeGetHrtime()));

	rvMutexUnlock_(&tm->mutex);
	rvLogLeave(&rvLog, "rvTimerMgrReset");

	return r;
}

/* Useful for debugging timer problems */
size_t rvTimerMgrFind(RvTimerMgr* tm, RvTimer* t) {
	size_t pos;
	rvMutexLock_(&tm->mutex);
	pos = rvTimerMgrFind_(tm, t);
	rvMutexUnlock_(&tm->mutex);
	return pos;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?