schedcall.c
来自「Sun公司Dream项目」· C语言 代码 · 共 271 行
C
271 行
/*
* 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]
*/
/*
* $(@)SchedCall.c $Revision: 1.2 $ $Date: 2006/07/15 00:02:35 $
*
* Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
*/
/*
* Copyright (c) 1995 by Sun Microsystems, Inc.
*/
#pragma ident "@(#)SchedCall.c 1.2 98/12/18 SMI"
/*
* SchedCall.c -- SchedCall is an object which manages future callbacks.
*/
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <synch.h>
#include <thread.h>
#include <sys/time.h>
#include "cobjs/PriQueue.h"
#include "cobjs/Log.h"
#include "cobjs/Macros.h"
#include "cobjs/Thread.h"
#include "cobjs/Time.h"
#include "cobjs/Types.h"
#include "SchedCall.h"
#define SCHED_CALL_INITIAL_QUEUE_LEN 20
/*
* Private types
*/
typedef struct SchedCallItem {
SchedCallHandler handler;
Time date;
Object delegate;
} SchedCallItem;
/*
* OBJECT SchedCall Instance Variables
*/
struct _SchedCall {
mutex_t mutex;
cond_t queueCond;
cond_t scipCond;
PriQueue priQueue;
Boolean isActive;
Time accuracy;
Boolean isRealtime;
int priority;
SchedCallItem *curScip;
thread_t threadId;
};
/*
* Private function prototypes
*/
static Boolean schedCallInOrder(const void *item1p, const void *item2p);
static void *schedCallThread(void *arg);
/*
* Private data
*/
static SchedCall globalSc;
/*
* OBJECT Template Class Methods
*/
/*
* Initialize global SchedCall object.
*/
void
schedCallInit(Time accuracy, Boolean isRealtime, int priority)
{
ABORT_IF_FALSE(globalSc == NULL);
globalSc = schedCallNew(accuracy, isRealtime, priority);
}
/*
* Shutdown global SchedCall object.
*/
void
schedCallFini(void)
{
if (globalSc != NULL) {
schedCallFree(globalSc);
globalSc = NULL;
}
}
SchedCall
schedCallNew(Time accuracy, Boolean isRealtime, int priority)
{
SchedCall sc;
ASSERT(accuracy >= 0);
sc = NEW_ZEROED(struct _SchedCall, 1);
sc->priQueue = priQueueNew(SCHED_CALL_INITIAL_QUEUE_LEN, schedCallInOrder);
sc->isRealtime = isRealtime;
sc->priority = priority;
ABORT_IF_ERRNO(mutex_init(&sc->mutex, USYNC_THREAD, 0));
ABORT_IF_ERRNO(cond_init(&sc->queueCond, USYNC_THREAD, 0));
ABORT_IF_ERRNO(cond_init(&sc->scipCond, USYNC_THREAD, 0));
sc->isActive = TRUE;
sc->accuracy = accuracy;
sc->curScip = NULL;
ABORT_IF_ERRNO(thr_create(NULL, 0, schedCallThread, sc,
THR_BOUND, &sc->threadId));
return sc;
}
/*
* OBJECT Template Instance Methods
*/
SchedCallTag
schedCallAdd(SchedCall sc, Time date, SchedCallHandler handler, Object delegate)
{
SchedCallItem *scip;
if (sc == NULL) {
ABORT_IF_FALSE(globalSc != NULL);
sc = globalSc;
}
if ((scip = NEW_ZEROED(SchedCallItem, 1)) == NULL) {
return NULL;
}
if (sc->accuracy != 0) {
date = ROUND_UP(date, sc->accuracy);
}
scip->date = date;
scip->handler = handler;
scip->delegate = delegate;
CHECK_IF_ERRNO(mutex_lock(&sc->mutex));
priQueueInsert(sc->priQueue, scip);
CHECK_IF_ERRNO(cond_signal(&sc->queueCond));
CHECK_IF_ERRNO(mutex_unlock(&sc->mutex));
return scip;
}
Boolean
schedCallRemove(SchedCall sc, SchedCallTag tag)
{
SchedCallItem *scip = NULL;
if (sc == NULL) {
ABORT_IF_FALSE(globalSc != NULL);
sc = globalSc;
}
ASSERT(tag != NULL);
CHECK_IF_ERRNO(mutex_lock(&sc->mutex));
if (priQueueDelete(sc->priQueue, tag)) {
scip = (SchedCallItem *)tag;
} else while (sc->curScip == (SchedCallItem *)tag) {
CHECK_IF_ERRNO(cond_wait(&sc->scipCond, &sc->mutex));
}
CHECK_IF_ERRNO(cond_signal(&sc->queueCond));
CHECK_IF_ERRNO(mutex_unlock(&sc->mutex));
if (scip != NULL) {
free(scip);
}
return Boolean(scip != NULL);
}
void
schedCallFree(SchedCall sc)
{
SchedCallItem *scip;
CHECK_IF_ERRNO(mutex_lock(&sc->mutex));
sc->isActive = FALSE;
CHECK_IF_ERRNO(cond_signal(&sc->queueCond));
CHECK_IF_ERRNO(mutex_unlock(&sc->mutex));
CHECK_IF_ERRNO(thr_join(sc->threadId, NULL, NULL));
while ((scip = (SchedCallItem*)priQueueRemove(sc->priQueue)) != NULL) {
free(scip);
}
priQueueFree(sc->priQueue);
ABORT_IF_ERRNO(cond_destroy(&sc->queueCond));
ABORT_IF_ERRNO(mutex_destroy(&sc->mutex));
free(sc);
}
/*
* OBJECT Template Private Functions
*/
static void *
schedCallThread(void *arg)
{
SchedCall sc = (SchedCall) arg;
SchedCallItem *scip;
if (sc->isRealtime) {
threadSetRtPriority(sc->priority);
}
CHECK_IF_ERRNO(mutex_lock(&sc->mutex));
while (sc->isActive) {
scip = (SchedCallItem*)priQueueHead(sc->priQueue);
if (scip == NULL) {
CHECK_IF_ERRNO(cond_wait(&sc->queueCond, &sc->mutex));
} else {
int err;
timestruc_t waitDate = timeToTimestruc(scip->date);
Time tod;
err = cond_timedwait(&sc->queueCond, &sc->mutex, &waitDate);
tod = timeOfDay();
switch (err) {
case 0:
case EINTR:
break;
case ETIME:
while ((scip = (SchedCallItem*)priQueueHead(sc->priQueue)) != NULL
&& scip->date <= tod) {
scip = (SchedCallItem*)priQueueRemove(sc->priQueue);
sc->curScip = scip;
CHECK_IF_ERRNO(mutex_unlock(&sc->mutex));
(*scip->handler) (scip->delegate, scip->date);
free(scip);
CHECK_IF_ERRNO(mutex_lock(&sc->mutex));
sc->curScip = NULL;
CHECK_IF_ERRNO(cond_signal(&sc->scipCond));
}
break;
default:
ABORT("schedCall");
break;
}
}
}
CHECK_IF_ERRNO(mutex_unlock(&sc->mutex));
return NULL;
}
static Boolean
schedCallInOrder(const void *item1p, const void *item2p)
{
const SchedCallItem *sciItem1p = (SchedCallItem *) item1p;
const SchedCallItem *sciItem2p = (SchedCallItem *) item2p;
return Boolean(sciItem1p->date <= sciItem2p->date);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?