Skip to content

Commit a9253fb

Browse files
authored
Fixed thread sanitizer warnings with partitions (#169)
* [#23686] Fixed Thread Sanitizer warnings with partitions Signed-off-by: danipiza <dpizarrogallego@gmail.com> * [#23686] Cleaned code and fixed uncrustify Signed-off-by: danipiza <dpizarrogallego@gmail.com> * [#23686] Removed lock in 'create_new_service_nts_' (already being used in the function where is being called) Signed-off-by: danipiza <dpizarrogallego@gmail.com> * [#23594] Solved DDS-Record-Replay TSAN execution warnings + review suggestions Signed-off-by: danipiza <dpizarrogallego@gmail.com> --------- Signed-off-by: danipiza <dpizarrogallego@gmail.com>
1 parent b5d04c8 commit a9253fb

2 files changed

Lines changed: 169 additions & 61 deletions

File tree

ddspipe_core/include/ddspipe_core/core/DdsPipe.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,11 @@ class DdsPipe
452452
* @brief Internal mutex for concurrent calls
453453
*/
454454
mutable std::mutex mutex_;
455+
456+
/**
457+
* @brief Internal mutex for bridges
458+
*/
459+
mutable std::mutex bridges_mutex_;
455460
};
456461

457462
} /* namespace core */

ddspipe_core/src/cpp/core/DdsPipe.cpp

Lines changed: 164 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,23 @@ void DdsPipe::reload_filter_partition(
135135
const std::set<std::string> filter_partition_set)
136136
{
137137
update_filter(filter_partition_set);
138-
for (const auto& pair: bridges_)
138+
139+
std::vector<DdsBridge*> targets;
140+
{
141+
std::lock_guard<std::mutex> lock(bridges_mutex_);
142+
143+
for (const auto& bridge : bridges_)
144+
{
145+
if (bridge.second)
146+
{
147+
targets.push_back(bridge.second.get());
148+
}
149+
}
150+
}
151+
152+
for (auto* target : targets)
139153
{
140-
pair.second->update_readers_track(filter_partition_set);
154+
target->update_readers_track(filter_partition_set);
141155
}
142156
}
143157

@@ -313,16 +327,25 @@ void DdsPipe::discovered_endpoint_nts_(
313327
// update the track of the topic to
314328
// add the partition in the reader if it is in the filter
315329

316-
const auto bridge_it = bridges_.find(utils::Heritable<DdsTopic>::make_heritable(endpoint.topic));
317-
std::ostringstream guid_ss;
318-
guid_ss << endpoint.guid; // get the source guid
319-
// add the specific partition of the endpoint in the bridges topic.
320-
if (bridge_it != bridges_.end())
330+
// update partitions under bridges_mutex_
321331
{
322-
bridge_it->second->add_partition_to_topic(
323-
guid_ss.str(), endpoint.specific_partitions.find(guid_ss.str())->second);
324-
}
332+
std::lock_guard<std::mutex> lock(bridges_mutex_);
325333

334+
const auto bridge_it = bridges_.find(utils::Heritable<DdsTopic>::make_heritable(endpoint.topic));
335+
// add the specific partition of the endpoint in the bridges topic.
336+
if (bridge_it != bridges_.end())
337+
{
338+
std::ostringstream guid_ss;
339+
guid_ss << endpoint.guid;
340+
341+
const auto part_it = endpoint.specific_partitions.find(guid_ss.str());
342+
if (part_it != endpoint.specific_partitions.end())
343+
{
344+
bridge_it->second->add_partition_to_topic(guid_ss.str(), part_it->second);
345+
}
346+
}
347+
}
348+
// update readers outside the lock
326349
if (!filter_partition_.empty())
327350
{
328351
update_readers_track(endpoint.topic.m_topic_name, filter_partition_);
@@ -347,6 +370,8 @@ void DdsPipe::removed_endpoint_nts_(
347370
}
348371
else if (configuration_.remove_unused_entities && is_endpoint_relevant_(endpoint))
349372
{
373+
std::lock_guard<std::mutex> lock(bridges_mutex_);
374+
350375
const auto& topic = utils::Heritable<DdsTopic>::make_heritable(endpoint.topic);
351376

352377
// Remove the subscriber from the topic.
@@ -450,24 +475,42 @@ void DdsPipe::discovered_topic_nts_(
450475
{
451476
EPROSIMA_LOG_INFO(DDSPIPE, "Discovered topic: " << topic << " by: " << topic->topic_discoverer() << ".");
452477

453-
// Check if the bridge (and the topic) already exist.
454-
auto it_bridge = bridges_.find(topic);
478+
bool need_activate = false;
479+
DdsBridge* to_create_writer = nullptr;
480+
ParticipantId writer_pid{};
455481

456-
if (it_bridge == bridges_.end())
457482
{
458-
// Add topic to current_topics as not activated
459-
current_topics_.emplace(topic, false);
483+
std::lock_guard<std::mutex> lock(bridges_mutex_);
460484

461-
// If Pipe is enabled and topic allowed, activate it
462-
if (enabled_ && allowed_topics_->is_topic_allowed(*topic))
485+
// Check if the bridge (and the topic) already exist.
486+
auto it_bridge = bridges_.find(topic);
487+
if (it_bridge == bridges_.end())
463488
{
464-
activate_topic_nts_(topic);
489+
// Add topic to current_topics as not activated
490+
current_topics_.emplace(topic, false);
491+
492+
// decide activation under lock, perform it after unlocking
493+
need_activate = enabled_ && allowed_topics_->is_topic_allowed(*topic);
465494
}
495+
else if (configuration_.remove_unused_entities && topic->topic_discoverer() != DEFAULT_PARTICIPANT_ID)
496+
{
497+
// The bridge already exists.
498+
// Create a writer in the participant who discovered it.
499+
// (out of the lock)
500+
to_create_writer = it_bridge->second.get();
501+
writer_pid = topic->topic_discoverer();
502+
}
503+
}
504+
505+
// call out of lock
506+
if (to_create_writer)
507+
{
508+
to_create_writer->create_writer(writer_pid);
466509
}
467-
else if (configuration_.remove_unused_entities && topic->topic_discoverer() != DEFAULT_PARTICIPANT_ID)
510+
// if Pipe is enabled and topic allowed, activate it
511+
if (need_activate)
468512
{
469-
// The bridge already exists. Create a writer in the participant who discovered it.
470-
it_bridge->second->create_writer(topic->topic_discoverer());
513+
activate_topic_nts_(topic);
471514
}
472515
}
473516

@@ -478,27 +521,30 @@ void DdsPipe::discovered_service_nts_(
478521
{
479522
EPROSIMA_LOG_INFO(DDSPIPE, "Discovered service: " << topic << ".");
480523

481-
auto it_bridge = rpc_bridges_.find(topic);
482-
483-
if (it_bridge == rpc_bridges_.end())
524+
RpcBridge* bridge = nullptr;
525+
bool should_enable = false;
484526
{
485-
// Create RpcBridge even if topic not allowed, as we need to store server in database
486-
create_new_service_nts_(topic);
527+
std::lock_guard<std::mutex> lock(bridges_mutex_);
487528

488-
if (allowed_topics_->is_service_allowed(topic))
489-
{
490-
current_services_[topic] = true;
491-
}
492-
else
529+
auto it_bridge = rpc_bridges_.find(topic);
530+
531+
if (it_bridge == rpc_bridges_.end())
493532
{
494-
current_services_[topic] = false;
533+
// Create RpcBridge even if topic not allowed, as we need to store server in database
534+
create_new_service_nts_(topic);
535+
current_services_[topic] = allowed_topics_->is_service_allowed(topic);
536+
537+
it_bridge = rpc_bridges_.find(topic);
495538
}
539+
bridge = it_bridge->second.get();
540+
should_enable = enabled_ && current_services_[topic];
496541
}
497542

498-
rpc_bridges_[topic]->discovered_service(server_participant_id, server_guid_prefix);
499-
if (enabled_ && current_services_[topic])
543+
// Calls outside the lock
544+
bridge->discovered_service(server_participant_id, server_guid_prefix);
545+
if (should_enable)
500546
{
501-
rpc_bridges_[topic]->enable();
547+
bridge->enable();
502548
}
503549
}
504550

@@ -509,11 +555,21 @@ void DdsPipe::removed_service_nts_(
509555
{
510556
EPROSIMA_LOG_INFO(DDSPIPE, "Removed service: " << topic << ".");
511557

512-
auto it_bridge = rpc_bridges_.find(topic);
558+
RpcBridge* bridge = nullptr;
559+
{
560+
std::lock_guard<std::mutex> lock(bridges_mutex_);
513561

514-
if (it_bridge != rpc_bridges_.end())
562+
auto it_bridge = rpc_bridges_.find(topic);
563+
564+
if (it_bridge != rpc_bridges_.end())
565+
{
566+
bridge = it_bridge->second.get();
567+
}
568+
}
569+
570+
if (bridge)
515571
{
516-
rpc_bridges_[topic]->removed_service(server_participant_id, server_guid_prefix);
572+
bridge->removed_service(server_participant_id, server_guid_prefix);
517573
}
518574
}
519575

@@ -530,8 +586,15 @@ void DdsPipe::create_new_bridge_nts_(
530586

531587
std::unique_ptr<DdsBridge> new_bridge;
532588

589+
bool filter_partition_empty;
590+
{
591+
// Avoid possible datarace with partitions filter
592+
std::lock_guard<std::mutex> lock(bridges_mutex_);
593+
filter_partition_empty = filter_partition_.empty();
594+
}
595+
533596
// check if there is a filter partition list
534-
if (filter_partition_.empty())
597+
if (filter_partition_empty)
535598
{
536599
// Create bridge instance
537600
new_bridge = std::make_unique<DdsBridge>(topic,
@@ -558,12 +621,22 @@ void DdsPipe::create_new_bridge_nts_(
558621
filter_partition_);
559622
}
560623

561-
if (enabled)
624+
DdsBridge* to_enable = nullptr;
562625
{
563-
new_bridge->enable();
626+
std::lock_guard<std::mutex> lock(bridges_mutex_);
627+
auto& slot = bridges_[topic];
628+
slot = std::move(new_bridge);
629+
if (enabled)
630+
{
631+
to_enable = slot.get();
632+
}
564633
}
565634

566-
bridges_[topic] = std::move(new_bridge);
635+
// enable without the lock
636+
if (to_enable)
637+
{
638+
to_enable->enable();
639+
}
567640
}
568641
catch (const utils::InitializationException& e)
569642
{
@@ -588,20 +661,29 @@ void DdsPipe::activate_topic_nts_(
588661
EPROSIMA_LOG_INFO(DDSPIPE, "Activating topic: " << topic << ".");
589662

590663
// Modify current_topics_ and set this topic as active
591-
current_topics_[topic] = true;
664+
{
665+
std::lock_guard<std::mutex> lock(bridges_mutex_);
666+
current_topics_[topic] = true;
667+
}
592668

593669
// Enable bridge. In case it is already enabled nothing should happen
594-
auto it_bridge = bridges_.find(topic);
595-
596-
if (it_bridge == bridges_.end())
670+
DdsBridge* to_enable = nullptr;
671+
{
672+
std::lock_guard<std::mutex> lock(bridges_mutex_);
673+
auto it = bridges_.find(topic);
674+
if (it != bridges_.end())
675+
{
676+
to_enable = it->second.get();
677+
}
678+
}
679+
if (!to_enable)
597680
{
598-
// The Bridge did not exist
681+
// Will enable after inserting (outside the lock) inside create_new_bridge_nts_
599682
create_new_bridge_nts_(topic, true);
600683
}
601684
else
602685
{
603-
// The Bridge already exists
604-
it_bridge->second->enable();
686+
to_enable->enable();
605687
}
606688
}
607689

@@ -610,16 +692,24 @@ void DdsPipe::deactivate_topic_nts_(
610692
{
611693
EPROSIMA_LOG_INFO(DDSPIPE, "Deactivating topic: " << topic << ".");
612694

613-
// Modify current_topics_ and set this topic as not active
614-
current_topics_[topic] = false;
695+
DdsBridge* to_disable = nullptr;
696+
{
697+
std::lock_guard<std::mutex> lock(bridges_mutex_);
698+
699+
// Modify current_topics_ and set this topic as not active
700+
current_topics_[topic] = false;
615701

616-
// Disable bridge. In case it is already disabled nothing should happen
617-
auto it_bridge = bridges_.find(topic);
702+
// Disable bridge. In case it is already disabled nothing should happen
703+
auto it_bridge = bridges_.find(topic);
704+
if (it_bridge != bridges_.end())
705+
{
706+
to_disable = it_bridge->second.get();
707+
}
708+
}
618709

619-
if (it_bridge != bridges_.end())
710+
if (to_disable)
620711
{
621-
// The Bridge already exists
622-
it_bridge->second->disable();
712+
to_disable->disable();
623713
}
624714
// If the Bridge does not exist, there is no need to create it
625715
}
@@ -649,20 +739,33 @@ void DdsPipe::update_readers_track(
649739
const std::string topic_name,
650740
const std::set<std::string> filter_partition_set)
651741
{
652-
653-
// search the track associated with the topic name
654-
for (const auto& pair: bridges_)
742+
// get the targets (with lock)
743+
std::vector<DdsBridge*> targets;
655744
{
656-
if (pair.first->m_topic_name == topic_name)
745+
std::lock_guard<std::mutex> lock(bridges_mutex_);
746+
747+
for (const auto& pair : bridges_)
657748
{
658-
pair.second->update_readers_track(filter_partition_set);
749+
if (pair.first->m_topic_name == topic_name && pair.second)
750+
{
751+
targets.push_back(pair.second.get());
752+
}
659753
}
660754
}
755+
756+
// update readers outside the lock
757+
for (auto* target : targets)
758+
{
759+
target->update_readers_track(filter_partition_set);
760+
}
661761
}
662762

663763
void DdsPipe::update_filter(
664764
const std::set<std::string> filter_partition_set)
665765
{
766+
// Avoid possible datarace with partitions filter
767+
std::lock_guard<std::mutex> lock(bridges_mutex_);
768+
666769
filter_partition_ = filter_partition_set;
667770
}
668771

0 commit comments

Comments
 (0)