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 <atomic>
13 : #include <chrono>
14 : #include <functional>
15 : #include <future>
16 : #include <string>
17 : #include <utility>
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 =
38 6 : std::bind(&CommandFacility::handle_command, this, std::placeholders::_1, std::placeholders::_2);
39 6 : m_active.store(true);
40 6 : m_executor = std::thread(&CommandFacility::executor, this);
41 : } else {
42 0 : ers::error(CommandFacilityInitialization(ERS_HERE, "set_commanded shall be called once."));
43 : }
44 6 : }
45 :
46 : void
47 0 : CommandFacility::execute_command(const cmdobj_t& cmd, cmd::CommandReply meta)
48 : {
49 0 : auto execfut = std::async(std::launch::deferred, m_command_callback, std::move(cmd), std::move(meta));
50 0 : m_completion_queue.push(std::move(execfut));
51 0 : }
52 :
53 : void
54 0 : CommandFacility::handle_command(const cmdobj_t& cmd, cmd::CommandReply meta)
55 : {
56 0 : try {
57 0 : m_commanded_object->execute(cmd);
58 0 : meta.success = true;
59 0 : meta.result = "OK";
60 0 : meta.appname = m_name;
61 0 : } catch (const ers::Issue& ei) {
62 0 : meta.success = false;
63 0 : meta.result = ei.what();
64 0 : meta.appname = m_name;
65 0 : ers::error(CommandExecutionFailed(ERS_HERE, "Caught ers::Issue", ei));
66 0 : } catch (const std::exception& exc) {
67 0 : meta.success = false;
68 0 : meta.result = exc.what();
69 0 : meta.appname = m_name;
70 0 : ers::error(CommandExecutionFailed(ERS_HERE, "Caught std::exception", exc));
71 0 : } catch (...) { // NOLINT JCF Jan-27-2021 violates letter of the law but not the spirit
72 0 : meta.success = false;
73 0 : meta.result = "Caught unknown exception";
74 0 : meta.appname = m_name;
75 0 : ers::error(CommandExecutionFailed(ERS_HERE, meta.result));
76 0 : }
77 0 : completion_callback(cmd, meta);
78 0 : }
79 :
80 : void
81 6 : CommandFacility::executor()
82 : {
83 6 : std::future<void> fut;
84 14 : while (m_active.load()) {
85 8 : if (m_completion_queue.empty()) {
86 8 : std::this_thread::sleep_for(std::chrono::milliseconds(10));
87 : } else {
88 0 : bool success = m_completion_queue.try_pop(fut);
89 0 : if (!success) {
90 0 : ers::error(CompletionQueueIssue(ERS_HERE, "Can't get from completion queue."));
91 : } else {
92 0 : fut.wait(); // trigger execution
93 : }
94 : }
95 : }
96 6 : }
|