Line data Source code
1 : /**
2 : * @file CommandFacility.cpp CommandFacility base implementation
3 : *
4 : * This is part of the DUNE DAQ Application Framework, copyright 2020.
5 : * Licensing/copyright details are in the COPYING file that you should have
6 : * received with this code.
7 : */
8 : #include "cmdlib/CommandFacility.hpp"
9 : #include "cmdlib/Issues.hpp"
10 : #include "logging/Logging.hpp"
11 :
12 : #include <future>
13 : #include <functional>
14 : #include <utility>
15 : #include <atomic>
16 : #include <chrono>
17 : #include <string>
18 :
19 : using namespace dunedaq::cmdlib;
20 :
21 10 : CommandFacility::~CommandFacility()
22 : {
23 10 : if (m_active.load()) {
24 6 : m_active.store(false);
25 6 : if(m_executor.joinable()) {
26 6 : m_executor.join();
27 : }
28 : }
29 10 : }
30 :
31 : void
32 6 : CommandFacility::set_commanded(CommandedObject& commanded, std::string name)
33 : {
34 6 : if (m_commanded_object == nullptr) {
35 6 : m_name = name;
36 6 : m_commanded_object = &commanded;
37 6 : m_command_callback = std::bind(&CommandFacility::handle_command, this, std::placeholders::_1, std::placeholders::_2);
38 6 : m_active.store(true);
39 6 : m_executor = std::thread(&CommandFacility::executor, this);
40 : } else {
41 0 : ers::error(CommandFacilityInitialization(ERS_HERE, "set_commanded shall be called once."));
42 : }
43 6 : }
44 :
45 : void
46 0 : CommandFacility::execute_command(const cmdobj_t& cmd, cmd::CommandReply meta)
47 : {
48 0 : auto execfut = std::async(std::launch::deferred, m_command_callback, std::move(cmd), std::move(meta));
49 0 : m_completion_queue.push(std::move(execfut));
50 0 : }
51 :
52 : void
53 0 : CommandFacility::handle_command(const cmdobj_t& cmd, cmd::CommandReply meta)
54 : {
55 0 : try {
56 0 : m_commanded_object->execute(cmd);
57 0 : meta.success = true;
58 0 : meta.result = "OK";
59 0 : meta.appname = m_name;
60 0 : } catch (const ers::Issue& ei ) {
61 0 : meta.success = false;
62 0 : meta.result = ei.what();
63 0 : meta.appname = m_name;
64 0 : ers::error(CommandExecutionFailed(ERS_HERE, "Caught ers::Issue", ei));
65 0 : } catch (const std::exception& exc) {
66 0 : meta.success = false;
67 0 : meta.result = exc.what();
68 0 : meta.appname = m_name;
69 0 : ers::error(CommandExecutionFailed(ERS_HERE, "Caught std::exception", exc));
70 0 : } catch (...) { // NOLINT JCF Jan-27-2021 violates letter of the law but not the spirit
71 0 : meta.success = false;
72 0 : meta.result = "Caught unknown exception";
73 0 : meta.appname = m_name;
74 0 : ers::error(CommandExecutionFailed(ERS_HERE, meta.result));
75 0 : }
76 0 : completion_callback(cmd, meta);
77 0 : }
78 :
79 : void
80 6 : CommandFacility::executor()
81 : {
82 6 : std::future<void> fut;
83 15 : while (m_active.load()) {
84 9 : if (m_completion_queue.empty()) {
85 9 : std::this_thread::sleep_for(std::chrono::milliseconds(10));
86 : } else {
87 0 : bool success = m_completion_queue.try_pop(fut);
88 0 : if (!success) {
89 0 : ers::error(CompletionQueueIssue(ERS_HERE, "Can't get from completion queue."));
90 : } else {
91 0 : fut.wait(); // trigger execution
92 : }
93 : }
94 : }
95 6 : }
|