2015-08-13 13:12:15 -07:00
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
|
|
|
|
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
|
|
|
|
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
|
|
|
|
/* the project. */
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
#include "RpcServer.h"
|
|
|
|
|
|
2015-12-28 08:28:24 -08:00
|
|
|
#include <queue>
|
|
|
|
|
|
2015-08-13 13:12:15 -07:00
|
|
|
#include "Log.h"
|
|
|
|
|
|
|
|
|
|
using namespace nt;
|
|
|
|
|
|
|
|
|
|
ATOMIC_STATIC_INIT(RpcServer)
|
|
|
|
|
|
2016-07-27 00:39:38 -07:00
|
|
|
class RpcServer::Thread : public wpi::SafeThread {
|
2015-12-28 08:28:24 -08:00
|
|
|
public:
|
|
|
|
|
Thread(std::function<void()> on_start, std::function<void()> on_exit)
|
|
|
|
|
: m_on_start(on_start), m_on_exit(on_exit) {}
|
|
|
|
|
|
|
|
|
|
void Main();
|
|
|
|
|
|
|
|
|
|
std::queue<RpcCall> m_call_queue;
|
|
|
|
|
|
|
|
|
|
std::function<void()> m_on_start;
|
|
|
|
|
std::function<void()> m_on_exit;
|
|
|
|
|
};
|
|
|
|
|
|
2015-08-13 13:12:15 -07:00
|
|
|
RpcServer::RpcServer() {
|
|
|
|
|
m_terminating = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RpcServer::~RpcServer() {
|
2015-09-12 21:44:51 -07:00
|
|
|
Logger::GetInstance().SetLogger(nullptr);
|
2015-08-13 13:12:15 -07:00
|
|
|
m_terminating = true;
|
|
|
|
|
m_poll_cond.notify_all();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RpcServer::Start() {
|
2015-12-28 08:28:24 -08:00
|
|
|
auto thr = m_owner.GetThread();
|
|
|
|
|
if (!thr) m_owner.Start(new Thread(m_on_start, m_on_exit));
|
2015-08-13 13:12:15 -07:00
|
|
|
}
|
|
|
|
|
|
2015-12-28 08:28:24 -08:00
|
|
|
void RpcServer::Stop() { m_owner.Stop(); }
|
2015-08-13 13:12:15 -07:00
|
|
|
|
|
|
|
|
void RpcServer::ProcessRpc(StringRef name, std::shared_ptr<Message> msg,
|
|
|
|
|
RpcCallback func, unsigned int conn_id,
|
|
|
|
|
SendMsgFunc send_response) {
|
2015-12-28 08:28:24 -08:00
|
|
|
if (func) {
|
|
|
|
|
auto thr = m_owner.GetThread();
|
|
|
|
|
if (!thr) return;
|
|
|
|
|
thr->m_call_queue.emplace(name, msg, func, conn_id, send_response);
|
|
|
|
|
thr->m_cond.notify_one();
|
|
|
|
|
} else {
|
|
|
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
2015-08-13 13:12:15 -07:00
|
|
|
m_poll_queue.emplace(name, msg, func, conn_id, send_response);
|
|
|
|
|
m_poll_cond.notify_one();
|
2015-12-28 08:28:24 -08:00
|
|
|
}
|
2015-08-13 13:12:15 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool RpcServer::PollRpc(bool blocking, RpcCallInfo* call_info) {
|
|
|
|
|
std::unique_lock<std::mutex> lock(m_mutex);
|
|
|
|
|
while (m_poll_queue.empty()) {
|
|
|
|
|
if (!blocking || m_terminating) return false;
|
|
|
|
|
m_poll_cond.wait(lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto& item = m_poll_queue.front();
|
|
|
|
|
unsigned int call_uid = (item.conn_id << 16) | item.msg->seq_num_uid();
|
|
|
|
|
call_info->rpc_id = item.msg->id();
|
|
|
|
|
call_info->call_uid = call_uid;
|
|
|
|
|
call_info->name = std::move(item.name);
|
|
|
|
|
call_info->params = item.msg->str();
|
|
|
|
|
m_response_map.insert(std::make_pair(std::make_pair(item.msg->id(), call_uid),
|
|
|
|
|
item.send_response));
|
|
|
|
|
m_poll_queue.pop();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RpcServer::PostRpcResponse(unsigned int rpc_id, unsigned int call_uid,
|
|
|
|
|
llvm::StringRef result) {
|
|
|
|
|
auto i = m_response_map.find(std::make_pair(rpc_id, call_uid));
|
|
|
|
|
if (i == m_response_map.end()) {
|
|
|
|
|
WARNING("posting RPC response to nonexistent call (or duplicate response)");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
(i->getSecond())(Message::RpcResponse(rpc_id, call_uid, result));
|
|
|
|
|
m_response_map.erase(i);
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-28 08:28:24 -08:00
|
|
|
void RpcServer::Thread::Main() {
|
|
|
|
|
if (m_on_start) m_on_start();
|
|
|
|
|
|
2015-08-13 13:12:15 -07:00
|
|
|
std::unique_lock<std::mutex> lock(m_mutex);
|
|
|
|
|
std::string tmp;
|
|
|
|
|
while (m_active) {
|
|
|
|
|
while (m_call_queue.empty()) {
|
2015-12-28 08:28:24 -08:00
|
|
|
m_cond.wait(lock);
|
2015-10-09 23:50:01 -07:00
|
|
|
if (!m_active) goto done;
|
2015-08-13 13:12:15 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (!m_call_queue.empty()) {
|
2015-10-09 23:50:01 -07:00
|
|
|
if (!m_active) goto done;
|
2015-08-13 13:12:15 -07:00
|
|
|
auto item = std::move(m_call_queue.front());
|
|
|
|
|
m_call_queue.pop();
|
|
|
|
|
|
|
|
|
|
DEBUG4("rpc calling " << item.name);
|
|
|
|
|
|
|
|
|
|
if (item.name.empty() || !item.msg || !item.func || !item.send_response)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// Don't hold mutex during callback execution!
|
|
|
|
|
lock.unlock();
|
|
|
|
|
auto result = item.func(item.name, item.msg->str());
|
|
|
|
|
item.send_response(Message::RpcResponse(item.msg->id(),
|
|
|
|
|
item.msg->seq_num_uid(), result));
|
|
|
|
|
lock.lock();
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-10-09 23:50:01 -07:00
|
|
|
|
|
|
|
|
done:
|
2015-12-28 08:28:24 -08:00
|
|
|
if (m_on_exit) m_on_exit();
|
2015-08-13 13:12:15 -07:00
|
|
|
}
|