Skip to content

Commit

Permalink
ioc: combine registrars and detect QSRV1
Browse files Browse the repository at this point in the history
  • Loading branch information
mdavidsaver committed Nov 4, 2023
1 parent 44e7af5 commit 1975a36
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 81 deletions.
17 changes: 7 additions & 10 deletions ioc/groupsourcehooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <pvxs/source.h>
#include <pvxs/iochooks.h>

#include "qsrvpvt.h"
#include "groupsource.h"
#include "groupconfigprocessor.h"
#include "iocshcommand.h"
Expand Down Expand Up @@ -176,8 +177,6 @@ using namespace pvxs;
*/
void qsrvGroupSourceInit(initHookState theInitHookState) {
try {
if(!IOCSource::enabled())
return;
if (theInitHookState == initHookAfterInitDatabase) {
GroupConfigProcessor processor;
epicsGuard<epicsMutex> G(processor.config.groupMapMutex);
Expand Down Expand Up @@ -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.
Expand All @@ -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<int, const char*>("pvxgl", "[level, [pattern]]",
"Group Sources list.\n"
Expand All @@ -236,10 +239,4 @@ void pvxsGroupSourceRegistrar() {
initHookRegister(&qsrvGroupSourceInit);
}

} // namespace

// in .dbd file
//registrar(pvxsGroupSourceRegistrar)
extern "C" {
epicsExportRegistrar(pvxsGroupSourceRegistrar);
}
}} // namespace pvxs::ioc
69 changes: 64 additions & 5 deletions ioc/iochooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@

#include <epicsExport.h>
#include <epicsExit.h>
#include <epicsString.h>
#include <initHooks.h>
#include <iocsh.h>
#include <dbAccess.h>
#include <dbStaticLib.h>
#include <registryDeviceSupport.h>

#include <pvxs/iochooks.h>
#include <pvxs/log.h>
Expand All @@ -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 <epicsStdio.h>

#if EPICS_VERSION_INT >= VERSION_INT(7, 0, 4, 0)
# define USE_DEINIT_HOOKS
#endif

namespace pvxs {
namespace ioc {

Expand Down Expand Up @@ -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.
Expand All @@ -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<int>("pvxsr", "[show_detailed_information?]", "PVXS Server Report. "
Expand All @@ -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());
}
Expand Down
40 changes: 0 additions & 40 deletions ioc/iocsource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<int> 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) {
Expand Down
2 changes: 0 additions & 2 deletions ioc/iocsource.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
20 changes: 13 additions & 7 deletions ioc/pvalink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "dbentry.h"
#include "iocshcommand.h"
#include "utilpvt.h"
#include "qsrvpvt.h"

#include <epicsStdio.h> /* redirects stdout/stderr; include after util.h from libevent */
#include <epicsExport.h> /* defines epicsExportSharedSymbols */
Expand Down Expand Up @@ -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<const char*, int>("dbpvar", "dbpvar", "record name", "level")
.implementation<&dbpvar>();
iocshRegisterVariable(pvaLinkNWorkersDef);

}

}} // namespace pvxs::ioc

extern "C" {
using pvxs::ioc::installPVAAddLinkHook;
epicsExportRegistrar(installPVAAddLinkHook);
epicsExportAddress(int, pvaLinkNWorkers);
}
2 changes: 0 additions & 2 deletions ioc/pvxs3x.dbd
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
registrar(pvxsBaseRegistrar)
registrar(pvxsSingleSourceRegistrar)
registrar(pvxsGroupSourceRegistrar)

# from demo.cpp
device(waveform, CONSTANT, devWfPDBQ2Demo, "QSRV2 Demo")
Expand Down
3 changes: 0 additions & 3 deletions ioc/pvxs7x.dbd
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
registrar(pvxsBaseRegistrar)
registrar(pvxsSingleSourceRegistrar)
registrar(pvxsGroupSourceRegistrar)
registrar(installPVAAddLinkHook)
link("pva", "lsetPVA")

# from demo.cpp
Expand Down
37 changes: 37 additions & 0 deletions ioc/qsrvpvt.h
Original file line number Diff line number Diff line change
@@ -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 <pvxs/version.h>
#include <pvxs/iochooks.h>

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
16 changes: 7 additions & 9 deletions ioc/singlesourcehooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <pvxs/server.h>
#include <pvxs/iochooks.h>

#include "qsrvpvt.h"
#include "iocshcommand.h"
#include "singlesource.h"

Expand Down Expand Up @@ -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
Expand All @@ -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.
Expand All @@ -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<int>("pvxsl", "details",
"List PV names.\n")
Expand All @@ -179,11 +182,6 @@ void pvxsSingleSourceRegistrar() {
initHookRegister(&qsrvSingleSourceInit);
}

} // namespace
}} // namespace pvxs::ioc

// in .dbd file
//registrar(pvxsSingleSourceRegistrar)
extern "C" {
epicsExportRegistrar(pvxsSingleSourceRegistrar);
}

3 changes: 0 additions & 3 deletions qsrv/softMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down

0 comments on commit 1975a36

Please sign in to comment.