Merged the db-test branch.

Also made additional changes:
* Simplified xRecord.c so it can run on vxWorks.
* Standard way to load DBD and DB files in tests

All test harnesses now run on vxWorks (but some tests still fail).
This commit is contained in:
Andrew Johnson
2012-07-02 11:03:55 -05:00
28 changed files with 654 additions and 306 deletions

View File

@@ -22,6 +22,7 @@
#include <dbStaticLib.h>
#include <epicsTypes.h>
#include <epicsStdio.h>
#include <epicsStdlib.h>
#include <epicsString.h>
#include <errlog.h>
#include <shareLib.h>
@@ -29,13 +30,6 @@
#define epicsExportSharedSymbols
#include "chfPlugin.h"
#ifndef HUGE_VALF
# define HUGE_VALF HUGE_VAL
#endif
#ifndef HUGE_VALL
# define HUGE_VALL (-(HUGE_VAL))
#endif
/*
* Data for a chfPlugin
*/
@@ -65,10 +59,11 @@ typedef enum chfPluginType {
} chfPluginType;
/*
* Convert the (long) integer value 'val' to the type named in 'opt->optType'
* and store the result at 'user + opt->offset'.
* Convert the (epicsInt32) integer value 'val' to the type named in
* 'opt->optType' and store the result at 'user + opt->offset'.
*/
static int store_integer_value(const chfPluginArgDef *opt, void *user, long val)
static int
store_integer_value(const chfPluginArgDef *opt, char *user, epicsInt32 val)
{
epicsInt32 *ival;
int *eval;
@@ -77,7 +72,10 @@ static int store_integer_value(const chfPluginArgDef *opt, void *user, long val)
char *sval;
char buff[22]; /* 2^64 = 1.8e+19, so 20 digits plus sign max */
/* printf("Got an integer for %s (type %d): %ld\n", opt->name, opt->optType, val); */
#ifdef DEBUG_CHF
printf("Got an integer for %s (type %d): %ld\n",
opt->name, opt->optType, (long) val);
#endif
if (!opt->convert && opt->optType != chfPluginArgInt32) {
return -1;
@@ -89,24 +87,23 @@ static int store_integer_value(const chfPluginArgDef *opt, void *user, long val)
*ival = val;
break;
case chfPluginArgBoolean:
eval = (int*) ((char*)user + opt->offset);
*eval = !!val;
sval = user + opt->offset;
*sval = !!val;
break;
case chfPluginArgDouble:
dval = (double*) ((char*)user + opt->offset);
*dval = (double) val;
dval = (double*) (user + opt->offset);
*dval = val;
break;
case chfPluginArgString:
sval = ((char*)user + opt->offset);
sprintf(buff, "%ld", val);
if (strlen(buff) > opt->size-1) {
sval = user + opt->offset;
if (sprintf(buff, "%ld", (long)val) > opt->size - 1) {
return -1;
}
strncpy(sval, buff, opt->size-1);
sval[opt->size-1]='\0';
break;
case chfPluginArgEnum:
eval = (int*) ((char*)user + opt->offset);
eval = (int*) (user + opt->offset);
for (emap = opt->enums; emap && emap->name; emap++) {
if (val == emap->value) {
*eval = val;
@@ -127,14 +124,16 @@ static int store_integer_value(const chfPluginArgDef *opt, void *user, long val)
* Convert the (int) boolean value 'val' to the type named in 'opt->optType'
* and store the result at 'user + opt->offset'.
*/
static int store_boolean_value(const chfPluginArgDef *opt, void *user, int val)
static int store_boolean_value(const chfPluginArgDef *opt, char *user, int val)
{
epicsInt32 *ival;
int *eval;
double *dval;
char *sval;
/* printf("Got a boolean for %s (type %d): %d\n", opt->name, opt->optType, val); */
#ifdef DEBUG_CHF
printf("Got a boolean for %s (type %d): %d\n",
opt->name, opt->optType, val);
#endif
if (!opt->convert && opt->optType != chfPluginArgBoolean) {
return -1;
@@ -142,24 +141,24 @@ static int store_boolean_value(const chfPluginArgDef *opt, void *user, int val)
switch (opt->optType) {
case chfPluginArgInt32:
ival = (epicsInt32 *) ((char*)user + opt->offset);
ival = (epicsInt32 *) (user + opt->offset);
*ival = val;
break;
case chfPluginArgBoolean:
eval = (int*) ((char*)user + opt->offset);
*eval = val;
sval = user + opt->offset;
*sval = val;
break;
case chfPluginArgDouble:
dval = (double*) ((char*)user + opt->offset);
*dval = val ? 1. : 0.;
dval = (double*) (user + opt->offset);
*dval = !!val;
break;
case chfPluginArgString:
sval = ((char*)user + opt->offset);
if ((val ? 4 : 5) > opt->size-1) {
sval = user + opt->offset;
if ((val ? 4 : 5) > opt->size - 1) {
return -1;
}
strncpy(sval, (val ? "true" : "false"), opt->size-1);
sval[opt->size-1]='\0';
strncpy(sval, val ? "true" : "false", opt->size - 1);
sval[opt->size - 1] = '\0';
break;
case chfPluginArgEnum:
case chfPluginArgInvalid:
@@ -172,43 +171,42 @@ static int store_boolean_value(const chfPluginArgDef *opt, void *user, int val)
* Convert the double value 'val' to the type named in 'opt->optType'
* and store the result at 'user + opt->offset'.
*/
static int store_double_value(const chfPluginArgDef *opt, void *user, double val)
static int
store_double_value(const chfPluginArgDef *opt, void *user, double val)
{
epicsInt32 *ival;
int *eval;
double *dval;
char *sval;
int i;
/*
#ifdef DEBUG_CHF
printf("Got a double for %s (type %d, convert: %s): %g\n",
opt->name, opt->optType, opt->convert?"yes":"no", val);
*/
opt->name, opt->optType, opt->convert ? "yes" : "no", val);
#endif
if (!opt->convert && opt->optType != chfPluginArgDouble) {
return -1;
}
switch (opt->optType) {
case chfPluginArgInt32:
#if (LONG_MAX > 0x7fffffff)
if (val < -0x80000000L || val > 0x7fffffff) {
if (val < INT_MIN || val > INT_MAX) {
return -1;
}
#endif
ival = (epicsInt32 *) ((char*)user + opt->offset);
*ival = val;
ival = (epicsInt32 *) (user + opt->offset);
*ival = (epicsInt32) val;
break;
case chfPluginArgBoolean:
eval = (int*) ((char*)user + opt->offset);
*eval = (val != 0.) ? 1 : 0;
sval = user + opt->offset;
*sval = !!val;
break;
case chfPluginArgDouble:
dval = (double*) ((char*)user + opt->offset);
dval = (double*) (user + opt->offset);
*dval = val;
break;
case chfPluginArgString:
sval = ((char*)user + opt->offset);
if (opt->size <= 8) { /* Play it safe: 3 exp + 2 sign + 'e' + '.' */
sval = user + opt->offset;
if (opt->size <= 8) { /* Play it safe: 3 exp + 2 sign + 'e' + '.' */
return -1;
}
i = epicsSnprintf(sval, opt->size, "%.*g", (int) opt->size - 7, val);
@@ -227,10 +225,11 @@ static int store_double_value(const chfPluginArgDef *opt, void *user, double val
* Convert the (char*) string value 'val' to the type named in 'opt->optType'
* and store the result at 'user + opt->offset'.
*/
static int store_string_value(const chfPluginArgDef *opt, void *user, const char *val, size_t len)
static int
store_string_value(const chfPluginArgDef *opt, char *user, const char *val,
size_t len)
{
epicsInt32 *ival;
long lval;
int *eval;
const chfPluginEnumType *emap;
double *dval;
@@ -238,57 +237,47 @@ static int store_string_value(const chfPluginArgDef *opt, void *user, const char
char *end;
int i;
/* printf("Got a string for %s (type %d): %.*s\n", opt->name, opt->optType, len, val); */
#ifdef DEBUG_CHF
printf("Got a string for %s (type %d): %.*s\n",
opt->name, opt->optType, (int) len, val);
#endif
if (!opt->convert && opt->optType != chfPluginArgString && opt->optType != chfPluginArgEnum) {
if (!opt->convert && opt->optType != chfPluginArgString &&
opt->optType != chfPluginArgEnum) {
return -1;
}
switch (opt->optType) {
case chfPluginArgInt32:
lval = strtol(val, &end, 0);
/* test for the myriad error conditions which strtol may use */
if (lval == LONG_MAX || lval == LONG_MIN
#if (LONG_MAX > 0x7fffffff)
|| lval < -0x80000000L || lval > 0x7fffffff
#endif
|| end == val) {
return -1;
}
ival = (epicsInt32 *) ((char*)user + opt->offset);
*ival = lval;
break;
ival = (epicsInt32 *) (user + opt->offset);
return epicsParseInt32(val, ival, 0, &end);
case chfPluginArgBoolean:
eval = (int*) ((char*)user + opt->offset);
sval = user + opt->offset;
if (epicsStrnCaseCmp(val, "true", len) == 0) {
*eval = 1;
*sval = 1;
} else if (epicsStrnCaseCmp(val, "false", len) == 0) {
*eval = 0;
*sval = 0;
} else {
i = strtol(val, &end, 0);
if (i > INT_MAX || i < INT_MIN || end == val) {
epicsInt8 i8;
if (epicsParseInt8(val, &i8, 0, &end))
return -1;
}
*eval = !!i;
*sval = !!i8;
}
break;
case chfPluginArgDouble:
dval = (double*) ((char*)user + opt->offset);
*dval = strtod(val, &end);
/* Indicates errors in the same manner as strtol */
if (*dval==HUGE_VALF||*dval==HUGE_VALL||end==val )
{
return -1;
}
break;
dval = (double*) (user + opt->offset);
return epicsParseDouble(val, dval, &end);
case chfPluginArgString:
i = opt->size-1 < len ? opt->size-1 : len;
sval = ((char*)user + opt->offset);
sval = user + opt->offset;
strncpy(sval, val, i);
sval[i] = '\0';
break;
case chfPluginArgEnum:
eval = (int*) ((char*)user + opt->offset);
eval = (int*) (user + opt->offset);
for (emap = opt->enums; emap && emap->name; emap++) {
if (strncmp(emap->name, val, len) == 0) {
*eval = emap->value;
@@ -327,7 +316,7 @@ static parse_result parse_start(chFilter *filter)
/* FIXME: Use a free-list */
f = calloc(1, sizeof(chfFilter));
if (!f) {
fprintf(stderr,"chfFilterCtx calloc failed\n");
errlogPrintf("chfFilterCtx calloc failed\n");
goto errfctx;
}
f->nextParam = -1;
@@ -336,7 +325,7 @@ static parse_result parse_start(chFilter *filter)
/* FIXME: Use a free-list */
f->found = calloc( (p->nopts/32)+1, sizeof(epicsUInt32) );
if (!f->found) {
fprintf(stderr,"chfConfigParseStart: bit array calloc failed\n");
errlogPrintf("chfConfigParseStart: bit array calloc failed\n");
goto errbitarray;
}
@@ -401,7 +390,8 @@ static parse_result parse_boolean(chFilter *filter, int boolVal)
const chfPluginArgDef *opts = ((chfPlugin*)filter->plug->puser)->opts;
chfFilter *f = (chfFilter*)filter->puser;
if (f->nextParam < 0 || store_boolean_value(&opts[f->nextParam], f->puser, boolVal)) {
if (f->nextParam < 0 ||
store_boolean_value(&opts[f->nextParam], f->puser, boolVal)) {
return parse_stop;
} else {
return parse_continue;
@@ -413,7 +403,13 @@ static parse_result parse_integer(chFilter *filter, long integerVal)
const chfPluginArgDef *opts = ((chfPlugin*)filter->plug->puser)->opts;
chfFilter *f = (chfFilter*)filter->puser;
if (f->nextParam < 0 || store_integer_value(&opts[f->nextParam], f->puser, integerVal)) {
if(sizeof(long)>sizeof(epicsInt32)) {
epicsInt32 temp=integerVal;
if(integerVal !=temp)
return parse_stop;
}
if (f->nextParam < 0 ||
store_integer_value(&opts[f->nextParam], f->puser, integerVal)) {
return parse_stop;
} else {
return parse_continue;
@@ -425,19 +421,22 @@ static parse_result parse_double(chFilter *filter, double doubleVal)
const chfPluginArgDef *opts = ((chfPlugin*)filter->plug->puser)->opts;
chfFilter *f = (chfFilter*)filter->puser;
if (f->nextParam < 0 || store_double_value(&opts[f->nextParam], f->puser, doubleVal)) {
if (f->nextParam < 0 ||
store_double_value(&opts[f->nextParam], f->puser, doubleVal)) {
return parse_stop;
} else {
return parse_continue;
}
}
static parse_result parse_string(chFilter *filter, const char *stringVal, size_t stringLen)
static parse_result
parse_string(chFilter *filter, const char *stringVal, size_t stringLen)
{
const chfPluginArgDef *opts = ((chfPlugin*)filter->plug->puser)->opts;
chfFilter *f = (chfFilter*)filter->puser;
if (f->nextParam < 0 || store_string_value(&opts[f->nextParam], f->puser, stringVal, stringLen)) {
if (f->nextParam < 0 ||
store_string_value(&opts[f->nextParam], f->puser, stringVal, stringLen)) {
return parse_stop;
} else {
return parse_continue;
@@ -449,7 +448,8 @@ static parse_result parse_start_map(chFilter *filter)
return parse_continue;
}
static parse_result parse_map_key(chFilter *filter, const char *key, size_t stringLen)
static parse_result
parse_map_key(chFilter *filter, const char *key, size_t stringLen)
{
const chfPluginArgDef *cur;
const chfPluginArgDef *opts = ((chfPlugin*)filter->plug->puser)->opts;
@@ -481,31 +481,38 @@ static long channel_open(chFilter *filter)
chfPlugin *p = (chfPlugin*) filter->plug->puser;
chfFilter *f = (chfFilter*) filter->puser;
if (p->pif->channel_open) return p->pif->channel_open(filter->chan, f->puser);
else return 0;
if (p->pif->channel_open)
return p->pif->channel_open(filter->chan, f->puser);
else
return 0;
}
static void channel_register_pre(chFilter *filter,
chPostEventFunc **cb_out, void **arg_out, db_field_log *probe)
static void
channel_register_pre(chFilter *filter, chPostEventFunc **cb_out,
void **arg_out, db_field_log *probe)
{
chfPlugin *p = (chfPlugin*) filter->plug->puser;
chfFilter *f = (chfFilter*) filter->puser;
if (p->pif->channelRegisterPre)
p->pif->channelRegisterPre(filter->chan, f->puser, cb_out, arg_out, probe);
p->pif->channelRegisterPre(filter->chan, f->puser, cb_out, arg_out,
probe);
}
static void channel_register_post(chFilter *filter,
chPostEventFunc **cb_out, void **arg_out, db_field_log *probe)
static void
channel_register_post(chFilter *filter, chPostEventFunc **cb_out,
void **arg_out, db_field_log *probe)
{
chfPlugin *p = (chfPlugin*) filter->plug->puser;
chfFilter *f = (chfFilter*) filter->puser;
if (p->pif->channelRegisterPost)
p->pif->channelRegisterPost(filter->chan, f->puser, cb_out, arg_out, probe);
p->pif->channelRegisterPost(filter->chan, f->puser, cb_out, arg_out,
probe);
}
static void channel_report(chFilter *filter, int level, const unsigned short indent)
static void channel_report(chFilter *filter, int level,
const unsigned short indent)
{
chfPlugin *p = (chfPlugin*) filter->plug->puser;
chfFilter *f = (chfFilter*) filter->puser;
@@ -525,11 +532,20 @@ static void channel_close(chFilter *filter)
free(f); /* FIXME: Use a free-list */
}
static void plugin_free(void* puser)
{
chfPlugin *p=puser;
free(p->required);
free(p);
}
/*
* chFilterIf for the wrapper
* we just support a simple one-level map, and no arrays
*/
static chFilterIf wrapper_fif = {
plugin_free,
parse_start,
parse_abort,
parse_end,
@@ -554,7 +570,8 @@ static chFilterIf wrapper_fif = {
channel_close
};
const char* chfPluginEnumString(const chfPluginEnumType *emap, int i, const char* def)
const char*
chfPluginEnumString(const chfPluginEnumType *emap, int i, const char* def)
{
for(; emap && emap->name; emap++) {
if ( i == emap->value ) {
@@ -564,7 +581,9 @@ const char* chfPluginEnumString(const chfPluginEnumType *emap, int i, const char
return def;
}
int chfPluginRegister(const char* key, const chfPluginIf *pif, const chfPluginArgDef* opts)
int
chfPluginRegister(const char* key, const chfPluginIf *pif,
const chfPluginArgDef* opts)
{
chfPlugin *p;
size_t i;
@@ -576,25 +595,22 @@ int chfPluginRegister(const char* key, const chfPluginIf *pif, const chfPluginAr
switch(cur->optType) {
case chfPluginArgInt32:
if (cur->size < sizeof(epicsInt32)) {
errlogPrintf("Plugin %s: provided storage (%d bytes) for %s is too small for epicsInt32 (%lu)\n",
key, cur->size, cur->name,
(unsigned long) sizeof(epicsInt32));
errlogPrintf("Plugin %s: %d bytes too small for epicsInt32 %s\n",
key, cur->size, cur->name);
return -1;
}
break;
case chfPluginArgBoolean:
if (cur->size < 1) {
errlogPrintf("Plugin %s: provided storage (%d bytes) for %s is too small for boolean (%lu)\n",
key, cur->size, cur->name,
(unsigned long) sizeof(char));
errlogPrintf("Plugin %s: %d bytes too small for boolean %s\n",
key, cur->size, cur->name);
return -1;
}
break;
case chfPluginArgDouble:
if (cur->size < sizeof(double)) {
errlogPrintf("Plugin %s: provided storage (%d bytes) for %s is too small for double (%lu)\n",
key, cur->size, cur->name,
(unsigned long) sizeof(double));
errlogPrintf("Plugin %s: %d bytes too small for double %s\n",
key, cur->size, cur->name);
return -1;
}
break;
@@ -603,17 +619,15 @@ int chfPluginRegister(const char* key, const chfPluginIf *pif, const chfPluginAr
/* Catch if someone has given us a char* instead of a char[]
* Also means that char buffers must be >=4.
*/
errlogPrintf("Plugin %s: provided storage (%d bytes) for %s is too small for string (>= %lu)\n",
key, cur->size, cur->name,
(unsigned long) sizeof(char*));
errlogPrintf("Plugin %s: %d bytes too small for string %s\n",
key, cur->size, cur->name);
return -1;
}
break;
case chfPluginArgEnum:
if (cur->size < sizeof(int)) {
errlogPrintf("Plugin %s: provided storage (%d bytes) for %s is too small for enum (%lu)\n",
key, cur->size, cur->name,
(unsigned long) sizeof(int));
errlogPrintf("Plugin %s: %d bytes too small for enum %s\n",
key, cur->size, cur->name);
return -1;
}
break;
@@ -628,7 +642,7 @@ int chfPluginRegister(const char* key, const chfPluginIf *pif, const chfPluginAr
/* Bit array used to find missing required keys */
reqd = dbCalloc((i/32)+1, sizeof(epicsUInt32));
if (!reqd) {
fprintf(stderr,"Plugin %s: bit array calloc failed\n", key);
errlogPrintf("Plugin %s: bit array calloc failed\n", key);
return -1;
}

View File

@@ -44,11 +44,12 @@ struct db_field_log;
*
* typedef struct myStruct {
* ... other stuff
* epicsUInt32 ival;
* epicsInt32 ival;
* double dval;
* epicsUInt32 ival2;
* epicsInt32 ival2;
* int enumval;
* char strval[20];
* char boolval;
* } myStruct;
*
* static const
@@ -61,6 +62,7 @@ struct db_field_log;
* chfDouble(myStruct, dval, "Double" , 1, 0),
* chfString(myStruct, strval , "String" , 1, 0),
* chfEnum (myStruct, enumval, "Color" , 1, 0, colorEnum),
* chfBoolean(myStruct, boolval, "Bool" , 1, 0),
* chfPluginEnd
* };
*

View File

@@ -584,6 +584,8 @@ long dbChannelOpen(dbChannel *chan)
}
/* Set up type probe */
probe.type = dbfl_type_val;
probe.ctx = dbfl_context_read;
probe.field_type = dbChannelFieldType(chan);
probe.no_elements = dbChannelElements(chan);
probe.field_size = dbChannelFieldSize(chan);

View File

@@ -72,6 +72,10 @@ typedef enum {
/* These routines must be implemented by each filter plug-in */
typedef struct chFilterIf {
/* cleanup pointer passed to dbRegisterFilter().
* Called during DB shutdown
*/
void (* priv_free)(void *puser);
/* Parsing event handlers: */
parse_result (* parse_start)(chFilter *filter);
/* If parse_start() returns parse_continue for a filter, one of

View File

@@ -74,6 +74,7 @@ struct event_user {
epicsMutexId lock;
epicsEventId ppendsem; /* Wait while empty */
epicsEventId pflush_sem; /* wait for flush */
epicsEventId pexitsem; /* wait for event task to join */
EXTRALABORFUNC *extralabor_sub;/* off load to event task */
void *extralabor_arg;/* parameter to above */
@@ -276,35 +277,44 @@ dbEventCtx epicsShareAPI db_init_events (void)
return NULL;
}
/* Flag will be cleared when event task starts */
evUser->pendexit = TRUE;
evUser->firstque.evUser = evUser;
evUser->firstque.writelock = epicsMutexCreate();
if (!evUser->firstque.writelock) {
return NULL;
}
if (!evUser->firstque.writelock)
goto fail;
evUser->ppendsem = epicsEventCreate(epicsEventEmpty);
if (!evUser->ppendsem) {
epicsMutexDestroy (evUser->firstque.writelock);
return NULL;
}
if (!evUser->ppendsem)
goto fail;
evUser->pflush_sem = epicsEventCreate(epicsEventEmpty);
if (!evUser->pflush_sem) {
epicsMutexDestroy (evUser->firstque.writelock);
epicsEventDestroy (evUser->ppendsem);
return NULL;
}
if (!evUser->pflush_sem)
goto fail;
evUser->lock = epicsMutexCreate();
if (!evUser->lock) {
epicsMutexDestroy (evUser->firstque.writelock);
epicsEventDestroy (evUser->pflush_sem);
epicsEventDestroy (evUser->ppendsem);
return NULL;
}
if (!evUser->lock)
goto fail;
evUser->pexitsem = epicsEventCreate(epicsEventEmpty);
if (!evUser->pexitsem)
goto fail;
evUser->flowCtrlMode = FALSE;
evUser->extraLaborBusy = FALSE;
evUser->pSuicideEvent = NULL;
return (dbEventCtx) evUser;
fail:
if(evUser->lock)
epicsMutexDestroy (evUser->lock);
if(evUser->firstque.writelock)
epicsMutexDestroy (evUser->firstque.writelock);
if(evUser->ppendsem)
epicsEventDestroy (evUser->ppendsem);
if(evUser->pflush_sem)
epicsEventDestroy (evUser->pflush_sem);
if(evUser->pexitsem)
epicsEventDestroy (evUser->pexitsem);
freeListFree(dbevEventUserFreeList,evUser);
return NULL;
}
/*
@@ -328,10 +338,26 @@ void epicsShareAPI db_close_events (dbEventCtx ctx)
* hazardous to the system's health.
*/
epicsMutexMustLock ( evUser->lock );
evUser->pendexit = TRUE;
if(!evUser->pendexit) { /* event task running */
evUser->pendexit = TRUE;
epicsMutexUnlock ( evUser->lock );
/* notify the waiting task */
epicsEventSignal(evUser->ppendsem);
/* wait for task to exit */
epicsEventMustWait(evUser->pexitsem);
epicsMutexMustLock ( evUser->lock );
}
epicsMutexUnlock ( evUser->lock );
/* notify the waiting task */
epicsEventSignal(evUser->ppendsem);
epicsEventDestroy(evUser->pexitsem);
epicsEventDestroy(evUser->ppendsem);
epicsEventDestroy(evUser->pflush_sem);
epicsMutexDestroy(evUser->lock);
freeListFree(dbevEventUserFreeList, evUser);
}
/*
@@ -824,7 +850,7 @@ void epicsShareAPI db_post_single_event (dbEventSubscription event)
pLog = db_create_event_log(pevent);
pLog = dbChannelRunPreChain(pevent->chan, pLog);
db_queue_event_log(pevent, pLog);
if(pLog) db_queue_event_log(pevent, pLog);
dbScanUnlock (prec);
}
@@ -1006,14 +1032,10 @@ static void event_task (void *pParm)
}
}
epicsEventDestroy(evUser->ppendsem);
epicsEventDestroy(evUser->pflush_sem);
epicsMutexDestroy(evUser->lock);
freeListFree(dbevEventUserFreeList, evUser);
taskwdRemove(epicsThreadGetIdSelf());
epicsEventSignal(evUser->pexitsem);
return;
}
@@ -1037,7 +1059,6 @@ int epicsShareAPI db_start_events (
return DB_EVENT_OK;
}
evUser->pendexit = FALSE;
evUser->init_func = init_func;
evUser->init_func_arg = init_func_arg;
if (!taskname) {
@@ -1051,6 +1072,7 @@ int epicsShareAPI db_start_events (
epicsMutexUnlock ( evUser->lock );
return DB_EVENT_ERROR;
}
evUser->pendexit = FALSE;
epicsMutexUnlock ( evUser->lock );
return DB_EVENT_OK;
}

View File

@@ -73,6 +73,13 @@ struct dbfl_val {
union native_value field; /* Field value */
};
/* External data reference.
* If dtor is provided then it should be called when the referenced
* data is no longer needed. This is done automatically by
* db_delete_field_log(). Any code which changes a dbfl_type_ref
* field log to another type, or to reference different data,
* must explicitly call the dtor function.
*/
struct dbfl_ref {
dbfl_freeFunc *dtor; /* Callback to free filter-allocated resources */
void *pvt; /* Private pointer */
@@ -81,7 +88,9 @@ struct dbfl_ref {
typedef struct db_field_log {
enum dbfl_type type:2; /* type (union) selector */
/* ctx is used for all types */
enum dbfl_context ctx:1; /* context (operation type) */
/* the following are used for value and reference types */
epicsTimeStamp time; /* Time stamp */
unsigned short stat; /* Alarm Status */
unsigned short sevr; /* Alarm Severity */
@@ -94,6 +103,29 @@ typedef struct db_field_log {
} u;
} db_field_log;
/*
* A db_field_log will in one of three types:
*
* dbfl_type_rec - Reference to record
* The field log stores no data itself. Data must instead be taken
* via the dbChannel* which must always be provided when along
* with the field log.
* For this type only the 'type' and 'ctx' members are used.
*
* dbfl_type_ref - Reference to outside value
* Used for variable size (array) data types. Meta-data
* is stored in the field log, but value data is stored externally
* (see struct dbfl_ref).
* For this type all meta-data members are used. The dbfl_ref side of the
* data union is used.
*
* dbfl_type_val - Internal value
* Used to store small scalar data. Meta-data and value are
* present in this structure and no external references are used.
* For this type all meta-data members are used. The dbfl_val side of the
* data union is used.
*/
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
#*************************************************************************
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
@@ -10,48 +10,63 @@ TOP=../../../..
include $(TOP)/configure/CONFIG
PROD_vxWorks += dbTestHarness
PROD_RTEMS += dbTestHarness
PROD_LIBS = dbCore ca Com
TESTPROD_HOST += callbackTest
callbackTest_SRCS += callbackTest.c
dbTestHarness_SRCS += callbackTest.c
testHarness_SRCS += callbackTest.c
TESTS += callbackTest
dbTestHarness_SRCS += epicsRunDbTests.c
dbTestHarness_SRCS_RTEMS = rtemsTestHarness.c
TESTSPEC_vxWorks = dbTestHarness.munch; epicsRunDbTests
TESTSPEC_RTEMS = dbTestHarness.boot; epicsRunDbTests
TESTPROD_HOST += dbChannelTest
dbChannelTest_SRCS += dbChannelTest.c xRecord_registerRecordDeviceDriver.cpp
OBJS_IOC_vxWorks += dbChannelTest
TESTS += dbChannelTest
TESTPROD_HOST += chfPluginTest
chfPluginTest_SRCS += chfPluginTest.c xRecord_registerRecordDeviceDriver.cpp
OBJS_IOC_vxWorks += chfPluginTest
TESTS += chfPluginTest
TESTPROD_HOST += arrShorthandTest
arrShorthandTest_SRCS += arrShorthandTest.c xRecord_registerRecordDeviceDriver.cpp
OBJS_IOC_vxWorks += arrShorthandTest
TESTS += arrShorthandTest
TESTPROD_HOST += dbStateTest
dbStateTest_SRCS += dbStateTest.c
OBJS_IOC_vxWorks += dbStateTest
testHarness_SRCS += dbStateTest.c
TESTS += dbStateTest
TARGETS += $(COMMON_DIR)/dbChannelTest.dbd
dbChannelTest_DBD += xRecord.dbd
TESTPROD_HOST += dbChannelTest
dbChannelTest_SRCS += xRecord.c
dbChannelTest_SRCS += dbChannelTest.c
dbChannelTest_SRCS += dbChannelTest_registerRecordDeviceDriver.cpp
testHarness_SRCS += dbChannelTest.c
testHarness_SRCS += dbChannelTest_registerRecordDeviceDriver.cpp
TESTS += dbChannelTest
TARGETS += $(COMMON_DIR)/chfPluginTest.dbd
chfPluginTest_DBD += xRecord.dbd
TESTPROD_HOST += chfPluginTest
chfPluginTest_SRCS += xRecord.c
chfPluginTest_SRCS += chfPluginTest.c
chfPluginTest_SRCS += chfPluginTest_registerRecordDeviceDriver.cpp
testHarness_SRCS += chfPluginTest.c
testHarness_SRCS += chfPluginTest_registerRecordDeviceDriver.cpp
TESTS += chfPluginTest
TARGETS += $(COMMON_DIR)/arrShorthandTest.dbd
arrShorthandTest_DBD += xRecord.dbd
TESTPROD_HOST += arrShorthandTest
arrShorthandTest_SRCS += xRecord.c
arrShorthandTest_SRCS += arrShorthandTest.c
arrShorthandTest_SRCS += arrShorthandTest_registerRecordDeviceDriver.cpp
testHarness_SRCS += arrShorthandTest.c
testHarness_SRCS += arrShorthandTest_registerRecordDeviceDriver.cpp
TESTS += arrShorthandTest
# The testHarness runs all the test programs in a known working order.
testHarness_SRCS += epicsRunDbTests.c
testHarness_SRCS += xRecord.c
dbTestHarness_SRCS += $(testHarness_SRCS)
dbTestHarness_SRCS_RTEMS += rtemsTestHarness.c
PROD_vxWorks = dbTestHarness
PROD_RTEMS = dbTestHarness
TESTSPEC_vxWorks = dbTestHarness.munch; epicsRunDbTests
TESTSPEC_RTEMS = dbTestHarness.boot; epicsRunDbTests
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
include $(TOP)/configure/RULES
dbChannelTest$(DEP): $(COMMON_DIR)/xRecord.h
chfPluginTest$(DEP): $(COMMON_DIR)/xRecord.h
arrShorthandTest$(DEP): $(COMMON_DIR)/xRecord.h
dbStateTest$(DEP): $(COMMON_DIR)/xRecord.h
xRecord$(DEP): $(COMMON_DIR)/xRecord.h

View File

@@ -21,8 +21,10 @@
#include "chfPlugin.h"
#include "dbStaticLib.h"
#include "dbAccessDefs.h"
#include "registry.h"
#include "epicsUnitTest.h"
#include "testMain.h"
#include "osiFileName.h"
typedef struct myStruct {
epicsInt32 start;
@@ -75,9 +77,9 @@ static void testHead (char* title) {
testDiag("--------------------------------------------------------");
}
void xRecord_registerRecordDeviceDriver(struct dbBase *);
void arrShorthandTest_registerRecordDeviceDriver(struct dbBase *);
MAIN(chfPluginTest)
MAIN(arrShorthandTest)
{
dbChannel *pch;
@@ -85,11 +87,14 @@ MAIN(chfPluginTest)
db_init_events();
if (dbReadDatabase(&pdbbase, "xRecord.dbd", "..", NULL))
if (dbReadDatabase(&pdbbase, "arrShorthandTest.dbd",
"." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR
"../O.Common", NULL))
testAbort("Database description not loaded");
xRecord_registerRecordDeviceDriver(pdbbase);
if (dbReadDatabase(&pdbbase, "dbChannelTest.db", "..", NULL))
arrShorthandTest_registerRecordDeviceDriver(pdbbase);
if (dbReadDatabase(&pdbbase, "xRecord.db",
"." OSI_PATH_LIST_SEPARATOR "..", NULL))
testAbort("Test database not loaded");
testHead("Register plugin");
@@ -124,16 +129,8 @@ MAIN(chfPluginTest)
TESTGOOD("range with incr [s:i:e]", "[2:3:4]", 2, 3, 4);
dbFreeBase(pdbbase);
registryFree();
pdbbase = NULL;
return testDone();
}
#define GEN_SIZE_OFFSET
#include "xRecord.h"
#include <recSup.h>
#include <epicsExport.h>
static rset xRSET;
epicsExportAddress(rset,xRSET);

View File

@@ -15,8 +15,10 @@
#include "chfPlugin.h"
#include "dbStaticLib.h"
#include "dbAccessDefs.h"
#include "registry.h"
#include "epicsUnitTest.h"
#include "testMain.h"
#include "osiFileName.h"
#define PATTERN 0x55555555
#define TYPE_START 0xAAA
@@ -445,15 +447,22 @@ static chfPluginIf postPif = {
static int checkValues(myStruct *my,
epicsUInt32 i, int f, double d, char *s, int c) {
int ret = 1;
if (!my) return 0;
if (my->sent1 == PATTERN && my->sent2 == PATTERN && my->sent3 == PATTERN
&& my->sent4 == PATTERN && my->sent5 == PATTERN && my->sent6 == PATTERN
&& my->ival == i && my->flag == f && my->dval == d && my->enumval == c
&& (strcmp(s, my->str) == 0)) {
return 1;
} else {
return 0;
}
#define CHK(A,B,FMT) if((A)!=(B)) {testDiag("Fail: " #A " (" FMT ") != " #B " (" FMT")", A, B); ret=0;}
CHK(my->sent1, PATTERN, "%08x")
CHK(my->sent2, PATTERN, "%08x")
CHK(my->sent3, PATTERN, "%08x")
CHK(my->sent4, PATTERN, "%08x")
CHK(my->sent5, PATTERN, "%08x")
CHK(my->sent6, PATTERN, "%08x")
CHK(my->ival, i, "%08x")
CHK(my->flag, f, "%02x")
CHK(my->dval, d, "%f")
CHK(my->enumval, c, "%d")
#undef CHK
if(strcmp(s, my->str) != 0) {testDiag("Fail: my->str (%s) != s (%s)", my->str, s); ret=0;}
return ret;
}
static void testHead (char* title) {
@@ -462,7 +471,7 @@ static void testHead (char* title) {
testDiag("--------------------------------------------------------");
}
void xRecord_registerRecordDeviceDriver(struct dbBase *);
void chfPluginTest_registerRecordDeviceDriver(struct dbBase *);
MAIN(chfPluginTest)
{
@@ -484,11 +493,14 @@ MAIN(chfPluginTest)
testOk(strcmp(chfPluginEnumString(colorEnum, 3, "-"), "-") == 0,
"Enum to string: invalid index");
if (dbReadDatabase(&pdbbase, "xRecord.dbd", "..", NULL))
if (dbReadDatabase(&pdbbase, "chfPluginTest.dbd",
"." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR
"../O.Common", NULL))
testAbort("Database description not loaded");
xRecord_registerRecordDeviceDriver(pdbbase);
if (dbReadDatabase(&pdbbase, "dbChannelTest.db", "..", NULL))
chfPluginTest_registerRecordDeviceDriver(pdbbase);
if (dbReadDatabase(&pdbbase, "xRecord.db",
"." OSI_PATH_LIST_SEPARATOR "..", NULL))
testAbort("Test database not loaded");
testHead("Try to register buggy plugins");
@@ -818,15 +830,8 @@ MAIN(chfPluginTest)
drop = -1;
dbFreeBase(pdbbase);
registryFree();
pdbbase = NULL;
return testDone();
}
#define GEN_SIZE_OFFSET
#include "xRecord.h"
#include <recSup.h>
#include <epicsExport.h>
static rset xRSET;
epicsExportAddress(rset,xRSET);

View File

@@ -16,9 +16,11 @@
#include "dbChannel.h"
#include "dbStaticLib.h"
#include "dbAccessDefs.h"
#include "registry.h"
#include "recSup.h"
#include "epicsUnitTest.h"
#include "testMain.h"
#include "osiFileName.h"
/* Expected call bit definitions */
#define e_start 0x00000001
@@ -143,11 +145,11 @@ void c_close(chFilter *filter)
}
chFilterIf testIf =
{ p_start, p_abort, p_end, p_null, p_boolean, p_integer, p_double,
{ NULL, p_start, p_abort, p_end, p_null, p_boolean, p_integer, p_double,
p_string, p_start_map, p_map_key, p_end_map, p_start_array, p_end_array,
c_open, c_reg_pre, c_reg_post, c_report, c_close };
void xRecord_registerRecordDeviceDriver(struct dbBase *);
void dbChannelTest_registerRecordDeviceDriver(struct dbBase *);
MAIN(testDbChannel) /* dbChannelTest is an API routine... */
{
@@ -155,11 +157,14 @@ MAIN(testDbChannel) /* dbChannelTest is an API routine... */
testPlan(66);
if (dbReadDatabase(&pdbbase, "xRecord.dbd", "..", NULL))
if (dbReadDatabase(&pdbbase, "dbChannelTest.dbd",
"." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR
"../O.Common", NULL))
testAbort("Database description not loaded");
xRecord_registerRecordDeviceDriver(pdbbase);
if (dbReadDatabase(&pdbbase, "dbChannelTest.db", "..", NULL))
dbChannelTest_registerRecordDeviceDriver(pdbbase);
if (dbReadDatabase(&pdbbase, "xRecord.db",
"." OSI_PATH_LIST_SEPARATOR "..", NULL))
testAbort("Test database not loaded");
r = e = 0;
@@ -247,15 +252,8 @@ MAIN(testDbChannel) /* dbChannelTest is an API routine... */
testOk1(!dbChannelCreate("x.{\"scalar\":{}}"));
dbFreeBase(pdbbase);
registryFree();
pdbbase = NULL;
return testDone();
}
#define GEN_SIZE_OFFSET
#include "xRecord.h"
#include <recSup.h>
#include <epicsExport.h>
static rset xRSET;
epicsExportAddress(rset,xRSET);

View File

@@ -14,14 +14,25 @@
#include "epicsUnitTest.h"
#include "epicsExit.h"
#include "dbmf.h"
int callbackTest(void);
int dbStateTest(void);
int testDbChannel(void);
int chfPluginTest(void);
int arrShorthandTest(void);
void epicsRunDbTests(void)
{
testHarness();
runTest(callbackTest);
runTest(dbStateTest);
runTest(testDbChannel);
runTest(chfPluginTest);
runTest(arrShorthandTest);
dbmfFreeChunks();
epicsExit(0); /* Trigger test harness */
}

View File

@@ -5,10 +5,40 @@
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifdef __rtems__
#include <stdio.h>
#include <envDefs.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#endif /* __rtems__ */
extern void epicsRunDbTests(void);
int main(int argc, char **argv)
{
#ifdef __rtems__
struct stat s;
printf("Try to create /tmp\n");
umask(0);
if(mkdir("/tmp", 0777)!=0)
perror("Can't create /tmp");
if(stat("/tmp", &s)==0) {
printf("Stat /tmp: %o %u,%u\n", s.st_mode, s.st_uid, s.st_gid);
}
epicsEnvSet("TMPDIR","/tmp");
{
char name[40];
if(getcwd(name,40))
printf("Running from %s\n", name);
else
printf("Can't determine PWD");
}
#endif
epicsRunDbTests(); /* calls epicsExit(0) */
return 0;
}

25
src/ioc/db/test/xRecord.c Normal file
View File

@@ -0,0 +1,25 @@
/*************************************************************************\
* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2010 Brookhaven National Laboratory.
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
* fuer Materialien und Energie GmbH.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Andrew Johnson <anj@aps.anl.gov>
* Ralph Lange <Ralph.Lange@bessy.de>
*/
#include "dbAccessDefs.h"
#include <recSup.h>
#define GEN_SIZE_OFFSET
#include "xRecord.h"
#include <epicsExport.h>
static rset xRSET;
epicsExportAddress(rset,xRSET);

View File

@@ -31,6 +31,7 @@
#include "epicsStdlib.h"
#include "epicsString.h"
#include "epicsStdio.h"
#include "dbChannel.h"
#define epicsExportSharedSymbols
#include "link.h"
@@ -592,6 +593,8 @@ void epicsShareAPI dbFreeBase(dbBase *pdbbase)
drvSup *pdrvSupNext;
brkTable *pbrkTable;
brkTable *pbrkTableNext;
chFilterPlugin *pfilt;
chFilterPlugin *pfiltNext;
int i;
DBENTRY dbentry;
@@ -651,6 +654,7 @@ void epicsShareAPI dbFreeBase(dbBase *pdbbase)
ellDelete(&pdbRecordType->attributeList,&pAttribute->node);
free((void *)pAttribute->name);
free((void *)pAttribute->pdbFldDes);
free(pAttribute);
pAttribute = pAttributeNext;
}
pdbRecordTypeNext = (dbRecordType *)ellNext(&pdbRecordType->node);
@@ -722,6 +726,15 @@ void epicsShareAPI dbFreeBase(dbBase *pdbbase)
free((void *)pbrkTable);
pbrkTable = pbrkTableNext;
}
pfilt = (chFilterPlugin *)ellFirst(&pdbbase->filterList);
while(pfilt) {
pfiltNext = (chFilterPlugin *)ellNext(&pfilt->node);
free((char*)pfilt->name);
if(pfilt->fif->priv_free)
(*pfilt->fif->priv_free)(pfilt->puser);
free(pfilt);
pfilt = pfiltNext;
}
gphFreeMem(pdbbase->pgpHash);
dbPvdFreeMem(pdbbase);
dbFreePath(pdbbase);

View File

@@ -186,8 +186,7 @@ print << 'END';
}
if (executed) {
printf("Registration already done.\n");
return 0;
printf("Warning: Registration already done.\n");
}
executed = 1;

View File

@@ -16,6 +16,7 @@
#ifndef DBMF_H
#define DBMF_H
#include <stdlib.h>
#include "shareLib.h"
#ifdef __cplusplus

View File

@@ -81,6 +81,7 @@ epicsShareFunc void epicsShareAPI registryFree(void)
{
if(!gphPvt) return;
gphFreeMem(gphPvt);
gphPvt = 0;
}
epicsShareFunc int epicsShareAPI registryDump(void)

View File

@@ -93,8 +93,10 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
}
}
}
if (drop) return NULL;
else return pfl;
if (drop) {
db_delete_field_log(pfl);
return NULL;
} else return pfl;
}
static void channelRegisterPre(dbChannel *chan, void *pvt,

View File

@@ -59,6 +59,8 @@ static void * allocPvt(void)
static void freePvt(void *pvt)
{
myStruct *my = (myStruct*) pvt;
db_delete_field_log(my->lastfl);
freeListFree(myStructFreeList, pvt);
}

View File

@@ -1,5 +1,5 @@
#*************************************************************************
# Copyright (c) 2006 UChicago Argonne LLC, as Operator of Argonne
# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
@@ -10,30 +10,62 @@ TOP=../../../..
include $(TOP)/configure/CONFIG
PROD_LIBS += dbRecStd dbCore ca Com
PROD_LIBS = dbRecStd dbCore ca Com
TARGETS += $(COMMON_DIR)/tsTest.dbd
tsTest_DBD += xRecord.dbd
TESTPROD_HOST += tsTest
tsTest_SRCS += tsTest.c xRecord_registerRecordDeviceDriver.cpp
OBJS_IOC_vxWorks += tsTest
tsTest_SRCS += xRecord.c
tsTest_SRCS += tsTest.c
tsTest_SRCS += tsTest_registerRecordDeviceDriver.cpp
testHarness_SRCS += tsTest.c
testHarness_SRCS += tsTest_registerRecordDeviceDriver.cpp
TESTS += tsTest
TARGETS += $(COMMON_DIR)/dbndTest.dbd
dbndTest_DBD += xRecord.dbd
TESTPROD_HOST += dbndTest
dbndTest_SRCS += dbndTest.c xRecord_registerRecordDeviceDriver.cpp
OBJS_IOC_vxWorks += dbndTest
dbndTest_SRCS += xRecord.c
dbndTest_SRCS += dbndTest.c
dbndTest_SRCS += dbndTest_registerRecordDeviceDriver.cpp
testHarness_SRCS += dbndTest.c
testHarness_SRCS += dbndTest_registerRecordDeviceDriver.cpp
TESTS += dbndTest
TARGETS += $(COMMON_DIR)/arrTest.dbd
arrTest_DBD += arrRecord.dbd
TESTPROD_HOST += arrTest
arrTest_SRCS += arrTest.cpp arrRecord.c arrRecord_registerRecordDeviceDriver.cpp
OBJS_IOC_vxWorks += arrTest
arrTest_SRCS += arrRecord.c
arrTest_SRCS += arrTest.cpp
arrTest_SRCS += arrTest_registerRecordDeviceDriver.cpp
testHarness_SRCS += arrRecord.c
testHarness_SRCS += arrTest.cpp
testHarness_SRCS += arrTest_registerRecordDeviceDriver.cpp
TESTS += arrTest
TARGETS += $(COMMON_DIR)/syncTest.dbd
syncTest_DBD += xRecord.dbd
TESTPROD_HOST += syncTest
syncTest_SRCS += syncTest.c xRecord_registerRecordDeviceDriver.cpp
OBJS_IOC_vxWorks += syncTest
syncTest_SRCS += xRecord.c
syncTest_SRCS += syncTest.c
syncTest_SRCS += syncTest_registerRecordDeviceDriver.cpp
testHarness_SRCS += syncTest.c
testHarness_SRCS += syncTest_registerRecordDeviceDriver.cpp
TESTS += syncTest
# epicsRunFilterTests runs all the test programs in a known working order.
testHarness_SRCS += epicsRunFilterTests.c
testHarness_SRCS += xRecord.c
filterTestHarness_SRCS += $(testHarness_SRCS)
filterTestHarness_SRCS_RTEMS += rtemsTestHarness.c
PROD_vxWorks = filterTestHarness
PROD_RTEMS = filterTestHarness
TESTSPEC_vxWorks = filterTestHarness.munch; epicsRunFilterTests
TESTSPEC_RTEMS = filterTestHarness.boot; epicsRunFilterTests
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
include $(TOP)/configure/RULES

View File

@@ -28,6 +28,8 @@
#include "epicsStdio.h"
#include "envDefs.h"
#include "dbStaticLib.h"
#include "dbmf.h"
#include "registry.h"
#include "subRecord.h"
#include "dbAddr.h"
#include "dbAccess.h"
@@ -37,10 +39,11 @@
#include "dbChannel.h"
#include "epicsUnitTest.h"
#include "testMain.h"
#include "osiFileName.h"
#include "arrRecord.h"
extern "C" int arrRecord_registerRecordDeviceDriver(struct dbBase *pdbbase);
extern "C" int arrTest_registerRecordDeviceDriver(struct dbBase *pdbbase);
extern "C" void (*pvar_func_arrInitialize)(void);
#define CA_SERVER_PORT "65535"
@@ -293,6 +296,19 @@ static void check(short dbr_type) {
TEST5B(3, -8, -4, "both sides from-end");
}
static dbEventCtx evtctx;
static void arrTestCleanup(void* junk)
{
dbFreeBase(pdbbase);
registryFree();
pdbbase=0;
db_close_events(evtctx);
dbmfFreeChunks();
}
MAIN(arrTest)
{
const chFilterPlugin *plug;
@@ -304,21 +320,25 @@ MAIN(arrTest)
epicsEnvSet("EPICS_CA_SERVER_PORT", server_port);
if (dbReadDatabase(&pdbbase, "arrRecord.dbd",
"..:../../../../../dbd", NULL))
if (dbReadDatabase(&pdbbase, "arrTest.dbd",
"." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR
"../O.Common", NULL))
testAbort("Database description not loaded");
(*pvar_func_arrInitialize)();
arrRecord_registerRecordDeviceDriver(pdbbase);
arrTest_registerRecordDeviceDriver(pdbbase);
registryFunctionAdd("exit", (REGISTRYFUNCTION) exitSubroutine);
if (dbReadDatabase(&pdbbase, "arrTest.db", "..", NULL))
if (dbReadDatabase(&pdbbase, "arrTest.db",
"." OSI_PATH_LIST_SEPARATOR "..", NULL))
testAbort("Test database not loaded");
epicsAtExit(&arrTestCleanup,NULL);
/* Start the IOC */
iocInit();
db_init_events();
evtctx = db_init_events();
epicsThreadSleep(0.2);
testOk(!!(plug = dbFindFilter(arr, strlen(arr))), "plugin arr registered correctly");
@@ -327,11 +347,5 @@ MAIN(arrTest)
check(DBR_DOUBLE);
check(DBR_STRING);
dbFreeBase(pdbbase);
return testDone();
epicsExit(EXIT_SUCCESS);
/*Note that the following statement will never be executed*/
return 0;
}

View File

@@ -16,10 +16,13 @@
#include "dbAccessDefs.h"
#include "db_field_log.h"
#include "dbCommon.h"
#include "registry.h"
#include "chfPlugin.h"
#include "epicsUnitTest.h"
#include "epicsTime.h"
#include "dbmf.h"
#include "testMain.h"
#include "osiFileName.h"
#define PATTERN 0x55
@@ -96,7 +99,7 @@ static void testHead (char* title) {
testDiag("--------------------------------------------------------");
}
void xRecord_registerRecordDeviceDriver(struct dbBase *);
void dbndTest_registerRecordDeviceDriver(struct dbBase *);
MAIN(dbndTest)
{
@@ -109,18 +112,22 @@ MAIN(dbndTest)
void *arg_out = NULL;
db_field_log *pfl2;
db_field_log fl1;
dbEventCtx evtctx;
testPlan(59);
db_init_events();
evtctx = db_init_events();
if (dbReadDatabase(&pdbbase, "xRecord.dbd", "..", NULL))
if (dbReadDatabase(&pdbbase, "dbndTest.dbd",
"." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR
"../O.Common", NULL))
testAbort("Database description not loaded");
(*pvar_func_dbndInitialize)(); /* manually initialize plugin */
xRecord_registerRecordDeviceDriver(pdbbase);
dbndTest_registerRecordDeviceDriver(pdbbase);
if (dbReadDatabase(&pdbbase, "dbChannelTest.db", "..", NULL))
if (dbReadDatabase(&pdbbase, "xRecord.db",
"." OSI_PATH_LIST_SEPARATOR "..", NULL))
testAbort("Test database not loaded");
testOk(!!(plug = dbFindFilter(dbnd, strlen(dbnd))), "plugin dbnd registered correctly");
@@ -160,9 +167,13 @@ MAIN(dbndTest)
fl_setup(pch, pfl2);
mustPassOnce(pch, pfl2, "abs", 0., 0);
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustPassOnce(pch, pfl2, "abs", 0., 1);
db_delete_field_log(pfl2);
dbChannelDelete(pch);
/* Delta = -1: pass any update */
@@ -192,11 +203,25 @@ MAIN(dbndTest)
fl_setup(pch, pfl2);
mustPassOnce(pch, pfl2, "abs", 3., 1);
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustDrop(pch, pfl2, "abs", 3., 3);
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustDrop(pch, pfl2, "abs", 3., 4);
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustPassOnce(pch, pfl2, "abs", 3., 5);
db_delete_field_log(pfl2);
dbChannelDelete(pch);
/* Delta = relative */
@@ -211,25 +236,51 @@ MAIN(dbndTest)
fl_setup(pch, pfl2);
mustPassOnce(pch, pfl2, "rel", 50., 1);
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustPassOnce(pch, pfl2, "rel", 50., 2);
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustDrop(pch, pfl2, "rel", 50., 3);
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustPassOnce(pch, pfl2, "rel", 50., 4);
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustDrop(pch, pfl2, "rel", 50., 5);
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustDrop(pch, pfl2, "rel", 50., 6);
pfl2 = db_create_read_log(pch);
testDiag("new field_log from record");
fl_setup(pch, pfl2);
mustPassOnce(pch, pfl2, "rel", 50., 7);
db_delete_field_log(pfl2);
dbChannelDelete(pch);
dbFreeBase(pdbbase);
registryFree();
pdbbase=0;
db_close_events(evtctx);
dbmfFreeChunks();
return testDone();
}
#define GEN_SIZE_OFFSET
#include "xRecord.h"
#include <recSup.h>
#include <epicsExport.h>
static rset xRSET;
epicsExportAddress(rset,xRSET);

View File

@@ -0,0 +1,33 @@
/*************************************************************************\
* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Run filter tests as a batch.
*/
#include "epicsUnitTest.h"
#include "epicsExit.h"
#include "dbmf.h"
int tsTest(void);
int dbndTest(void);
int syncTest(void);
int arrTest(void);
void epicsRunFilterTests(void)
{
testHarness();
runTest(tsTest);
runTest(dbndTest);
runTest(syncTest);
runTest(arrTest);
dbmfFreeChunks();
epicsExit(0); /* Trigger test harness */
}

View File

@@ -17,11 +17,14 @@
#include "db_field_log.h"
#include "dbCommon.h"
#include "dbChannel.h"
#include "registry.h"
#include "chfPlugin.h"
#include "dbmf.h"
#include "epicsUnitTest.h"
#include "epicsTime.h"
#include "dbState.h"
#include "testMain.h"
#include "osiFileName.h"
#define PATTERN 0x55
@@ -127,7 +130,7 @@ static void checkAndOpenChannel(dbChannel *pch, const chFilterPlugin *plug) {
checkCtxRead(pch, red);
}
void xRecord_registerRecordDeviceDriver(struct dbBase *);
void syncTest_registerRecordDeviceDriver(struct dbBase *);
MAIN(syncTest)
{
@@ -136,18 +139,22 @@ MAIN(syncTest)
char myname[] = "sync";
db_field_log *pfl[10];
int i;
dbEventCtx evtctx;
testPlan(0);
db_init_events();
evtctx = db_init_events();
if (dbReadDatabase(&pdbbase, "xRecord.dbd", "..", NULL))
if (dbReadDatabase(&pdbbase, "syncTest.dbd",
"." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR
"../O.Common", NULL))
testAbort("Database description not loaded");
(*pvar_func_syncInitialize)(); /* manually initialize plugin */
xRecord_registerRecordDeviceDriver(pdbbase);
syncTest_registerRecordDeviceDriver(pdbbase);
if (dbReadDatabase(&pdbbase, "dbChannelTest.db", "..", NULL))
if (dbReadDatabase(&pdbbase, "xRecord.db",
"." OSI_PATH_LIST_SEPARATOR "..", NULL))
testAbort("Test database not loaded");
testOk(!!(plug = dbFindFilter(myname, strlen(myname))), "plugin %s registered correctly", myname);
@@ -194,6 +201,8 @@ MAIN(syncTest)
for (i = 0; i < 10; i++)
db_delete_field_log(pfl[i]);
dbChannelDelete(pch);
/* mode UNLESS */
testHead("Mode UNLESS (m='unless', s='red')");
@@ -225,6 +234,8 @@ MAIN(syncTest)
for (i = 0; i < 10; i++)
db_delete_field_log(pfl[i]);
dbChannelDelete(pch);
/* mode BEFORE */
testHead("Mode BEFORE (m='before', s='red')");
@@ -254,8 +265,9 @@ MAIN(syncTest)
mustDrop(pch, pfl[8], "state=FALSE, log8");
mustDrop(pch, pfl[9], "state=FALSE, log9");
for (i = 0; i < 10; i++)
db_delete_field_log(pfl[i]);
db_delete_field_log(pfl[2]);
dbChannelDelete(pch);
/* mode FIRST */
@@ -285,8 +297,10 @@ MAIN(syncTest)
mustDrop(pch, pfl[7], "state=FALSE, log7");
mustDrop(pch, pfl[8], "state=FALSE, log8");
for (i = 0; i < 10; i++)
db_delete_field_log(pfl[i]);
db_delete_field_log(pfl[3]);
db_delete_field_log(pfl[9]);
dbChannelDelete(pch);
/* mode LAST */
@@ -317,8 +331,9 @@ MAIN(syncTest)
mustDrop(pch, pfl[8], "state=FALSE, log8");
mustDrop(pch, pfl[9], "state=FALSE, log9");
for (i = 0; i < 10; i++)
db_delete_field_log(pfl[i]);
db_delete_field_log(pfl[5]);
dbChannelDelete(pch);
/* mode AFTER */
@@ -348,20 +363,17 @@ MAIN(syncTest)
mustDrop(pch, pfl[7], "state=FALSE, log7");
mustDrop(pch, pfl[8], "state=FALSE, log8");
for (i = 0; i < 10; i++)
db_delete_field_log(pfl[i]);
db_delete_field_log(pfl[6]);
db_delete_field_log(pfl[9]);
dbChannelDelete(pch);
dbFreeBase(pdbbase);
registryFree();
pdbbase=0;
db_close_events(evtctx);
dbmfFreeChunks();
return testDone();
}
#define GEN_SIZE_OFFSET
#include "xRecord.h"
#include <recSup.h>
#include <epicsExport.h>
static rset xRSET;
epicsExportAddress(rset,xRSET);

View File

@@ -16,8 +16,11 @@
#include "dbAccessDefs.h"
#include "chfPlugin.h"
#include "epicsUnitTest.h"
#include "registry.h"
#include "dbmf.h"
#include "epicsTime.h"
#include "testMain.h"
#include "osiFileName.h"
#define PATTERN 0x55
@@ -36,7 +39,7 @@ static int fl_equal_ex_ts(const db_field_log *pfl1, const db_field_log *pfl2) {
return fl_equal(&fl1, pfl2);
}
void xRecord_registerRecordDeviceDriver(struct dbBase *);
void tsTest_registerRecordDeviceDriver(struct dbBase *);
MAIN(tsTest)
{
@@ -50,18 +53,22 @@ MAIN(tsTest)
db_field_log fl1;
db_field_log *pfl2;
epicsTimeStamp stamp, now;
dbEventCtx evtctx;
testPlan(12);
db_init_events();
evtctx = db_init_events();
if (dbReadDatabase(&pdbbase, "xRecord.dbd", "..", NULL))
if (dbReadDatabase(&pdbbase, "tsTest.dbd",
"." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR
"../O.Common", NULL))
testAbort("Database description not loaded");
(*pvar_func_tsInitialize)(); /* manually initialize plugin */
xRecord_registerRecordDeviceDriver(pdbbase);
tsTest_registerRecordDeviceDriver(pdbbase);
if (dbReadDatabase(&pdbbase, "dbChannelTest.db", "..", NULL))
if (dbReadDatabase(&pdbbase, "xRecord.db",
"." OSI_PATH_LIST_SEPARATOR "..", NULL))
testAbort("Test database not loaded");
testOk(!!(plug = dbFindFilter(ts, strlen(ts))), "plugin ts registered correctly");
@@ -92,6 +99,8 @@ MAIN(tsTest)
testOk(!!(pfl2 = db_create_read_log(pch)), "create field log from channel");
stamp = pfl2->time;
db_delete_field_log(pfl2);
pfl2 = dbChannelRunPreChain(pch, &fl1);
epicsTimeGetCurrent(&now);
testOk(epicsTimeDiffInSeconds(&pfl2->time, &stamp) > 0. &&
@@ -99,15 +108,12 @@ MAIN(tsTest)
dbChannelDelete(pch);
dbFreeBase(pdbbase);
registryFree();
pdbbase=0;
db_close_events(evtctx);
dbmfFreeChunks();
return testDone();
}
#define GEN_SIZE_OFFSET
#include "xRecord.h"
#include <recSup.h>
#include <epicsExport.h>
static rset xRSET;
epicsExportAddress(rset,xRSET);

View File

@@ -0,0 +1,25 @@
/*************************************************************************\
* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2010 Brookhaven National Laboratory.
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
* fuer Materialien und Energie GmbH.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Andrew Johnson <anj@aps.anl.gov>
* Ralph Lange <Ralph.Lange@bessy.de>
*/
#include "dbAccessDefs.h"
#include <recSup.h>
#define GEN_SIZE_OFFSET
#include "xRecord.h"
#include <epicsExport.h>
static rset xRSET;
epicsExportAddress(rset,xRSET);