From 0d8725857bf4ba66efce8f10e6ed2303ce9f5a16 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Wed, 27 Oct 2010 21:56:12 +0200 Subject: [PATCH] new approach to handle named events efficiently --- src/db/dbScan.c | 163 +++++++++++++++++---------------- src/db/dbScan.h | 4 +- src/dev/softDev/devEventSoft.c | 8 +- src/rec/calcoutRecord.c | 11 ++- src/rec/calcoutRecord.dbd | 8 ++ src/rec/eventRecord.c | 23 ++++- src/rec/eventRecord.dbd | 8 ++ 7 files changed, 136 insertions(+), 89 deletions(-) diff --git a/src/db/dbScan.c b/src/db/dbScan.c index 32740a53a..5ba5500a9 100644 --- a/src/db/dbScan.c +++ b/src/db/dbScan.c @@ -101,14 +101,13 @@ static char *priorityName[NUM_CALLBACK_PRIORITIES] = { /* EVENT */ -typedef struct event_scan_list { - CALLBACK callback; - scan_list scan_list; - struct event_scan_list *next; +typedef struct event_list { + CALLBACK callback[NUM_CALLBACK_PRIORITIES]; + scan_list scan_list[NUM_CALLBACK_PRIORITIES]; + struct event_list *next; char event_name[MAX_STRING_SIZE]; -} event_scan_list; -static event_scan_list *pevent_list[NUM_CALLBACK_PRIORITIES]; -static epicsMutexId event_list_lock[NUM_CALLBACK_PRIORITIES]; +} event_list; +static event_list * volatile pevent_list[256]; /* IO_EVENT*/ @@ -206,47 +205,24 @@ void scanAdd(struct dbCommon *precord) recGblRecordError(-1, (void *)precord, "scanAdd detected illegal SCAN value"); } else if (scan == menuScanEvent) { - char* evnt; + char* eventname; int prio; - event_scan_list *pesl; + event_list *pel; - evnt = precord->evnt; - if (*evnt == 0) { - recGblRecordError(S_db_badField, (void *)precord, - "scanAdd: illegal empty EVNT value"); - /*precord->scan = menuScanPassive;*/ - return; - } - if (strlen(evnt) >= MAX_STRING_SIZE) { + eventname = precord->evnt; + if (strlen(eventname) >= MAX_STRING_SIZE) { recGblRecordError(S_db_badField, (void *)precord, "scanAdd: too long EVNT value"); - /*precord->scan = menuScanPassive;*/ return; } prio = precord->prio; if (prio < 0 || prio >= NUM_CALLBACK_PRIORITIES) { recGblRecordError(-1, (void *)precord, "scanAdd: illegal prio field"); - /*precord->scan = menuScanPassive;*/ return; } - epicsMutexMustLock(event_list_lock[prio]); - for (pesl = pevent_list[prio]; pesl; pesl=pesl->next) { - if (strcmp(pesl->event_name, evnt) == 0) break; - } - if (pesl == NULL) { - pesl = dbCalloc(1, sizeof(event_scan_list)); - strcpy(pesl->event_name, evnt); - pesl->scan_list.lock = epicsMutexMustCreate(); - callbackSetCallback(eventCallback, &pesl->callback); - callbackSetPriority(prio, &pesl->callback); - callbackSetUser(pesl, &pesl->callback); - ellInit(&pesl->scan_list.list); - pesl->next=pevent_list[prio]; - pevent_list[prio]=pesl; - } - epicsMutexUnlock(event_list_lock[prio]); - addToList(precord, &pesl->scan_list); + pel = eventNameToHandle(eventname); + if (pel) addToList(precord, &pel->scan_list[prio]); } else if (scan == menuScanI_O_Intr) { io_scan_list *piosl = NULL; int prio; @@ -301,25 +277,25 @@ void scanDelete(struct dbCommon *precord) recGblRecordError(-1, (void *)precord, "scanDelete detected illegal SCAN value"); } else if (scan == menuScanEvent) { - char* evnt; + char* eventname; int prio; - event_scan_list *pesl; + event_list *pel; scan_list *psl = 0; - evnt = precord->evnt; + eventname = precord->evnt; prio = precord->prio; if (prio < 0 || prio >= NUM_CALLBACK_PRIORITIES) { recGblRecordError(-1, (void *)precord, "scanDelete detected illegal PRIO field"); return; } - epicsMutexMustLock(event_list_lock[prio]); - pesl = pevent_list[prio]; - epicsMutexUnlock(event_list_lock[prio]); - for (; pesl; pesl=pesl->next) { - if (strcmp(pesl->event_name, evnt) == 0) break; + do /* multitheading: make sure pel is consistent */ + pel = pevent_list[0]; + while (pel != pevent_list[0]); + for (; pel; pel=pel->next) { + if (strcmp(pel->event_name, eventname) == 0) break; } - if (pesl && (psl = &pesl->scan_list)) + if (pel && (psl = &pel->scan_list[prio])) deleteFromList(precord, psl); } else if (scan == menuScanI_O_Intr) { io_scan_list *piosl=NULL; @@ -380,21 +356,21 @@ int scanppl(double period) /* print periodic list */ return 0; } -int scanpel(char* evnt) /* print event list */ +int scanpel(char* eventname) /* print event list */ { char message[80]; int prio; - event_scan_list *pesl; + event_list *pel; - for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) { - epicsMutexMustLock(event_list_lock[prio]); - pesl = pevent_list[prio]; - epicsMutexUnlock(event_list_lock[prio]); - for (; pesl; pesl = pesl->next) { - if (!evnt || strcmp(pesl->event_name, evnt) == 0) { - if (ellCount(&pesl->scan_list.list) == 0) continue; - sprintf(message, "Event \"%s\" Priority %s", pesl->event_name, priorityName[prio]); - printList(&pesl->scan_list, message); + do /* multitheading: make sure pel is consistent */ + pel = pevent_list[0]; + while (pel != pevent_list[0]); + for (; pel; pel = pel->next) { + if (!eventname || strcmp(pel->event_name, eventname) == 0) { + for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) { + if (ellCount(&pel->scan_list[prio].list) == 0) continue; + sprintf(message, "Event \"%s\" Priority %s", pel->event_name, priorityName[prio]); + printList(&pel->scan_list[prio], message); } } } @@ -421,48 +397,73 @@ int scanpiol(void) /* print io_event list */ static void eventCallback(CALLBACK *pcallback) { - event_scan_list *pesl; + scan_list *psl; - callbackGetUser(pesl, pcallback); - scanList(&pesl->scan_list); + callbackGetUser(psl, pcallback); + scanList(psl); } static void initEvent(void) { - int prio; - - for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) { - pevent_list[prio] = NULL; - event_list_lock[prio] = epicsMutexMustCreate(); - } } -void post_named_event(char* evnt) +event_list *eventNameToHandle(char *eventname) { int prio; - event_scan_list *pesl; + event_list *pel; + static epicsMutexId lock = NULL; - if (scanCtl != ctlRun) return; - if (!evnt || *evnt == 0) return; - for (prio=0; prionext) { - if (strcmp(pesl->event_name, evnt) == 0) { - if (ellCount(&pesl->scan_list.list) >0) - callbackRequest((void *)pesl); - } + if (!lock) lock = epicsMutexMustCreate(); + if (!eventname || eventname[0] == 0) return NULL; + epicsMutexMustLock(lock); + for (pel = pevent_list[0]; pel; pel=pel->next) { + if (strcmp(pel->event_name, eventname) == 0) break; + } + if (pel == NULL) { + pel = dbCalloc(1, sizeof(event_list)); + strcpy(pel->event_name, eventname); + for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) { + callbackSetUser(&pel->scan_list[prio], &pel->callback[prio]); + callbackSetPriority(prio, &pel->callback[prio]); + callbackSetCallback(eventCallback, &pel->callback[prio]); + pel->scan_list[prio].lock = epicsMutexMustCreate(); + ellInit(&pel->scan_list[prio].list); + } + pel->next=pevent_list[0]; + pevent_list[0]=pel; + { /* backward compatibility */ + char* p; + long e = strtol(eventname, &p, 0); + if (*p == 0 && e > 0 && e <= 255) + pevent_list[e]=pel; } } + epicsMutexUnlock(lock); + return pel; } +void postEvent(event_list *pel) +{ + int prio; + + if (scanCtl != ctlRun) return; + if (!pel) return; + for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) { + if (ellCount(&pel->scan_list[prio].list) >0) + callbackRequest(&pel->callback[prio]); + } +} + +/* backward compatibility */ void post_event(int event) { - char event_name[10]; + event_list* pel; - sprintf(event_name, "%i", event); - post_named_event(event_name); + if (event <= 0 || event > 255) return; + do { /* multitheading: make sure pel is consistent */ + pel = pevent_list[event]; + } while (pel != pevent_list[event]); + postEvent(pel); } void scanIoInit(IOSCANPVT *ppioscanpvt) diff --git a/src/db/dbScan.h b/src/db/dbScan.h index 62e04c500..966849511 100644 --- a/src/db/dbScan.h +++ b/src/db/dbScan.h @@ -37,6 +37,7 @@ extern "C" { struct io_scan_list; typedef struct io_scan_list *IOSCANPVT; +typedef struct event_list *EVENTPVT; struct dbCommon; @@ -44,8 +45,9 @@ epicsShareFunc long scanInit(void); epicsShareFunc void scanRun(void); epicsShareFunc void scanPause(void); +epicsShareFunc EVENTPVT eventNameToHandle(char* event); +epicsShareFunc void postEvent(EVENTPVT epvt); epicsShareFunc void post_event(int event) EPICS_DEPRECATED; -epicsShareFunc void post_named_event(char* event); epicsShareFunc void scanAdd(struct dbCommon *); epicsShareFunc void scanDelete(struct dbCommon *); epicsShareFunc double scanPeriod(int scan); diff --git a/src/dev/softDev/devEventSoft.c b/src/dev/softDev/devEventSoft.c index ba69fdecc..bde80a452 100644 --- a/src/dev/softDev/devEventSoft.c +++ b/src/dev/softDev/devEventSoft.c @@ -69,9 +69,15 @@ static long init_record(eventRecord *prec) static long read_event(eventRecord *prec) { long status; + char newEvent[MAX_STRING_SIZE]; - status = dbGetLink(&prec->inp, DBR_STRING, prec->val, 0, 0); + if (prec->inp.type == CONSTANT) return 0; + status = dbGetLinkValue(&prec->inp, DBR_STRING, newEvent, 0, 0); if (!status) { + if (strcmp(newEvent, prec->val) != 0) { + strcpy(prec->val, newEvent); + prec->epvt = eventNameToHandle(prec->val); + } prec->udf = FALSE; if (prec->tsel.type == CONSTANT && prec->tse == epicsTimeEventDeviceTime) diff --git a/src/rec/calcoutRecord.c b/src/rec/calcoutRecord.c index c8ee0069d..3cbef9fe1 100644 --- a/src/rec/calcoutRecord.c +++ b/src/rec/calcoutRecord.c @@ -197,6 +197,8 @@ static long init_record(calcoutRecord *prec, int pass) callbackSetUser(prec, &prpvt->checkLinkCb); prpvt->cbScheduled = 0; + prec->epvt = eventNameToHandle(prec->oevt); + if (pcalcoutDSET->init_record) pcalcoutDSET->init_record(prec); prec->pval = prec->val; prec->mlst = prec->val; @@ -357,6 +359,9 @@ static long special(DBADDR *paddr, int after) } db_post_events(prec, plinkValid, DBE_VALUE); return 0; + case(calcoutRecordOEVT): + prec->epvt = eventNameToHandle(prec->oevt); + return 0; default: recGblDbaddrError(S_db_badChoice, paddr, "calc: special"); return(S_db_badChoice); @@ -540,12 +545,12 @@ static void execOutput(calcoutRecord *prec) /* Output the value */ status = writeValue(prec); /* post output event if set */ - post_named_event(prec->oevt); + if (prec->epvt) postEvent(prec->epvt); } else switch (prec->ivoa) { case menuIvoaContinue_normally: status = writeValue(prec); /* post output event if set */ - post_named_event(prec->oevt); + if (prec->epvt) postEvent(prec->epvt); break; case menuIvoaDon_t_drive_outputs: break; @@ -553,7 +558,7 @@ static void execOutput(calcoutRecord *prec) prec->oval = prec->ivov; status = writeValue(prec); /* post output event if set */ - post_named_event(prec->oevt); + if (prec->epvt) postEvent(prec->epvt); break; default: status = -1; diff --git a/src/rec/calcoutRecord.dbd b/src/rec/calcoutRecord.dbd index 539351d1f..45779b22d 100644 --- a/src/rec/calcoutRecord.dbd +++ b/src/rec/calcoutRecord.dbd @@ -258,9 +258,17 @@ recordtype(calcout) { field(OEVT,DBF_STRING) { prompt("Event To Issue") promptgroup(GUI_CLOCK) + special(SPC_MOD) asl(ASL0) size(40) } + %#include "dbScan.h" + field(EPVT, DBF_NOACCESS) { + prompt("Event private") + special(SPC_NOMOD) + interest(4) + extra("EVENTPVT epvt") + } field(IVOA,DBF_MENU) { prompt("INVALID output action") promptgroup(GUI_OUTPUT) diff --git a/src/rec/eventRecord.c b/src/rec/eventRecord.c index 9ba509857..f9a278428 100644 --- a/src/rec/eventRecord.c +++ b/src/rec/eventRecord.c @@ -32,6 +32,7 @@ #include "errMdef.h" #include "recSup.h" #include "recGbl.h" +#include "special.h" #include "menuYesNo.h" #define GEN_SIZE_OFFSET #include "eventRecord.h" @@ -43,7 +44,7 @@ #define initialize NULL static long init_record(eventRecord *, int); static long process(eventRecord *); -#define special NULL +static long special(DBADDR *, int); static long get_value(eventRecord *, struct valueDes *); #define cvt_dbaddr NULL #define get_array_info NULL @@ -106,6 +107,8 @@ static long init_record(eventRecord *prec, int pass) recGblInitConstantLink(&prec->siol,DBF_STRING,&prec->sval); } + prec->epvt = eventNameToHandle(prec->val); + if( (pdset=(struct eventdset *)(prec->dset)) && (pdset->init_record) ) status=(*pdset->init_record)(prec); return(status); @@ -123,7 +126,7 @@ static long process(eventRecord *prec) if ( !pact && prec->pact ) return(0); prec->pact = TRUE; - post_named_event(prec->val); + postEvent(prec->epvt); recGblGetTimeStamp(prec); @@ -137,7 +140,18 @@ static long process(eventRecord *prec) return(status); } + +static long special(DBADDR *paddr, int after) +{ + eventRecord *prec = (eventRecord *)paddr->precord; + + if (!after) return 0; + if (dbGetFieldIndex(paddr) == eventRecordVAL) { + prec->epvt = eventNameToHandle(prec->val); + } +} + static long get_value(eventRecord *prec, struct valueDes *pvdes) { pvdes->field_type = DBF_STRING; @@ -180,7 +194,10 @@ static long readValue(eventRecord *prec) status=dbGetLink(&(prec->siol),DBR_STRING, &(prec->sval),0,0); if (status==0) { - strcpy(prec->val, prec->sval); + if (strcmp(prec->sval, prec->val) != 0) { + strcpy(prec->val, prec->sval); + prec->epvt = eventNameToHandle(prec->val); + } prec->udf=FALSE; } } else { diff --git a/src/rec/eventRecord.dbd b/src/rec/eventRecord.dbd index da60de56a..f7bbb7ee7 100644 --- a/src/rec/eventRecord.dbd +++ b/src/rec/eventRecord.dbd @@ -12,9 +12,17 @@ recordtype(event) { field(VAL,DBF_STRING) { prompt("Event Name To Post") promptgroup(GUI_INPUTS) + special(SPC_MOD) asl(ASL0) size(40) } + %#include "dbScan.h" + field(EPVT, DBF_NOACCESS) { + prompt("Event private") + special(SPC_NOMOD) + interest(4) + extra("EVENTPVT epvt") + } field(INP,DBF_INLINK) { prompt("Input Specification") promptgroup(GUI_INPUTS)