From 1975a36a9ecb8152793d29041fb184a778e974c9 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 31 Oct 2023 09:49:37 -0700 Subject: [PATCH] ioc: combine registrars and detect QSRV1 --- ioc/groupsourcehooks.cpp | 17 ++++------ ioc/iochooks.cpp | 69 ++++++++++++++++++++++++++++++++++++--- ioc/iocsource.cpp | 40 ----------------------- ioc/iocsource.h | 2 -- ioc/pvalink.cpp | 20 ++++++++---- ioc/pvxs3x.dbd | 2 -- ioc/pvxs7x.dbd | 3 -- ioc/qsrvpvt.h | 37 +++++++++++++++++++++ ioc/singlesourcehooks.cpp | 16 ++++----- qsrv/softMain.cpp | 3 -- 10 files changed, 128 insertions(+), 81 deletions(-) create mode 100644 ioc/qsrvpvt.h diff --git a/ioc/groupsourcehooks.cpp b/ioc/groupsourcehooks.cpp index 9b5050b5a..a5395a547 100644 --- a/ioc/groupsourcehooks.cpp +++ b/ioc/groupsourcehooks.cpp @@ -20,6 +20,7 @@ #include #include +#include "qsrvpvt.h" #include "groupsource.h" #include "groupconfigprocessor.h" #include "iocshcommand.h" @@ -176,8 +177,6 @@ using namespace pvxs; */ void qsrvGroupSourceInit(initHookState theInitHookState) { try { - if(!IOCSource::enabled()) - return; if (theInitHookState == initHookAfterInitDatabase) { GroupConfigProcessor processor; epicsGuard G(processor.config.groupMapMutex); @@ -209,6 +208,10 @@ void qsrvGroupSourceInit(initHookState theInitHookState) { } } +} // namespace + +namespace pvxs { +namespace ioc { /** * IOC pvxs Group Source registrar. This implements the required registrar function that is called by xxxx_registerRecordDeviceDriver, * the auto-generated stub created for all IOC implementations. @@ -220,7 +223,7 @@ void qsrvGroupSourceInit(initHookState theInitHookState) { * group record type sources defined so far. Note that you can define sources up until the `iocInit()` call, * after which point the `initHookAfterIocBuilt` handlers are called and will register all the defined records. */ -void pvxsGroupSourceRegistrar() { +void group_enable() { // Register commands to be available in the IOC shell IOCShCommand("pvxgl", "[level, [pattern]]", "Group Sources list.\n" @@ -236,10 +239,4 @@ void pvxsGroupSourceRegistrar() { initHookRegister(&qsrvGroupSourceInit); } -} // namespace - -// in .dbd file -//registrar(pvxsGroupSourceRegistrar) -extern "C" { -epicsExportRegistrar(pvxsGroupSourceRegistrar); -} +}} // namespace pvxs::ioc diff --git a/ioc/iochooks.cpp b/ioc/iochooks.cpp index 020a119ae..f4c820415 100644 --- a/ioc/iochooks.cpp +++ b/ioc/iochooks.cpp @@ -18,8 +18,12 @@ #include #include +#include #include #include +#include +#include +#include #include #include @@ -28,14 +32,11 @@ #include "iocshcommand.h" #include "utilpvt.h" +#include "qsrvpvt.h" // include last to avoid clash of #define printf with other headers #include -#if EPICS_VERSION_INT >= VERSION_INT(7, 0, 4, 0) -# define USE_DEINIT_HOOKS -#endif - namespace pvxs { namespace ioc { @@ -286,6 +287,56 @@ using namespace pvxs::ioc; namespace { +bool enable2() { + // detect if also linked with qsrv.dbd + const bool permit = !registryDeviceSupportFind("devWfPDBDemo"); + bool request = permit; + bool quiet = false; + + auto env_dis = getenv("EPICS_IOC_IGNORE_SERVERS"); + auto env_ena = getenv("PVXS_QSRV_ENABLE"); + + if(env_dis && strstr(env_dis, "qsrv2")) { + request = false; + quiet = true; + + } else if(env_ena && epicsStrCaseCmp(env_ena, "YES")==0) { + request = true; + + } else if(env_ena && epicsStrCaseCmp(env_ena, "NO")==0) { + request = false; + quiet = true; + + } else if(env_ena) { + // will be seen during initialization, print synchronously + fprintf(stderr, "ERROR: PVXS_QSRV_ENABLE=%s not YES/NO. Defaulting to %s.\n", + env_ena, + request ? "YES" : "NO"); + } + + const bool enable = permit && request; + + if(quiet) { + // shut up, I know what I'm doing... + } else if(request && !permit) { + fprintf(stderr, + "WARNING: QSRV1 detected, disabling QSRV2.\n" + " If not intended, omit qsrv.dbd when including pvxsIoc.dbd\n"); + + } else { + printf("INFO: PVXS QSRV2 is loaded, %spermitted, and %s.\n", + permit ? "" : "NOT ", + enable ? "ENABLED" : "disabled"); + + if(!permit) { + printf(" Not permitted due to confict with QSRV1.\n" + " Remove qsrv.dbd from IOC.\n"); + } + } + + return enable; +} + /** * IOC pvxs base registrar. This implements the required registrar function that is called by xxxx_registerRecordDeviceDriver, * the auto-generated stub created for all IOC implementations. @@ -296,10 +347,12 @@ namespace { * 2. Also make sure that you initialize your server implementation - PVXS in our case - so that it will be available for the shell. * 3. Lastly register your hook handler to handle any state hooks that you want to implement */ -void pvxsBaseRegistrar() { +void pvxsBaseRegistrar() noexcept { try { pvxs::logger_config_env(); + bool enableQ = enable2(); + pvxServer = new pvxServer_t(); IOCShCommand("pvxsr", "[show_detailed_information?]", "PVXS Server Report. " @@ -320,6 +373,12 @@ void pvxsBaseRegistrar() { // Register our hook handler to intercept certain state changes initHookRegister(&pvxsInitHook); + + if(enableQ) { + single_enable(); + group_enable(); + pvalink_enable(); + } } catch (std::exception& e) { fprintf(stderr, "Error in %s : %s\n", __func__, e.what()); } diff --git a/ioc/iocsource.cpp b/ioc/iocsource.cpp index 8ebabf96b..869d7d830 100644 --- a/ioc/iocsource.cpp +++ b/ioc/iocsource.cpp @@ -36,46 +36,6 @@ DEFINE_LOGGER(_log, "pvxs.ioc.db"); namespace pvxs { namespace ioc { - -bool IOCSource::enabled() -{ - /* -1 - disabled - * 0 - lazy init, check environment - * 1 - enabled - */ - static std::atomic ena{}; - - auto e = ena.load(); - if(e==0) { - e = inUnitTest() ? 1 : -1; // default to disabled normally (not unittest) - - auto env_dis = getenv("EPICS_IOC_IGNORE_SERVERS"); - auto env_ena = getenv("PVXS_QSRV_ENABLE"); - - if(env_dis && strstr(env_dis, "qsrv2")) { - e = -1; - - } else if(env_ena && epicsStrCaseCmp(env_ena, "YES")==0) { - e = 1; - - } else if(env_ena && epicsStrCaseCmp(env_ena, "NO")==0) { - e = -1; - - } else if(env_ena) { - // will be seen during initialization, print synchronously - fprintf(stderr, "ERROR: PVXS_QSRV_ENABLE=%s not YES/NO. Defaulting to %s.\n", - env_ena, - e==1 ? "YES" : "NO"); - } - printf("INFO: PVXS QSRV2 is loaded and %s\n", - e==1 ? "ENABLED." : "disabled.\n" - " To enable set: epicsEnvSet(\"PVXS_QSRV_ENABLE\",\"YES\")\n" - " and ensure that $EPICS_IOC_IGNORE_SERVERS does not contain \"qsrv2\"."); - ena = e; - } - return e==1; -} - void IOCSource::initialize(Value& value, const MappingInfo &info, const Channel& chan) { if(info.type==MappingInfo::Scalar) { diff --git a/ioc/iocsource.h b/ioc/iocsource.h index 9b16bd73a..c4b27795e 100644 --- a/ioc/iocsource.h +++ b/ioc/iocsource.h @@ -43,8 +43,6 @@ enum type { class IOCSource { public: - static bool enabled(); - static void initialize(Value& value, const MappingInfo &info, const Channel &chan); static void get(Value& valuePrototype, diff --git a/ioc/pvalink.cpp b/ioc/pvalink.cpp index 257889660..2621b8ce0 100644 --- a/ioc/pvalink.cpp +++ b/ioc/pvalink.cpp @@ -36,6 +36,7 @@ #include "dbentry.h" #include "iocshcommand.h" #include "utilpvt.h" +#include "qsrvpvt.h" #include /* redirects stdout/stderr; include after util.h from libevent */ #include /* defines epicsExportSharedSymbols */ @@ -404,17 +405,22 @@ void dbpvar(const char *precordname, int level) } static -void installPVAAddLinkHook() +const iocshVarDef pvaLinkNWorkersDef[] = { + { + "pvaLinkNWorkers", + iocshArgInt, + &pvaLinkNWorkers + }, + {0, iocshArgInt, 0} +}; + +void pvalink_enable() { initHookRegister(&initPVALink); IOCShCommand("dbpvar", "dbpvar", "record name", "level") .implementation<&dbpvar>(); + iocshRegisterVariable(pvaLinkNWorkersDef); + } }} // namespace pvxs::ioc - -extern "C" { - using pvxs::ioc::installPVAAddLinkHook; - epicsExportRegistrar(installPVAAddLinkHook); - epicsExportAddress(int, pvaLinkNWorkers); -} diff --git a/ioc/pvxs3x.dbd b/ioc/pvxs3x.dbd index 6330d4a3e..b5273d354 100644 --- a/ioc/pvxs3x.dbd +++ b/ioc/pvxs3x.dbd @@ -1,6 +1,4 @@ registrar(pvxsBaseRegistrar) -registrar(pvxsSingleSourceRegistrar) -registrar(pvxsGroupSourceRegistrar) # from demo.cpp device(waveform, CONSTANT, devWfPDBQ2Demo, "QSRV2 Demo") diff --git a/ioc/pvxs7x.dbd b/ioc/pvxs7x.dbd index e0ec7a6b3..aa4957652 100644 --- a/ioc/pvxs7x.dbd +++ b/ioc/pvxs7x.dbd @@ -1,7 +1,4 @@ registrar(pvxsBaseRegistrar) -registrar(pvxsSingleSourceRegistrar) -registrar(pvxsGroupSourceRegistrar) -registrar(installPVAAddLinkHook) link("pva", "lsetPVA") # from demo.cpp diff --git a/ioc/qsrvpvt.h b/ioc/qsrvpvt.h new file mode 100644 index 000000000..3649fc976 --- /dev/null +++ b/ioc/qsrvpvt.h @@ -0,0 +1,37 @@ +/* Copyright - See the COPYRIGHT that is included with this distribution. + * pvxs is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +#ifndef QSRVPVT_H +#define QSRVPVT_H + +#include +#include + +namespace pvxs { +namespace ioc { + +#if EPICS_VERSION_INT >= VERSION_INT(3, 15, 0 ,0) +void single_enable(); +#else +static inline +void single_enable() {} +#endif + +#if EPICS_VERSION_INT >= VERSION_INT(7, 0, 0 ,0) +void group_enable(); +void pvalink_enable(); +#else +static inline +void group_enable() {} +static inline +void pvalink_enable() {} +#endif + +#if EPICS_VERSION_INT >= VERSION_INT(7, 0, 4, 0) +# define USE_DEINIT_HOOKS +#endif + +}} // namespace pvxs::ioc + +#endif // QSRVPVT_H diff --git a/ioc/singlesourcehooks.cpp b/ioc/singlesourcehooks.cpp index e86a278a8..b88da6c79 100644 --- a/ioc/singlesourcehooks.cpp +++ b/ioc/singlesourcehooks.cpp @@ -21,6 +21,7 @@ #include #include +#include "qsrvpvt.h" #include "iocshcommand.h" #include "singlesource.h" @@ -148,8 +149,6 @@ dbServer qsrv2Server = { * @param theInitHookState the initHook state - we only want to trigger on the initHookAfterIocBuilt state - ignore all others */ void qsrvSingleSourceInit(initHookState theInitHookState) { - if(!IOCSource::enabled()) - return; if (theInitHookState == initHookAtBeginning) { (void)dbRegisterServer(&qsrv2Server); } else @@ -158,6 +157,10 @@ void qsrvSingleSourceInit(initHookState theInitHookState) { } } +} // namespace + +namespace pvxs { +namespace ioc { /** * IOC pvxs Single Source registrar. This implements the required registrar function that is called by xxxx_registerRecordDeviceDriver, * the auto-generated stub created for all IOC implementations. @@ -170,7 +173,7 @@ void qsrvSingleSourceInit(initHookState theInitHookState) { * single record type sources defined so far. Note that you can define sources up until the `iocInit()` call, * after which point the `initHookAfterIocBuilt` handlers are called and will register all the defined records. */ -void pvxsSingleSourceRegistrar() { +void single_enable() { // Register commands to be available in the IOC shell IOCShCommand("pvxsl", "details", "List PV names.\n") @@ -179,11 +182,6 @@ void pvxsSingleSourceRegistrar() { initHookRegister(&qsrvSingleSourceInit); } -} // namespace +}} // namespace pvxs::ioc -// in .dbd file -//registrar(pvxsSingleSourceRegistrar) -extern "C" { -epicsExportRegistrar(pvxsSingleSourceRegistrar); -} diff --git a/qsrv/softMain.cpp b/qsrv/softMain.cpp index c5e3d179d..eb98d3231 100644 --- a/qsrv/softMain.cpp +++ b/qsrv/softMain.cpp @@ -141,9 +141,6 @@ int main(int argc, char *argv[]) bool loadedDb = false; bool ranScript = false; - if(!getenv("PVXS_QSRV_ENABLE")) - epicsEnvSet("PVXS_QSRV_ENABLE","YES"); - #if EPICS_VERSION_INT >= VERSION_INT(7, 0, 3, 1) // attempt to compute relative paths {