| 151 | } |
| 152 | |
| 153 | std::vector<Bundle> |
| 154 | BundleRegistry::Install(std::string const& location, |
| 155 | BundlePrivate* installingBundle, |
| 156 | cppmicroservices::AnyMap const& bundleManifest) |
| 157 | { |
| 158 | using namespace std::chrono_literals; |
| 159 | |
| 160 | CheckIllegalState(); |
| 161 | |
| 162 | // Grab the lock for the BundleRegistry object so that we can |
| 163 | // read into the map without any data races |
| 164 | auto l = this->Lock(); |
| 165 | US_UNUSED(l); |
| 166 | |
| 167 | // Search the multimap for the current bundle location |
| 168 | auto bundlesAtLocationRange = (bundles.Lock(), bundles.v.equal_range(location)); |
| 169 | |
| 170 | /* |
| 171 | If the bundle is already installed, then execute the regular |
| 172 | install process. In this case, there are no data races to worry about. |
| 173 | |
| 174 | If the bundle isn't installed, then one of two things can happen: 1) either |
| 175 | the current thread is the first thread trying to install this bundle or 2) the |
| 176 | current thread is trying to install a bundle that is not installed but another |
| 177 | thread is currently installing that bundle. |
| 178 | |
| 179 | If 1): Create an entry in the initialBundleInstallMap which keeps track of whether |
| 180 | or not a given bundle is being installed for the first time. After creating this |
| 181 | entry, the thread performs the install and notifies all threads waiting on that |
| 182 | install to finish so that they too can perform an install (but in the context of it |
| 183 | being already installed). |
| 184 | |
| 185 | If 2): Increment the reference counter for the bundle in the initialBundleInstallMap. |
| 186 | This ensures that when we decrement the count after the installing thread is done, |
| 187 | the map entry isn't deleted since the current thread needs access to the |
| 188 | condition_variable and boolean flag. Once the installing thread notifies the thread |
| 189 | that it is able to continue with it's install, it goes ahead and performs the regular |
| 190 | install procedure. |
| 191 | */ |
| 192 | |
| 193 | /** |
| 194 | * safe to use these iterators to say 'there are already bundles here matching that location' but not to use |
| 195 | * them outside of the bundles.lock() critical region |
| 196 | */ |
| 197 | if (bundlesAtLocationRange.first != bundlesAtLocationRange.second) |
| 198 | { |
| 199 | l.UnLock(); |
| 200 | std::vector<Bundle> resultingBundles; |
| 201 | std::vector<std::string> alreadyInstalled; |
| 202 | // Populate the resultingBundles and alreadyInstalled vectors with the appropriate data |
| 203 | // based on what bundles are already installed |
| 204 | auto resCont = GetAlreadyInstalledBundlesAtLocation(location, |
| 205 | bundleManifest, |
| 206 | resultingBundles, |
| 207 | alreadyInstalled, |
| 208 | installingBundle->id != 0); |
| 209 | |
| 210 | // Perform the install |