@@ -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
663763void 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