eventsim.c
来自「Sun公司Dream项目」· C语言 代码 · 共 520 行
C
520 行
/*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the "License"). You may not use this file except
* in compliance with the License.
*
* You can obtain a copy of the license at
* http://www.opensource.org/licenses/cddl1.php
* See the License for the specific language governing
* permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* HEADER in each file and include the License file at
* http://www.opensource.org/licenses/cddl1.php. If
* applicable, add the following below this CDDL HEADER,
* with the fields enclosed by brackets "[]" replaced
* with your own identifying information:
* Portions Copyright [yyyy]
* [name of copyright owner]
*/
/*
* $(@)EventSim.c $Revision: 1.2 $ $Date: 2006/07/15 00:02:34 $
*
* Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
*/
/*
* Copyright (c) 1997 by Sun Microsystems, Inc.
*/
#pragma ident "@(#)EventSim.c 1.2 99/03/22 SMI"
/*
* EventSim.c -- Event simulation framework object
*/
#include <sys/types.h>
#include <errno.h>
#include <time.h>
#include <thread.h>
#include <synch.h>
#include <stdlib.h>
#include "cobjs/Log.h"
#include "cobjs/Macros.h"
#include "cobjs/PriQueue.h"
#include "cobjs/Types.h"
#include "cobjs/Time.h"
#include "cobjs/EventSim.h"
/*************************************************************************
* OBJECT EventSim Instance Variables
*************************************************************************/
struct _EventSim {
mutex_t lock; /* locks sim and all actors */
PriQueue delayQueue; /* queue of all blocked actors */
cond_t runCond; /* start/stop condition */
Boolean shouldRun; /* sim should run cmd */
Boolean isRunning; /* sim running status */
Time nowTime; /* current sim time */
Time stopTime; /* time when sim stops */
cond_t realTimeCond; /* realtime sim condition */
double realTimeFrac; /* sim rate control */
Time realTimeBase; /* real time base */
Time simTimeBase; /* sim time base */
};
/*************************************************************************
* OBJECT EventSim Private types
*************************************************************************/
typedef enum EventQueueType {
EVENT_QUEUE_RUNNING, /* Actor running */
EVENT_QUEUE_DELAY, /* Actor delaying */
EVENT_QUEUE_WAIT /* Actor waiting for signal */
} EventQueueType;
struct _EventActor {
EventSim es; /* parent sim environment */
EventBody body; /* Actor body */
void *bodyArg; /* arg to actor body */
cond_t delayCond; /* wakeup condition */
Time wakeupTime; /* end of delay time */
EventQueueType queueType; /* actor state */
cond_t liveCond; /* live condition */
Boolean shouldLive; /* eventActor should live */
Boolean isLive; /* eventActor is live */
thread_t threadId; /* actor thread id */
};
/*************************************************************************
* OBJECT EventSim Private method prototypes
*************************************************************************/
static void eventSimStart(EventSim es, Boolean shouldRun);
/*************************************************************************
* OBJECT EventActor Private method prototypes
*************************************************************************/
static Time
eventActorYield(EventActor ea, EventQueueType queueType, Time delayTime);
static void eventActorSwitch(EventActor ea);
/*************************************************************************
* OBJECT EventSim Private function prototypes
*************************************************************************/
static void *eventActor(void *arg);
static Boolean eventSimInOrder(const void *item1p, const void *item2p);
/*************************************************************************
* OBJECT EventSim Class Methods
*************************************************************************/
EventSim
eventSimNew(void)
{
EventSim es = NEW_ZEROED(struct _EventSim, 1);
ABORT_IF_ERRNO(mutex_init(&es->lock, USYNC_THREAD, 0));
es->delayQueue = priQueueNew(400, eventSimInOrder);
ABORT_IF_ERRNO(cond_init(&es->runCond, USYNC_THREAD, 0));
es->shouldRun = FALSE;
es->isRunning = FALSE;
es->nowTime = 0LL;
es->stopTime = EVENT_TIME_FOREVER;
ABORT_IF_ERRNO(cond_init(&es->realTimeCond, USYNC_THREAD, 0));
es->realTimeFrac = 0.0;
return es;
}
/*************************************************************************
* OBJECT EventSim Instance Methods
*************************************************************************/
void
eventSimFree(EventSim es)
{
ASSERT(!es->isRunning && !es->shouldRun);
ABORT_IF_ERRNO(cond_destroy(&es->realTimeCond));
ABORT_IF_ERRNO(cond_destroy(&es->runCond));
ASSERT(priQueueLength(es->delayQueue) == 0);
priQueueFree(es->delayQueue);
ABORT_IF_ERRNO(mutex_destroy(&es->lock));
free(es);
}
double
eventSimSetRealTimeFrac(EventSim es, double realTimeFrac)
{
double oldRealTimeFrac;
CHECK_IF_ERRNO(mutex_lock(&es->lock));
oldRealTimeFrac = es->realTimeFrac;
es->realTimeFrac = realTimeFrac;
CHECK_IF_ERRNO(mutex_unlock(&es->lock));
return oldRealTimeFrac;
}
Time
eventSimSetStopTime(EventSim es, Time stopTime)
{
Time oldStopTime;
CHECK_IF_ERRNO(mutex_lock(&es->lock));
oldStopTime = es->stopTime;
es->stopTime = stopTime;
if (es->stopTime < es->nowTime) {
CHECK_IF_ERRNO(cond_signal(&es->realTimeCond));
}
CHECK_IF_ERRNO(mutex_unlock(&es->lock));
return oldStopTime;
}
Time
eventSimNow(EventSim es)
{
Time nowTime;
CHECK_IF_ERRNO(mutex_lock(&es->lock));
nowTime = es->nowTime;
CHECK_IF_ERRNO(mutex_unlock(&es->lock));
return nowTime;
}
void
eventSimRun(EventSim es)
{
eventSimStart(es, TRUE);
}
void
eventSimStep(EventSim es)
{
eventSimStart(es, FALSE);
}
void
eventSimStop(EventSim es)
{
CHECK_IF_ERRNO(mutex_lock(&es->lock));
es->shouldRun = FALSE;
while (es->isRunning) {
CHECK_IF_ERRNO(cond_wait(&es->runCond, &es->lock));
}
CHECK_IF_ERRNO(mutex_unlock(&es->lock));
}
void
eventSimWaitStopped(EventSim es)
{
CHECK_IF_ERRNO(mutex_lock(&es->lock));
while (es->isRunning) {
CHECK_IF_ERRNO(cond_wait(&es->runCond, &es->lock));
}
CHECK_IF_ERRNO(mutex_unlock(&es->lock));
}
/*************************************************************************
* OBJECT EventActor Class Methods
*************************************************************************/
EventActor
eventActorNew(EventSim es, size_t stackSize, EventBody body, void *bodyArg)
{
EventActor ea = NEW_ZEROED(struct _EventActor, 1);
ea->es = es;
ea->body = body;
ea->bodyArg = bodyArg;
ABORT_IF_ERRNO(cond_init(&ea->delayCond, USYNC_THREAD, 0));
ea->wakeupTime = 0LL;
ea->queueType = EVENT_QUEUE_RUNNING;
ABORT_IF_ERRNO(cond_init(&ea->liveCond, USYNC_THREAD, 0));
ea->shouldLive = TRUE;
ea->isLive = FALSE;
ABORT_IF_ERRNO(thr_create(NULL, stackSize, eventActor, ea, 0,
&ea->threadId));
CHECK_IF_ERRNO(mutex_lock(&es->lock));
while (!ea->isLive) {
CHECK_IF_ERRNO(cond_wait(&ea->liveCond, &es->lock));
}
CHECK_IF_ERRNO(mutex_unlock(&es->lock));
return ea;
}
/*************************************************************************
* OBJECT EventActor Instance Methods
*************************************************************************/
void
eventActorFree(EventActor ea)
{
EventSim es = ea->es;
CHECK_IF_ERRNO(mutex_lock(&es->lock));
ea->shouldLive = FALSE;
ASSERT(!es->isRunning);
ASSERT(ea->queueType != EVENT_QUEUE_RUNNING);
(void) priQueueDelete(es->delayQueue, ea);
CHECK_IF_ERRNO(cond_signal(&ea->delayCond));
while (ea->isLive) {
CHECK_IF_ERRNO(cond_wait(&ea->liveCond, &es->lock));
}
CHECK_IF_ERRNO(mutex_unlock(&es->lock));
ABORT_IF_ERRNO(thr_join(ea->threadId, NULL, NULL));
ABORT_IF_ERRNO(cond_destroy(&ea->liveCond));
ABORT_IF_ERRNO(cond_destroy(&ea->delayCond));
free(ea);
}
Boolean
eventActorShouldRun(EventActor ea)
{
return ea->shouldLive;
}
Time
eventActorDelay(EventActor ea, Time delayTime)
{
EventSim es = ea->es;
Time nowTime;
CHECK_IF_ERRNO(mutex_lock(&es->lock));
if (delayTime == 0LL) {
delayTime = 1LL;
}
nowTime = eventActorYield(ea, EVENT_QUEUE_DELAY, delayTime);
CHECK_IF_ERRNO(mutex_unlock(&es->lock));
return nowTime;
}
Time
eventActorWait(EventActor ea)
{
EventSim es = ea->es;
Time nowTime;
CHECK_IF_ERRNO(mutex_lock(&es->lock));
nowTime = eventActorYield(ea, EVENT_QUEUE_WAIT, EVENT_TIME_FOREVER);
CHECK_IF_ERRNO(mutex_unlock(&es->lock));
return nowTime;
}
Time
eventActorTimedWait(EventActor ea, Time maxWaitTime)
{
EventSim es = ea->es;
Time nowTime;
CHECK_IF_ERRNO(mutex_lock(&es->lock));
nowTime = eventActorYield(ea, EVENT_QUEUE_WAIT, maxWaitTime);
CHECK_IF_ERRNO(mutex_unlock(&es->lock));
return nowTime;
}
void
eventActorSignal(EventActor ea)
{
EventSim es = ea->es;
CHECK_IF_ERRNO(mutex_lock(&es->lock));
if (ea->queueType == EVENT_QUEUE_WAIT) {
(void) priQueueDelete(es->delayQueue, ea);
ea->wakeupTime = es->nowTime;
priQueueInsert(es->delayQueue, ea);
}
CHECK_IF_ERRNO(mutex_unlock(&es->lock));
}
Time
eventActorNow(EventActor ea)
{
return eventSimNow(ea->es);
}
void
eventActorStopSim(EventActor ea)
{
EventSim es = ea->es;
CHECK_IF_ERRNO(mutex_lock(&es->lock));
es->shouldRun = FALSE;
(void) eventActorYield(ea, EVENT_QUEUE_WAIT, 0LL);
CHECK_IF_ERRNO(mutex_unlock(&es->lock));
}
/*************************************************************************
* OBJECT EventSim Private Methods
*************************************************************************/
static void
eventSimStart(EventSim es, Boolean shouldRun)
{
CHECK_IF_ERRNO(mutex_lock(&es->lock));
es->shouldRun = shouldRun;
if (!es->isRunning) {
EventActor ea = (EventActor)priQueueRemove(es->delayQueue);
if (ea != NULL) {
CHECK_IF_ERRNO(cond_signal(&ea->delayCond));
es->isRunning = TRUE;
es->realTimeBase = timeOfDay();
es->simTimeBase = es->nowTime;
}
}
CHECK_IF_ERRNO(mutex_unlock(&es->lock));
}
/*************************************************************************
* OBJECT EventSim Private Methods
*************************************************************************/
static Time
eventActorYield(EventActor ea, EventQueueType queueType, Time delayTime)
{
EventSim es = ea->es;
ASSERT(ea->queueType == EVENT_QUEUE_RUNNING);
if (!ea->shouldLive) {
return -1LL;
}
ea->wakeupTime = es->nowTime + delayTime;
ea->queueType = queueType;
eventActorSwitch(ea);
ea->queueType = EVENT_QUEUE_RUNNING;
if (!ea->shouldLive) {
return -1LL;
}
if (es->realTimeFrac > 0.0) {
double realDelay;
Time futureTime;
Time curTime;
realDelay = timeToDouble(ea->wakeupTime - es->simTimeBase)
* es->realTimeFrac;
futureTime = timeFromDouble(realDelay) + es->realTimeBase;
curTime = timeOfDay();
if (futureTime > curTime) {
timestruc_t to;
to = timeToTimestruc(futureTime);
while (es->stopTime > ea->wakeupTime) {
int error;
error = cond_timedwait(&es->realTimeCond, &es->lock, &to);
switch (error) {
case ETIME:
goto done;
case 0:
case EINTR:
break;
default:
ABORT_WITH_ERRNO(error, "cond_timedwait");
}
done: ;
}
}
}
ASSERT(ea->wakeupTime >= es->nowTime);
es->nowTime = ea->wakeupTime;
return es->nowTime;
}
static void
eventActorSwitch(EventActor ea)
{
EventSim es = ea->es;
EventActor newEa;
if (ea->isLive) {
priQueueInsert(es->delayQueue, ea);
}
newEa = (EventActor)priQueueRemove(es->delayQueue);
if (newEa == NULL || newEa->wakeupTime > es->stopTime || !es->shouldRun) {
if (newEa != NULL) {
priQueueInsert(es->delayQueue, newEa);
newEa = NULL;
}
es->isRunning = FALSE;
es->shouldRun = FALSE;
CHECK_IF_ERRNO(cond_broadcast(&es->runCond));
}
if (newEa != ea) {
if (newEa != NULL) {
CHECK_IF_ERRNO(cond_signal(&newEa->delayCond));
}
if (ea->isLive) {
CHECK_IF_ERRNO(cond_wait(&ea->delayCond, &es->lock));
}
}
}
/*************************************************************************
* OBJECT EventSim Private Functions
*************************************************************************/
static void *
eventActor(void *arg)
{
EventActor ea = (EventActor) arg;
EventSim es = ea->es;
CHECK_IF_ERRNO(mutex_lock(&es->lock));
ea->isLive = TRUE;
CHECK_IF_ERRNO(cond_signal(&ea->liveCond));
(void) eventActorYield(ea, EVENT_QUEUE_DELAY, 0LL);
CHECK_IF_ERRNO(mutex_unlock(&es->lock));
(ea->body) (ea, ea->bodyArg);
CHECK_IF_ERRNO(mutex_lock(&es->lock));
ea->isLive = FALSE;
CHECK_IF_ERRNO(cond_signal(&ea->liveCond));
eventActorSwitch(ea);
CHECK_IF_ERRNO(mutex_unlock(&es->lock));
return NULL;
}
static Boolean
eventSimInOrder(const void *item1p, const void *item2p)
{
EventActor eventActor1 = (EventActor) item1p;
EventActor eventActor2 = (EventActor) item2p;
return Boolean(eventActor1->wakeupTime <= eventActor2->wakeupTime);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?