/** * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace pvxs; namespace { std::atomic instance{}; DEFINE_LOGGER(log, "pvxs.ioc"); void pvxsl(int detail) { try { if(auto serv = instance.load()) { for(auto& pair : serv->listSource()) { auto src = serv->getSource(pair.first); if(!src) continue; // race? auto list = src->onList(); if(detail>0) printf("# Source %s@%d%s\n", pair.first.c_str(), pair.second, list.dynamic ? " [dynamic]":""); if(!list.names) { if(detail>0) printf("# no PVs\n"); } else { for(auto& name : *list.names) { printf("%s\n", name.c_str()); } } } } } catch(std::exception& e) { fprintf(stderr, "Error in %s : %s\n", __func__, e.what()); } } void pvxsr(int detail) { try { if(auto serv = instance.load()) { std::ostringstream strm; Detailed D(strm, detail); strm<<*serv; printf("%s", strm.str().c_str()); } } catch(std::exception& e) { fprintf(stderr, "Error in %s : %s\n", __func__, e.what()); } } void pvxs_target_info() { try { std::ostringstream capture; target_information(capture); printf("%s", capture.str().c_str()); } catch(std::exception& e) { fprintf(stderr, "Error in %s : %s\n", __func__, e.what()); } } // index_sequence from: //http://stackoverflow.com/questions/17424477/implementation-c14-make-integer-sequence template< std::size_t ... I > struct index_sequence { using type = index_sequence; using value_type = std::size_t; static constexpr std::size_t size() { return sizeof ... (I); } }; template< typename Seq1, typename Seq2 > struct concat_sequence; template< std::size_t ... I1, std::size_t ... I2 > struct concat_sequence< index_sequence< I1 ... >, index_sequence< I2 ... > > : public index_sequence< I1 ..., (sizeof ... (I1)+I2) ... > {}; template< std::size_t I > struct make_index_sequence : public concat_sequence< typename make_index_sequence< I/2 >::type, typename make_index_sequence< I-I/2 >::type > {}; template<> struct make_index_sequence< 0 > : public index_sequence<> {}; template<> struct make_index_sequence< 1 > : public index_sequence< 0 > {}; template struct Arg; template<> struct Arg { static constexpr iocshArgType code = iocshArgInt; static int get(const iocshArgBuf& buf) { return buf.ival; } }; template<> struct Arg { static constexpr iocshArgType code = iocshArgDouble; static double get(const iocshArgBuf& buf) { return buf.dval; } }; template<> struct Arg { static constexpr iocshArgType code = iocshArgString; static const char* get(const iocshArgBuf& buf) { return buf.sval; } }; template struct ToStr { typedef const char* type; }; template struct Reg { const char* const name; const char* const argnames[1+sizeof...(Args)]; constexpr explicit Reg(const char* name, typename ToStr::type... descs) :name(name) ,argnames{descs..., 0} {} template static void call(const iocshArgBuf* args) { (*fn)(Arg::get(args[Idxs])...); } template void doit(index_sequence) { static const iocshArg argstack[1+sizeof...(Args)] = {{argnames[Idxs], Arg::code}...}; static const iocshArg * const args[] = {&argstack[Idxs]..., 0}; static const iocshFuncDef def = {name, sizeof...(Args), args}; iocshRegister(&def, &call); } template void ister() { doit(make_index_sequence{}); } }; void pvxsAtExit(void* unused) { try { if(auto serv = instance.load()) { if(instance.compare_exchange_strong(serv, nullptr)) { // take ownership std::unique_ptr trash(serv); trash->stop(); log_debug_printf(log, "Stopped Server?%s", "\n"); } } } catch(std::exception& e) { fprintf(stderr, "Error in %s : %s\n", __func__, e.what()); } } void pvxsInitHook(initHookState state) { try { // iocBuild() if(state==initHookAfterInitDatabase) { // we want to run before exitDatabase epicsAtExit(&pvxsAtExit, nullptr); } // iocRun()/iocPause() if(state==initHookAfterCaServerRunning) { if(auto serv = instance.load()) { serv->start(); log_debug_printf(log, "Started Server %p", serv); } } if(state==initHookAfterCaServerPaused) { if(auto serv = instance.load()) { serv->stop(); log_debug_printf(log, "Stopped Server %p", serv); } } } catch(std::exception& e) { fprintf(stderr, "Error in %s : %s\n", __func__, e.what()); } } void pvxsRegistrar() { try { pvxs::logger_config_env(); Reg("pvxsl", "detail").ister<&pvxsl>(); Reg("pvxsr", "detail").ister<&pvxsr>(); Reg<>("pvxs_target_info").ister<&pvxs_target_info>(); auto serv = instance.load(); if(!serv) { std::unique_ptr temp(new server::Server(server::Config::from_env())); if(instance.compare_exchange_strong(serv, temp.get())) { log_debug_printf(log, "Installing Server %p\n", temp.get()); temp.release(); } else { log_crit_printf(log, "Race installing Server? %p\n", serv); } } else { log_err_printf(log, "Stale Server? %p\n", serv); } initHookRegister(&pvxsInitHook); } catch(std::exception& e) { fprintf(stderr, "Error in %s : %s\n", __func__, e.what()); } } } // namespace namespace pvxs { namespace ioc { server::Server server() { if(auto serv = instance.load()) { return *serv; } else { throw std::logic_error("No Instance"); } } }} // namespace pvxs::ioc extern "C" { epicsExportRegistrar(pvxsRegistrar); }