Merged changes from 3.14 branch up to 2011-11-02
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
# Copyright (c) 2011 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.
|
||||
# EPICS BASE Versions 3.13.7
|
||||
# and higher are distributed subject to a Software License Agreement found
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
#RULES.Db
|
||||
@@ -23,8 +22,8 @@ vpath %.acs $(USR_VPATH) $(GENERIC_SRC_DIRS) $(COMMON_DIR)
|
||||
##################################################### dbdflags
|
||||
|
||||
# dbExpand
|
||||
INSTALL_DBDFLAGS += -I $(INSTALL_LOCATION)/dbd
|
||||
INSTALL_DBFLAGS += -I $(INSTALL_LOCATION)/db
|
||||
INSTALL_DBDFLAGS += -I $(INSTALL_DBD)
|
||||
INSTALL_DBFLAGS += -I $(INSTALL_DB)
|
||||
DBDFLAGS = $(USR_DBDFLAGS) -I . -I .. $(INSTALL_DBDFLAGS) $(RELEASE_DBDFLAGS)
|
||||
DBFLAGS = $($*_DBFLAGS) $(USR_DBFLAGS) -I. -I.. $(INSTALL_DBFLAGS) $(RELEASE_DBFLAGS)
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ PROD_LIBS = ca Com
|
||||
PROD_SYS_LIBS_WIN32 = ws2_32 advapi32 user32
|
||||
|
||||
PROD_HOST += caRepeater catime acctst caConnTest casw caEventRate
|
||||
OBJS_IOC_vxWorks += catime acctst caConnTest casw caEventRate
|
||||
OBJS_IOC += catime acctst caConnTest casw caEventRate acctstRegister
|
||||
caRepeater_SRCS = caRepeater.cpp
|
||||
catime_SRCS = catimeMain.c catime.c
|
||||
acctst_SRCS = acctstMain.c acctst.c
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
|
||||
/*
|
||||
* CA regression test
|
||||
* Authors:
|
||||
* Jeff Hill
|
||||
* Murali Shankar - initial versions of verifyMultithreadSubscr
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -26,6 +30,8 @@
|
||||
*/
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsEvent.h"
|
||||
#include "epicsTime.h"
|
||||
#include "dbDefs.h"
|
||||
#include "envDefs.h"
|
||||
@@ -2719,6 +2725,186 @@ void fdRegCB ( void * parg, int fd, int opened )
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char m_chanName[100u];
|
||||
struct ca_client_context * m_pCtx;
|
||||
chid m_chan;
|
||||
epicsMutexId m_mutex;
|
||||
epicsEventId m_testCompleteEvent;
|
||||
epicsEventId m_threadExitEvent;
|
||||
size_t m_nUpdatesReceived;
|
||||
size_t m_nUpdatesRequired;
|
||||
int m_testInitiated;
|
||||
int m_testComplete;
|
||||
unsigned m_interestLevel;
|
||||
} MultiThreadSubscrTest;
|
||||
|
||||
static void testMultithreadSubscrSubscrCallback
|
||||
( struct event_handler_args eha )
|
||||
{
|
||||
const epicsEventId firstUpdateEvent = ( epicsEventId ) eha.usr;
|
||||
epicsEventSignal ( firstUpdateEvent );
|
||||
}
|
||||
|
||||
static void testMultithreadSubscrCreateSubscr ( void * pParm )
|
||||
{
|
||||
static unsigned nElem = 0;
|
||||
int testComplete = FALSE;
|
||||
evid id;
|
||||
epicsEventId firstUpdateEvent;
|
||||
epicsEventWaitStatus eventWaitStatus;
|
||||
MultiThreadSubscrTest * const pMultiThreadSubscrTest =
|
||||
( MultiThreadSubscrTest * ) pParm;
|
||||
|
||||
/* this is required for the ca_flush below to work correctly */
|
||||
int status = ca_attach_context ( pMultiThreadSubscrTest->m_pCtx );
|
||||
verify ( status == ECA_NORMAL );
|
||||
firstUpdateEvent = epicsEventMustCreate ( epicsEventEmpty );
|
||||
verify ( firstUpdateEvent );
|
||||
status = ca_create_subscription (
|
||||
DBR_TIME_LONG,
|
||||
nElem,
|
||||
pMultiThreadSubscrTest->m_chan,
|
||||
DBE_VALUE,
|
||||
testMultithreadSubscrSubscrCallback,
|
||||
firstUpdateEvent,
|
||||
& id );
|
||||
verify ( status == ECA_NORMAL );
|
||||
status = ca_flush_io ();
|
||||
verify ( status == ECA_NORMAL );
|
||||
/* wait for first update */
|
||||
eventWaitStatus = epicsEventWaitWithTimeout (
|
||||
firstUpdateEvent, 60.0 * 10 );
|
||||
verify ( eventWaitStatus == epicsEventWaitOK );
|
||||
epicsEventDestroy ( firstUpdateEvent );
|
||||
status = ca_clear_subscription ( id );
|
||||
verify ( status == ECA_NORMAL );
|
||||
epicsMutexMustLock ( pMultiThreadSubscrTest->m_mutex );
|
||||
pMultiThreadSubscrTest->m_nUpdatesReceived++;
|
||||
testComplete = ( pMultiThreadSubscrTest->m_nUpdatesReceived ==
|
||||
pMultiThreadSubscrTest->m_nUpdatesRequired );
|
||||
pMultiThreadSubscrTest->m_testComplete = testComplete;
|
||||
epicsMutexUnlock ( pMultiThreadSubscrTest->m_mutex );
|
||||
if ( testComplete ) {
|
||||
epicsEventSignal ( pMultiThreadSubscrTest->m_testCompleteEvent );
|
||||
}
|
||||
}
|
||||
|
||||
void testMultithreadSubscrConnHandler ( struct connection_handler_args args )
|
||||
{
|
||||
MultiThreadSubscrTest * const pMultiThreadSubscrTest =
|
||||
( MultiThreadSubscrTest * ) ca_puser ( args.chid );
|
||||
epicsMutexMustLock ( pMultiThreadSubscrTest->m_mutex );
|
||||
if ( !pMultiThreadSubscrTest->m_testInitiated &&
|
||||
args.op == CA_OP_CONN_UP ) {
|
||||
int i;
|
||||
pMultiThreadSubscrTest->m_testInitiated = TRUE;
|
||||
for ( i = 0; i < pMultiThreadSubscrTest->m_nUpdatesRequired; i++ ) {
|
||||
char threadname[64];
|
||||
epicsThreadId threadId;
|
||||
sprintf(threadname, "testSubscr%06u", i);
|
||||
threadId = epicsThreadCreate ( threadname,
|
||||
epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackSmall),
|
||||
testMultithreadSubscrCreateSubscr,
|
||||
pMultiThreadSubscrTest );
|
||||
verify ( threadId );
|
||||
}
|
||||
}
|
||||
epicsMutexUnlock ( pMultiThreadSubscrTest->m_mutex );
|
||||
}
|
||||
|
||||
void testMultithreadSubscr ( void * pParm )
|
||||
{
|
||||
MultiThreadSubscrTest * const pMultiThreadSubscrTest =
|
||||
( MultiThreadSubscrTest * ) pParm;
|
||||
int status;
|
||||
unsigned i;
|
||||
|
||||
status = ca_context_create ( ca_enable_preemptive_callback );
|
||||
verify ( status == ECA_NORMAL );
|
||||
pMultiThreadSubscrTest->m_pCtx = ca_current_context ();
|
||||
verify ( pMultiThreadSubscrTest->m_pCtx );
|
||||
status = ca_create_channel (
|
||||
pMultiThreadSubscrTest->m_chanName,
|
||||
testMultithreadSubscrConnHandler,
|
||||
pMultiThreadSubscrTest,
|
||||
CA_PRIORITY_MIN,
|
||||
& pMultiThreadSubscrTest->m_chan );
|
||||
verify ( status == ECA_NORMAL );
|
||||
|
||||
showProgressBegin ( "verifyMultithreadSubscr",
|
||||
pMultiThreadSubscrTest->m_interestLevel );
|
||||
i = 0;
|
||||
while ( TRUE ) {
|
||||
int success = FALSE;
|
||||
epicsEventWaitStatus eventWaitStatus;
|
||||
epicsMutexMustLock ( pMultiThreadSubscrTest->m_mutex );
|
||||
success = pMultiThreadSubscrTest->m_testComplete;
|
||||
epicsMutexUnlock ( pMultiThreadSubscrTest->m_mutex );
|
||||
if ( success ) {
|
||||
break;
|
||||
}
|
||||
eventWaitStatus = epicsEventWaitWithTimeout (
|
||||
pMultiThreadSubscrTest->m_testCompleteEvent, 0.1 );
|
||||
verify ( eventWaitStatus == epicsEventWaitOK ||
|
||||
eventWaitStatus == epicsEventWaitTimeout );
|
||||
if ( i++ % 100 == 0u )
|
||||
showProgress ( pMultiThreadSubscrTest->m_interestLevel );
|
||||
verify ( i < 1000 );
|
||||
}
|
||||
showProgressEnd ( pMultiThreadSubscrTest->m_interestLevel );
|
||||
|
||||
status = ca_clear_channel ( pMultiThreadSubscrTest->m_chan );
|
||||
verify ( status == ECA_NORMAL );
|
||||
ca_context_destroy ();
|
||||
epicsEventSignal ( pMultiThreadSubscrTest->m_threadExitEvent );
|
||||
}
|
||||
|
||||
/*
|
||||
* test installation of subscriptions similar to usage paterns
|
||||
* employed by modern versions of the sequencer
|
||||
*/
|
||||
void verifyMultithreadSubscr ( const char * pName, unsigned interestLevel )
|
||||
{
|
||||
static unsigned nSubscr = 3000;
|
||||
epicsThreadId threadId;
|
||||
MultiThreadSubscrTest * const pMultiThreadSubscrTest =
|
||||
(MultiThreadSubscrTest*) calloc ( 1,
|
||||
sizeof ( MultiThreadSubscrTest ) );
|
||||
verify ( pMultiThreadSubscrTest);
|
||||
pMultiThreadSubscrTest->m_mutex = epicsMutexMustCreate ();
|
||||
verify ( pMultiThreadSubscrTest->m_mutex );
|
||||
pMultiThreadSubscrTest->m_testCompleteEvent =
|
||||
epicsEventMustCreate ( epicsEventEmpty );
|
||||
verify ( pMultiThreadSubscrTest->m_testCompleteEvent );
|
||||
pMultiThreadSubscrTest->m_threadExitEvent =
|
||||
epicsEventMustCreate ( epicsEventEmpty );
|
||||
verify ( pMultiThreadSubscrTest->m_threadExitEvent );
|
||||
strncpy ( pMultiThreadSubscrTest->m_chanName, pName,
|
||||
sizeof ( pMultiThreadSubscrTest->m_chanName ) );
|
||||
pMultiThreadSubscrTest->m_chanName
|
||||
[ sizeof ( pMultiThreadSubscrTest->m_chanName ) - 1u ] = '\0';
|
||||
pMultiThreadSubscrTest->m_nUpdatesRequired = nSubscr;
|
||||
pMultiThreadSubscrTest->m_interestLevel = interestLevel;
|
||||
threadId = epicsThreadCreate (
|
||||
"testMultithreadSubscr",
|
||||
epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackSmall),
|
||||
testMultithreadSubscr, pMultiThreadSubscrTest );
|
||||
verify ( threadId );
|
||||
{
|
||||
epicsEventWaitStatus eventWaitStatus;
|
||||
eventWaitStatus = epicsEventWaitWithTimeout (
|
||||
pMultiThreadSubscrTest->m_threadExitEvent, 1000.0 );
|
||||
verify ( eventWaitStatus == epicsEventWaitOK );
|
||||
}
|
||||
epicsEventDestroy ( pMultiThreadSubscrTest->m_testCompleteEvent );
|
||||
epicsEventDestroy ( pMultiThreadSubscrTest->m_threadExitEvent );
|
||||
epicsMutexDestroy ( pMultiThreadSubscrTest->m_mutex );
|
||||
free ( pMultiThreadSubscrTest );
|
||||
}
|
||||
|
||||
void fdManagerVerify ( const char * pName, unsigned interestLevel )
|
||||
{
|
||||
int status;
|
||||
@@ -2965,17 +3151,22 @@ void verifyContextRundownFlush ( const char * pName, unsigned interestLevel )
|
||||
SEVCHK ( status, "context create failed" );
|
||||
|
||||
status = ca_create_channel ( pName, 0, 0, 0, & chan );
|
||||
SEVCHK ( status, NULL );
|
||||
|
||||
status = ca_pend_io( timeoutToPendIO );
|
||||
SEVCHK ( status, "channel connect failed" );
|
||||
|
||||
status = ca_put ( DBR_DOUBLE, chan, & stim );
|
||||
SEVCHK ( status, "channel put failed" );
|
||||
|
||||
status = ca_clear_channel ( chan );
|
||||
SEVCHK ( status, NULL );
|
||||
|
||||
/*
|
||||
* currently in-memory channels cant be used with this test
|
||||
* !!!! FIX ME, FIX ME, FIX ME, FIX ME !!!!
|
||||
*/
|
||||
if ( status != ECA_UNAVAILINSERV ) {
|
||||
SEVCHK ( status, NULL );
|
||||
|
||||
status = ca_pend_io( timeoutToPendIO );
|
||||
SEVCHK ( status, "channel connect failed" );
|
||||
|
||||
status = ca_put ( DBR_DOUBLE, chan, & stim );
|
||||
SEVCHK ( status, "channel put failed" );
|
||||
|
||||
status = ca_clear_channel ( chan );
|
||||
SEVCHK ( status, NULL );
|
||||
}
|
||||
ca_context_destroy ();
|
||||
}
|
||||
|
||||
@@ -2985,24 +3176,28 @@ void verifyContextRundownFlush ( const char * pName, unsigned interestLevel )
|
||||
dbr_double_t resp;
|
||||
status = ca_context_create ( ca_disable_preemptive_callback );
|
||||
SEVCHK ( status, "context create failed" );
|
||||
|
||||
|
||||
status = ca_create_channel ( pName, 0, 0, 0, & chan );
|
||||
SEVCHK ( status, NULL );
|
||||
|
||||
status = ca_pend_io( timeoutToPendIO );
|
||||
SEVCHK ( status, "channel connect failed" );
|
||||
|
||||
status = ca_get ( DBR_DOUBLE, chan, & resp );
|
||||
SEVCHK ( status, "channel get failed" );
|
||||
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
SEVCHK ( status, "get, pend io failed" );
|
||||
|
||||
verify ( stim == resp );
|
||||
|
||||
status = ca_clear_channel ( chan );
|
||||
SEVCHK ( status, NULL );
|
||||
|
||||
/*
|
||||
* currently in-memory channels cant be used with this test
|
||||
* !!!! FIX ME, FIX ME, FIX ME, FIX ME !!!!
|
||||
*/
|
||||
if ( status != ECA_UNAVAILINSERV ) {
|
||||
status = ca_pend_io( timeoutToPendIO );
|
||||
SEVCHK ( status, "channel connect failed" );
|
||||
|
||||
status = ca_get ( DBR_DOUBLE, chan, & resp );
|
||||
SEVCHK ( status, "channel get failed" );
|
||||
|
||||
status = ca_pend_io ( timeoutToPendIO );
|
||||
SEVCHK ( status, "get, pend io failed" );
|
||||
|
||||
verify ( stim == resp );
|
||||
|
||||
status = ca_clear_channel ( chan );
|
||||
SEVCHK ( status, NULL );
|
||||
}
|
||||
ca_context_destroy ();
|
||||
}
|
||||
|
||||
@@ -3028,6 +3223,13 @@ void verifyContextRundownChanStillExist (
|
||||
|
||||
for ( i = 0; i < NELEMENTS ( chan ); i++ ) {
|
||||
status = ca_create_channel ( pName, 0, 0, 0, & chan[i] );
|
||||
/*
|
||||
* currently in-memory channels cant be used with this test
|
||||
* !!!! FIX ME, FIX ME, FIX ME, FIX ME !!!!
|
||||
*/
|
||||
if ( status == ECA_UNAVAILINSERV ) {
|
||||
break;
|
||||
}
|
||||
SEVCHK ( status, NULL );
|
||||
}
|
||||
|
||||
@@ -3123,6 +3325,7 @@ int acctst ( const char * pName, unsigned interestLevel, unsigned channelCount,
|
||||
verifyHighThroughputReadCallback ( chan, interestLevel );
|
||||
verifyHighThroughputWriteCallback ( chan, interestLevel );
|
||||
verifyBadString ( chan, interestLevel );
|
||||
verifyMultithreadSubscr ( pName, interestLevel );
|
||||
if ( select != ca_enable_preemptive_callback ) {
|
||||
fdManagerVerify ( pName, interestLevel );
|
||||
}
|
||||
|
||||
69
src/ca/client/acctstRegister.cpp
Normal file
69
src/ca/client/acctstRegister.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* CA client library diagnostics IOC shell registration
|
||||
* Authors:
|
||||
* Jeff Hill
|
||||
*/
|
||||
|
||||
#include <iocsh.h>
|
||||
#include "caDiagnostics.h"
|
||||
|
||||
/* Information needed by iocsh */
|
||||
static const iocshArg acctstArg0 = { "channel name", iocshArgString };
|
||||
static const iocshArg acctstArg1 = { "interest level", iocshArgInt };
|
||||
static const iocshArg acctstArg2 = { "channel count", iocshArgInt };
|
||||
static const iocshArg acctstArg3 = { "repetition count", iocshArgInt };
|
||||
static const iocshArg acctstArg4 = { "preemptive callback select", iocshArgInt };
|
||||
|
||||
static const iocshArg *acctstArgs[] =
|
||||
{
|
||||
&acctstArg0,
|
||||
&acctstArg1,
|
||||
&acctstArg2,
|
||||
&acctstArg3,
|
||||
&acctstArg4
|
||||
};
|
||||
static const iocshFuncDef acctstFuncDef = {"acctst", 5, acctstArgs};
|
||||
|
||||
|
||||
/* Wrapper called by iocsh, selects the argument types that print needs */
|
||||
static void acctstCallFunc(const iocshArgBuf *args) {
|
||||
if ( args[1].ival < 0 ) {
|
||||
printf ( "negative interest level not allowed\n" );
|
||||
return;
|
||||
}
|
||||
if ( args[2].ival < 0 ) {
|
||||
printf ( "negative channel count not allowed\n" );
|
||||
return;
|
||||
}
|
||||
if ( args[3].ival < 0 ) {
|
||||
printf ( "negative repetition count not allowed\n" );
|
||||
return;
|
||||
}
|
||||
acctst (
|
||||
args[0].sval, /* channel name */
|
||||
( unsigned ) args[1].ival, /* interest level */
|
||||
( unsigned ) args[2].ival, /* channel count */
|
||||
( unsigned ) args[3].ival, /* repetition count */
|
||||
( ca_preemptive_callback_select ) args[4].ival ); /* preemptive callback select */
|
||||
}
|
||||
|
||||
struct AutoInit {
|
||||
AutoInit ();
|
||||
};
|
||||
|
||||
AutoInit :: AutoInit ()
|
||||
{
|
||||
iocshRegister ( &acctstFuncDef, acctstCallFunc );
|
||||
}
|
||||
|
||||
AutoInit autoInit;
|
||||
|
||||
@@ -185,7 +185,8 @@ epicsShareFunc enum channel_state epicsShareAPI ca_state (chid chan);
|
||||
epicsShareFunc int epicsShareAPI ca_task_initialize (void);
|
||||
enum ca_preemptive_callback_select
|
||||
{ ca_disable_preemptive_callback, ca_enable_preemptive_callback };
|
||||
epicsShareFunc int epicsShareAPI ca_context_create (enum ca_preemptive_callback_select select);
|
||||
epicsShareFunc int epicsShareAPI
|
||||
ca_context_create (enum ca_preemptive_callback_select select);
|
||||
epicsShareFunc void epicsShareAPI ca_detach_context ();
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
@@ -126,7 +126,6 @@ static void event_handler (evargs args)
|
||||
ppv->dbrType = args.type;
|
||||
ppv->value = calloc(1, dbr_size_n(args.type, args.count));
|
||||
memcpy(ppv->value, args.dbr, dbr_size_n(args.type, args.count));
|
||||
ppv->onceConnected = 1;
|
||||
ppv->nElems = args.count;
|
||||
nRead++;
|
||||
}
|
||||
@@ -159,12 +158,13 @@ static int caget (pv *pvs, int nPvs, RequestT request, OutputT format,
|
||||
int n, result;
|
||||
|
||||
for (n = 0; n < nPvs; n++) {
|
||||
unsigned long nElems;
|
||||
|
||||
/* Set up pvs structure */
|
||||
/* -------------------- */
|
||||
|
||||
/* Get natural type and array count */
|
||||
pvs[n].nElems = ca_element_count(pvs[n].chid);
|
||||
nElems = ca_element_count(pvs[n].chid);
|
||||
pvs[n].dbfType = ca_field_type(pvs[n].chid);
|
||||
pvs[n].dbrType = dbrType;
|
||||
|
||||
@@ -183,10 +183,6 @@ static int caget (pv *pvs, int nPvs, RequestT request, OutputT format,
|
||||
pvs[n].dbrType = DBR_TIME_STRING;
|
||||
}
|
||||
}
|
||||
/* Adjust array count */
|
||||
if (reqElems > pvs[n].nElems)
|
||||
reqElems = pvs[n].nElems;
|
||||
pvs[n].reqElems = reqElems;
|
||||
|
||||
/* Issue CA request */
|
||||
/* ---------------- */
|
||||
@@ -196,21 +192,24 @@ static int caget (pv *pvs, int nPvs, RequestT request, OutputT format,
|
||||
nConn++;
|
||||
pvs[n].onceConnected = 1;
|
||||
if (request == callback)
|
||||
{ /* Event handler will allocate value */
|
||||
{
|
||||
/* Event handler will allocate value and set nElems */
|
||||
pvs[n].reqElems = reqElems > nElems ? nElems : reqElems;
|
||||
result = ca_array_get_callback(pvs[n].dbrType,
|
||||
pvs[n].reqElems,
|
||||
pvs[n].chid,
|
||||
event_handler,
|
||||
(void*)&pvs[n]);
|
||||
} else {
|
||||
/* Allocate value structure */
|
||||
/* We allocate value structure and set nElems */
|
||||
pvs[n].nElems = reqElems && reqElems < nElems ? reqElems : nElems;
|
||||
pvs[n].value = calloc(1, dbr_size_n(pvs[n].dbrType, pvs[n].nElems));
|
||||
if(!pvs[n].value) {
|
||||
fprintf(stderr,"Allocation failed\n");
|
||||
if (!pvs[n].value) {
|
||||
fprintf(stderr,"Memory allocation failed\n");
|
||||
return 1;
|
||||
}
|
||||
result = ca_array_get(pvs[n].dbrType,
|
||||
pvs[n].reqElems,
|
||||
pvs[n].nElems,
|
||||
pvs[n].chid,
|
||||
pvs[n].value);
|
||||
}
|
||||
@@ -252,9 +251,6 @@ static int caget (pv *pvs, int nPvs, RequestT request, OutputT format,
|
||||
/* -------------- */
|
||||
|
||||
for (n = 0; n < nPvs; n++) {
|
||||
/* Truncate the data printed to what was requested. */
|
||||
if (pvs[n].reqElems != 0 && pvs[n].nElems > pvs[n].reqElems)
|
||||
pvs[n].nElems = pvs[n].reqElems;
|
||||
|
||||
switch (format) {
|
||||
case plain: /* Emulate old caget behaviour */
|
||||
@@ -377,7 +373,7 @@ static void complainIfNotPlainAndSet (OutputT *current, const OutputT requested)
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
int n = 0;
|
||||
int n;
|
||||
int result; /* CA result */
|
||||
OutputT format = plain; /* User specified format */
|
||||
RequestT request = get; /* User specified request type */
|
||||
@@ -389,7 +385,7 @@ int main (int argc, char *argv[])
|
||||
int digits = 0; /* getopt() no. of float digits */
|
||||
|
||||
int nPvs; /* Number of PVs */
|
||||
pv* pvs = 0; /* Array of PV structures */
|
||||
pv* pvs; /* Array of PV structures */
|
||||
|
||||
LINE_BUFFER(stdout); /* Configure stdout buffering */
|
||||
|
||||
@@ -529,7 +525,7 @@ int main (int argc, char *argv[])
|
||||
result = ca_context_create(ca_disable_preemptive_callback);
|
||||
if (result != ECA_NORMAL) {
|
||||
fprintf(stderr, "CA error %s occurred while trying "
|
||||
"to start channel access '%s'.\n", ca_message(result), pvs[n].name);
|
||||
"to start channel access.\n", ca_message(result));
|
||||
return 1;
|
||||
}
|
||||
/* Allocate PV structure array */
|
||||
|
||||
@@ -127,13 +127,13 @@ int cainfo (pv *pvs, int nPvs)
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
int n = 0;
|
||||
int n;
|
||||
int result; /* CA result */
|
||||
|
||||
int opt; /* getopt() current option */
|
||||
|
||||
int nPvs; /* Number of PVs */
|
||||
pv* pvs = 0; /* Array of PV structures */
|
||||
pv* pvs; /* Array of PV structures */
|
||||
|
||||
LINE_BUFFER(stdout); /* Configure stdout buffering */
|
||||
|
||||
@@ -195,7 +195,7 @@ int main (int argc, char *argv[])
|
||||
result = ca_context_create(ca_disable_preemptive_callback);
|
||||
if (result != ECA_NORMAL) {
|
||||
fprintf(stderr, "CA error %s occurred while trying "
|
||||
"to start channel access '%s'.\n", ca_message(result), pvs[n].name);
|
||||
"to start channel access.\n", ca_message(result));
|
||||
return 1;
|
||||
}
|
||||
/* Allocate PV structure array */
|
||||
|
||||
@@ -92,7 +92,7 @@ void usage (void)
|
||||
* Function: event_handler
|
||||
*
|
||||
* Description: CA event_handler for request type callback
|
||||
* Allocates the dbr structure and copies the data
|
||||
* Prints the event data
|
||||
*
|
||||
* Arg(s) In: args - event handler args (see CA manual)
|
||||
*
|
||||
@@ -107,10 +107,12 @@ static void event_handler (evargs args)
|
||||
{
|
||||
pv->dbrType = args.type;
|
||||
pv->nElems = args.count;
|
||||
memcpy(pv->value, args.dbr, dbr_size_n(args.type, args.count));
|
||||
pv->value = (void *) args.dbr; /* casting away const */
|
||||
|
||||
print_time_val_sts(pv, reqElems);
|
||||
fflush(stdout);
|
||||
|
||||
pv->value = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,51 +131,39 @@ static void connection_handler ( struct connection_handler_args args )
|
||||
{
|
||||
pv *ppv = ( pv * ) ca_puser ( args.chid );
|
||||
if ( args.op == CA_OP_CONN_UP ) {
|
||||
nConn++;
|
||||
if (!ppv->onceConnected) {
|
||||
ppv->onceConnected = 1;
|
||||
/* Set up pv structure */
|
||||
/* ------------------- */
|
||||
|
||||
/* Get natural type and array count */
|
||||
ppv->nElems = ca_element_count(ppv->chid);
|
||||
ppv->dbfType = ca_field_type(ppv->chid);
|
||||
ppv->dbfType = ca_field_type(ppv->chid);
|
||||
ppv->dbrType = dbf_type_to_DBR_TIME(ppv->dbfType); /* Use native type */
|
||||
if (dbr_type_is_ENUM(ppv->dbrType)) /* Enums honour -n option */
|
||||
{
|
||||
if (enumAsNr) ppv->dbrType = DBR_TIME_INT;
|
||||
else ppv->dbrType = DBR_TIME_STRING;
|
||||
}
|
||||
else if (floatAsString &&
|
||||
(dbr_type_is_FLOAT(ppv->dbrType) || dbr_type_is_DOUBLE(ppv->dbrType)))
|
||||
{
|
||||
ppv->dbrType = DBR_TIME_STRING;
|
||||
}
|
||||
/* Set request count */
|
||||
ppv->nElems = ca_element_count(ppv->chid);
|
||||
ppv->reqElems = reqElems > ppv->nElems ? ppv->nElems : reqElems;
|
||||
|
||||
/* Set up value structures */
|
||||
ppv->dbrType = dbf_type_to_DBR_TIME(ppv->dbfType); /* Use native type */
|
||||
if (dbr_type_is_ENUM(ppv->dbrType)) /* Enums honour -n option */
|
||||
{
|
||||
if (enumAsNr) ppv->dbrType = DBR_TIME_INT;
|
||||
else ppv->dbrType = DBR_TIME_STRING;
|
||||
}
|
||||
|
||||
else if (floatAsString &&
|
||||
(dbr_type_is_FLOAT(ppv->dbrType) || dbr_type_is_DOUBLE(ppv->dbrType)))
|
||||
{
|
||||
ppv->dbrType = DBR_TIME_STRING;
|
||||
}
|
||||
/* Adjust array count */
|
||||
if (reqElems > ppv->nElems)
|
||||
reqElems = ppv->nElems;
|
||||
ppv->reqElems = reqElems;
|
||||
|
||||
ppv->onceConnected = 1;
|
||||
nConn++;
|
||||
/* Issue CA request */
|
||||
/* ---------------- */
|
||||
/* install monitor once with first connect */
|
||||
if ( ! ppv->value ) {
|
||||
/* Allocate value structure */
|
||||
ppv->value = calloc(1, dbr_size_n(ppv->dbrType, ppv->nElems));
|
||||
if ( ppv->value ) {
|
||||
ppv->status = ca_create_subscription(ppv->dbrType,
|
||||
/* install monitor once with first connect */
|
||||
ppv->status = ca_create_subscription(ppv->dbrType,
|
||||
ppv->reqElems,
|
||||
ppv->chid,
|
||||
eventMask,
|
||||
event_handler,
|
||||
(void*)ppv,
|
||||
NULL);
|
||||
if ( ppv->status != ECA_NORMAL ) {
|
||||
free ( ppv->value );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( args.op == CA_OP_CONN_DOWN ) {
|
||||
@@ -203,7 +193,7 @@ static void connection_handler ( struct connection_handler_args args )
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
int returncode = 0;
|
||||
int n = 0;
|
||||
int n;
|
||||
int result; /* CA result */
|
||||
IntFormatT outType; /* Output type */
|
||||
|
||||
@@ -211,7 +201,7 @@ int main (int argc, char *argv[])
|
||||
int digits = 0; /* getopt() no. of float digits */
|
||||
|
||||
int nPvs; /* Number of PVs */
|
||||
pv* pvs = 0; /* Array of PV structures */
|
||||
pv* pvs; /* Array of PV structures */
|
||||
|
||||
LINE_BUFFER(stdout); /* Configure stdout buffering */
|
||||
|
||||
@@ -356,7 +346,7 @@ int main (int argc, char *argv[])
|
||||
result = ca_context_create(ca_disable_preemptive_callback);
|
||||
if (result != ECA_NORMAL) {
|
||||
fprintf(stderr, "CA error %s occurred while trying "
|
||||
"to start channel access '%s'.\n", ca_message(result), pvs[n].name);
|
||||
"to start channel access.\n", ca_message(result));
|
||||
return 1;
|
||||
}
|
||||
/* Allocate PV structure array */
|
||||
|
||||
@@ -251,7 +251,7 @@ int caget (pv *pvs, int nPvs, OutputT format,
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
int n = 0;
|
||||
int n;
|
||||
int i;
|
||||
int result; /* CA result */
|
||||
OutputT format = plain; /* User specified format */
|
||||
@@ -273,7 +273,7 @@ int main (int argc, char *argv[])
|
||||
struct dbr_gr_enum bufGrEnum;
|
||||
|
||||
int nPvs; /* Number of PVs */
|
||||
pv* pvs = 0; /* Array of PV structures */
|
||||
pv* pvs; /* Array of PV structures */
|
||||
|
||||
LINE_BUFFER(stdout); /* Configure stdout buffering */
|
||||
putenv("POSIXLY_CORRECT="); /* Behave correct on GNU getopt systems */
|
||||
@@ -372,7 +372,7 @@ int main (int argc, char *argv[])
|
||||
result = ca_context_create(ca_enable_preemptive_callback);
|
||||
if (result != ECA_NORMAL) {
|
||||
fprintf(stderr, "CA error %s occurred while trying "
|
||||
"to start channel access '%s'.\n", ca_message(result), pvs[n].name);
|
||||
"to start channel access.\n", ca_message(result));
|
||||
return 1;
|
||||
}
|
||||
/* Allocate PV structure array */
|
||||
|
||||
@@ -203,35 +203,44 @@ int epicsShareAPI dbel ( const char *pname, unsigned level )
|
||||
}
|
||||
|
||||
if ( level > 1 ) {
|
||||
unsigned nEntriesFree = ringSpace ( pevent->ev_que );
|
||||
unsigned nEntriesFree;
|
||||
const void * taskId;
|
||||
LOCKEVQUE(pevent->ev_que);
|
||||
nEntriesFree = ringSpace ( pevent->ev_que );
|
||||
taskId = ( void * ) pevent->ev_que->evUser->taskid;
|
||||
UNLOCKEVQUE(pevent->ev_que);
|
||||
if ( nEntriesFree == 0u ) {
|
||||
printf ( ", thread=%p, queue full",
|
||||
(void *) pevent->ev_que->evUser->taskid );
|
||||
(void *) taskId );
|
||||
}
|
||||
else if ( nEntriesFree == EVENTQUESIZE ) {
|
||||
printf ( ", thread=%p, queue empty",
|
||||
(void *) pevent->ev_que->evUser->taskid );
|
||||
(void *) taskId );
|
||||
}
|
||||
else {
|
||||
printf ( ", thread=%p, unused entries=%u",
|
||||
(void *) pevent->ev_que->evUser->taskid, nEntriesFree );
|
||||
(void *) taskId, nEntriesFree );
|
||||
}
|
||||
}
|
||||
|
||||
if ( level > 2 ) {
|
||||
unsigned nDuplicates;
|
||||
unsigned nCanceled;
|
||||
if ( pevent->nreplace ) {
|
||||
printf (", discarded by replacement=%ld", pevent->nreplace);
|
||||
}
|
||||
if ( ! pevent->valque ) {
|
||||
printf (", queueing disabled" );
|
||||
}
|
||||
if ( pevent->ev_que->nDuplicates ) {
|
||||
printf (", duplicate count =%u\n",
|
||||
pevent->ev_que->nDuplicates );
|
||||
LOCKEVQUE(pevent->ev_que);
|
||||
nDuplicates = pevent->ev_que->nDuplicates;
|
||||
nCanceled = pevent->ev_que->nCanceled;
|
||||
UNLOCKEVQUE(pevent->ev_que);
|
||||
if ( nDuplicates ) {
|
||||
printf (", duplicate count =%u\n", nDuplicates );
|
||||
}
|
||||
if ( pevent->ev_que->nCanceled ) {
|
||||
printf (", canceled count =%u\n",
|
||||
pevent->ev_que->nCanceled );
|
||||
if ( nCanceled ) {
|
||||
printf (", canceled count =%u\n", nCanceled );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,7 +273,7 @@ int epicsShareAPI dbel ( const char *pname, unsigned level )
|
||||
*/
|
||||
dbEventCtx epicsShareAPI db_init_events (void)
|
||||
{
|
||||
struct event_user *evUser;
|
||||
struct event_user * evUser;
|
||||
|
||||
if (!dbevEventUserFreeList) {
|
||||
freeListInitPvt(&dbevEventUserFreeList,
|
||||
@@ -326,7 +335,7 @@ dbEventCtx epicsShareAPI db_init_events (void)
|
||||
*/
|
||||
void epicsShareAPI db_close_events (dbEventCtx ctx)
|
||||
{
|
||||
struct event_user *evUser = (struct event_user *) ctx;
|
||||
struct event_user * const evUser = (struct event_user *) ctx;
|
||||
|
||||
/*
|
||||
* Exit not forced on event blocks for now - this is left to channel
|
||||
@@ -336,13 +345,32 @@ void epicsShareAPI db_close_events (dbEventCtx ctx)
|
||||
* NOTE: not deleting events before calling this routine could be
|
||||
* hazardous to the system's health.
|
||||
*/
|
||||
|
||||
epicsMutexMustLock ( evUser->lock );
|
||||
evUser->pendexit = TRUE;
|
||||
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
/* notify the waiting task */
|
||||
epicsEventSignal(evUser->ppendsem);
|
||||
}
|
||||
|
||||
/*
|
||||
* create_ev_que()
|
||||
*/
|
||||
static struct event_que * create_ev_que ( struct event_user * const evUser )
|
||||
{
|
||||
struct event_que * const ev_que = (struct event_que *)
|
||||
freeListCalloc ( dbevEventQueueFreeList );
|
||||
if ( ! ev_que ) {
|
||||
return NULL;
|
||||
}
|
||||
ev_que->writelock = epicsMutexCreate();
|
||||
if ( ! ev_que->writelock ) {
|
||||
freeListFree ( dbevEventQueueFreeList, ev_que );
|
||||
return NULL;
|
||||
}
|
||||
ev_que->evUser = evUser;
|
||||
return ev_que;
|
||||
}
|
||||
|
||||
/*
|
||||
* DB_ADD_EVENT()
|
||||
*/
|
||||
@@ -350,13 +378,9 @@ dbEventSubscription epicsShareAPI db_add_event (
|
||||
dbEventCtx ctx, struct dbAddr *paddr,
|
||||
EVENTFUNC *user_sub, void *user_arg, unsigned select)
|
||||
{
|
||||
struct event_user *evUser = (struct event_user *) ctx;
|
||||
struct dbCommon *precord;
|
||||
struct event_que *ev_que;
|
||||
struct event_que *tmp_que;
|
||||
struct evSubscrip *pevent;
|
||||
|
||||
precord = paddr->precord;
|
||||
struct event_user * const evUser = (struct event_user *) ctx;
|
||||
struct event_que * ev_que;
|
||||
struct evSubscrip * pevent;
|
||||
|
||||
/*
|
||||
* Don't add events which will not be triggered
|
||||
@@ -365,38 +389,42 @@ dbEventSubscription epicsShareAPI db_add_event (
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pevent = freeListCalloc (dbevEventBlockFreeList);
|
||||
if (!pevent) {
|
||||
pevent = freeListCalloc ( dbevEventBlockFreeList );
|
||||
if ( ! pevent ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* find an event que block with enough quota */
|
||||
/* otherwise add a new one to the list */
|
||||
ev_que = &evUser->firstque;
|
||||
while (TRUE) {
|
||||
if (ev_que->quota + ev_que->nCanceled < EVENTQUESIZE - EVENTENTRIES) {
|
||||
epicsMutexMustLock ( evUser->lock );
|
||||
ev_que = & evUser->firstque;
|
||||
while ( TRUE ) {
|
||||
int success = 0;
|
||||
LOCKEVQUE ( ev_que );
|
||||
success = ( ev_que->quota + ev_que->nCanceled <
|
||||
EVENTQUESIZE - EVENTENTRIES );
|
||||
if ( success ) {
|
||||
ev_que->quota += EVENTENTRIES;
|
||||
}
|
||||
UNLOCKEVQUE ( ev_que );
|
||||
if ( success ) {
|
||||
break;
|
||||
}
|
||||
if (!ev_que->nextque) {
|
||||
tmp_que = (struct event_que *)
|
||||
freeListCalloc(dbevEventQueueFreeList);
|
||||
if (!tmp_que) {
|
||||
freeListFree (dbevEventBlockFreeList, pevent);
|
||||
return NULL;
|
||||
if ( ! ev_que->nextque ) {
|
||||
ev_que->nextque = create_ev_que ( evUser );
|
||||
if ( ! ev_que->nextque ) {
|
||||
ev_que = NULL;
|
||||
break;
|
||||
}
|
||||
tmp_que->evUser = evUser;
|
||||
tmp_que->writelock = epicsMutexCreate();
|
||||
if (!tmp_que->writelock) {
|
||||
freeListFree (dbevEventBlockFreeList, pevent);
|
||||
freeListFree (dbevEventQueueFreeList, tmp_que);
|
||||
return NULL;
|
||||
}
|
||||
ev_que->nextque = tmp_que;
|
||||
ev_que = tmp_que;
|
||||
break;
|
||||
}
|
||||
ev_que = ev_que->nextque;
|
||||
}
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
|
||||
if ( ! ev_que ) {
|
||||
freeListFree ( dbevEventBlockFreeList, pevent );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pevent->npend = 0ul;
|
||||
pevent->nreplace = 0ul;
|
||||
@@ -409,10 +437,6 @@ dbEventSubscription epicsShareAPI db_add_event (
|
||||
pevent->enabled = FALSE;
|
||||
pevent->ev_que = ev_que;
|
||||
|
||||
LOCKEVQUE(ev_que);
|
||||
ev_que->quota += EVENTENTRIES;
|
||||
UNLOCKEVQUE(ev_que);
|
||||
|
||||
/*
|
||||
* Simple types values queued up for reliable interprocess
|
||||
* communication (for other types they get whatever happens to be
|
||||
@@ -434,10 +458,9 @@ dbEventSubscription epicsShareAPI db_add_event (
|
||||
*/
|
||||
void epicsShareAPI db_event_enable (dbEventSubscription es)
|
||||
{
|
||||
struct evSubscrip *pevent = (struct evSubscrip *) es;
|
||||
struct dbCommon *precord;
|
||||
|
||||
precord = (struct dbCommon *) pevent->paddr->precord;
|
||||
struct evSubscrip * const pevent = (struct evSubscrip *) es;
|
||||
struct dbCommon * const precord =
|
||||
(struct dbCommon *) pevent->paddr->precord;
|
||||
|
||||
LOCKREC(precord);
|
||||
if ( ! pevent->enabled ) {
|
||||
@@ -452,10 +475,9 @@ void epicsShareAPI db_event_enable (dbEventSubscription es)
|
||||
*/
|
||||
void epicsShareAPI db_event_disable (dbEventSubscription es)
|
||||
{
|
||||
struct evSubscrip *pevent = (struct evSubscrip *) es;
|
||||
struct dbCommon *precord;
|
||||
|
||||
precord = (struct dbCommon *) pevent->paddr->precord;
|
||||
struct evSubscrip * const pevent = (struct evSubscrip *) es;
|
||||
struct dbCommon * const precord =
|
||||
(struct dbCommon *) pevent->paddr->precord;
|
||||
|
||||
LOCKREC(precord);
|
||||
if ( pevent->enabled ) {
|
||||
@@ -472,7 +494,7 @@ void epicsShareAPI db_event_disable (dbEventSubscription es)
|
||||
static void event_remove ( struct event_que *ev_que,
|
||||
unsigned short index, struct evSubscrip *placeHolder )
|
||||
{
|
||||
struct evSubscrip *pEvent = ev_que->evque[index];
|
||||
struct evSubscrip * const pEvent = ev_que->evque[index];
|
||||
|
||||
ev_que->evque[index] = placeHolder;
|
||||
if ( pEvent->npend == 1u ) {
|
||||
@@ -495,12 +517,9 @@ static void event_remove ( struct event_que *ev_que,
|
||||
*/
|
||||
void epicsShareAPI db_cancel_event (dbEventSubscription es)
|
||||
{
|
||||
struct evSubscrip * pevent = ( struct evSubscrip * ) es;
|
||||
struct dbCommon * precord;
|
||||
struct evSubscrip * const pevent = ( struct evSubscrip * ) es;
|
||||
unsigned short getix;
|
||||
|
||||
precord = ( struct dbCommon * ) pevent->paddr->precord;
|
||||
|
||||
db_event_disable ( es );
|
||||
|
||||
/*
|
||||
@@ -564,12 +583,12 @@ void epicsShareAPI db_cancel_event (dbEventSubscription es)
|
||||
*/
|
||||
void epicsShareAPI db_flush_extra_labor_event (dbEventCtx ctx)
|
||||
{
|
||||
struct event_user *evUser = (struct event_user *) ctx;
|
||||
struct event_user * const evUser = (struct event_user *) ctx;
|
||||
|
||||
epicsMutexMustLock ( evUser->lock );
|
||||
while ( evUser->extraLaborBusy ) {
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
epicsThreadSleep(1.0);
|
||||
epicsThreadSleep(0.1);
|
||||
epicsMutexMustLock ( evUser->lock );
|
||||
}
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
@@ -585,7 +604,7 @@ void epicsShareAPI db_flush_extra_labor_event (dbEventCtx ctx)
|
||||
int epicsShareAPI db_add_extra_labor_event (
|
||||
dbEventCtx ctx, EXTRALABORFUNC *func, void *arg)
|
||||
{
|
||||
struct event_user *evUser = (struct event_user *) ctx;
|
||||
struct event_user * const evUser = (struct event_user *) ctx;
|
||||
|
||||
epicsMutexMustLock ( evUser->lock );
|
||||
evUser->extralabor_sub = func;
|
||||
@@ -600,7 +619,7 @@ int epicsShareAPI db_add_extra_labor_event (
|
||||
*/
|
||||
int epicsShareAPI db_post_extra_labor (dbEventCtx ctx)
|
||||
{
|
||||
struct event_user *evUser = (struct event_user *) ctx;
|
||||
struct event_user * const evUser = (struct event_user *) ctx;
|
||||
int doit;
|
||||
|
||||
epicsMutexMustLock ( evUser->lock );
|
||||
@@ -627,12 +646,10 @@ int epicsShareAPI db_post_extra_labor (dbEventCtx ctx)
|
||||
*/
|
||||
static void db_post_single_event_private (struct evSubscrip *event)
|
||||
{
|
||||
struct event_que *ev_que;
|
||||
db_field_log *pLog;
|
||||
int firstEventFlag;
|
||||
unsigned rngSpace;
|
||||
|
||||
ev_que = event->ev_que;
|
||||
struct event_que * const ev_que = event->ev_que;
|
||||
db_field_log * pLog;
|
||||
int firstEventFlag;
|
||||
unsigned rngSpace;
|
||||
|
||||
/*
|
||||
* evUser ring buffer must be locked for the multiple
|
||||
@@ -747,10 +764,10 @@ void *pField,
|
||||
unsigned int caEventMask
|
||||
)
|
||||
{
|
||||
struct dbCommon *pdbc = (struct dbCommon *)pRecord;
|
||||
struct evSubscrip *event;
|
||||
struct dbCommon * const pdbc = (struct dbCommon *)pRecord;
|
||||
struct evSubscrip * event;
|
||||
|
||||
if (pdbc->mlis.count == 0) return DB_EVENT_OK; /* no monitors set */
|
||||
if (pdbc->mlis.count == 0) return DB_EVENT_OK; /* no monitors set */
|
||||
|
||||
LOCKREC(pdbc);
|
||||
|
||||
@@ -762,8 +779,7 @@ unsigned int caEventMask
|
||||
* changed or pval==NULL and waiting on alarms and alarms changed
|
||||
*/
|
||||
if ( (event->paddr->pfield == (void *)pField || pField==NULL) &&
|
||||
(caEventMask & event->select)) {
|
||||
|
||||
(caEventMask & event->select) ) {
|
||||
db_post_single_event_private (event);
|
||||
}
|
||||
}
|
||||
@@ -778,8 +794,8 @@ unsigned int caEventMask
|
||||
*/
|
||||
void epicsShareAPI db_post_single_event (dbEventSubscription es)
|
||||
{
|
||||
struct evSubscrip *event = (struct evSubscrip *) es;
|
||||
struct dbCommon *precord = event->paddr->precord;
|
||||
struct evSubscrip * const event = (struct evSubscrip *) es;
|
||||
struct dbCommon * const precord = event->paddr->precord;
|
||||
|
||||
dbScanLock (precord);
|
||||
db_post_single_event_private (event);
|
||||
@@ -898,8 +914,8 @@ static int event_read ( struct event_que *ev_que )
|
||||
*/
|
||||
static void event_task (void *pParm)
|
||||
{
|
||||
struct event_user *evUser = (struct event_user *) pParm;
|
||||
struct event_que *ev_que;
|
||||
struct event_user * const evUser = (struct event_user *) pParm;
|
||||
struct event_que * ev_que;
|
||||
|
||||
/* init hook */
|
||||
if (evUser->init_func) {
|
||||
@@ -934,12 +950,14 @@ static void event_task (void *pParm)
|
||||
epicsMutexMustLock ( evUser->lock );
|
||||
}
|
||||
evUser->extraLaborBusy = FALSE;
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
|
||||
for ( ev_que = &evUser->firstque; ev_que;
|
||||
ev_que = ev_que->nextque ) {
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
event_read (ev_que);
|
||||
epicsMutexMustLock ( evUser->lock );
|
||||
}
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
|
||||
} while( ! evUser->pendexit );
|
||||
|
||||
@@ -975,7 +993,7 @@ int epicsShareAPI db_start_events (
|
||||
dbEventCtx ctx,const char *taskname, void (*init_func)(void *),
|
||||
void *init_func_arg, unsigned osiPriority )
|
||||
{
|
||||
struct event_user *evUser = (struct event_user *) ctx;
|
||||
struct event_user * const evUser = (struct event_user *) ctx;
|
||||
|
||||
epicsMutexMustLock ( evUser->lock );
|
||||
|
||||
@@ -995,7 +1013,8 @@ int epicsShareAPI db_start_events (
|
||||
taskname = EVENT_PEND_NAME;
|
||||
}
|
||||
evUser->taskid = epicsThreadCreate (
|
||||
taskname, osiPriority, epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
taskname, osiPriority,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
event_task, (void *)evUser);
|
||||
if (!evUser->taskid) {
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
@@ -1008,9 +1027,10 @@ int epicsShareAPI db_start_events (
|
||||
/*
|
||||
* db_event_change_priority()
|
||||
*/
|
||||
void epicsShareAPI db_event_change_priority ( dbEventCtx ctx, unsigned epicsPriority )
|
||||
void epicsShareAPI db_event_change_priority ( dbEventCtx ctx,
|
||||
unsigned epicsPriority )
|
||||
{
|
||||
struct event_user * evUser = ( struct event_user * ) ctx;
|
||||
struct event_user * const evUser = ( struct event_user * ) ctx;
|
||||
epicsThreadSetPriority ( evUser->taskid, epicsPriority );
|
||||
}
|
||||
|
||||
@@ -1019,9 +1039,11 @@ void epicsShareAPI db_event_change_priority ( dbEventCtx ctx, unsigned epicsPrio
|
||||
*/
|
||||
void epicsShareAPI db_event_flow_ctrl_mode_on (dbEventCtx ctx)
|
||||
{
|
||||
struct event_user *evUser = (struct event_user *) ctx;
|
||||
struct event_user * const evUser = (struct event_user *) ctx;
|
||||
|
||||
epicsMutexMustLock ( evUser->lock );
|
||||
evUser->flowCtrlMode = TRUE;
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
/*
|
||||
* notify the event handler task
|
||||
*/
|
||||
@@ -1036,9 +1058,11 @@ void epicsShareAPI db_event_flow_ctrl_mode_on (dbEventCtx ctx)
|
||||
*/
|
||||
void epicsShareAPI db_event_flow_ctrl_mode_off (dbEventCtx ctx)
|
||||
{
|
||||
struct event_user *evUser = (struct event_user *) ctx;
|
||||
struct event_user * const evUser = (struct event_user *) ctx;
|
||||
|
||||
epicsMutexMustLock ( evUser->lock );
|
||||
evUser->flowCtrlMode = FALSE;
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
/*
|
||||
* notify the event handler task
|
||||
*/
|
||||
|
||||
@@ -74,7 +74,7 @@ void dbPutNotifyBlocker::cancel (
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
if ( this->pn.paddr ) {
|
||||
if ( this->pNotify ) {
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
dbNotifyCancel ( &this->pn );
|
||||
}
|
||||
@@ -100,26 +100,31 @@ void dbPutNotifyBlocker::expandValueBuf (
|
||||
|
||||
extern "C" void putNotifyCompletion ( putNotify *ppn )
|
||||
{
|
||||
dbPutNotifyBlocker * pBlocker = static_cast < dbPutNotifyBlocker * > ( ppn->usrPvt );
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( pBlocker->mutex );
|
||||
if ( pBlocker->pNotify ) {
|
||||
if ( pBlocker->pn.status != putNotifyOK) {
|
||||
pBlocker->pNotify->exception (
|
||||
guard, ECA_PUTFAIL, "put notify unsuccessful",
|
||||
static_cast <unsigned> (pBlocker->pn.dbrType),
|
||||
static_cast <unsigned> (pBlocker->pn.nRequest) );
|
||||
}
|
||||
else {
|
||||
pBlocker->pNotify->completion ( guard );
|
||||
}
|
||||
dbPutNotifyBlocker * const pBlocker =
|
||||
static_cast < dbPutNotifyBlocker * > ( ppn->usrPvt );
|
||||
epicsGuard < epicsMutex > guard ( pBlocker->mutex );
|
||||
cacWriteNotify * const pNtfy = pBlocker->pNotify;
|
||||
if ( pNtfy ) {
|
||||
pBlocker->pNotify = 0;
|
||||
// Its necessary to signal the initiators now before we call
|
||||
// the user callback. This is less efficent, and potentially
|
||||
// causes more thread context switching, but its probably
|
||||
// unavoidable because its possible that the use callback
|
||||
// might destroy this object.
|
||||
pBlocker->block.signal ();
|
||||
if ( pBlocker->pn.status != putNotifyOK ) {
|
||||
pNtfy->exception (
|
||||
guard, ECA_PUTFAIL, "put notify unsuccessful",
|
||||
static_cast < unsigned > (pBlocker->pn.dbrType),
|
||||
static_cast < unsigned > (pBlocker->pn.nRequest) );
|
||||
}
|
||||
else {
|
||||
errlogPrintf ( "put notify completion with nill pNotify?\n" );
|
||||
pNtfy->completion ( guard );
|
||||
}
|
||||
pBlocker->pNotify = 0;
|
||||
}
|
||||
pBlocker->block.signal ();
|
||||
else {
|
||||
errlogPrintf ( "put notify completion with nill pNotify?\n" );
|
||||
}
|
||||
}
|
||||
|
||||
void dbPutNotifyBlocker::initiatePutNotify (
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "dbLock.h"
|
||||
#include "devSup.h"
|
||||
#include "drvSup.h"
|
||||
#include "menuConvert.h"
|
||||
#include "menuPini.h"
|
||||
#include "registryRecordType.h"
|
||||
#include "registryDeviceSupport.h"
|
||||
@@ -68,6 +69,7 @@ static enum {
|
||||
} iocState = iocVirgin;
|
||||
|
||||
/* define forward references*/
|
||||
static int checkDatabase(dbBase *pdbbase);
|
||||
static void initDrvSup(void);
|
||||
static void initRecSup(void);
|
||||
static void initDevSup(void);
|
||||
@@ -98,8 +100,8 @@ int iocBuild(void)
|
||||
}
|
||||
|
||||
errlogPrintf("Starting iocInit\n");
|
||||
if (!pdbbase) {
|
||||
errlogPrintf("iocBuild: Aborting, no database loaded!\n");
|
||||
if (checkDatabase(pdbbase)) {
|
||||
errlogPrintf("iocBuild: Aborting, bad database definition (DBD)!\n");
|
||||
return -1;
|
||||
}
|
||||
epicsSignalInstallSigHupIgnore();
|
||||
@@ -203,6 +205,83 @@ int iocPause(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Database sanity checks
|
||||
*
|
||||
* This is not an attempt to sanity-check the whole .dbd file, only
|
||||
* two menus normally get modified by users: menuConvert and menuScan.
|
||||
*
|
||||
* The menuConvert checks were added to flag problems with IOCs
|
||||
* converted from 3.13.x, where the SLOPE choice didn't exist.
|
||||
*
|
||||
* The menuScan checks make sure the user didn't fiddle too much
|
||||
* when creating new periodic scan choices.
|
||||
*/
|
||||
|
||||
static int checkDatabase(dbBase *pdbbase)
|
||||
{
|
||||
const dbMenu *pMenu;
|
||||
|
||||
if (!pdbbase) {
|
||||
errlogPrintf("checkDatabase: No database definitions loaded.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pMenu = dbFindMenu(pdbbase, "menuConvert");
|
||||
if (!pMenu) {
|
||||
errlogPrintf("checkDatabase: menuConvert not defined.\n");
|
||||
return -1;
|
||||
}
|
||||
if (pMenu->nChoice <= menuConvertLINEAR) {
|
||||
errlogPrintf("checkDatabase: menuConvert has too few choices.\n");
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(pMenu->papChoiceName[menuConvertNO_CONVERSION],
|
||||
"menuConvertNO_CONVERSION")) {
|
||||
errlogPrintf("checkDatabase: menuConvertNO_CONVERSION doesn't match.\n");
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(pMenu->papChoiceName[menuConvertSLOPE], "menuConvertSLOPE")) {
|
||||
errlogPrintf("checkDatabase: menuConvertSLOPE doesn't match.\n");
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(pMenu->papChoiceName[menuConvertLINEAR], "menuConvertLINEAR")) {
|
||||
errlogPrintf("checkDatabase: menuConvertLINEAR doesn't match.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pMenu = dbFindMenu(pdbbase, "menuScan");
|
||||
if (!pMenu) {
|
||||
errlogPrintf("checkDatabase: menuScan not defined.\n");
|
||||
return -1;
|
||||
}
|
||||
if (pMenu->nChoice <= menuScanI_O_Intr) {
|
||||
errlogPrintf("checkDatabase: menuScan has too few choices.\n");
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(pMenu->papChoiceName[menuScanPassive],
|
||||
"menuScanPassive")) {
|
||||
errlogPrintf("checkDatabase: menuScanPassive doesn't match.\n");
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(pMenu->papChoiceName[menuScanEvent],
|
||||
"menuScanEvent")) {
|
||||
errlogPrintf("checkDatabase: menuScanEvent doesn't match.\n");
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(pMenu->papChoiceName[menuScanI_O_Intr],
|
||||
"menuScanI_O_Intr")) {
|
||||
errlogPrintf("checkDatabase: menuScanI_O_Intr doesn't match.\n");
|
||||
return -1;
|
||||
}
|
||||
if (pMenu->nChoice <= SCAN_1ST_PERIODIC) {
|
||||
errlogPrintf("checkDatabase: menuScan has no periodic choices.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void initDrvSup(void) /* Locate all driver support entry tables */
|
||||
{
|
||||
|
||||
@@ -232,19 +232,30 @@ int min = sched_get_priority_min(prm->policy);
|
||||
int max = sched_get_priority_max(prm->policy);
|
||||
int low, try;
|
||||
|
||||
prm->min_pri = -1;
|
||||
prm->max_pri = -1;
|
||||
|
||||
if ( -1 == min || -1 == max ) {
|
||||
/* something is very wrong... */
|
||||
/* something is very wrong; maintain old behavior
|
||||
* (warning message if sched_get_priority_xxx() fails
|
||||
* and use default policy's sched_priority [even if
|
||||
* that is likely to cause epicsThreadCreate to fail
|
||||
* because that priority is not suitable for SCHED_FIFO]).
|
||||
*/
|
||||
prm->min_pri = prm->max_pri = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if ( try_pri(min, prm->policy) ) {
|
||||
/* cannot create thread at minimum priority;
|
||||
* probably no permission to use SCHED_FIFO
|
||||
* at all.
|
||||
* at all. However, we still must return
|
||||
* a priority range accepted by the SCHED_FIFO
|
||||
* policy. Otherwise, epicsThreadCreate() cannot
|
||||
* detect the unsufficient permission (EPERM)
|
||||
* and fall back to a non-RT thread (because
|
||||
* pthread_attr_setschedparam would fail with
|
||||
* EINVAL due to the bad priority).
|
||||
*/
|
||||
prm->min_pri = prm->max_pri = min;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#!/usr/bin/perl
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
# Copyright (c) 2011 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.
|
||||
# EPICS BASE Versions 3.13.7
|
||||
# and higher are distributed subject to a Software License Agreement found
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
#
|
||||
@@ -62,18 +61,13 @@ foreach $source ( @files )
|
||||
$basename=$source;
|
||||
$basename=~s'.*[/\\]'';
|
||||
$target = "$install_dir/$basename";
|
||||
$temp = "$target.$$";
|
||||
|
||||
# The Win32 filesystem seems to be 'slow',
|
||||
# i.e. $target may look like 'up to date'
|
||||
# unless you wait an hour.
|
||||
# -> skip this test on WIN32 ?
|
||||
#if (-f $target and $^O ne "MSWin32")
|
||||
if (-f $target)
|
||||
{
|
||||
if (-M $target < -M $source and
|
||||
if (-M $target < -M $source and
|
||||
-C $target < -C $source)
|
||||
{
|
||||
print "$target is up to date\n";
|
||||
next;
|
||||
}
|
||||
else
|
||||
@@ -84,8 +78,9 @@ foreach $source ( @files )
|
||||
}
|
||||
}
|
||||
|
||||
# print "Installing $source into $install_dir\n";
|
||||
copy ($source, $target) or die "Copy failed";
|
||||
# Using copy + rename fixes problems with parallel builds:
|
||||
copy ($source, $temp) or die "Copy failed: $!\n";
|
||||
rename ($temp, $target) or die "Rename failed: $!\n";
|
||||
|
||||
# chmod 0555 <read-only> DOES work on WIN32, but:
|
||||
# Another chmod 0777 to make it write- and deletable
|
||||
|
||||
Reference in New Issue
Block a user