mavtables  0.2.1
MAVLink router and firewall.
InterfaceThreader.cpp
Go to the documentation of this file.
1 // MAVLink router and firewall.
2 // Copyright (C) 2018 Michael R. Shannon <mrshannon.aerospace@gmail.com>
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17 
18 #include <chrono>
19 #include <memory>
20 #include <stdexcept>
21 #include <utility>
22 
23 #include "Interface.hpp"
24 #include "InterfaceThreader.hpp"
25 #include "PartialSendError.hpp"
26 
27 
28 /** The transmitting thread runner.
29  *
30  * This handles all transmission related tasks in a separate thread.
31  */
32 void InterfaceThreader::tx_runner_()
33 {
34  while (running_.load())
35  {
36  try
37  {
38  interface_->send_packet(timeout_);
39  }
40  // Ignore partial write errors on shutdown.
41  // TODO: A better way to handle this error might be in order. Not even
42  // sure exactly why it happens on close.
43  catch (const PartialSendError &)
44  {
45  if (running_.load())
46  {
47  throw;
48  }
49  }
50  }
51 }
52 
53 
54 /** The receiving thread runner.
55  *
56  * This handles all receiving related tasks in a separate thread.
57  */
58 void InterfaceThreader::rx_runner_()
59 {
60  while (running_.load())
61  {
62  interface_->receive_packet(timeout_);
63  }
64 }
65 
66 
67 /** Construct and optionally start an interface threader.
68  *
69  * \param interface The \ref Interface to run in TX/RX threads. It's \ref
70  * Interface::send_packet and \ref Interface::receive_packet methods will
71  * be called repeatedly in two separate worker threads.
72  * \param timeout The maximum amount of time to wait for incoming data or a
73  * packet to transmit. The default value is 100000 us (100 ms).
74  * \param start_threads Set to \ref InterfaceThreader::START (the default
75  * value) to start the interface (including worker threads) on
76  * construction. Set to \ref InterfaceThreader::DELAY_START to delay
77  * starting the interface (and worker threads) until the \ref start method
78  * is called.
79  */
81  std::unique_ptr<Interface> interface,
82  std::chrono::microseconds timeout,
83  Threads start_threads)
84  : interface_(std::move(interface)),
85  timeout_(std::move(timeout)),
86  running_(false)
87 {
88  if (start_threads == InterfaceThreader::START)
89  {
90  start();
91  }
92 }
93 
94 
95 /** Shutdown the interface and its associated worker threads.
96  */
98 {
99  shutdown();
100 }
101 
102 
103 /** Start the worker threads for the interface.
104  *
105  * This starts the receiver and transmitter threads.
106  */
108 {
109  running_.store(true);
110  tx_thread_ = std::thread(&InterfaceThreader::tx_runner_, this);
111  rx_thread_ = std::thread(&InterfaceThreader::rx_runner_, this);
112 }
113 
114 
115 /** Shutdown the interface and its associated worker threads.
116  *
117  * \note This will always be called by the interface's destructor.
118  */
120 {
121  if (running_.load())
122  {
123  running_.store(false);
124  tx_thread_.join();
125  rx_thread_.join();
126  }
127 }
Start the interface (and worker threads) immediately.
STL namespace.
InterfaceThreader(std::unique_ptr< Interface > interface, std::chrono::microseconds=std::chrono::microseconds(100000), Threads start_threads=InterfaceThreader::START)