1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
/*
* Copyright (c) 2017 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __VOM_RPC_CMD_H__
#define __VOM_RPC_CMD_H__
#include <future>
#include "vom/cmd.hpp"
#include "vom/logger.hpp"
namespace VOM {
/**
* A base class for all RPC commands to VPP.
* RPC commands are one of the sub-set of command types to VPP
* that modify/create state in VPP and thus return an error code.
* Commands are issued in one thread context, but read in another. The
* command has an associated std::promise that is met by the RX thread.
* this allows the sender, which waits on the promise's future, to
* experience a synchronous command.
*
* The command is templatised on the type of the HW::item to be set by
* the command, and the data returned in the promise,
*/
template <typename HWITEM, typename DATA, typename MSG>
class rpc_cmd : public cmd
{
public:
/**
* convenient typedef
*/
typedef MSG msg_t;
/**
* Constructor taking the HW item that will be updated by the command
*/
rpc_cmd(HWITEM& item)
: cmd()
, m_hw_item(item)
, m_promise()
{
}
/**
* Desructor
*/
virtual ~rpc_cmd() {}
/**
* return the HW item the command updates
*/
HWITEM& item() { return m_hw_item; }
/**
* return the const HW item the command updates
*/
const HWITEM& item() const { return m_hw_item; }
/**
* Fulfill the commands promise. Called from the RX thread
*/
void fulfill(const DATA& d)
{
m_promise.set_value(d);
/*
* we reset the promise after setting the value to reuse it
* when we run the retire command from the same cmd object
*/
m_promise = std::promise<DATA>();
}
/**
* Wait on the commands promise. i.e. block on the completion
* of the command.
*/
DATA wait()
{
std::future_status status;
std::future<DATA> result;
result = m_promise.get_future();
status = result.wait_for(std::chrono::seconds(5));
if (status != std::future_status::ready) {
return (DATA(rc_t::TIMEOUT));
}
return (result.get());
}
/**
* Called by the HW Command Q when it is disabled to indicate the
* command can be considered successful without issuing it to HW
*/
virtual void succeeded() { m_hw_item.set(rc_t::OK); }
/**
* call operator used as a callback by VAPI when the reply is available
*/
virtual vapi_error_e operator()(MSG& reply)
{
int retval = reply.get_response().get_payload().retval;
VOM_LOG(log_level_t::DEBUG) << to_string() << " " << retval;
fulfill(rc_t::from_vpp_retval(retval));
return (VAPI_OK);
}
/**
* Retire/cancel a long running command
*/
virtual void retire(connection& con) {}
protected:
/**
* A reference to an object's HW::item that the command will update
*/
HWITEM& m_hw_item;
/**
* The promise that implements the synchronous issue
*/
std::promise<DATA> m_promise;
};
};
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/
#endif
|