diff --git a/src/seq/seqPvt.h b/src/seq/seqPvt.h index 0d6f3dc775bdbb3b5f7734d8755a5b6309e30a42..bb0ef27695f577864dae264374d1259b1601c780 100644 --- a/src/seq/seqPvt.h +++ b/src/seq/seqPvt.h @@ -42,7 +42,7 @@ #define chNum(ch) ((ch)-(ch)->sprog->chan) #define metaIx(ch,ss) (((ch)->sprog->options&OPT_SAFE)?ssNum(ss):0) -#define metaPtr(ch,ss) ((ch)->dbch->metaData+metaIx(ch,ss)) +#define metaPtr(ch,ss) (((ch)->sprog->options&OPT_SAFE)?((ch)->dbch->ssMetaData+ssNum(ss)):(&(ch)->dbch->metaData)) /* Generic iteration on lists */ #define foreach(e,l) for (e = l; e != 0; e = e->next) @@ -117,9 +117,9 @@ struct db_channel boolean connected; /* whether channel is connected */ void *monid; /* monitor id (supplied by PV lib) */ boolean gotOneMonitor; /* whether got at least one monitor */ - PVMETA *metaData; /* array of meta data from last access, - one for each state set (safe mode) - or just one (unsafe mode) */ + PVMETA metaData; /* meta data from last access (ca buffer) */ + PVMETA *ssMetaData; /* array of meta data, + one for each state set (safe mode) */ }; struct state_set @@ -187,6 +187,7 @@ struct program_instance unsigned monitorCount; /* number of channels monitored */ unsigned firstMonitorCount; /* number of channels that received at least one monitor event */ + void *pvReqPool; /* freeList for pv requests (has own lock) */ boolean die; /* flag set when seqStop is called */ epicsEventId ready; /* all channels connected & got 1st monitor */ @@ -210,7 +211,7 @@ struct pvreq /* seq_task.c */ void sequencer (void *arg); -void ss_write_buffer(SSCB *pwSS, CHAN *ch, void *val); +void ss_write_buffer(SSCB *pwSS, CHAN *ch, void *val, PVMETA *meta); void ss_read_buffer(SSCB *ss, CHAN *ch); void seqWakeup(SPROG *sp, unsigned eventNum); void seqCreatePvSys(SPROG *sp); diff --git a/src/seq/seq_ca.c b/src/seq/seq_ca.c index 8c3b6aae1c34adbd85d180244d91304ae0aa4b96..ea120041c25d4ab14553299aadc1b2995f149f26 100644 --- a/src/seq/seq_ca.c +++ b/src/seq/seq_ca.c @@ -69,6 +69,8 @@ pvStat seq_connect(SPROG *sp, boolean wait) if (ch->dbch == NULL) continue; /* skip anonymous pvs */ + /* Note: need not take programLock because state sets not yet + running and CA channels not yet created */ sp->assignCount += 1; if (ch->monitored) sp->monitorCount++; /* do it before pvVarCreate */ @@ -213,28 +215,28 @@ static void proc_db_events( return; } - /* Copy value returned into user variable (can get NULL value pointer - for put completion only) */ + /* Copy value and meta data into user variable CA buffer + (can get NULL value pointer for put completion only) */ if (value != NULL) { void *val = pv_value_ptr(value,type); - PVMETA *meta = metaPtr(ch,ss); - - /* Write value to CA buffer (lock-free) */ - ss_write_buffer(0, ch, val); - - /* Copy status, severity and time stamp */ - meta->status = *pv_status_ptr(value,type); - meta->severity = *pv_severity_ptr(value,type); - meta->timeStamp = *pv_stamp_ptr(value,type); - - /* Copy error message (only when severity indicates error) */ - if (meta->severity != pvSevrNONE) + PVMETA meta = { + *pv_stamp_ptr(value,type), + *pv_status_ptr(value,type), + *pv_severity_ptr(value,type), + 0 + }; + + /* Set error message only when severity indicates error */ + if (meta.severity != pvSevrNONE) { const char *pmsg = pvVarGetMess(dbch->pvid); if (!pmsg) pmsg = "unknown"; - meta->message = pmsg; + meta.message = pmsg; } + + /* Write value and meta data to CA buffers (lock-free) */ + ss_write_buffer(0, ch, val, &meta); } /* Wake up each state set that uses this channel in an event */ diff --git a/src/seq/seq_if.c b/src/seq/seq_if.c index 3737404c41bbcb1085e7210edd11ab516b0d8abc..77afa101efece1620b329bf3dd00dfce2015a087 100644 --- a/src/seq/seq_if.c +++ b/src/seq/seq_if.c @@ -202,6 +202,7 @@ static void anonymous_put(SS_ID ss, CHAN *ch) size_t size = ch->type->size; char value[pv_size_n(type, ch->count)]; int full; + DEBUG("seq_pvPut: type=%d, size=%d, count=%d, value=%p, val_ptr=%p, buf_size=%d, q=%p\n", type, size, ch->count, value, pv_value_ptr(value, type), pv_size_n(type, ch->count), queue); @@ -222,7 +223,7 @@ static void anonymous_put(SS_ID ss, CHAN *ch) /* check if monitored to mirror behaviour for named PVs */ else if (ch->monitored) { - ss_write_buffer(ss, ch, var); + ss_write_buffer(ss, ch, var, 0); } /* Must give varLock before calling seq_efSet, else (possible) deadlock! */ epicsMutexUnlock(ch->varLock); @@ -798,11 +799,10 @@ static void *getq_cp(void *dest, const void *value, size_t elemSize) { struct getq_cp_arg *arg = (struct getq_cp_arg *)dest; CHAN *ch = arg->ch; - DBCHAN *dbch = ch->dbch; PVMETA *meta = arg->meta; void *var = arg->var; pvType type = ch->type->getType; - if (dbch) + if (ch->dbch) { assert(pv_is_time_type(type)); /* Copy status, severity and time stamp */ @@ -838,11 +838,6 @@ epicsShareFunc boolean epicsShareAPI seq_pvGetQ(SS_ID ss, VAR_ID varId) /* If set, queue should be non-empty */ if (isSet) { -#if 0 - pvType type = ch->type->getType; - char buffer[pv_size_n(type, ch->count)]; - pvValue *value = (pvValue *)buffer; -#endif struct getq_cp_arg arg = {ch, var, meta}; QUEUE queue = ch->queue; boolean empty; @@ -853,22 +848,10 @@ epicsShareFunc boolean epicsShareAPI seq_pvGetQ(SS_ID ss, VAR_ID varId) errlogSevPrintf(errlogMajor, "pvGetQ: event flag set but queue is empty\n"); } - else + else if (dbch) { - if (dbch) - { -#if 0 - assert(pv_is_time_type(type)); - /* Copy status, severity and time stamp */ - meta->status = *pv_status_ptr(value,type); - meta->severity = *pv_severity_ptr(value,type); - meta->timeStamp = *pv_stamp_ptr(value,type); - memcpy(var, pv_value_ptr(value,type), ch->type->size * ch->count); -#endif - /* If queue is now empty, clear the event flag */ - if (seqQueueIsEmpty(queue)) - bitClear(sp->evFlags, ev_flag); - } + /* If queue is now empty, clear the event flag */ + if (seqQueueIsEmpty(queue)) bitClear(sp->evFlags, ev_flag); } } epicsMutexUnlock(sp->programLock); diff --git a/src/seq/seq_main.c b/src/seq/seq_main.c index 34eea84aca0cbc94707c0ce0ca0a6082a34582d5..6c2cde1da1d23a65f4aea44604db979b9dbde2be 100644 --- a/src/seq/seq_main.c +++ b/src/seq/seq_main.c @@ -254,9 +254,7 @@ static void init_chan(SPROG *sp, CHAN *ch, seqChan *seqChan) DBCHAN *dbch = new(DBCHAN); dbch->dbName = epicsStrDup(name_buffer); if (sp->options & OPT_SAFE) - dbch->metaData = newArray(PVMETA, sp->numSS); - else - dbch->metaData = new(PVMETA); + dbch->ssMetaData = newArray(PVMETA, sp->numSS); ch->dbch = dbch; } DEBUG(" assigned name=%s, expanded name=%s\n", @@ -379,8 +377,8 @@ void seq_free(SPROG *sp) if (ch->dbch) { - if (ch->dbch->metaData) - free(ch->dbch->metaData); + if (ch->dbch->ssMetaData) + free(ch->dbch->ssMetaData); if (ch->dbch->dbName != NULL) free(ch->dbch->dbName); free(ch->dbch); diff --git a/src/seq/seq_qry.c b/src/seq/seq_qry.c index eead66b187e51448fc28388eb186d4b1497d2ed6..c3e02482bcbd9553e909ac864c01c6e9a270b0f7 100644 --- a/src/seq/seq_qry.c +++ b/src/seq/seq_qry.c @@ -45,6 +45,7 @@ epicsShareFunc void epicsShareAPI seqShow(epicsThreadId tid) if (sp->numQueues > 0) printf(" queue array address = %p\n",sp->queues); printf(" number of channels = %d\n", sp->numChans); + /* Note: need not take programLock since read-ony */ printf(" number of channels assigned = %d\n", sp->assignCount); printf(" number of channels connected = %d\n", sp->connectCount); printf(" number of channels monitored = %d\n", sp->monitorCount); @@ -182,7 +183,7 @@ epicsShareFunc void epicsShareAPI seqChanShow(epicsThreadId tid, const char *str if (dbch) printf(" Assigned to \"%s\"\n", dbch->dbName); else - printf(" Not assigned\n"); + printf(" Anonymous\n"); if(dbch && dbch->connected) printf(" Connected\n"); diff --git a/src/seq/seq_task.c b/src/seq/seq_task.c index f0a8e65d0c9a52e47df70ca4f9a018cd87dca8a1..a50faa341ad4da9dc40b99713fd73ce47a459c5e 100644 --- a/src/seq/seq_task.c +++ b/src/seq/seq_task.c @@ -141,6 +141,11 @@ static void ss_read_buffer_static(SSCB *ss, CHAN *ch) DEBUG("ss %s: before read %s", ss->ssName, ch->varName); print_channel_value(DEBUG,ch,val); memcpy(val, buf, var_size); + if (ch->dbch) { + int nss = (int)(ss - sp->ss); + /* structure copy */ + ch->dbch->ssMetaData[nss] = ch->dbch->metaData; + } DEBUG("ss %s: after read %s", ss->ssName, ch->varName); print_channel_value(DEBUG,ch,val); } while ((ch->busy || ss->dirty[nch]) @@ -177,7 +182,7 @@ static void ss_read_all_buffer(SPROG *sp, SSCB *ss) * ss_write_buffer() - Only used in safe mode. * Lock-free writing of variable buffer. */ -void ss_write_buffer(SSCB *pwSS, CHAN *ch, void *val) +void ss_write_buffer(SSCB *pwSS, CHAN *ch, void *val, PVMETA *meta) { SPROG *sp = ch->sprog; char *buf = bufPtr(ch); @@ -190,6 +195,10 @@ void ss_write_buffer(SSCB *pwSS, CHAN *ch, void *val) DEBUG("ss %s: before write %s", ss_name, ch->varName); print_channel_value(DEBUG,ch,buf); memcpy(buf, val, var_size); + if (ch->dbch && meta) { + /* structure copy */ + ch->dbch->metaData = *meta; + } DEBUG("ss %s: after write %s", ss_name, ch->varName); print_channel_value(DEBUG,ch,buf); for (nss = 0; nss < sp->numSS; nss++)