Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

197 lines
5.3KB

  1. /*
  2. * Carla library counter
  3. * Copyright (C) 2013-2014 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #ifndef CARLA_LIB_COUNTER_HPP_INCLUDED
  18. #define CARLA_LIB_COUNTER_HPP_INCLUDED
  19. #include "CarlaLibUtils.hpp"
  20. #include "CarlaMutex.hpp"
  21. #include "LinkedList.hpp"
  22. // -----------------------------------------------------------------------
  23. class LibCounter
  24. {
  25. public:
  26. LibCounter() noexcept
  27. : fMutex(),
  28. fLibs() {}
  29. ~LibCounter() noexcept
  30. {
  31. // might have some leftovers
  32. for (LinkedList<Lib>::Itenerator it = fLibs.begin2(); it.valid(); it.next())
  33. {
  34. static Lib libFallback = { nullptr, nullptr, 0, false };
  35. Lib& lib(it.getValue(libFallback));
  36. CARLA_SAFE_ASSERT_CONTINUE(lib.count > 0);
  37. CARLA_SAFE_ASSERT_CONTINUE(lib.lib != nullptr);
  38. // all libs should be closed by now except those explicitly marked non-delete
  39. CARLA_SAFE_ASSERT(! lib.canDelete);
  40. if (! lib_close(lib.lib))
  41. carla_stderr("LibCounter cleanup failed, reason:\n%s", lib_error(lib.filename));
  42. lib.lib = nullptr;
  43. if (lib.filename != nullptr)
  44. {
  45. delete[] lib.filename;
  46. lib.filename = nullptr;
  47. }
  48. }
  49. fLibs.clear();
  50. }
  51. lib_t open(const char* const filename, const bool canDelete = true) noexcept
  52. {
  53. CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', nullptr);
  54. // try duplicating filename first, it can throw
  55. const char* dfilename = nullptr;
  56. try {
  57. dfilename = carla_strdup(filename);
  58. } CARLA_SAFE_EXCEPTION_RETURN("LibCounter::open", nullptr);
  59. const CarlaMutexLocker cml(fMutex);
  60. for (LinkedList<Lib>::Itenerator it = fLibs.begin2(); it.valid(); it.next())
  61. {
  62. static Lib libFallback = { nullptr, nullptr, 0, false };
  63. Lib& lib(it.getValue(libFallback));
  64. CARLA_SAFE_ASSERT_CONTINUE(lib.count > 0);
  65. CARLA_SAFE_ASSERT_CONTINUE(lib.filename != nullptr);
  66. if (std::strcmp(lib.filename, filename) == 0)
  67. {
  68. // will not be needed
  69. delete[] dfilename;
  70. ++lib.count;
  71. return lib.lib;
  72. }
  73. }
  74. const lib_t libPtr = lib_open(filename);
  75. if (libPtr == nullptr)
  76. {
  77. delete[] dfilename;
  78. return nullptr;
  79. }
  80. Lib lib;
  81. lib.lib = libPtr;
  82. lib.filename = dfilename;
  83. lib.count = 1;
  84. lib.canDelete = canDelete;
  85. #ifdef BUILD_BRIDGE
  86. lib.canDelete = true;
  87. #endif
  88. if (fLibs.append(lib))
  89. return libPtr;
  90. delete[] dfilename;
  91. return nullptr;
  92. }
  93. bool close(const lib_t libPtr) noexcept
  94. {
  95. CARLA_SAFE_ASSERT_RETURN(libPtr != nullptr, false);
  96. const CarlaMutexLocker cml(fMutex);
  97. for (LinkedList<Lib>::Itenerator it = fLibs.begin2(); it.valid(); it.next())
  98. {
  99. static Lib libFallback = { nullptr, nullptr, 0, false };
  100. Lib& lib(it.getValue(libFallback));
  101. CARLA_SAFE_ASSERT_CONTINUE(lib.count > 0);
  102. CARLA_SAFE_ASSERT_CONTINUE(lib.lib != nullptr);
  103. if (lib.lib != libPtr)
  104. continue;
  105. if (lib.count == 1 && ! lib.canDelete)
  106. return true;
  107. if (--lib.count == 0)
  108. {
  109. if (! lib_close(lib.lib))
  110. carla_stderr("LibCounter::close() failed, reason:\n%s", lib_error(lib.filename));
  111. lib.lib = nullptr;
  112. if (lib.filename != nullptr)
  113. {
  114. delete[] lib.filename;
  115. lib.filename = nullptr;
  116. }
  117. fLibs.remove(it);
  118. }
  119. return true;
  120. }
  121. carla_safe_assert("invalid lib pointer", __FILE__, __LINE__);
  122. return false;
  123. }
  124. void setCanDelete(const lib_t libPtr, const bool canDelete)
  125. {
  126. CARLA_SAFE_ASSERT_RETURN(libPtr != nullptr,);
  127. const CarlaMutexLocker cml(fMutex);
  128. for (LinkedList<Lib>::Itenerator it = fLibs.begin2(); it.valid(); it.next())
  129. {
  130. static Lib libFallback = { nullptr, nullptr, 0, false };
  131. Lib& lib(it.getValue(libFallback));
  132. CARLA_SAFE_ASSERT_CONTINUE(lib.lib != nullptr);
  133. if (lib.lib != libPtr)
  134. continue;
  135. lib.canDelete = canDelete;
  136. return;
  137. }
  138. }
  139. private:
  140. struct Lib {
  141. lib_t lib;
  142. const char* filename;
  143. int count;
  144. bool canDelete;
  145. };
  146. CarlaMutex fMutex;
  147. LinkedList<Lib> fLibs;
  148. };
  149. // -----------------------------------------------------------------------
  150. #endif // CARLA_LIB_COUNTER_HPP_INCLUDED