1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 /// \file staticInterface.cpp
25
26 #include "pxr/pxr.h"
27 #include "pxr/base/plug/staticInterface.h"
28 #include "pxr/base/plug/interfaceFactory.h"
29 #include "pxr/base/plug/plugin.h"
30 #include "pxr/base/plug/registry.h"
31 #include "pxr/base/tf/diagnostic.h"
32 #include "pxr/base/tf/scoped.h"
33 #include <mutex>
34 #include <string>
35
36 PXR_NAMESPACE_OPEN_SCOPE
37
38 static std::mutex _initializationMutex;
39
40 void
_LoadAndInstantiate(const std::type_info & type) const41 Plug_StaticInterfaceBase::_LoadAndInstantiate(const std::type_info& type) const
42 {
43 // Double checked locking.
44 std::lock_guard<std::mutex> lock(_initializationMutex);
45 if (_initialized) {
46 // Someone beat us to the initialization.
47 return;
48 }
49
50 // We attempt initialization only once so set _initialized when we return
51 // even if we fail to load or instantiate. We must not set it before we
52 // return because other threads would be able to observe partial
53 // initialization.
54 TfScoped<> initializeOnReturn{[this]() { _initialized = true; }};
55
56 // Validate type.
57 // We use FindByName because Find requres that std::type_info has been
58 // regisered, but that won't happen until the plugin is loaded.
59 const TfType &tfType =
60 TfType::FindByName(TfType::GetCanonicalTypeName(type));
61 if (!tfType) {
62 TF_CODING_ERROR("Failed to load plugin interface: "
63 "Can't find type %s", type.name());
64 return;
65 }
66 if (tfType.IsRoot()) {
67 TF_CODING_ERROR("Failed to load plugin interface: "
68 "Can't manufacture type %s",
69 tfType.GetTypeName().c_str());
70 return;
71 }
72
73 // Get the plugin with type.
74 PlugPluginPtr plugin = PlugRegistry::GetInstance().GetPluginForType(tfType);
75 if (!plugin) {
76 TF_RUNTIME_ERROR("Failed to load plugin interface: "
77 "Can't find plugin that defines type %s",
78 tfType.GetTypeName().c_str());
79 return;
80 }
81
82 // Load the plugin.
83 if (!plugin->Load()) {
84 // Error already reported.
85 return;
86 }
87
88 // Manufacture the type.
89 Plug_InterfaceFactory::Base* factory =
90 tfType.GetFactory<Plug_InterfaceFactory::Base>();
91 if (!factory) {
92 TF_CODING_ERROR("Failed to load plugin interface: "
93 "No default constructor for type %s",
94 tfType.GetTypeName().c_str());
95 return;
96 }
97 _ptr = factory->New();
98
99 // Report on error.
100 if (!_ptr) {
101 TF_CODING_ERROR("Failed to load plugin interface: "
102 "Plugin didn't manufacture an instance of %s",
103 tfType.GetTypeName().c_str());
104 }
105 }
106
107 PXR_NAMESPACE_CLOSE_SCOPE
108