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.

123 lines
3.1KB

  1. /*
  2. * DISTRHO Cardinal Plugin
  3. * Copyright (C) 2021-2022 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 3 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 LICENSE file.
  16. */
  17. #pragma once
  18. #include <pthread.h>
  19. #ifdef __MOD_DEVICES__
  20. #include <linux/futex.h>
  21. #include <sys/time.h>
  22. #include <errno.h>
  23. #include <syscall.h>
  24. #include <unistd.h>
  25. #endif
  26. /* replace Rack's mutex with our own custom one, which can do priority inversion. */
  27. namespace rack {
  28. struct SharedMutex {
  29. pthread_mutex_t readLock;
  30. #ifdef __MOD_DEVICES__
  31. int writeLock;
  32. #else
  33. pthread_mutex_t writeLock;
  34. #endif
  35. SharedMutex() noexcept {
  36. pthread_mutexattr_t attr;
  37. pthread_mutexattr_init(&attr);
  38. pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
  39. pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
  40. pthread_mutex_init(&readLock, &attr);
  41. pthread_mutexattr_destroy(&attr);
  42. #ifdef __MOD_DEVICES__
  43. writeLock = 1;
  44. #else
  45. pthread_mutexattr_t attr2;
  46. pthread_mutexattr_init(&attr2);
  47. pthread_mutexattr_setprotocol(&attr2, PTHREAD_PRIO_NONE);
  48. pthread_mutexattr_settype(&attr2, PTHREAD_MUTEX_NORMAL);
  49. pthread_mutex_init(&writeLock, &attr2);
  50. pthread_mutexattr_destroy(&attr2);
  51. #endif
  52. }
  53. ~SharedMutex() noexcept {
  54. pthread_mutex_destroy(&readLock);
  55. #ifndef __MOD_DEVICES__
  56. pthread_mutex_destroy(&writeLock);
  57. #endif
  58. }
  59. // for std::lock_guard usage, writers lock
  60. void lock() noexcept {
  61. #ifdef __MOD_DEVICES__
  62. for (;;)
  63. {
  64. if (__sync_bool_compare_and_swap(&writeLock, 1, 0))
  65. return;
  66. if (syscall(__NR_futex, &writeLock, FUTEX_WAIT_PRIVATE, 0, nullptr, nullptr, 0) != 0)
  67. {
  68. if (errno != EAGAIN && errno != EINTR)
  69. return;
  70. }
  71. }
  72. #else
  73. pthread_mutex_lock(&writeLock);
  74. #endif
  75. pthread_mutex_lock(&readLock);
  76. }
  77. void unlock() noexcept {
  78. pthread_mutex_unlock(&readLock);
  79. #ifdef __MOD_DEVICES__
  80. if (__sync_bool_compare_and_swap(&writeLock, 0, 1))
  81. syscall(__NR_futex, &writeLock, FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0);
  82. #else
  83. pthread_mutex_unlock(&writeLock);
  84. #endif
  85. }
  86. // for SharedLock usage, readers lock
  87. void lock_shared() noexcept {
  88. pthread_mutex_lock(&readLock);
  89. }
  90. void unlock_shared() noexcept {
  91. pthread_mutex_unlock(&readLock);
  92. }
  93. };
  94. template <class Mutex>
  95. struct SharedLock {
  96. Mutex& mutex;
  97. SharedLock(Mutex& m) noexcept : mutex(m) {
  98. mutex.lock_shared();
  99. }
  100. ~SharedLock() noexcept {
  101. mutex.unlock_shared();
  102. }
  103. };
  104. } // namespace rack