diff --git a/include/Channel.hpp b/include/Channel.hpp index 3a2ad9b7..cb350df2 100644 --- a/include/Channel.hpp +++ b/include/Channel.hpp @@ -47,6 +47,7 @@ class Channel { Channel(const std::list &pOptions, const std::string api, const std::string pUuid, ReadingIdentifier::Ptr pIdentifier); virtual ~Channel(); + bool running(); // Doesn't touch the object, could also be static, but static breaks google mock. void start(Ptr this_shared) { @@ -70,8 +71,6 @@ class Channel { pthread_cancel(_thread); } - bool running() const { return _thread_running; } - const char *name() const { return _name.c_str(); } std::list &options() { return _options; } diff --git a/include/Config_Options.hpp b/include/Config_Options.hpp index d0fe7079..6c3f3f15 100644 --- a/include/Config_Options.hpp +++ b/include/Config_Options.hpp @@ -76,6 +76,7 @@ class Config_Options { bool channel_index() const { return _channel_index; } bool local() const { return _local; } bool foreground() const { return _foreground; } + bool singleshot() const { return _singleshot; } bool doRegistration() const { return _doRegistration; } @@ -93,6 +94,8 @@ class Config_Options { void foreground(const bool v) { _foreground = v; } + void singleshot(const bool v) { _singleshot = v; } + void doRegistration(const bool v) { _doRegistration = v; } PushDataServer *pushDataServer() const { return _pds; } @@ -113,6 +116,7 @@ class Config_Options { int _channel_index : 1; // give a index of all available channels via local interface int _local : 1; // enable local interface int _foreground : 1; // don't daemonize + int _singleshot : 1; // only get a single reading from each meter, then exit int _doRegistration : 1; // FIXME }; diff --git a/include/MeterMap.hpp b/include/MeterMap.hpp index c26b7999..b7db7d7b 100644 --- a/include/MeterMap.hpp +++ b/include/MeterMap.hpp @@ -83,7 +83,7 @@ class MeterMap { inline iterator end() { return _channels.end(); } inline size_t size() { return _channels.size(); } - bool running() const { return _thread_running; } + bool running(); private: Meter::Ptr _meter; diff --git a/src/Channel.cpp b/src/Channel.cpp index 88b57643..0a6f57db 100644 --- a/src/Channel.cpp +++ b/src/Channel.cpp @@ -89,6 +89,21 @@ Channel::Channel(const std::list &pOptions, const std::string apiProtoco pthread_cond_init(&condition, NULL); // initialize thread syncronization helpers } +bool Channel::running() { + if (!_thread_running) return _thread_running; + int ret=pthread_tryjoin_np(_thread, NULL); + if (ret==EBUSY){ + // thread still running + _thread_running = true; + } else if (ret!=0){ + print(log_alert, "error from pthread_tryjoin_np()", name()); + } else { + _thread_running = false; + } + return _thread_running; +} + + /** * Free all allocated memory recursively */ diff --git a/src/Config_Options.cpp b/src/Config_Options.cpp index cd456a78..a1126d88 100644 --- a/src/Config_Options.cpp +++ b/src/Config_Options.cpp @@ -41,13 +41,15 @@ static const char *option_type_str[] = {"null", "boolean", "double", "int", Config_Options::Config_Options() : _config("/etc/vzlogger.conf"), _log(""), _pds(0), _port(8080), _verbosity(0), - _comet_timeout(30), _buffer_length(-1), _retry_pause(15), _local(false), _foreground(false) { + _comet_timeout(30), _buffer_length(-1), _retry_pause(15), _local(false), _foreground(false), + _singleshot(false) { _logfd = NULL; } Config_Options::Config_Options(const std::string filename) : _config(filename), _log(""), _pds(0), _port(8080), _verbosity(0), _comet_timeout(30), - _buffer_length(-1), _retry_pause(15), _local(false), _foreground(false) { + _buffer_length(-1), _retry_pause(15), _local(false), _foreground(false), + _singleshot(false) { _logfd = NULL; } diff --git a/src/protocols/MeterS0.cpp b/src/protocols/MeterS0.cpp index ed47677c..1b0e24fa 100644 --- a/src/protocols/MeterS0.cpp +++ b/src/protocols/MeterS0.cpp @@ -36,6 +36,9 @@ #include "Options.hpp" #include "protocols/MeterS0.hpp" #include +#include + +extern Config_Options options; MeterS0::MeterS0(std::list options, HWIF *hwif, HWIF *hwif_dir) : Protocol("s0"), _hwif(hwif), _hwif_dir(hwif_dir), _counter_thread_stop(false), @@ -417,10 +420,12 @@ ssize_t MeterS0::read(std::vector &rds, size_t n) { rds[ret].value(value); ++ret; } - rds[ret].identifier(new StringIdentifier("Impulse")); - rds[ret].time(req); - rds[ret].value(t_imp); - ++ret; + if (!options.singleshot()){ + rds[ret].identifier(new StringIdentifier("Impulse")); + rds[ret].time(req); + rds[ret].value(t_imp); + ++ret; + } } if (_send_zero || t_imp_neg > 0) { @@ -431,10 +436,12 @@ ssize_t MeterS0::read(std::vector &rds, size_t n) { rds[ret].value(value); ++ret; } - rds[ret].identifier(new StringIdentifier("Impulse_neg")); - rds[ret].time(req); - rds[ret].value(t_imp_neg); - ++ret; + if (!options.singleshot()){ + rds[ret].identifier(new StringIdentifier("Impulse_neg")); + rds[ret].time(req); + rds[ret].value(t_imp_neg); + ++ret; + } } if (_first_impulse && ret > 0) _first_impulse = false; diff --git a/src/threads.cpp b/src/threads.cpp index 0799b90b..4f16d1de 100644 --- a/src/threads.cpp +++ b/src/threads.cpp @@ -166,6 +166,8 @@ void *reading_thread(void *arg) { } } + if (options.singleshot()) break; + if (mtr->interval() > 0) { print(log_info, "Next reading in %i seconds", mtr->name(), mtr->interval()); sleep(mtr->interval()); @@ -220,6 +222,8 @@ void *logging_thread(void *arg) { // gets started from Channel::start and stoppe try { ch->wait(); api->send(); + + if (options.singleshot()) break; } catch (std::exception &e) { print(log_alert, "Logging thread failed due to: %s", ch->name(), e.what()); } diff --git a/src/vzlogger.cpp b/src/vzlogger.cpp index 74c4285b..27a22c60 100644 --- a/src/vzlogger.cpp +++ b/src/vzlogger.cpp @@ -76,6 +76,7 @@ const struct option long_options[] = { {"config", required_argument, 0, 'c'}, {"log", required_argument, 0, 'o'}, {"foreground", no_argument, 0, 'f'}, + {"singleshot", no_argument, 0, '1'}, #ifdef LOCAL_SUPPORT {"httpd", no_argument, 0, 'l'}, {"httpd-port", required_argument, 0, 'p'}, @@ -94,6 +95,7 @@ const char *long_options_descs[] = { "configuration file", "log file", "run in foreground, do not daemonize", + "get only one reading for each meter, then exit", #ifdef LOCAL_SUPPORT "activate local interface (tiny HTTPd which serves live readings)", "TCP port for HTTPd", @@ -285,7 +287,7 @@ void signalHandlerQuit(int sig) { */ int config_parse_cli(int argc, char *argv[], Config_Options *options) { while (1) { - int c = getopt_long(argc, argv, "c:o:p:lhrVfv:", long_options, NULL); + int c = getopt_long(argc, argv, "c:o:p:lhrVf1v:", long_options, NULL); /* detect the end of the options. */ if (c == -1) @@ -310,6 +312,10 @@ int config_parse_cli(int argc, char *argv[], Config_Options *options) { options->foreground(1); break; + case '1': + options->singleshot(1); + break; + case 'c': /* config file */ options->config(optarg); break;