Skip to content

Commit 7b94729

Browse files
committed
WIP: Use a queue to track component registration from mulitple sources
Signed-off-by: Addisu Z. Taddese <[email protected]>
1 parent ba96ec8 commit 7b94729

File tree

4 files changed

+68
-1126
lines changed

4 files changed

+68
-1126
lines changed

include/ignition/gazebo/components/Factory.hh

+63-54
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include <cstdint>
2121
#include <cstring>
22+
#include <deque>
2223
#include <map>
2324
#include <memory>
2425
#include <string>
@@ -114,6 +115,9 @@ namespace components
114115
class Factory
115116
: public ignition::common::SingletonT<Factory>
116117
{
118+
/// \brief Get an instance of the singleton
119+
public: static Factory *Instance();
120+
117121
/// \brief Register a component so that the factory can create instances
118122
/// of the component and its storage based on an ID.
119123
/// \param[in] _type Type of component to register.
@@ -139,13 +143,6 @@ namespace components
139143
public: template<typename ComponentTypeT>
140144
void Register(const std::string &_type, ComponentDescriptorBase *_compDesc)
141145
{
142-
// Every time a plugin which uses a component type is loaded, it attempts
143-
// to register it again, so we skip it.
144-
if (ComponentTypeT::typeId != 0)
145-
{
146-
return;
147-
}
148-
149146
auto typeHash = ignition::common::hash64(_type);
150147

151148
// Initialize static member variable - we need to set these
@@ -169,8 +166,8 @@ namespace components
169166
<< runtimeNameIt->second << "] and type [" << runtimeName
170167
<< "] with name [" << _type << "]. Second type will not work."
171168
<< std::endl;
169+
return;
172170
}
173-
return;
174171
}
175172

176173
// This happens at static initialization time, so we can't use common
@@ -184,7 +181,7 @@ namespace components
184181
}
185182

186183
// Keep track of all types
187-
this->compsById[ComponentTypeT::typeId] = _compDesc;
184+
this->compsById[ComponentTypeT::typeId].push_front(_compDesc);
188185
namesById[ComponentTypeT::typeId] = ComponentTypeT::typeName;
189186
runtimeNamesById[ComponentTypeT::typeId] = runtimeName;
190187
}
@@ -193,11 +190,9 @@ namespace components
193190
/// of the component anymore.
194191
/// \tparam ComponentTypeT Type of component to unregister.
195192
public: template<typename ComponentTypeT>
196-
void Unregister()
193+
void Unregister(ComponentDescriptorBase *_compDesc = nullptr)
197194
{
198-
this->Unregister(ComponentTypeT::typeId);
199-
200-
ComponentTypeT::typeId = 0;
195+
this->Unregister(ComponentTypeT::typeId, _compDesc);
201196
}
202197

203198
/// \brief Unregister a component so that the factory can't create instances
@@ -206,7 +201,8 @@ namespace components
206201
/// within the component type itself. Prefer using the templated
207202
/// `Unregister` function when possible.
208203
/// \param[in] _typeId Type of component to unregister.
209-
public: void Unregister(ComponentTypeId _typeId)
204+
public: void Unregister(ComponentTypeId _typeId,
205+
ComponentDescriptorBase *_compDesc = nullptr)
210206
{
211207
// Not registered
212208
if (_typeId == 0)
@@ -216,26 +212,30 @@ namespace components
216212

217213
{
218214
auto it = this->compsById.find(_typeId);
219-
if (it != this->compsById.end())
215+
if (it != this->compsById.end() && !it->second.empty())
220216
{
221-
delete it->second;
222-
this->compsById.erase(it);
217+
if (nullptr == _compDesc)
218+
{
219+
ComponentDescriptorBase *compDesc = it->second.back();
220+
it->second.pop_back();
221+
delete compDesc;
222+
}
223+
else
224+
{
225+
auto compIt =
226+
std::find(it->second.begin(), it->second.end(), _compDesc);
227+
if (compIt != it->second.end())
228+
{
229+
ComponentDescriptorBase* compDesc = *compIt;
230+
it->second.erase(compIt);
231+
delete compDesc;
232+
}
233+
}
223234
}
224-
}
225-
226-
{
227-
auto it = namesById.find(_typeId);
228-
if (it != namesById.end())
235+
// Check again since we may have updated the list
236+
if (it->second.empty())
229237
{
230-
namesById.erase(it);
231-
}
232-
}
233-
234-
{
235-
auto it = runtimeNamesById.find(_typeId);
236-
if (it != runtimeNamesById.end())
237-
{
238-
runtimeNamesById.erase(it);
238+
this->compsById.erase(it);
239239
}
240240
}
241241
}
@@ -261,9 +261,15 @@ namespace components
261261
// Create a new component if a FactoryFn has been assigned to this type.
262262
std::unique_ptr<components::BaseComponent> comp;
263263
auto it = this->compsById.find(_type);
264-
if (it != this->compsById.end() && nullptr != it->second)
265-
comp = it->second->Create();
266-
264+
if (it != this->compsById.end() && !it->second.empty()){
265+
comp = it->second.front()->Create();
266+
}
267+
else
268+
{
269+
ignerr << "New(no data) Error: (it, empty)"
270+
<< (it != this->compsById.end()) << " "
271+
<< (it->second.size()) << std::endl;
272+
}
267273
return comp;
268274
}
269275

@@ -291,8 +297,16 @@ namespace components
291297
else
292298
{
293299
auto it = this->compsById.find(_type);
294-
if (it != this->compsById.end() && nullptr != it->second)
295-
comp = it->second->Create(_data);
300+
if (it != this->compsById.end() && !it->second.empty())
301+
{
302+
comp = it->second.front()->Create(_data);
303+
}
304+
else
305+
{
306+
ignerr << "New(data) Error: (it, empty)"
307+
<< (it != this->compsById.end()) << " "
308+
<< (it->second.size()) << std::endl;
309+
}
296310
}
297311

298312
return comp;
@@ -339,19 +353,8 @@ namespace components
339353
}
340354

341355
/// \brief A list of registered components where the key is its id.
342-
///
343-
/// Note about compsByName and compsById. The maps store pointers as the
344-
/// values, but never cleans them up, which may (at first glance) seem like
345-
/// incorrect behavior. This is not a mistake. Since ComponentDescriptors
346-
/// are created at the point in the code where components are defined, this
347-
/// generally ends up in a shared library that will be loaded at runtime.
348-
///
349-
/// Because this and the plugin loader both use static variables, and the
350-
/// order of static initialization and destruction are not guaranteed, this
351-
/// can lead to a scenario where the shared library is unloaded (with the
352-
/// ComponentDescriptor), but the Factory still exists. For this reason,
353-
/// we just keep a pointer, which will dangle until the program is shutdown.
354-
private: std::map<ComponentTypeId, ComponentDescriptorBase *> compsById;
356+
private: std::map<ComponentTypeId, std::deque<ComponentDescriptorBase *>>
357+
compsById;
355358

356359
/// \brief A list of IDs and their equivalent names.
357360
public: std::map<ComponentTypeId, std::string> namesById;
@@ -375,13 +378,19 @@ namespace components
375378
{ \
376379
public: IgnGazeboComponents##_classname() \
377380
{ \
378-
if (_classname::typeId != 0) \
379-
return; \
380-
using namespace ignition;\
381-
using Desc = gazebo::components::ComponentDescriptor<_classname>; \
381+
using namespace ignition; \
382+
this->desc = new Desc(); \
382383
gazebo::components::Factory::Instance()->Register<_classname>(\
383-
_compType, new Desc());\
384+
_compType, this->desc);\
385+
} \
386+
public: ~IgnGazeboComponents##_classname() \
387+
{ \
388+
using namespace ignition; \
389+
using namespace gazebo; \
390+
components::Factory::Instance()->Unregister<_classname>(this->desc); \
384391
} \
392+
using Desc = ignition::gazebo::components::ComponentDescriptor<_classname>;\
393+
private: Desc *desc; \
385394
}; \
386395
static IgnGazeboComponents##_classname\
387396
IgnitionGazeboComponentsInitializer##_classname;

src/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ set (sources
4646
Barrier.cc
4747
BaseView.cc
4848
Conversions.cc
49+
ComponentFactory.cc
4950
EntityComponentManager.cc
5051
LevelManager.cc
5152
Link.cc

src/ComponentFactory_TEST.cc

+2-5
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ TEST_F(ComponentFactoryTest, Register)
6868
EXPECT_EQ(registeredCount + 1, ids.size());
6969
EXPECT_NE(ids.end(), std::find(ids.begin(), ids.end(), MyCustom::typeId));
7070

71-
// Fail to register same component twice
71+
// Registering the component twice doesn't change the number of type ids.
7272
factory->Register<MyCustom>("ign_gazebo_components.MyCustom",
7373
new components::ComponentDescriptor<MyCustom>());
7474

@@ -85,11 +85,8 @@ TEST_F(ComponentFactoryTest, Register)
8585
// Unregister
8686
factory->Unregister<MyCustom>();
8787

88-
// Check it has no type id yet
8988
ids = factory->TypeIds();
90-
EXPECT_EQ(registeredCount, ids.size());
91-
EXPECT_EQ(0u, MyCustom::typeId);
92-
EXPECT_EQ("", factory->Name(MyCustom::typeId));
89+
EXPECT_EQ(registeredCount + 1, ids.size());
9390
}
9491

9592
/////////////////////////////////////////////////

0 commit comments

Comments
 (0)