Restructured pre- and post-event queue chains, type/size change detection

* Add new db_field_log type "probe" for type change detection
* Move linked lists for pre- and post-event-queue chains into dbChannel,
  function pointers and arguments into chFilter
* Remove set-type-chain completely
* Simplify register functions in filter and plugin interfaces
* Add functions to run the pre and post chains to dbChannel
* Refactor in db_field_log: field_size -> element_size
* Refactor in dbEvent:
  db_post_single_event_first -> db_create_event_log
  db_post_single_event_final -> db_queue_event_log (removed from public interface)
* Change tests to compile
This commit is contained in:
Ralph Lange
2012-04-27 13:21:55 -04:00
committed by Michael Davidsaver
parent b99975cf71
commit c41fcef260
10 changed files with 153 additions and 222 deletions

View File

@@ -480,38 +480,24 @@ static long channel_open(chFilter *filter)
else return 0;
}
static void channel_register_pre_eventq(chFilter *filter,
chPostEventFunc *pe_in, void *pe_arg_in,
chSetTypeFunc *st_in, void *st_arg_in,
chPostEventFunc **pe_out, void **pe_arg_out,
chSetTypeFunc **st_out, void **st_arg_out)
static void channel_register_pre(chFilter *filter,
chPostEventFunc **cb_out, void **arg_out)
{
chfPlugin *p = (chfPlugin*) filter->plug->puser;
chfFilter *f = (chfFilter*) filter->puser;
if (p->pif->channelRegisterPreEventQue)
p->pif->channelRegisterPreEventQue(filter->chan, f->puser,
pe_in, pe_arg_in,
st_in, st_arg_in,
pe_out, pe_arg_out,
st_out, st_arg_out);
if (p->pif->channelRegisterPre)
p->pif->channelRegisterPre(filter->chan, f->puser, cb_out, arg_out);
}
static void channel_register_post_eventq(chFilter *filter,
chPostEventFunc *pe_in, void *pe_arg_in,
chSetTypeFunc *st_in, void *st_arg_in,
chPostEventFunc **pe_out, void **pe_arg_out,
chSetTypeFunc **st_out, void **st_arg_out)
static void channel_register_post(chFilter *filter,
chPostEventFunc **cb_out, void **arg_out)
{
chfPlugin *p = (chfPlugin*) filter->plug->puser;
chfFilter *f = (chfFilter*) filter->puser;
if (p->pif->channelRegisterPostEventQue)
p->pif->channelRegisterPostEventQue(filter->chan, f->puser,
pe_in, pe_arg_in,
st_in, st_arg_in,
pe_out, pe_arg_out,
st_out, st_arg_out);
if (p->pif->channelRegisterPost)
p->pif->channelRegisterPost(filter->chan, f->puser, cb_out, arg_out);
}
static void channel_report(chFilter *filter, const char *intro, int level)
@@ -519,7 +505,8 @@ static void channel_report(chFilter *filter, const char *intro, int level)
chfPlugin *p = (chfPlugin*) filter->plug->puser;
chfFilter *f = (chfFilter*) filter->puser;
if (p->pif->channel_report) p->pif->channel_report(filter->chan, f->puser, intro, level);
if (p->pif->channel_report)
p->pif->channel_report(filter->chan, f->puser, intro, level);
}
static void channel_close(chFilter *filter)
@@ -556,8 +543,8 @@ static chFilterIf wrapper_fif = {
NULL, /* parse_end_array, */
channel_open,
channel_register_pre_eventq,
channel_register_post_eventq,
channel_register_pre,
channel_register_post,
channel_report,
channel_close
};

View File

@@ -137,38 +137,19 @@ typedef struct chfPluginIf {
* This function is called to establish the stack of plugins that an event
* is passed through between the database and the event queue.
*
* The plugin must call the supplied 'pe_in' function (usually within
* its own post-event callback) with 'pe_arg_in' as first argument to forward
* the data to the next plugin towards the event queue.
* It must set pe_out to point to its own post-event callback in order to be
* called when a data update is sent from the database towards the event queue.
*
* The plugin must call the supplied 'st_in' function (from within
* its own set-type callback) with 'st_arg_in' as first argument after changing
* the data type and/or array size of 'chan'.
* The plugin must set pe_out to point to its own post-event callback in order
* to be called when a data update is sent from the database towards the
* event queue.
*
* @param chan dbChannel for which the connection is being made.
* @param pvt Pointer to private structure.
* @param pe_in Pointer to the next plugin's post-event callback
* @param pe_arg_in Argument that must be supplied when this plugin calls
* the next plugin's post-event callback
* @param st_in Pointer to the next plugin's set-type callback
* @param st_arg_in Argument that must be supplied when this plugin calls
* the next plugin's set-type callback
* @param pe_out Pointer to this plugin's post-event callback (set to NULL to bypass
* this plugin)
* @param pe_arg_out Argument that must be supplied when calling
* this plugin's post-event callback
* @param st_out Pointer to this plugin's set-type callback (set to NULL if plugin
* does not change the data type or size)
* @param st_arg_out Argument that must be supplied when calling
* this plugin's set-type callback
* @param cb_out Pointer to this plugin's post-event callback (NULL to bypass
* this plugin).
* @param arg_out Argument that must be supplied when calling
* this plugin's post-event callback.
*/
void (* channelRegisterPreEventQue) (dbChannel *chan, void *pvt,
chPostEventFunc *pe_in, void *pe_arg_in,
chSetTypeFunc *st_in, void *st_arg_in,
chPostEventFunc **pe_out, void **pe_arg_out,
chSetTypeFunc **st_out, void **st_arg_out);
void (* channelRegisterPre) (dbChannel *chan, void *pvt,
chPostEventFunc **cb_out, void **arg_out);
/** @brief Register callbacks for post-event-queue operation.
*
@@ -178,12 +159,9 @@ typedef struct chfPluginIf {
* is passed through between the event queue and the final user (CA server or
* database access).
*
* The plugin must call the supplied 'pe_in' function (usually within
* its own post-event callback) with 'arg_in' as first argument to forward
* the data to the next plugin towards the final user.
* It must set pe_out to point to its own post-event callback in order to be
* called when a data update is sent from the event queue towards the final
* user.
* The plugin must set pe_out to point to its own post-event callback in order
* to be called when a data update is sent from the event queue towards the
* final user.
*
* The plugin must call the supplied 'st_in' function (from within
* its own set-type callback) with 'arg_in' as first argument after changing
@@ -191,26 +169,13 @@ typedef struct chfPluginIf {
*
* @param chan dbChannel for which the connection is being made.
* @param pvt Pointer to private structure.
* @param pe_in Pointer to the next plugin's post-event callback
* @param pe_arg_in Argument that must be supplied when this plugin calls
* the next plugin's post-event callback
* @param st_in Pointer to the next plugin's set-type callback
* @param st_arg_in Argument that must be supplied when this plugin calls
* the next plugin's set-type callback
* @param pe_out Pointer to this plugin's post-event callback (set to NULL to bypass
* this plugin)
* @param pe_arg_out Argument that must be supplied when calling
* this plugin's post-event callback
* @param st_out Pointer to this plugin's set-type callback (set to NULL if plugin
* does not change the data type or size)
* @param st_arg_out Argument that must be supplied when calling
* this plugin's set-type callback
* @param cb_out Pointer to this plugin's post-event callback (NULL to bypass
* this plugin).
* @param arg_out Argument that must be supplied when calling
* this plugin's post-event callback.
*/
void (* channelRegisterPostEventQue) (dbChannel *chan, void *pvt,
chPostEventFunc *pe_in, void *pe_arg_in,
chSetTypeFunc *st_in, void *st_arg_in,
chPostEventFunc **pe_out, void **pe_arg_out,
chSetTypeFunc **st_out, void **st_arg_out);
void (* channelRegisterPost) (dbChannel *chan, void *pvt,
chPostEventFunc **cb_out, void **arg_out);
/** @brief Channel report request.
*

View File

@@ -838,9 +838,9 @@ long epicsShareAPI dbGet(DBADDR *paddr, short dbrType,
} else {
DBADDR localAddr = *paddr; /* Structure copy */
localAddr.field_type = pfl->field_type;
localAddr.field_size = pfl->field_size;
localAddr.field_size = pfl->element_size;
localAddr.no_elements = pfl->no_elements;
if (pfl->type == dbfl_type_val)
if (pfl->type == dbfl_type_value)
localAddr.pfield = (char *) &pfl->u.v.field;
else
localAddr.pfield = (char *) pfl->u.r.field;
@@ -874,9 +874,9 @@ long epicsShareAPI dbGet(DBADDR *paddr, short dbrType,
} else {
DBADDR localAddr = *paddr; /* Structure copy */
localAddr.field_type = pfl->field_type;
localAddr.field_size = pfl->field_size;
localAddr.field_size = pfl->element_size;
localAddr.no_elements = pfl->no_elements;
if (pfl->type == dbfl_type_val)
if (pfl->type == dbfl_type_value)
localAddr.pfield = (char *) &pfl->u.v.field;
else
localAddr.pfield = (char *) pfl->u.r.field;

View File

@@ -346,6 +346,8 @@ dbChannel * dbChannelCreate(const char *name)
chan = (dbChannel *) callocMustSucceed(1, sizeof(*chan), "dbChannelCreate");
chan->name = strdup(name); /* FIXME: free-list */
ellInit(&chan->filters);
ellInit(&chan->pre_chain);
ellInit(&chan->post_chain);
paddr = &chan->addr;
pflddes = dbEntry.pflddes;
@@ -413,89 +415,95 @@ finish:
return chan;
}
static void setFinalType(void *pvt, long no_elements, short field_type, short element_size) {
dbChannel *chan = (dbChannel*) pvt;
db_field_log* dbChannelRunPreChain(dbChannel *chan, db_field_log *pLogIn) {
chFilter *filter;
ELLNODE *node;
db_field_log *pLog = pLogIn;
chan->final_no_elements = no_elements;
chan->final_element_size = element_size;
chan->final_type = field_type;
chan->dbr_final_type = dbDBRnewToDBRold[mapDBFToDBR[field_type]];
for (node = ellFirst(&chan->pre_chain); node; node = ellNext(node)) {
filter = CONTAINER(node, chFilter, pre_node);
pLog = filter->pre_func(filter->pre_arg, chan, pLog);
}
return pLog;
}
db_field_log* dbChannelRunPostChain(dbChannel *chan, db_field_log *pLogIn) {
chFilter *filter;
ELLNODE *node;
db_field_log *pLog = pLogIn;
for (node = ellFirst(&chan->post_chain); node; node = ellNext(node)) {
filter = CONTAINER(node, chFilter, post_node);
pLog = filter->post_func(filter->post_arg, chan, pLog);
}
return pLog;
}
long dbChannelOpen(dbChannel *chan)
{
chFilter *filter;
long status = 0;
chPostEventFunc *pre_pe_next = db_post_single_event_final;
void *pre_nextarg = NULL;
chPostEventFunc *pre_pe_this = NULL;
void *pre_thisarg = NULL;
chPostEventFunc *post_pe_next = NULL;
void *post_nextarg = NULL;
chPostEventFunc *post_pe_this = NULL;
void *post_thisarg = NULL;
chSetTypeFunc *st_next = setFinalType;
void *st_nextarg = chan;
chSetTypeFunc *st_this = NULL;
void *st_thisarg = NULL;
chPostEventFunc *func;
void *arg;
long status;
filter = (chFilter *) ellFirst(&chan->filters);
while (filter) {
status = filter->plug->fif->channel_open(filter);
if (status) goto finish;
/*
* Call channel_open for all filters
*/
status = 0;
if (filter->plug->fif->channel_open)
status = filter->plug->fif->channel_open(filter);
if (status) return status;
/*
* Build up the pre- and post-event-queue filter chains
*/
func = NULL;
arg = NULL;
if (filter->plug->fif->channel_register_post) {
filter->plug->fif->channel_register_post(filter, &func, &arg);
if (func) {
ellAdd(&chan->post_chain, &filter->post_node);
filter->post_func = func;
filter->post_arg = arg;
}
}
func = NULL;
arg = NULL;
if (filter->plug->fif->channel_register_pre) {
filter->plug->fif->channel_register_pre(filter, &func, &arg);
if (func) {
ellAdd(&chan->pre_chain, &filter->pre_node);
filter->pre_func = func;
filter->pre_arg = arg;
}
}
filter = (chFilter *) ellNext(&filter->node);
}
/*
* Build up the post-event-queue and pre-event-queue filter chains.
* Must be done top-down and separate, since there is only one callback chain
* for type/size changes.
*/
filter = (chFilter *) ellLast(&chan->filters);
while (filter && filter->plug->fif->channel_register_post_eventq) {
filter->plug->fif->channel_register_post_eventq(filter,
post_pe_next, post_nextarg,
st_next, st_nextarg,
&post_pe_this, &post_thisarg,
&st_this, &st_thisarg);
if (post_pe_this) {
post_pe_next = post_pe_this;
post_nextarg = post_thisarg;
}
if (st_this) {
st_next = st_this;
st_nextarg = st_thisarg;
}
filter = (chFilter *) ellPrevious(&filter->node);
}
chan->post_event_cb = post_pe_next;
chan->post_event_arg = post_nextarg;
/* Set up type probe */
db_field_log probe;
db_field_log *pfl;
probe.type = dbfl_type_probe;
probe.field_type = dbChannelFieldType(chan);
probe.no_elements = dbChannelElements(chan);
probe.element_size = dbChannelElementSize(chan);
filter = (chFilter *) ellLast(&chan->filters);
while (filter && filter->plug->fif->channel_register_pre_eventq) {
filter->plug->fif->channel_register_pre_eventq(filter,
pre_pe_next, pre_nextarg,
st_next, st_nextarg,
&pre_pe_this, &pre_thisarg,
&st_this, &st_thisarg);
if (pre_pe_this) {
pre_pe_next = pre_pe_this;
pre_nextarg = pre_thisarg;
}
if (st_this) {
st_next = st_this;
st_nextarg = st_thisarg;
}
filter = (chFilter *) ellPrevious(&filter->node);
}
chan->pre_event_cb = pre_pe_next;
chan->pre_event_arg = pre_nextarg;
/* Call filter chains to determine data type/size changes */
pfl = dbChannelRunPreChain(chan, &probe);
if (pfl != &probe) return -1;
pfl = dbChannelRunPostChain(chan, &probe);
if (pfl != &probe) return -1;
/* Call filter chain to determine data type/size changes */
if (st_next) st_next(st_nextarg, chan->addr.no_elements, chan->addr.field_type, chan->addr.field_size);
/* Save probe results */
chan->final_no_elements = probe.no_elements;
chan->final_element_size = probe.element_size;
chan->final_type = probe.field_type;
chan->dbr_final_type = dbDBRnewToDBRold[mapDBFToDBR[probe.field_type]];
finish:
return status;
return 0;
}
/* FIXME: For performance we should make these one-liners into macros,

View File

@@ -41,26 +41,21 @@ typedef struct evSubscrip {
typedef struct chFilter chFilter;
/* Prototype for the post event function that is called recursively in filter stacks */
typedef void (chPostEventFunc)(void *pvt, struct evSubscrip *event, db_field_log *pLog);
/* A dbChannel points to a record field, and can have multiple filters */
typedef struct dbChannel {
const char *name;
dbAddr addr;
dbAddr addr; /* address structure for record/field */
long final_no_elements; /* final number of elements (arrays) */
short final_element_size; /* final size of element */
short final_type; /* final type of database field */
short dbr_final_type; /* final field type as seen by database request */
chPostEventFunc *pre_event_cb;
void *pre_event_arg;
chPostEventFunc *post_event_cb;
void *post_event_arg;
ELLLIST filters;
ELLLIST filters; /* list of filters as created from JSON */
ELLLIST pre_chain; /* list of filters to be called pre-event-queue */
ELLLIST post_chain; /* list of filters to be called post-event-queue */
} dbChannel;
/* Prototype for the set type function that is called recursively in filter stacks */
typedef void (chSetTypeFunc)(void *pvt, long no_elements, short field_type, short element_size);
/* Prototype for the post event function that is called in filter stacks */
typedef db_field_log* (chPostEventFunc)(void *pvt, dbChannel *chan, db_field_log *pLog);
/* Return values from chFilterIf->parse_* routines: */
typedef enum {
@@ -102,16 +97,8 @@ typedef struct chFilterIf {
/* Channel operations: */
long (* channel_open)(chFilter *filter);
void (* channel_register_pre_eventq) (chFilter *filter,
chPostEventFunc *pe_in, void *arg_pe_in,
chSetTypeFunc *st_in, void *arg_st_in,
chPostEventFunc **pe_out, void **arg_pe_out,
chSetTypeFunc **st_out, void **arg_st_out);
void (* channel_register_post_eventq)(chFilter *filter,
chPostEventFunc *pe_in, void *arg_pe_in,
chSetTypeFunc *st_in, void *arg_st_in,
chPostEventFunc **pe_out, void **arg_pe_out,
chSetTypeFunc **st_out, void **arg_st_out);
void (* channel_register_pre) (chFilter *filter, chPostEventFunc **cb_out, void **arg_out);
void (* channel_register_post)(chFilter *filter, chPostEventFunc **cb_out, void **arg_out);
void (* channel_report)(chFilter *filter, const char *intro, int level);
/* FIXME: More filter routines here ... */
void (* channel_close)(chFilter *filter);
@@ -128,8 +115,14 @@ typedef struct chFilterPlugin {
/* A chFilter holds data for a single filter instance */
struct chFilter {
ELLNODE node;
ELLNODE pre_node;
ELLNODE post_node;
dbChannel *chan;
const chFilterPlugin *plug;
chPostEventFunc *pre_func;
void *pre_arg;
chPostEventFunc *post_func;
void *post_arg;
void *puser;
};
@@ -167,6 +160,8 @@ epicsShareFunc void dbChannelFilterShow(dbChannel *chan, const char *intro,
epicsShareFunc void dbChannelDelete(dbChannel *chan);
epicsShareFunc void dbRegisterFilter(const char *key, const chFilterIf *fif, void *puser);
epicsShareFunc db_field_log* dbChannelRunPreChain(dbChannel *chan, db_field_log *pLogIn);
epicsShareFunc db_field_log* dbChannelRunPostChain(dbChannel *chan, db_field_log *pLogIn);
epicsShareFunc const chFilterPlugin * dbFindFilter(const char *key, size_t len);
#ifdef __cplusplus

View File

@@ -621,20 +621,20 @@ int epicsShareAPI db_post_extra_labor (dbEventCtx ctx)
}
/*
* DB_POST_SINGLE_EVENT_FIRST()
* DB_CREATE_EVENT_LOG()
*
* NOTE: This assumes that the db scan lock is already applied
* (as it copies data from the record)
*/
db_field_log* db_post_single_event_first (struct evSubscrip *pevent)
static db_field_log* db_create_event_log (struct evSubscrip *pevent)
{
db_field_log *pLog = (db_field_log *) freeListCalloc(dbevFieldLogFreeList);;
db_field_log *pLog = (db_field_log *) freeListCalloc(dbevFieldLogFreeList);
if (pLog) {
struct dbChannel *chan = pevent->chan;
struct dbCommon *prec = dbChannelRecord(chan);
if (pevent->useValque) {
pLog->type = dbfl_type_val;
pLog->type = dbfl_type_value;
pLog->stat = prec->stat;
pLog->sevr = prec->sevr;
pLog->time = prec->time;
@@ -656,10 +656,10 @@ db_field_log* db_post_single_event_first (struct evSubscrip *pevent)
}
/*
* DB_POST_SINGLE_EVENT_FINAL()
* DB_QUEUE_EVENT_LOG()
*
*/
void db_post_single_event_final (void *pvt, evSubscrip *pevent, db_field_log *pLog)
static void db_queue_event_log (evSubscrip *pevent, db_field_log *pLog)
{
struct event_que *ev_que;
int firstEventFlag;
@@ -783,10 +783,9 @@ unsigned int caEventMask
*/
if ( (dbChannelField(pevent->chan) == (void *)pField || pField==NULL) &&
(caEventMask & pevent->select)) {
/* Call the head of the filter chain */
pevent->chan->pre_event_cb(pevent->chan->pre_event_arg,
pevent,
db_post_single_event_first(pevent));
db_field_log *pLog = db_create_event_log(pevent);
pLog = dbChannelRunPreChain(pevent->chan, pLog);
db_queue_event_log(pevent, pLog);
}
}
@@ -805,10 +804,9 @@ void epicsShareAPI db_post_single_event (dbEventSubscription event)
dbScanLock (prec);
/* Call the head of the filter chain */
pevent->chan->pre_event_cb(pevent->chan->pre_event_arg,
pevent,
db_post_single_event_first(pevent));
db_field_log *pLog = db_create_event_log(pevent);
pLog = dbChannelRunPreChain(pevent->chan, pLog);
db_queue_event_log(pevent, pLog);
dbScanUnlock (prec);
}

View File

@@ -72,7 +72,6 @@ epicsShareFunc void epicsShareAPI db_cancel_event (dbEventSubscription es);
epicsShareFunc void epicsShareAPI db_post_single_event (dbEventSubscription es);
epicsShareFunc void epicsShareAPI db_event_enable (dbEventSubscription es);
epicsShareFunc void epicsShareAPI db_event_disable (dbEventSubscription es);
epicsShareFunc void epicsShareAPI db_post_single_event_final (void *pvt, struct evSubscrip *pevent, struct db_field_log *pLog);
epicsShareFunc void epicsShareAPI db_delete_field_log (struct db_field_log *pfl);

View File

@@ -52,11 +52,12 @@ typedef void (dbfl_freeFunc)(struct db_field_log *pfl);
/* Types of db_field_log: rec = use record, val = val inside, ref = reference inside */
typedef enum dbfl_type {
dbfl_type_rec = 0,
dbfl_type_val,
dbfl_type_ref
dbfl_type_value,
dbfl_type_ref,
dbfl_type_probe
} dbfl_type;
#define dbflTypeStr(t) (t==dbfl_type_val?"val":t==dbfl_type_rec?"rec":"ref")
#define dbflTypeStr(t) (t==dbfl_type_value?"val":t==dbfl_type_rec?"rec":t==dbfl_type_probe?"prb":"ref")
struct dbfl_val {
union native_value field; /* Field value */
@@ -74,7 +75,7 @@ typedef struct db_field_log {
unsigned short stat; /* Alarm Status */
unsigned short sevr; /* Alarm Severity */
short field_type; /* DBF type of data */
short field_size; /* Data size */
short element_size; /* Data size */
long no_elements; /* No of array elements */
union {
struct dbfl_val v;

View File

@@ -44,14 +44,6 @@ typedef struct myStruct {
int sent6;
char c;
char c1[2];
chPostEventFunc *pe_pre;
void *pe_pre_arg;
chPostEventFunc *pe_post;
void *pe_post_arg;
chPostEventFunc *st_pre;
void *st_pre_arg;
chPostEventFunc *st_post;
void *st_post_arg;
} myStruct;
static const
@@ -173,26 +165,16 @@ static long channel_open(dbChannel *chan, void *user)
return c_open_return;
}
static void channelRegisterPreEventQue(dbChannel *chan, void *user,
chPostEventFunc *pe_in, void *pe_arg_in,
chSetTypeFunc *st_in, void *st_arg_in,
chPostEventFunc **pe_out, void **pe_arg_out,
chSetTypeFunc **st_out, void **st_arg_out)
static void channelRegisterPre(dbChannel *chan, void *user,
chPostEventFunc **cb_out, void **arg_out)
{
myStruct *my = (myStruct*)user;
my->pe_pre = pe_in;
my->pe_pre_arg = pe_arg_in;
}
static void channelRegisterPostEventQue(dbChannel *chan, void *user,
chPostEventFunc *pe_in, void *pe_arg_in,
chSetTypeFunc *st_in, void *st_arg_in,
chPostEventFunc **pe_out, void **pe_arg_out,
chSetTypeFunc **st_out, void **st_arg_out)
static void channelRegisterPost(dbChannel *chan, void *user,
chPostEventFunc **cb_out, void **arg_out)
{
myStruct *my = (myStruct*)user;
my->pe_post = pe_in;
my->pe_post_arg = pe_arg_in;
}
static void channel_report(dbChannel *chan, void *user, const char *intro, int level)
@@ -217,8 +199,8 @@ static chfPluginIf myPif = {
parse_ok,
channel_open,
channelRegisterPreEventQue,
channelRegisterPostEventQue,
channelRegisterPre,
channelRegisterPost,
channel_report,
channel_close
};

View File

@@ -116,17 +116,13 @@ long c_open(chFilter *filter)
testOk(e & e_open, "channel_open called");
return 0;
}
void c_reg_pre(chFilter *filter,
chPostEventFunc *pe_in, void *pe_arg_in, chSetTypeFunc *st_in, void *st_arg_in,
chPostEventFunc **pe_out, void **arg_out, chSetTypeFunc **st_out, void **st_arg_out)
void c_reg_pre(chFilter *filter, chPostEventFunc **cb_out, void **arg_out)
{
testOk(e & e_reg_pre, "channel_register_pre_event_queue called");
testOk(e & e_reg_pre, "channel_register_pre called");
}
void c_reg_post(chFilter *filter,
chPostEventFunc *pe_in, void *pe_arg_in, chSetTypeFunc *st_in, void *st_arg_in,
chPostEventFunc **pe_out, void **arg_out, chSetTypeFunc **st_out, void **st_arg_out)
void c_reg_post(chFilter *filter, chPostEventFunc **cb_out, void **arg_out)
{
testOk(e & e_reg_post, "channel_register_post_event_queue called");
testOk(e & e_reg_post, "channel_register_post called");
}
void c_report(chFilter *filter, const char *intro, int level)
{