/* * Copyright information and license terms for this software can be * found in the file LICENSE that is included with the distribution */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pvutils.h" #ifndef EXECNAME # define EXECNAME "pvget" #endif namespace { size_t pvnamewidth; int haderror; void usage (void) { fprintf (stderr, "\nUsage: " EXECNAME " [options] ...\n" "\n" COMMON_OPTIONS " deprecated options:\n" " -q, -t, -i, -n, -F: ignored\n" " -f : errors\n" " Output details:\n" " -m -v: Monitor in Raw mode. Print only fields marked as changed.\n" " -m -vv: Monitor in Raw mode. Highlight fields marked as changed, show all valid fields.\n" " -m -vvv: Monitor in Raw mode. Highlight fields marked as changed, show all fields.\n" " -vv: Get in Raw mode. Highlight valid fields, show all fields.\n" "\n" "example: " EXECNAME " double01\n\n" , request.c_str(), timeout, defaultProvider.c_str()); } struct Getter : public pvac::ClientChannel::GetCallback, public Tracker { POINTER_DEFINITIONS(Getter); pvac::Operation op; Getter(pvac::ClientChannel& channel, const pvd::PVStructurePtr& pvRequest) { op = channel.get(this, pvRequest); } virtual ~Getter() {} virtual void getDone(const pvac::GetEvent& event) OVERRIDE FINAL { std::cout<stream() .format(outmode)); if(verbosity>=2) fmt.highlight(*event.valid); // show all, highlight valid else fmt.show(*event.valid); // only show valid, highlight none std::cout< value_type; typedef std::tr1::weak_ptr weak_type; // work queue holds only weak_ptr // so jobs must be kept alive seperately typedef std::deque > queue_t; queue_t queue; epicsEvent event; bool running; pvd::Thread worker; WorkQueue() :running(true) ,worker(pvd::Thread::Config() .name("Monitor handler") .autostart(true) .run(this)) {} ~WorkQueue() {close();} void close() { { Guard G(mutex); running = false; } event.signal(); worker.exitWait(); } void push(const weak_type& cb, const pvac::MonitorEvent& evt) { bool wake; { Guard G(mutex); if(!running) return; // silently refuse to queue during/after close() wake = queue.empty(); queue.push_back(std::make_pair(cb, evt)); } if(wake) event.signal(); } virtual void run() OVERRIDE FINAL { Guard G(mutex); while(running) { if(queue.empty()) { UnGuard U(G); event.wait(); } else { queue_t::value_type ent(queue.front()); value_type cb(ent.first.lock()); queue.pop_front(); if(!cb) continue; try { UnGuard U(G); cb->process(ent.second); }catch(std::exception& e){ std::cout<<"Error in monitor handler : "< { POINTER_DEFINITIONS(MonTracker); MonTracker(WorkQueue& monwork, pvac::ClientChannel& channel, const pvd::PVStructurePtr& pvRequest) :monwork(monwork) ,mon(channel.monitor(this, pvRequest)) {} virtual ~MonTracker() {mon.cancel();} WorkQueue& monwork; pvd::BitSet valid; // only access for process() pvac::Monitor mon; // must be last data member virtual void monitorEvent(const pvac::MonitorEvent& evt) OVERRIDE FINAL { // shared_from_this() will fail as Cancel is delivered in our dtor. if(evt.event==pvac::MonitorEvent::Cancel) return; // running on internal provider worker thread // minimize work here. monwork.push(shared_from_this(), evt); } virtual void process(const pvac::MonitorEvent& evt) OVERRIDE FINAL { // running on our worker thread switch(evt.event) { case pvac::MonitorEvent::Fail: std::cerr<\n"; valid.clear(); break; case pvac::MonitorEvent::Data: { unsigned n; for(n=0; n<2 && mon.poll(); n++) { valid |= mon.changed; pvd::PVStructure::Formatter fmt(mon.root->stream() .format(outmode)); if(verbosity>=3) fmt.highlight(mon.changed); // show all else if(verbosity>=2) fmt.highlight(mon.changed).show(valid); else fmt.show(mon.changed); // highlight none std::cout<0 && outmode==pvd::PVStructure::Formatter::NT) outmode = pvd::PVStructure::Formatter::Raw; pvd::PVStructure::shared_pointer pvRequest; try { pvRequest = pvd::createRequest(request); } catch(std::exception& e){ fprintf(stderr, "failed to parse request string: %s\n", e.what()); return 1; } for(int i = optind; i < argc; i++) { pvnamewidth = std::max(pvnamewidth, strlen(argv[i])); } SET_LOG_LEVEL(debugFlag ? pva::logLevelDebug : pva::logLevelError); epics::pvAccess::ca::CAClientFactory::start(); { pvac::ClientProvider provider(defaultProvider); std::vector > tracked; epics::auto_ptr Q; if(monitor) Q.reset(new WorkQueue); for(int i = optind; i < argc; i++) { pvac::ClientChannel chan(provider.connect(argv[i])); if(monitor) { std::tr1::shared_ptr mon(new MonTracker(*Q, chan, pvRequest)); tracked.push_back(mon); } else { // Get std::tr1::shared_ptr get(new Getter(chan, pvRequest)); tracked.push_back(get); } } // ========================== Wait for operations to complete, or timeout Tracker::prepare(); // install signal handler if(debugFlag) std::cerr<<"Waiting...\n"; { Guard G(Tracker::doneLock); while(Tracker::inprog.size() && !Tracker::abort) { UnGuard U(G); if(timeout<=0) Tracker::doneEvt.wait(); else if(!Tracker::doneEvt.wait(timeout)) { haderror = 1; std::cerr<<"Timeout\n"; break; } } } } if(refmon.running()) { refmon.stop(); // show final counts refmon.current(); } // ========================== All done now if(debugFlag) std::cerr<<"Done\n"; return haderror ? 1 : 0; } catch(std::exception& e) { std::cerr<<"Error: "<