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.

260 lines
6.3KB

  1. /*
  2. * Carla shared memory utils
  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_SHM_UTILS_HPP_INCLUDED
  18. #define CARLA_SHM_UTILS_HPP_INCLUDED
  19. #include "CarlaUtils.hpp"
  20. #ifdef CARLA_OS_WIN
  21. struct shm_t { HANDLE shm; HANDLE map; };
  22. #else
  23. # include <fcntl.h>
  24. # include <sys/mman.h>
  25. struct shm_t { int fd; const char* filename; };
  26. #endif
  27. // -----------------------------------------------------------------------
  28. // shared memory calls
  29. /*
  30. * Null object returned when a shared memory operation fails.
  31. */
  32. #ifdef CARLA_OS_WIN
  33. static const shm_t gNullCarlaShm = { nullptr, nullptr };
  34. #else
  35. static const shm_t gNullCarlaShm = { -1, nullptr };
  36. #endif
  37. /*
  38. * Initialize a shared memory object to an invalid state.
  39. */
  40. static inline
  41. void carla_shm_init(shm_t& shm) noexcept
  42. {
  43. #ifdef CARLA_OS_WIN
  44. shm.shm = nullptr;
  45. shm.map = nullptr;
  46. #else
  47. shm.fd = -1;
  48. shm.filename = nullptr;
  49. #endif
  50. }
  51. /*
  52. * Check if a shared memory object is valid.
  53. */
  54. static inline
  55. bool carla_is_shm_valid(const shm_t& shm) noexcept
  56. {
  57. #ifdef CARLA_OS_WIN
  58. return (shm.shm != nullptr && shm.shm != INVALID_HANDLE_VALUE);
  59. #else
  60. return (shm.fd >= 0);
  61. #endif
  62. }
  63. /*
  64. * Create and open a new shared memory object.
  65. * Returns an invalid object if the operation failed or the filename already exists.
  66. */
  67. static inline
  68. shm_t carla_shm_create(const char* const filename) noexcept
  69. {
  70. CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', gNullCarlaShm);
  71. shm_t ret;
  72. try {
  73. #ifdef CARLA_OS_WIN
  74. ret.shm = nullptr; // TODO
  75. ret.map = nullptr;
  76. #else
  77. ret.fd = ::shm_open(filename, O_CREAT|O_EXCL|O_RDWR, 0600);
  78. ret.filename = (ret.fd >= 0) ? carla_strdup(filename) : nullptr;
  79. #endif
  80. }
  81. catch(...) {
  82. carla_safe_exception("carla_shm_create", __FILE__, __LINE__);
  83. ret = gNullCarlaShm;
  84. }
  85. return ret;
  86. }
  87. /*
  88. * Attach to an existing shared memory object.
  89. */
  90. static inline
  91. shm_t carla_shm_attach(const char* const filename) noexcept
  92. {
  93. CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', gNullCarlaShm);
  94. shm_t ret;
  95. try {
  96. #ifdef CARLA_OS_WIN
  97. ret.shm = ::CreateFileA(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
  98. ret.map = nullptr;
  99. #else
  100. ret.fd = ::shm_open(filename, O_RDWR, 0);
  101. ret.filename = nullptr;
  102. #endif
  103. }
  104. catch(...) {
  105. ret = gNullCarlaShm;
  106. }
  107. return ret;
  108. }
  109. /*
  110. * Close a shared memory object and invalidate it.
  111. */
  112. static inline
  113. void carla_shm_close(shm_t& shm) noexcept
  114. {
  115. CARLA_SAFE_ASSERT_RETURN(carla_is_shm_valid(shm),);
  116. #ifdef CARLA_OS_WIN
  117. CARLA_SAFE_ASSERT(shm.map == nullptr);
  118. #endif
  119. try {
  120. #ifdef CARLA_OS_WIN
  121. ::CloseHandle(shm.shm);
  122. #else
  123. ::close(shm.fd);
  124. if (shm.filename != nullptr)
  125. {
  126. ::shm_unlink(shm.filename);
  127. delete[] shm.filename;
  128. }
  129. #endif
  130. } CARLA_SAFE_EXCEPTION("carla_shm_close");
  131. shm = gNullCarlaShm;
  132. }
  133. /*
  134. * Map a shared memory object to @a size bytes and return the memory address.
  135. * @note One shared memory object can only have one mapping at a time.
  136. */
  137. static inline
  138. void* carla_shm_map(shm_t& shm, const size_t size) noexcept
  139. {
  140. CARLA_SAFE_ASSERT_RETURN(carla_is_shm_valid(shm), nullptr);
  141. CARLA_SAFE_ASSERT_RETURN(size > 0, nullptr);
  142. #ifdef CARLA_OS_WIN
  143. CARLA_SAFE_ASSERT_RETURN(shm.map == nullptr, nullptr);
  144. #endif
  145. try {
  146. #ifdef CARLA_OS_WIN
  147. const HANDLE map = ::CreateFileMapping(shm.shm, NULL, PAGE_READWRITE, size, size, NULL);
  148. CARLA_SAFE_ASSERT_RETURN(map != nullptr, nullptr);
  149. HANDLE ptr = ::MapViewOfFile(map, FILE_MAP_COPY, 0, 0, size);
  150. if (ptr == nullptr)
  151. {
  152. carla_safe_assert("ptr != nullptr", __FILE__, __LINE__);
  153. ::CloseHandle(map);
  154. return nullptr;
  155. }
  156. shm.map = map;
  157. return ptr;
  158. #else
  159. const int ret = ::ftruncate(shm.fd, static_cast<off_t>(size));
  160. CARLA_SAFE_ASSERT_RETURN(ret == 0, nullptr);
  161. return ::mmap(nullptr, size, PROT_READ|PROT_WRITE, MAP_SHARED, shm.fd, 0);
  162. #endif
  163. } CARLA_SAFE_EXCEPTION_RETURN("carla_shm_map", nullptr);
  164. }
  165. /*
  166. * Unmap a shared memory object address.
  167. */
  168. static inline
  169. void carla_shm_unmap(shm_t& shm, void* const ptr, const size_t size) noexcept
  170. {
  171. CARLA_SAFE_ASSERT_RETURN(carla_is_shm_valid(shm),);
  172. CARLA_SAFE_ASSERT_RETURN(ptr != nullptr,);
  173. CARLA_SAFE_ASSERT_RETURN(size > 0,);
  174. #ifdef CARLA_OS_WIN
  175. CARLA_SAFE_ASSERT_RETURN(shm.map != nullptr,);
  176. #endif
  177. try {
  178. #ifdef CARLA_OS_WIN
  179. const HANDLE map = shm.map;
  180. shm.map = nullptr;
  181. ::UnmapViewOfFile(ptr);
  182. ::CloseHandle(map);
  183. #else
  184. const int ret = ::munmap(ptr, size);
  185. CARLA_SAFE_ASSERT(ret == 0);
  186. #endif
  187. } CARLA_SAFE_EXCEPTION("carla_shm_unmap");
  188. return; // unused depending on platform
  189. (void)shm;
  190. (void)size;
  191. }
  192. // -----------------------------------------------------------------------
  193. // shared memory, templated calls
  194. /*
  195. * Map a shared memory object, handling object type and size.
  196. */
  197. template<typename T>
  198. static inline
  199. T* carla_shm_map(shm_t& shm) noexcept
  200. {
  201. return (T*)carla_shm_map(shm, sizeof(T));
  202. }
  203. /*
  204. * Map a shared memory object and return if it's non-null.
  205. */
  206. template<typename T>
  207. static inline
  208. bool carla_shm_map(shm_t& shm, T*& value) noexcept
  209. {
  210. value = (T*)carla_shm_map(shm, sizeof(T));
  211. return (value != nullptr);
  212. }
  213. /*
  214. * Unmap a shared memory object address and set it as null.
  215. */
  216. template<typename T>
  217. static inline
  218. void carla_shm_unmap(shm_t& shm, T*& value) noexcept
  219. {
  220. carla_shm_unmap(shm, value, sizeof(T));
  221. value = nullptr;
  222. }
  223. // -----------------------------------------------------------------------
  224. #endif // CARLA_SHM_UTILS_HPP_INCLUDED