📄 schedcl.cpp
字号:
/**************************************************************************
* *
* Light OPC Server development library *
* *
* Copyright (c) 2000 Timofei Bondarenko *
*
thread procedures for LightOPCServer::async scheduler
**************************************************************************/
#ifndef _WIN32_DCOM
#define _WIN32_DCOM /* for CoInitializeEx() */
#endif
#include "privopc.h"
#if 0
#include <malloc.h>
#define LO_HEAPCHECK(pp) { int hc; if (_HEAPOK != (hc = _heapchk())) \
UL_ERROR((LOGID, "heapchk() %d %p %s %d", hc, pp, __FILE__, __LINE__)); }
#else
#define LO_HEAPCHECK(pp)
#endif
#define loHUGESLEEP (((loMilliSec)~0)>>2)
#define loMAXSLEEP (0xfffff) /* ~17min default refresh period */
#if 0
#define SATURATE_PERCENT (1) /* 0/1 */
#define USE_DOUBLE (1) /* 0/1 */
#define USE_PAIR (0) /* probably == !USE_DOUBLE */
#else
#define SATURATE_PERCENT (1) /* 0/1 */
#define USE_DOUBLE (0) /* 0/1 */
#define USE_PAIR (1) /* probably == !USE_DOUBLE */
#endif
#if 0
#define loSTATPERIOD (1024) /* time for averaging bandwidth value */
unsigned lo_statperiod(unsigned stp) { return loSTATPERIOD; }
#else
static loMilliSec loSTATPERIOD = 1024/*1412*/;
unsigned lo_statperiod(unsigned stp)
{
if ((stp >> 2) && stp <= (loHUGESLEEP >> 8)) loSTATPERIOD = stp;
return loSTATPERIOD;
}
#endif
typedef struct loUpdTimes
{
loMilliSec awoke, beginupd, finish;
loMilliSec syncpoint, latency, nextsleep;
unsigned datasent, overload, updated;
#if 0 != USE_DOUBLE
double bandwidth;
# if 0 != USE_PAIR
double bandwidth0;
# endif
#else
unsigned long bandwidth;
# if 0 != USE_PAIR
unsigned long bandwidth0;
# endif
#endif
} loUpdTimes;
static void update_sheduler(LightOPCServer *cli, loService *se, loUpdTimes *times)
{
unsigned gndx;
unsigned advmask;
LightOPCGroup *grp;
loMilliSec curtime, syncpoint, latency,
nextsleep = loHUGESLEEP;
loUpdList upl;
lo_upl_init(&upl, loUPL_variant | loUPL_timestamp | loUPL_quality | loUPL_errors |
loUPL_opchandle);
curtime = times->beginupd;
latency = se->driver.ldRefreshRate;
syncpoint = curtime + (latency >> 1); /* or latency-1 ? We searching closest synchronization point. */
latency = (syncpoint - times->syncpoint) % latency;
times->syncpoint = (syncpoint -= latency);
times->overload = 0;
times->updated = 0;
latency = 0;
if (cli)
{
upl.rctx = cli->ctxt;
cli->lock_read();
for(gndx = 0; gndx < cli->grl.gl_count; gndx++)
if ((grp = (LightOPCGroup*)cli->grl.gl_list[gndx]) && grp->Active &&
(advmask = grp->advise_present & grp->advise_enabled))
{
int justactuated = grp->justactuated;
loMilliSec updrate = grp->UpdateRate;
loMilliSec elapsed = curtime - grp->LastUpdate;
if (justactuated || elapsed >= updrate)
{
grp->justactuated = 0;
/******* data refreshing code **********/
lw_rw_rdlock(&se->lkPrim);
if (grp->last_trid != se->prim_trid) /* is cache changed? */
{
grp->last_trid = se->prim_trid;
upl.rctx.cta.vc_lcid = grp->grLCID;
lo_refresh_items(se, &upl, grp);
}
lw_rw_unlock(&se->lkPrim);
if (upl.used)
{
/* upl.trqid = 0; */
times->datasent +=
cli->send_callback(grp, 0, &upl, advmask | loRQ_OP_REFRESH);
loVariant_clear(upl.variant, upl.used); upl.used = 0;
cli->lock_read(); /* relock me again */
}
/******* end of data refreshing code ***/
elapsed -= updrate;
if (elapsed <= updrate && !justactuated)
{
if (elapsed > latency) latency = elapsed;
grp->LastUpdate += updrate; /* Ok */
// UL_WARNING((LOGID, "late %u/%u = %u%% >>%u ",
// elapsed, updrate, load, loadmax));
}
else /* we're late */
{
// UL_ERROR((LOGID, "late %u", elapsed));
if (!justactuated)
{
times->overload++;
#if 0 == SATURATE_PERCENT
if (elapsed > latency) latency = elapsed;
#endif
}
elapsed = curtime - (grp->LastUpdate = syncpoint);
}
times->updated++;
} /* if (elapsed >= updrate) */
updrate -= elapsed;
if (updrate < nextsleep) nextsleep = updrate;
} /* end of loop */
cli->unlock();
} /* enf of If(cli) */
lo_upl_clear(&upl);
times->latency = latency;
times->nextsleep = nextsleep;
}
/* There are four case for timing:
a) overload -> 100%
b) Doesn't updated -> (finish - awoke) / statperiod * 100%
where:
statperiod = finish - times->finish
if (nextsleep <= (finish - beginupd)) nextsleep = 0;
else nextsleep <= (finish - beginupd);
Updated:
c) (finish - awoke) / (finish - awoke + nextsleep) * 100%
d) (finish - beginupd + latency) /
(finish - beginupd + latency + nextsleep) * 100%
*/
static void sched_timings(loUpdTimes *upt, loMilliSec finish)
{
unsigned long percent;
loMilliSec nextsleep = upt->nextsleep;
loMilliSec statperiod, consumed2;
consumed2 = finish - upt->beginupd;
if (nextsleep > consumed2) nextsleep -= consumed2;
else nextsleep = 0, upt->overload = 1;
statperiod = upt->finish;
upt->finish = finish;
if (0 == (statperiod = finish - statperiod))
{
#if 0
statperiod = 1;
#else
goto SkipBW;
#endif
}
#if 0 != SATURATE_PERCENT
if (upt->overload) percent = 100;
else
#endif
{
unsigned long percent2;
loMilliSec consumed1 = finish - upt->awoke;
percent = consumed1 * 100;
if (consumed1 += nextsleep)
{
if (consumed1 > statperiod) consumed1 = statperiod;
percent = (percent + (consumed1 >> 1)) / consumed1;
}
percent2 = (consumed2 + upt->latency) * 100;
#if 0 != SATURATE_PERCENT
if (consumed2 += nextsleep + upt->latency)
#else
if (consumed2 = upt->nextsleep + upt->latency)
#endif
percent2 = (percent2 + (consumed2 >> 1)) / consumed2;
if (percent < percent2) percent = percent2;
#if 0 == SATURATE_PERCENT
if (percent > 100)
{
statperiod = (statperiod * percent + 50) / 100;
// UL_ERROR((LOGID, "percent=%u", percent));
percent = 100;
}
#else
// if (percent > 100) UL_ERROR((LOGID, "percent=%u", percent));
#endif
}
/*
UL_DEBUG((LOGID, "period=%u/%u percent=%u+%u => %u",
loSTATPERIOD, statperiod,
(int)upt->bandwidth, percent, (int)(
(upt->bandwidth * (loSTATPERIOD - statperiod) +
percent * statperiod) / loSTATPERIOD)));
// */
#if 0 == USE_PAIR
upt->bandwidth = (upt->bandwidth * loSTATPERIOD +
percent * statperiod) / (statperiod + loSTATPERIOD);
#else
/*
normalizing statperiod by statperiod /= shortslice
to be converted from shortslice <= statperiod <= longslice
to 1 <= statperiod <= div_short * div_long
shortslice = loSTATPERIOD / div_short
longslice = loSTATPERIOD * div_long
loSTATPERIOD ==> div_short
bw0 (old bandwidth) = (bw0 + percent * statperiod) * div_short /
(statperiod + div_short)
bw (current bandwidth) = bw0 / div_short
to avoid overflows must be :
(1 << 32) > 100 * div_short * (div_long + 1) * div_short
thus: 7 bits for "100%"
25 bits for least: 2 div_short + div_long
for example div_short = div_long = 1 << 8
or, for better resolution on short periods:
div_short = 1 << 10, div_long = 1 << 5
*/
#if 0
{ unsigned long period;
if (statperiod >= (loSTATPERIOD << 5)) period = 1 << 15;
else if (0 == (period =
((statperiod << 10) + (loSTATPERIOD >> 1)) / loSTATPERIOD))
period = 1;
upt->bandwidth0 = (upt->bandwidth0 + percent * period) * (1 << 10);
#if 0
upt->bandwidth0 /= (1 << 10) + period;
#else
period += (1 << 10);
upt->bandwidth0 = (upt->bandwidth0 + (period >> 1)) / period;
#endif
upt->bandwidth = (upt->bandwidth0 + (1 << 9)) / (1 << 10);
}
#else
if (statperiod >= (loSTATPERIOD << 1))
upt->bandwidth0 = percent << 12;
else
{
unsigned long period = ((statperiod << 11) +
(loSTATPERIOD >> 1)) / loSTATPERIOD;
if (0 == period) period = 1;
else if (period > (1 << 12)) period = 1 << 12;
#if 1
upt->bandwidth0 -= (upt->bandwidth0 * period + (1 << 11)) / (1 << 12);
#else
upt->bandwidth0 = (upt->bandwidth0 * ((1 << 12) - period) + (1 << 11)) / (1 << 12);
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -