1 //===----------- rtl.cpp - Target independent OpenMP target RTL -----------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Functionality for handling RTL plugins.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "rtl.h"
14 #include "device.h"
15 #include "private.h"
16 
17 #include "llvm/Object/OffloadBinary.h"
18 
19 #include <cassert>
20 #include <cstdlib>
21 #include <cstring>
22 #include <dlfcn.h>
23 #include <mutex>
24 #include <string>
25 
26 // List of all plugins that can support offloading.
27 static const char *RTLNames[] = {
28     /* PowerPC target       */ "libomptarget.rtl.ppc64.so",
29     /* x86_64 target        */ "libomptarget.rtl.x86_64.so",
30     /* CUDA target          */ "libomptarget.rtl.cuda.so",
31     /* AArch64 target       */ "libomptarget.rtl.aarch64.so",
32     /* SX-Aurora VE target  */ "libomptarget.rtl.ve.so",
33     /* AMDGPU target        */ "libomptarget.rtl.amdgpu.so",
34     /* Remote target        */ "libomptarget.rtl.rpc.so",
35 };
36 
37 PluginManager *PM;
38 
39 #if OMPTARGET_PROFILE_ENABLED
40 static char *ProfileTraceFile = nullptr;
41 #endif
42 
43 __attribute__((constructor(101))) void init() {
44   DP("Init target library!\n");
45 
46   bool UseEventsForAtomicTransfers = true;
47   if (const char *ForceAtomicMap = getenv("LIBOMPTARGET_MAP_FORCE_ATOMIC")) {
48     std::string ForceAtomicMapStr(ForceAtomicMap);
49     if (ForceAtomicMapStr == "false" || ForceAtomicMapStr == "FALSE")
50       UseEventsForAtomicTransfers = false;
51     else if (ForceAtomicMapStr != "true" && ForceAtomicMapStr != "TRUE")
52       fprintf(stderr,
53               "Warning: 'LIBOMPTARGET_MAP_FORCE_ATOMIC' accepts only "
54               "'true'/'TRUE' or 'false'/'FALSE' as options, '%s' ignored\n",
55               ForceAtomicMap);
56   }
57 
58   PM = new PluginManager(UseEventsForAtomicTransfers);
59 
60 #ifdef OMPTARGET_PROFILE_ENABLED
61   ProfileTraceFile = getenv("LIBOMPTARGET_PROFILE");
62   // TODO: add a configuration option for time granularity
63   if (ProfileTraceFile)
64     llvm::timeTraceProfilerInitialize(500 /* us */, "libomptarget");
65 #endif
66 }
67 
68 __attribute__((destructor(101))) void deinit() {
69   DP("Deinit target library!\n");
70   delete PM;
71 
72 #ifdef OMPTARGET_PROFILE_ENABLED
73   if (ProfileTraceFile) {
74     // TODO: add env var for file output
75     if (auto E = llvm::timeTraceProfilerWrite(ProfileTraceFile, "-"))
76       fprintf(stderr, "Error writing out the time trace\n");
77 
78     llvm::timeTraceProfilerCleanup();
79   }
80 #endif
81 }
82 
83 void RTLsTy::loadRTLs() {
84   // Parse environment variable OMP_TARGET_OFFLOAD (if set)
85   PM->TargetOffloadPolicy =
86       (kmp_target_offload_kind_t)__kmpc_get_target_offload();
87   if (PM->TargetOffloadPolicy == tgt_disabled) {
88     return;
89   }
90 
91   DP("Loading RTLs...\n");
92 
93   // Attempt to open all the plugins and, if they exist, check if the interface
94   // is correct and if they are supporting any devices.
95   for (auto *Name : RTLNames) {
96     DP("Loading library '%s'...\n", Name);
97     void *DynlibHandle = dlopen(Name, RTLD_NOW);
98 
99     if (!DynlibHandle) {
100       // Library does not exist or cannot be found.
101       DP("Unable to load library '%s': %s!\n", Name, dlerror());
102       continue;
103     }
104 
105     DP("Successfully loaded library '%s'!\n", Name);
106 
107     AllRTLs.emplace_back();
108 
109     // Retrieve the RTL information from the runtime library.
110     RTLInfoTy &R = AllRTLs.back();
111 
112     bool ValidPlugin = true;
113 
114     if (!(*((void **)&R.is_valid_binary) =
115               dlsym(DynlibHandle, "__tgt_rtl_is_valid_binary")))
116       ValidPlugin = false;
117     if (!(*((void **)&R.number_of_devices) =
118               dlsym(DynlibHandle, "__tgt_rtl_number_of_devices")))
119       ValidPlugin = false;
120     if (!(*((void **)&R.init_device) =
121               dlsym(DynlibHandle, "__tgt_rtl_init_device")))
122       ValidPlugin = false;
123     if (!(*((void **)&R.load_binary) =
124               dlsym(DynlibHandle, "__tgt_rtl_load_binary")))
125       ValidPlugin = false;
126     if (!(*((void **)&R.data_alloc) =
127               dlsym(DynlibHandle, "__tgt_rtl_data_alloc")))
128       ValidPlugin = false;
129     if (!(*((void **)&R.data_submit) =
130               dlsym(DynlibHandle, "__tgt_rtl_data_submit")))
131       ValidPlugin = false;
132     if (!(*((void **)&R.data_retrieve) =
133               dlsym(DynlibHandle, "__tgt_rtl_data_retrieve")))
134       ValidPlugin = false;
135     if (!(*((void **)&R.data_delete) =
136               dlsym(DynlibHandle, "__tgt_rtl_data_delete")))
137       ValidPlugin = false;
138     if (!(*((void **)&R.run_region) =
139               dlsym(DynlibHandle, "__tgt_rtl_run_target_region")))
140       ValidPlugin = false;
141     if (!(*((void **)&R.run_team_region) =
142               dlsym(DynlibHandle, "__tgt_rtl_run_target_team_region")))
143       ValidPlugin = false;
144 
145     // Invalid plugin
146     if (!ValidPlugin) {
147       DP("Invalid plugin as necessary interface is not found.\n");
148       AllRTLs.pop_back();
149       continue;
150     }
151 
152     // No devices are supported by this RTL?
153     if (!(R.NumberOfDevices = R.number_of_devices())) {
154       // The RTL is invalid! Will pop the object from the RTLs list.
155       DP("No devices supported in this RTL\n");
156       AllRTLs.pop_back();
157       continue;
158     }
159 
160     R.LibraryHandler = DynlibHandle;
161 
162 #ifdef OMPTARGET_DEBUG
163     R.RTLName = Name;
164 #endif
165 
166     DP("Registering RTL %s supporting %d devices!\n", R.RTLName.c_str(),
167        R.NumberOfDevices);
168 
169     // Optional functions
170     *((void **)&R.is_valid_binary_info) =
171         dlsym(DynlibHandle, "__tgt_rtl_is_valid_binary_info");
172     *((void **)&R.deinit_device) =
173         dlsym(DynlibHandle, "__tgt_rtl_deinit_device");
174     *((void **)&R.init_requires) =
175         dlsym(DynlibHandle, "__tgt_rtl_init_requires");
176     *((void **)&R.data_submit_async) =
177         dlsym(DynlibHandle, "__tgt_rtl_data_submit_async");
178     *((void **)&R.data_retrieve_async) =
179         dlsym(DynlibHandle, "__tgt_rtl_data_retrieve_async");
180     *((void **)&R.run_region_async) =
181         dlsym(DynlibHandle, "__tgt_rtl_run_target_region_async");
182     *((void **)&R.run_team_region_async) =
183         dlsym(DynlibHandle, "__tgt_rtl_run_target_team_region_async");
184     *((void **)&R.synchronize) = dlsym(DynlibHandle, "__tgt_rtl_synchronize");
185     *((void **)&R.data_exchange) =
186         dlsym(DynlibHandle, "__tgt_rtl_data_exchange");
187     *((void **)&R.data_exchange_async) =
188         dlsym(DynlibHandle, "__tgt_rtl_data_exchange_async");
189     *((void **)&R.is_data_exchangable) =
190         dlsym(DynlibHandle, "__tgt_rtl_is_data_exchangable");
191     *((void **)&R.register_lib) = dlsym(DynlibHandle, "__tgt_rtl_register_lib");
192     *((void **)&R.unregister_lib) =
193         dlsym(DynlibHandle, "__tgt_rtl_unregister_lib");
194     *((void **)&R.supports_empty_images) =
195         dlsym(DynlibHandle, "__tgt_rtl_supports_empty_images");
196     *((void **)&R.set_info_flag) =
197         dlsym(DynlibHandle, "__tgt_rtl_set_info_flag");
198     *((void **)&R.print_device_info) =
199         dlsym(DynlibHandle, "__tgt_rtl_print_device_info");
200     *((void **)&R.create_event) = dlsym(DynlibHandle, "__tgt_rtl_create_event");
201     *((void **)&R.record_event) = dlsym(DynlibHandle, "__tgt_rtl_record_event");
202     *((void **)&R.wait_event) = dlsym(DynlibHandle, "__tgt_rtl_wait_event");
203     *((void **)&R.sync_event) = dlsym(DynlibHandle, "__tgt_rtl_sync_event");
204     *((void **)&R.destroy_event) =
205         dlsym(DynlibHandle, "__tgt_rtl_destroy_event");
206     *((void **)&R.release_async_info) =
207         dlsym(DynlibHandle, "__tgt_rtl_release_async_info");
208     *((void **)&R.init_async_info) =
209         dlsym(DynlibHandle, "__tgt_rtl_init_async_info");
210     *((void **)&R.init_device_info) =
211         dlsym(DynlibHandle, "__tgt_rtl_init_device_info");
212   }
213 
214   DP("RTLs loaded!\n");
215 
216   return;
217 }
218 
219 ////////////////////////////////////////////////////////////////////////////////
220 // Functionality for registering libs
221 
222 static void registerImageIntoTranslationTable(TranslationTable &TT,
223                                               RTLInfoTy &RTL,
224                                               __tgt_device_image *Image) {
225 
226   // same size, as when we increase one, we also increase the other.
227   assert(TT.TargetsTable.size() == TT.TargetsImages.size() &&
228          "We should have as many images as we have tables!");
229 
230   // Resize the Targets Table and Images to accommodate the new targets if
231   // required
232   unsigned TargetsTableMinimumSize = RTL.Idx + RTL.NumberOfDevices;
233 
234   if (TT.TargetsTable.size() < TargetsTableMinimumSize) {
235     TT.TargetsImages.resize(TargetsTableMinimumSize, 0);
236     TT.TargetsTable.resize(TargetsTableMinimumSize, 0);
237   }
238 
239   // Register the image in all devices for this target type.
240   for (int32_t I = 0; I < RTL.NumberOfDevices; ++I) {
241     // If we are changing the image we are also invalidating the target table.
242     if (TT.TargetsImages[RTL.Idx + I] != Image) {
243       TT.TargetsImages[RTL.Idx + I] = Image;
244       TT.TargetsTable[RTL.Idx + I] = 0; // lazy initialization of target table.
245     }
246   }
247 }
248 
249 ////////////////////////////////////////////////////////////////////////////////
250 // Functionality for registering Ctors/Dtors
251 
252 static void registerGlobalCtorsDtorsForImage(__tgt_bin_desc *Desc,
253                                              __tgt_device_image *Img,
254                                              RTLInfoTy *RTL) {
255 
256   for (int32_t I = 0; I < RTL->NumberOfDevices; ++I) {
257     DeviceTy &Device = *PM->Devices[RTL->Idx + I];
258     Device.PendingGlobalsMtx.lock();
259     Device.HasPendingGlobals = true;
260     for (__tgt_offload_entry *Entry = Img->EntriesBegin;
261          Entry != Img->EntriesEnd; ++Entry) {
262       if (Entry->flags & OMP_DECLARE_TARGET_CTOR) {
263         DP("Adding ctor " DPxMOD " to the pending list.\n",
264            DPxPTR(Entry->addr));
265         Device.PendingCtorsDtors[Desc].PendingCtors.push_back(Entry->addr);
266       } else if (Entry->flags & OMP_DECLARE_TARGET_DTOR) {
267         // Dtors are pushed in reverse order so they are executed from end
268         // to beginning when unregistering the library!
269         DP("Adding dtor " DPxMOD " to the pending list.\n",
270            DPxPTR(Entry->addr));
271         Device.PendingCtorsDtors[Desc].PendingDtors.push_front(Entry->addr);
272       }
273 
274       if (Entry->flags & OMP_DECLARE_TARGET_LINK) {
275         DP("The \"link\" attribute is not yet supported!\n");
276       }
277     }
278     Device.PendingGlobalsMtx.unlock();
279   }
280 }
281 
282 static __tgt_device_image getExecutableImage(__tgt_device_image *Image) {
283   llvm::StringRef ImageStr(static_cast<char *>(Image->ImageStart),
284                            static_cast<char *>(Image->ImageEnd) -
285                                static_cast<char *>(Image->ImageStart));
286   auto BinaryOrErr =
287       llvm::object::OffloadBinary::create(llvm::MemoryBufferRef(ImageStr, ""));
288   if (!BinaryOrErr) {
289     llvm::consumeError(BinaryOrErr.takeError());
290     return *Image;
291   }
292 
293   void *Begin = const_cast<void *>(
294       static_cast<const void *>((*BinaryOrErr)->getImage().bytes_begin()));
295   void *End = const_cast<void *>(
296       static_cast<const void *>((*BinaryOrErr)->getImage().bytes_end()));
297 
298   return {Begin, End, Image->EntriesBegin, Image->EntriesEnd};
299 }
300 
301 static __tgt_image_info getImageInfo(__tgt_device_image *Image) {
302   llvm::StringRef ImageStr(static_cast<char *>(Image->ImageStart),
303                            static_cast<char *>(Image->ImageEnd) -
304                                static_cast<char *>(Image->ImageStart));
305   auto BinaryOrErr =
306       llvm::object::OffloadBinary::create(llvm::MemoryBufferRef(ImageStr, ""));
307   if (!BinaryOrErr) {
308     llvm::consumeError(BinaryOrErr.takeError());
309     return __tgt_image_info{};
310   }
311 
312   return __tgt_image_info{(*BinaryOrErr)->getArch().data()};
313 }
314 
315 void RTLsTy::registerRequires(int64_t Flags) {
316   // TODO: add more elaborate check.
317   // Minimal check: only set requires flags if previous value
318   // is undefined. This ensures that only the first call to this
319   // function will set the requires flags. All subsequent calls
320   // will be checked for compatibility.
321   assert(Flags != OMP_REQ_UNDEFINED &&
322          "illegal undefined flag for requires directive!");
323   if (RequiresFlags == OMP_REQ_UNDEFINED) {
324     RequiresFlags = Flags;
325     return;
326   }
327 
328   // If multiple compilation units are present enforce
329   // consistency across all of them for require clauses:
330   //  - reverse_offload
331   //  - unified_address
332   //  - unified_shared_memory
333   if ((RequiresFlags & OMP_REQ_REVERSE_OFFLOAD) !=
334       (Flags & OMP_REQ_REVERSE_OFFLOAD)) {
335     FATAL_MESSAGE0(
336         1, "'#pragma omp requires reverse_offload' not used consistently!");
337   }
338   if ((RequiresFlags & OMP_REQ_UNIFIED_ADDRESS) !=
339       (Flags & OMP_REQ_UNIFIED_ADDRESS)) {
340     FATAL_MESSAGE0(
341         1, "'#pragma omp requires unified_address' not used consistently!");
342   }
343   if ((RequiresFlags & OMP_REQ_UNIFIED_SHARED_MEMORY) !=
344       (Flags & OMP_REQ_UNIFIED_SHARED_MEMORY)) {
345     FATAL_MESSAGE0(
346         1,
347         "'#pragma omp requires unified_shared_memory' not used consistently!");
348   }
349 
350   // TODO: insert any other missing checks
351 
352   DP("New requires flags %" PRId64 " compatible with existing %" PRId64 "!\n",
353      Flags, RequiresFlags);
354 }
355 
356 void RTLsTy::initRTLonce(RTLInfoTy &R) {
357   // If this RTL is not already in use, initialize it.
358   if (!R.IsUsed && R.NumberOfDevices != 0) {
359     // Initialize the device information for the RTL we are about to use.
360     const size_t Start = PM->Devices.size();
361     PM->Devices.reserve(Start + R.NumberOfDevices);
362     for (int32_t DeviceId = 0; DeviceId < R.NumberOfDevices; DeviceId++) {
363       PM->Devices.push_back(std::make_unique<DeviceTy>(&R));
364       // global device ID
365       PM->Devices[Start + DeviceId]->DeviceID = Start + DeviceId;
366       // RTL local device ID
367       PM->Devices[Start + DeviceId]->RTLDeviceID = DeviceId;
368     }
369 
370     // Initialize the index of this RTL and save it in the used RTLs.
371     R.Idx = (UsedRTLs.empty())
372                 ? 0
373                 : UsedRTLs.back()->Idx + UsedRTLs.back()->NumberOfDevices;
374     assert((size_t)R.Idx == Start &&
375            "RTL index should equal the number of devices used so far.");
376     R.IsUsed = true;
377     UsedRTLs.push_back(&R);
378 
379     DP("RTL " DPxMOD " has index %d!\n", DPxPTR(R.LibraryHandler), R.Idx);
380   }
381 }
382 
383 void RTLsTy::initAllRTLs() {
384   for (auto &R : AllRTLs)
385     initRTLonce(R);
386 }
387 
388 void RTLsTy::registerLib(__tgt_bin_desc *Desc) {
389   PM->RTLsMtx.lock();
390 
391   // Extract the exectuable image and extra information if availible.
392   for (int32_t i = 0; i < Desc->NumDeviceImages; ++i)
393     PM->Images.emplace_back(getExecutableImage(&Desc->DeviceImages[i]),
394                             getImageInfo(&Desc->DeviceImages[i]));
395 
396   // Register the images with the RTLs that understand them, if any.
397   for (auto &ImageAndInfo : PM->Images) {
398     // Obtain the image and information that was previously extracted.
399     __tgt_device_image *Img = &ImageAndInfo.first;
400     __tgt_image_info *Info = &ImageAndInfo.second;
401 
402     RTLInfoTy *FoundRTL = nullptr;
403 
404     // Scan the RTLs that have associated images until we find one that supports
405     // the current image.
406     for (auto &R : AllRTLs) {
407       if (R.is_valid_binary_info) {
408         if (!R.is_valid_binary_info(Img, Info)) {
409           DP("Image " DPxMOD " is NOT compatible with RTL %s!\n",
410              DPxPTR(Img->ImageStart), R.RTLName.c_str());
411           continue;
412         }
413       } else if (!R.is_valid_binary(Img)) {
414         DP("Image " DPxMOD " is NOT compatible with RTL %s!\n",
415            DPxPTR(Img->ImageStart), R.RTLName.c_str());
416         continue;
417       }
418 
419       DP("Image " DPxMOD " is compatible with RTL %s!\n",
420          DPxPTR(Img->ImageStart), R.RTLName.c_str());
421 
422       initRTLonce(R);
423 
424       // Initialize (if necessary) translation table for this library.
425       PM->TrlTblMtx.lock();
426       if (!PM->HostEntriesBeginToTransTable.count(Desc->HostEntriesBegin)) {
427         PM->HostEntriesBeginRegistrationOrder.push_back(Desc->HostEntriesBegin);
428         TranslationTable &TransTable =
429             (PM->HostEntriesBeginToTransTable)[Desc->HostEntriesBegin];
430         TransTable.HostTable.EntriesBegin = Desc->HostEntriesBegin;
431         TransTable.HostTable.EntriesEnd = Desc->HostEntriesEnd;
432       }
433 
434       // Retrieve translation table for this library.
435       TranslationTable &TransTable =
436           (PM->HostEntriesBeginToTransTable)[Desc->HostEntriesBegin];
437 
438       DP("Registering image " DPxMOD " with RTL %s!\n", DPxPTR(Img->ImageStart),
439          R.RTLName.c_str());
440       registerImageIntoTranslationTable(TransTable, R, Img);
441       PM->TrlTblMtx.unlock();
442       FoundRTL = &R;
443 
444       // Load ctors/dtors for static objects
445       registerGlobalCtorsDtorsForImage(Desc, Img, FoundRTL);
446 
447       // if an RTL was found we are done - proceed to register the next image
448       break;
449     }
450 
451     if (!FoundRTL) {
452       DP("No RTL found for image " DPxMOD "!\n", DPxPTR(Img->ImageStart));
453     }
454   }
455   PM->RTLsMtx.unlock();
456 
457   DP("Done registering entries!\n");
458 }
459 
460 void RTLsTy::unregisterLib(__tgt_bin_desc *Desc) {
461   DP("Unloading target library!\n");
462 
463   PM->RTLsMtx.lock();
464   // Find which RTL understands each image, if any.
465   for (auto &ImageAndInfo : PM->Images) {
466     // Obtain the image and information that was previously extracted.
467     __tgt_device_image *Img = &ImageAndInfo.first;
468     __tgt_image_info *Info = &ImageAndInfo.second;
469 
470     RTLInfoTy *FoundRTL = NULL;
471 
472     // Scan the RTLs that have associated images until we find one that supports
473     // the current image. We only need to scan RTLs that are already being used.
474     for (auto *R : UsedRTLs) {
475 
476       assert(R->IsUsed && "Expecting used RTLs.");
477 
478       if (R->is_valid_binary_info) {
479         if (!R->is_valid_binary_info(Img, Info)) {
480           DP("Image " DPxMOD " is NOT compatible with RTL %s!\n",
481              DPxPTR(Img->ImageStart), R->RTLName.c_str());
482           continue;
483         }
484       } else if (!R->is_valid_binary(Img)) {
485         DP("Image " DPxMOD " is NOT compatible with RTL %s!\n",
486            DPxPTR(Img->ImageStart), R->RTLName.c_str());
487         continue;
488       }
489 
490       DP("Image " DPxMOD " is compatible with RTL " DPxMOD "!\n",
491          DPxPTR(Img->ImageStart), DPxPTR(R->LibraryHandler));
492 
493       FoundRTL = R;
494 
495       // Execute dtors for static objects if the device has been used, i.e.
496       // if its PendingCtors list has been emptied.
497       for (int32_t I = 0; I < FoundRTL->NumberOfDevices; ++I) {
498         DeviceTy &Device = *PM->Devices[FoundRTL->Idx + I];
499         Device.PendingGlobalsMtx.lock();
500         if (Device.PendingCtorsDtors[Desc].PendingCtors.empty()) {
501           AsyncInfoTy AsyncInfo(Device);
502           for (auto &Dtor : Device.PendingCtorsDtors[Desc].PendingDtors) {
503             int Rc = target(nullptr, Device, Dtor, 0, nullptr, nullptr, nullptr,
504                             nullptr, nullptr, nullptr, 1, 1, 0, true /*team*/,
505                             AsyncInfo);
506             if (Rc != OFFLOAD_SUCCESS) {
507               DP("Running destructor " DPxMOD " failed.\n", DPxPTR(Dtor));
508             }
509           }
510           // Remove this library's entry from PendingCtorsDtors
511           Device.PendingCtorsDtors.erase(Desc);
512           // All constructors have been issued, wait for them now.
513           if (AsyncInfo.synchronize() != OFFLOAD_SUCCESS)
514             DP("Failed synchronizing destructors kernels.\n");
515         }
516         Device.PendingGlobalsMtx.unlock();
517       }
518 
519       DP("Unregistered image " DPxMOD " from RTL " DPxMOD "!\n",
520          DPxPTR(Img->ImageStart), DPxPTR(R->LibraryHandler));
521 
522       break;
523     }
524 
525     // if no RTL was found proceed to unregister the next image
526     if (!FoundRTL) {
527       DP("No RTLs in use support the image " DPxMOD "!\n",
528          DPxPTR(Img->ImageStart));
529     }
530   }
531   PM->RTLsMtx.unlock();
532   DP("Done unregistering images!\n");
533 
534   // Remove entries from PM->HostPtrToTableMap
535   PM->TblMapMtx.lock();
536   for (__tgt_offload_entry *Cur = Desc->HostEntriesBegin;
537        Cur < Desc->HostEntriesEnd; ++Cur) {
538     PM->HostPtrToTableMap.erase(Cur->addr);
539   }
540 
541   // Remove translation table for this descriptor.
542   auto TransTable =
543       PM->HostEntriesBeginToTransTable.find(Desc->HostEntriesBegin);
544   if (TransTable != PM->HostEntriesBeginToTransTable.end()) {
545     DP("Removing translation table for descriptor " DPxMOD "\n",
546        DPxPTR(Desc->HostEntriesBegin));
547     PM->HostEntriesBeginToTransTable.erase(TransTable);
548   } else {
549     DP("Translation table for descriptor " DPxMOD " cannot be found, probably "
550        "it has been already removed.\n",
551        DPxPTR(Desc->HostEntriesBegin));
552   }
553 
554   PM->TblMapMtx.unlock();
555 
556   // TODO: Remove RTL and the devices it manages if it's not used anymore?
557   // TODO: Write some RTL->unload_image(...) function?
558 
559   DP("Done unregistering library!\n");
560 }
561