Skip to content

Commit

Permalink
vsomeip 2.9.3
Browse files Browse the repository at this point in the history
  • Loading branch information
juergengehring committed Jan 25, 2018
1 parent d61c5b0 commit c3e889f
Show file tree
Hide file tree
Showing 12 changed files with 134 additions and 72 deletions.
8 changes: 8 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
Changes
=======
v2.9.3
- Fixed race condition on application shutdown
- Fixed bug that application object was not destroyed
- Enabled client side logging of received messages
to DLT if environment variable VSOMEIP_CLIENTSIDELOGGING
is set to empty string or another arbitrary value.
- Ensure that the correct source port is used for sending events

v2.9.2
- fix handling of received response messages for unknown
clients.
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ project (vsomeip)

set (VSOMEIP_MAJOR_VERSION 2)
set (VSOMEIP_MINOR_VERSION 9)
set (VSOMEIP_PATCH_VERSION 2)
set (VSOMEIP_PATCH_VERSION 3)
set (VSOMEIP_VERSION ${VSOMEIP_MAJOR_VERSION}.${VSOMEIP_MINOR_VERSION}.${VSOMEIP_PATCH_VERSION})
set (PACKAGE_VERSION ${VSOMEIP_VERSION}) # Used in documentatin/doxygen.in
set (CMAKE_VERBOSE_MAKEFILE off)
Expand Down
5 changes: 5 additions & 0 deletions documentation/vsomeipUserGuide
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,11 @@ On startup the following environment variables are read out:
applications, all other configuration files are only read by the application that is
responsible for connections to external devices. If this configuration variable is not set,
the default mandatory files vsomeip_std.json, vsomeip_app.json and vsomeip_plc.json are used.
* `VSOMEIP_CLIENTSIDELOGGING`: Set this variable to an empty string or an arbitrary
value to enable logging of received messages to DLT in all applications
acting as routing manager proxies. For example add the following line to the
application's systemd service file:
`Environment=VSOMEIP_CLIENTSIDELOGGING=""`

NOTE: If the file/folder that is configured by `VSOMEIP_CONFIGURATION` does _not_ exist,
the default configuration locations will be used.
Expand Down
1 change: 1 addition & 0 deletions implementation/configuration/include/internal.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#define VSOMEIP_ENV_CONFIGURATION_MODULE "VSOMEIP_CONFIGURATION_MODULE"
#define VSOMEIP_ENV_MANDATORY_CONFIGURATION_FILES "VSOMEIP_MANDATORY_CONFIGURATION_FILES"
#define VSOMEIP_ENV_LOAD_PLUGINS "VSOMEIP_LOAD_PLUGINS"
#define VSOMEIP_ENV_CLIENTSIDELOGGING "VSOMEIP_CLIENTSIDELOGGING"

#define VSOMEIP_DEFAULT_CONFIGURATION_FILE "/etc/vsomeip.json"
#define VSOMEIP_LOCAL_CONFIGURATION_FILE "./vsomeip.json"
Expand Down
13 changes: 8 additions & 5 deletions implementation/endpoints/include/endpoint_definition.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <mutex>

#include <boost/asio/ip/address.hpp>
#include <vsomeip/primitive_types.hpp>

#include <vsomeip/export.hpp>

Expand All @@ -21,7 +22,7 @@ class endpoint_definition {
public:
VSOMEIP_EXPORT static std::shared_ptr<endpoint_definition> get(
const boost::asio::ip::address &_address,
uint16_t _port, bool _is_reliable);
uint16_t _port, bool _is_reliable, service_t _service, instance_t _instance);

VSOMEIP_EXPORT const boost::asio::ip::address &get_address() const;

Expand All @@ -42,10 +43,12 @@ class endpoint_definition {
bool is_reliable_;

static std::mutex definitions_mutex_;
static std::map<boost::asio::ip::address,
std::map<uint16_t,
std::map<bool,
std::shared_ptr<endpoint_definition> > > > definitions_;
static std::map<service_t,
std::map<instance_t,
std::map<boost::asio::ip::address,
std::map<uint16_t,
std::map<bool,
std::shared_ptr<endpoint_definition> > > > > > definitions_;
};

} // namespace vsomeip
Expand Down
34 changes: 21 additions & 13 deletions implementation/endpoints/src/endpoint_definition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,42 @@

namespace vsomeip {

std::map<boost::asio::ip::address,
std::map<uint16_t,
std::map<bool, std::shared_ptr<endpoint_definition> > > >
endpoint_definition::definitions_;
std::map<service_t,
std::map<instance_t,
std::map<boost::asio::ip::address,
std::map<uint16_t,
std::map<bool,
std::shared_ptr<endpoint_definition> > > > > > endpoint_definition::definitions_;

std::mutex endpoint_definition::definitions_mutex_;

std::shared_ptr<endpoint_definition>
endpoint_definition::get(const boost::asio::ip::address &_address,
uint16_t _port, bool _is_reliable) {
uint16_t _port, bool _is_reliable, service_t _service, instance_t _instance) {
std::lock_guard<std::mutex> its_lock(definitions_mutex_);
std::shared_ptr<endpoint_definition> its_result;

auto find_address = definitions_.find(_address);
if (find_address != definitions_.end()) {
auto find_port = find_address->second.find(_port);
if (find_port != find_address->second.end()) {
auto found_reliable = find_port->second.find(_is_reliable);
if (found_reliable != find_port->second.end()) {
its_result = found_reliable->second;
auto find_service = definitions_.find(_service);
if( find_service != definitions_.end()) {
auto find_instance = find_service->second.find(_instance);
if (find_instance != find_service->second.end()) {
auto find_address = find_instance->second.find(_address);
if (find_address != find_instance->second.end()) {
auto find_port = find_address->second.find(_port);
if (find_port != find_address->second.end()) {
auto found_reliable = find_port->second.find(_is_reliable);
if (found_reliable != find_port->second.end()) {
its_result = found_reliable->second;
}
}
}
}
}

if (!its_result) {
its_result = std::make_shared<endpoint_definition>(
_address, _port, _is_reliable);
definitions_[_address][_port][_is_reliable] = its_result;
definitions_[_service][_instance][_address][_port][_is_reliable] = its_result;
}
return its_result;
}
Expand Down
2 changes: 2 additions & 0 deletions implementation/routing/include/routing_manager_proxy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ class routing_manager_proxy: public routing_manager_base {
std::mutex request_timer_mutex_;
boost::asio::steady_timer request_debounce_timer_;
bool request_debounce_timer_running_;

bool client_side_logging_;
};

} // namespace vsomeip
Expand Down
8 changes: 4 additions & 4 deletions implementation/routing/src/routing_manager_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2051,10 +2051,10 @@ void routing_manager_impl::add_routing_info(
// Add endpoint(s) if necessary
if (_reliable_port != ILLEGAL_PORT && !is_reliable_known) {
std::shared_ptr<endpoint_definition> endpoint_def_tcp
= endpoint_definition::get(_reliable_address, _reliable_port, true);
= endpoint_definition::get(_reliable_address, _reliable_port, true, _service, _instance);
if (_unreliable_port != ILLEGAL_PORT && !is_unreliable_known) {
std::shared_ptr<endpoint_definition> endpoint_def_udp
= endpoint_definition::get(_unreliable_address, _unreliable_port, false);
= endpoint_definition::get(_unreliable_address, _unreliable_port, false, _service, _instance);
{
std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_);
remote_service_info_[_service][_instance][false] = endpoint_def_udp;
Expand Down Expand Up @@ -2142,7 +2142,7 @@ void routing_manager_impl::add_routing_info(
if (_unreliable_port != ILLEGAL_PORT && !is_unreliable_known) {
if (!udp_inserted) {
std::shared_ptr<endpoint_definition> endpoint_def
= endpoint_definition::get(_unreliable_address, _unreliable_port, false);
= endpoint_definition::get(_unreliable_address, _unreliable_port, false, _service, _instance);
{
std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_);
remote_service_info_[_service][_instance][false] = endpoint_def;
Expand Down Expand Up @@ -2599,7 +2599,7 @@ void routing_manager_impl::on_subscribe_ack(service_t _service,
// Save multicast info to be able to delete the endpoint
// as soon as the instance stops offering its service
std::shared_ptr<endpoint_definition> endpoint_def =
endpoint_definition::get(_address, _port, false);
endpoint_definition::get(_address, _port, false, _service, _instance);
multicast_info[_service][_instance] = endpoint_def;
}
}
Expand Down
18 changes: 16 additions & 2 deletions implementation/routing/src/routing_manager_proxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ routing_manager_proxy::routing_manager_proxy(routing_manager_host *_host) :
register_application_timer_(io_),
logger_(logger::get()),
request_debounce_timer_ (io_),
request_debounce_timer_running_(false)
request_debounce_timer_running_(false),
client_side_logging_(false)
{
}

Expand All @@ -54,7 +55,11 @@ routing_manager_proxy::~routing_manager_proxy() {

void routing_manager_proxy::init() {
routing_manager_base::init();

const char *client_side_logging = getenv(VSOMEIP_ENV_CLIENTSIDELOGGING);
if (client_side_logging != nullptr) {
client_side_logging_ = true;
VSOMEIP_INFO << "Client side logging is enabled";
}
{
std::lock_guard<std::mutex> its_lock(sender_mutex_);
sender_ = create_local(VSOMEIP_ROUTING_CLIENT);
Expand Down Expand Up @@ -877,6 +882,15 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size,
return;
}
}
#ifdef USE_DLT
if (client_side_logging_) {
tc::trace_header its_header;
if (its_header.prepare(nullptr, false, its_instance))
tc_->trace(its_header.data_, VSOMEIP_TRACE_HEADER_SIZE,
&_data[VSOMEIP_COMMAND_PAYLOAD_POS],
static_cast<std::uint16_t>(its_message_size));
}
#endif
host_->on_message(std::move(its_message));
} else {
VSOMEIP_ERROR << "Routing proxy: on_message: "
Expand Down
12 changes: 12 additions & 0 deletions implementation/runtime/include/application_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,18 @@ class application_impl: public application,
eventgroup_id_(0),
handler_type_(handler_type_e::UNKNOWN) { }

sync_handler(service_t _service_id, instance_t _instance_id,
method_t _method_id, session_t _session_id,
eventgroup_t _eventgroup_id, handler_type_e _handler_type) :
handler_(nullptr),
is_dispatching_(false),
service_id_(_service_id),
instance_id_(_instance_id),
method_id_(_method_id),
session_id_(_session_id),
eventgroup_id_(_eventgroup_id),
handler_type_(_handler_type) { }

std::function<void()> handler_;
bool is_dispatching_;
service_t service_id_;
Expand Down
89 changes: 49 additions & 40 deletions implementation/runtime/src/application_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1484,12 +1484,6 @@ void application_impl::main_dispatch() {
}
}
}
// application was stopped
{
std::lock_guard<std::mutex> its_lock(dispatcher_mutex_);
dispatchers_.erase(its_id);
}
remove_elapsed_dispatchers();
its_lock.unlock();
}

Expand All @@ -1500,6 +1494,9 @@ void application_impl::dispatch() {
if (is_dispatching_ && handlers_.empty()) {
dispatcher_condition_.wait(its_lock);
if (handlers_.empty()) { // Maybe woken up from main dispatcher
if (!is_dispatching_) {
return;
}
std::lock_guard<std::mutex> its_lock(dispatcher_mutex_);
elapsed_dispatchers_.insert(its_id);
return;
Expand All @@ -1521,7 +1518,7 @@ void application_impl::dispatch() {
std::lock_guard<std::mutex> its_lock(handlers_mutex_);
dispatcher_condition_.notify_all();
}
{
if (is_dispatching_) {
std::lock_guard<std::mutex> its_lock(dispatcher_mutex_);
elapsed_dispatchers_.insert(its_id);
}
Expand All @@ -1530,11 +1527,17 @@ void application_impl::dispatch() {
void application_impl::invoke_handler(std::shared_ptr<sync_handler> &_handler) {
const std::thread::id its_id = std::this_thread::get_id();

std::shared_ptr<sync_handler> its_sync_handler
= std::make_shared<sync_handler>(_handler->service_id_,
_handler->instance_id_, _handler->method_id_,
_handler->eventgroup_id_, _handler->session_id_,
_handler->handler_type_);

boost::asio::steady_timer its_dispatcher_timer(io_);
its_dispatcher_timer.expires_from_now(std::chrono::milliseconds(max_dispatch_time_));
its_dispatcher_timer.async_wait([this, its_id, _handler](const boost::system::error_code &_error) {
its_dispatcher_timer.async_wait([this, its_id, its_sync_handler](const boost::system::error_code &_error) {
if (!_error) {
print_blocking_call(_handler);
print_blocking_call(its_sync_handler);
bool active_dispatcher_available(false);
{
std::lock_guard<std::mutex> its_lock(dispatcher_mutex_);
Expand All @@ -1549,7 +1552,7 @@ void application_impl::invoke_handler(std::shared_ptr<sync_handler> &_handler) {
// If this is _not_ possible, dispatching is blocked until
// at least one of the active handler calls returns.
std::lock_guard<std::mutex> its_lock(dispatcher_mutex_);
if (dispatchers_.size() < max_dispatchers_) {
if (dispatchers_.size() < max_dispatchers_ && is_dispatching_) {
auto its_dispatcher = std::make_shared<std::thread>(
std::bind(&application_impl::dispatch, shared_from_this()));
dispatchers_[its_dispatcher->get_id()] = its_dispatcher;
Expand All @@ -1565,7 +1568,7 @@ void application_impl::invoke_handler(std::shared_ptr<sync_handler> &_handler) {

_handler->handler_();
its_dispatcher_timer.cancel();
{
if (is_dispatching_) {
std::lock_guard<std::mutex> its_lock(dispatcher_mutex_);
blocked_dispatchers_.erase(its_id);
}
Expand All @@ -1582,6 +1585,9 @@ bool application_impl::has_active_dispatcher() {
}

bool application_impl::is_active_dispatcher(const std::thread::id &_id) {
if (!is_dispatching_) {
return is_dispatching_;
}
std::lock_guard<std::mutex> its_lock(dispatcher_mutex_);
for (const auto &d : dispatchers_) {
if (d.first != _id &&
Expand All @@ -1594,14 +1600,16 @@ bool application_impl::is_active_dispatcher(const std::thread::id &_id) {
}

void application_impl::remove_elapsed_dispatchers() {
std::lock_guard<std::mutex> its_lock(dispatcher_mutex_);
for (auto id : elapsed_dispatchers_) {
auto its_dispatcher = dispatchers_.find(id);
if (its_dispatcher->second->joinable())
its_dispatcher->second->join();
dispatchers_.erase(id);
if (is_dispatching_) {
std::lock_guard<std::mutex> its_lock(dispatcher_mutex_);
for (auto id : elapsed_dispatchers_) {
auto its_dispatcher = dispatchers_.find(id);
if (its_dispatcher->second->joinable())
its_dispatcher->second->join();
dispatchers_.erase(id);
}
elapsed_dispatchers_.clear();
}
elapsed_dispatchers_.clear();
}

void application_impl::clear_all_handler() {
Expand Down Expand Up @@ -1647,35 +1655,36 @@ void application_impl::shutdown() {
stop_cv_.wait(its_lock);
}
}
std::map<std::thread::id, std::shared_ptr<std::thread>> its_dispatchers;
{
std::lock_guard<std::mutex> its_lock(dispatcher_mutex_);
its_dispatchers = dispatchers_;
}
{
std::lock_guard<std::mutex> its_handler_lock(handlers_mutex_);
is_dispatching_ = false;
dispatcher_condition_.notify_all();
}
for (auto its_dispatcher : its_dispatchers) {
if (its_dispatcher.second->get_id() != stop_caller_id_) {
if (its_dispatcher.second->joinable()) {
its_dispatcher.second->join();
{
std::lock_guard<std::mutex> its_lock(dispatcher_mutex_);
for (auto its_dispatcher : dispatchers_) {
if (its_dispatcher.second->get_id() != stop_caller_id_) {
if (its_dispatcher.second->joinable()) {
its_dispatcher.second->join();
}
} else {
// If the caller of stop() is one of our dispatchers
// it can happen the shutdown mechanism will block
// as that thread probably can't be joined. The reason
// is the caller of stop() probably wants to join the
// thread once call start (which got to the IO-Thread)
// and which is expected to return after stop() has been
// called.
// Therefore detach this thread instead of joining because
// after it will return to "main_dispatch" it will be
// properly shutdown anyways because "is_dispatching_"
// was set to "false" here.
its_dispatcher.second->detach();
}
} else {
// If the caller of stop() is one of our dispatchers
// it can happen the shutdown mechanism will block
// as that thread probably can't be joined. The reason
// is the caller of stop() probably wants to join the
// thread once call start (which got to the IO-Thread)
// and which is expected to return after stop() has been
// called.
// Therefore detach this thread instead of joining because
// after it will return to "main_dispatch" it will be
// properly shutdown anyways because "is_dispatching_"
// was set to "false" here.
its_dispatcher.second->detach();
}
blocked_dispatchers_.clear();
elapsed_dispatchers_.clear();
dispatchers_.clear();
}

if (routing_)
Expand Down
Loading

0 comments on commit c3e889f

Please sign in to comment.