18 #ifndef vapi_hpp_included
19 #define vapi_hpp_included
33 #include <vapi/vpe.api.vapi.h>
35 #if VAPI_CPP_DEBUG_LEAKS
36 #include <unordered_set>
49 template <
typename Req,
typename Resp,
typename... Args>
class Request;
50 template <
typename M>
class Msg;
53 template <
typename M,
typename... Args>
61 virtual const char *
what ()
const throw ()
63 return "unexpected message id";
70 virtual const char *
what ()
const throw ()
72 return "message unavailable";
103 return response_state;
115 response_state =
state;
118 virtual std::tuple<vapi_error_e, bool> assign_response (
vapi_msg_id_t id,
121 void set_context (
u32 context)
136 template <
typename M>
friend class Msg;
138 template <
typename Req,
typename Resp,
typename... Args>
141 template <
typename Req,
typename Resp,
typename... Args>
friend class Dump;
164 throw std::bad_alloc ();
175 #if VAPI_CPP_DEBUG_LEAKS
176 for (
auto x : shm_data_set)
178 printf (
"Leaked shm_data@%p!\n", x);
204 bool handle_keepalives =
true)
218 auto x = requests.size ();
221 VAPI_DBG (
"popping request @%p", requests.front ());
222 requests.pop_front ();
252 std::lock_guard<std::mutex> lock (dispatch_mutex);
254 bool loop_again =
true;
258 size_t shm_data_size;
265 #if VAPI_CPP_DEBUG_LEAKS
266 on_shm_data_alloc (shm_data);
268 std::lock_guard<std::recursive_mutex> requests_lock (requests_mutex);
269 std::lock_guard<std::recursive_mutex> events_lock (events_mutex);
271 vapi_ctx, be16toh (*
static_cast<u16 *
> (shm_data)));
273 bool break_dispatch =
false;
279 const auto x = requests.front ();
283 std::tie (
rv, break_dispatch) =
284 x->assign_response (
id, shm_data);
288 std::tie (
rv, break_dispatch) =
289 x->assign_response (
id,
nullptr);
293 requests.pop_front ();
300 std::tie (
rv, break_dispatch) =
301 events[
id]->assign_response (
id, shm_data);
302 matching_req = events[
id];
309 if ((matching_req && matching_req == limit && break_dispatch) ||
314 loop_again = !requests.empty () || (event_count > 0);
344 void msg_free (
void *shm_data)
346 #if VAPI_CPP_DEBUG_LEAKS
347 on_shm_data_free (shm_data);
352 template <
template <
typename XReq,
typename XResp,
typename... XArgs>
354 typename Req, typename Resp, typename... Args>
362 req_context_counter.fetch_add (1, std::memory_order_relaxed);
363 req->request.shm_data->header.context = req_context;
364 vapi_swap_to_be<Req> (req->request.shm_data);
365 std::lock_guard<std::recursive_mutex> lock (requests_mutex);
370 requests.emplace_back (req);
371 req->set_context (req_context);
372 #if VAPI_CPP_DEBUG_LEAKS
373 on_shm_data_free (req->request.shm_data);
375 req->request.shm_data =
nullptr;
379 vapi_swap_to_host<Req> (req->request.shm_data);
384 template <
template <
typename XReq,
typename XResp,
typename... XArgs>
386 typename Req, typename Resp, typename... Args>
387 vapi_error_e send_with_control_ping (X<Req, Resp, Args...> *req)
394 req_context_counter.fetch_add (1, std::memory_order_relaxed);
395 req->request.shm_data->header.context = req_context;
396 vapi_swap_to_be<Req> (req->request.shm_data);
397 std::lock_guard<std::recursive_mutex> lock (requests_mutex);
399 vapi_ctx, req->request.shm_data, req_context);
403 requests.emplace_back (req);
404 req->set_context (req_context);
405 #if VAPI_CPP_DEBUG_LEAKS
406 on_shm_data_free (req->request.shm_data);
408 req->request.shm_data =
nullptr;
412 vapi_swap_to_host<Req> (req->request.shm_data);
417 void unregister_request (Common_req *
request)
419 std::lock_guard<std::recursive_mutex> lock (requests_mutex);
420 std::remove (requests.begin (), requests.end (),
request);
423 template <
typename M>
void register_event (Event_registration<M> *event)
426 std::lock_guard<std::recursive_mutex> lock (events_mutex);
431 template <
typename M>
void unregister_event (Event_registration<M> *event)
434 std::lock_guard<std::recursive_mutex> lock (events_mutex);
440 std::atomic_ulong req_context_counter;
441 std::mutex dispatch_mutex;
443 std::recursive_mutex requests_mutex;
444 std::recursive_mutex events_mutex;
445 std::deque<Common_req *> requests;
446 std::vector<Common_req *>
events;
449 template <
typename Req,
typename Resp,
typename... Args>
452 template <
typename Req,
typename Resp,
typename... Args>
friend class Dump;
458 template <
typename M,
typename... Args>
461 template <
typename M>
friend class Msg;
463 #if VAPI_CPP_DEBUG_LEAKS
464 void on_shm_data_alloc (
void *shm_data)
468 auto pos = shm_data_set.find (shm_data);
469 if (pos == shm_data_set.end ())
471 shm_data_set.insert (shm_data);
475 printf (
"Double-add shm_data @%p!\n", shm_data);
480 void on_shm_data_free (
void *shm_data)
482 auto pos = shm_data_set.find (shm_data);
483 if (pos == shm_data_set.end ())
485 printf (
"Freeing untracked shm_data @%p!\n", shm_data);
489 shm_data_set.erase (pos);
492 std::unordered_set<void *> shm_data_set;
496 template <
typename Req,
typename Resp,
typename... Args>
class Request;
498 template <
typename Req,
typename Resp,
typename... Args>
class Dump;
520 template <
typename M>
class Msg
523 Msg (
const Msg &) =
delete;
527 VAPI_DBG (
"Destroy Msg<%s>@%p, shm_data@%p",
531 con.get ().msg_free (shm_data);
538 return *msg_id_holder ();
541 template <
typename X = M>
543 decltype (X::payload) &>
::type
546 return shm_data->payload;
552 VAPI_DBG (
"Move construct Msg<%s> from msg@%p to msg@%p, shm_data@%p",
554 shm_data = msg.shm_data;
555 msg.shm_data =
nullptr;
558 Msg<M> &operator= (Msg<M> &&msg)
560 VAPI_DBG (
"Move assign Msg<%s> from msg@%p to msg@%p, shm_data@%p",
562 con.get ().msg_free (shm_data);
564 shm_data = msg.shm_data;
565 msg.shm_data =
nullptr;
571 template <
class U,
class... Args>
void construct (U *p, Args &&... args)
573 ::new ((
void *)p) U (std::forward<Args> (args)...);
585 (
id == *msg_id_holder ()));
586 *msg_id_holder () =
id;
599 throw Msg_not_available_exception ();
601 this->shm_data =
static_cast<shm_data_type *
> (shm_data);
608 assert (
nullptr == this->shm_data);
611 throw Unexpected_msg_id_exception ();
613 this->shm_data =
static_cast<M *
> (shm_data);
614 vapi_swap_to_host<M> (this->shm_data);
615 VAPI_DBG (
"Assign response to Msg<%s>@%p shm_data@%p",
619 std::reference_wrapper<Connection> con;
620 using shm_data_type =
M;
621 shm_data_type *shm_data;
625 template <
typename Req,
typename Resp,
typename... Args>
628 template <
typename Req,
typename Resp,
typename... Args>
friend class Dump;
642 template <
typename Req,
typename Resp,
typename... Args>
650 request{
con, vapi_alloc<Req> (
con, args...)}, response{
con,
nullptr}
660 con.unregister_request (
this);
666 return con.send (
this);
680 virtual std::tuple<vapi_error_e, bool> assign_response (
vapi_msg_id_t id,
684 response.assign_response (
id, shm_data);
686 if (
nullptr != callback)
688 return std::make_pair (callback (*
this),
true);
690 return std::make_pair (
VAPI_OK,
true);
722 typename std::vector<Msg<M>,
746 void mark_complete ()
756 throw Unexpected_msg_id_exception ();
761 vapi_swap_to_host<M> (
static_cast<M *
> (shm_data));
762 set.emplace_back (con, shm_data);
763 VAPI_DBG (
"Result_set@%p emplace_back shm_data@%p",
this, shm_data);
775 template <
typename Req,
typename Resp,
typename... Args>
friend class Dump;
784 template <
typename Req,
typename Resp,
typename... Args>
792 result_set{
con}, callback{callback}
807 con.msg_free (shm_data);
808 result_set.mark_complete ();
810 if (
nullptr != callback)
812 return std::make_pair (callback (*
this),
true);
814 return std::make_pair (
VAPI_OK,
true);
818 result_set.assign_response (
id, shm_data);
820 return std::make_pair (
VAPI_OK,
false);
825 return con.send_with_control_ping (
this);
860 if (!
con.is_msg_available (M::get_msg_id ()))
862 throw Msg_not_available_exception ();
864 con.register_event (
this);
871 con.unregister_event (
this);
877 result_set.assign_response (
id, shm_data);
878 if (
nullptr != callback)
880 return std::make_pair (callback (*
this),
true);
882 return std::make_pair (
VAPI_OK,
true);