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.
 
 
 
 
 
 

225 lines
4.7 KiB

  1. /*
  2. * This file is part of PowerDNS or dnsdist.
  3. * Copyright -- PowerDNS.COM B.V. and its contributors
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of version 2 of the GNU General Public License as
  7. * published by the Free Software Foundation.
  8. *
  9. * In addition, for the avoidance of any doubt, permission is granted to
  10. * link this program with OpenSSL and to (re)distribute the binaries
  11. * produced as the result of such linking.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. */
  22. #pragma once
  23. #include <pthread.h>
  24. #include <errno.h>
  25. #include "misc.hh"
  26. #include "pdnsexception.hh"
  27. class ReadWriteLock
  28. {
  29. public:
  30. ReadWriteLock()
  31. {
  32. if (pthread_rwlock_init(&d_lock, nullptr) != 0) {
  33. throw std::runtime_error("Error creating a read-write lock: " + stringerror());
  34. }
  35. }
  36. ~ReadWriteLock() {
  37. /* might have been moved */
  38. pthread_rwlock_destroy(&d_lock);
  39. }
  40. ReadWriteLock(const ReadWriteLock& rhs) = delete;
  41. ReadWriteLock& operator=(const ReadWriteLock& rhs) = delete;
  42. pthread_rwlock_t* getLock()
  43. {
  44. return &d_lock;
  45. }
  46. private:
  47. pthread_rwlock_t d_lock;
  48. };
  49. class ReadLock
  50. {
  51. public:
  52. ReadLock(ReadWriteLock& lock): ReadLock(lock.getLock())
  53. {
  54. }
  55. ReadLock(ReadWriteLock* lock): ReadLock(lock->getLock())
  56. {
  57. }
  58. ~ReadLock()
  59. {
  60. if(d_lock) // may have been moved
  61. pthread_rwlock_unlock(d_lock);
  62. }
  63. ReadLock(ReadLock&& rhs)
  64. {
  65. d_lock = rhs.d_lock;
  66. rhs.d_lock = nullptr;
  67. }
  68. ReadLock(const ReadLock& rhs) = delete;
  69. ReadLock& operator=(const ReadLock& rhs) = delete;
  70. private:
  71. ReadLock(pthread_rwlock_t *lock) : d_lock(lock)
  72. {
  73. int err;
  74. if((err = pthread_rwlock_rdlock(d_lock))) {
  75. throw PDNSException("error acquiring rwlock readlock: "+stringerror(err));
  76. }
  77. }
  78. pthread_rwlock_t *d_lock;
  79. };
  80. class WriteLock
  81. {
  82. public:
  83. WriteLock(ReadWriteLock& lock): WriteLock(lock.getLock())
  84. {
  85. }
  86. WriteLock(ReadWriteLock* lock): WriteLock(lock->getLock())
  87. {
  88. }
  89. WriteLock(WriteLock&& rhs)
  90. {
  91. d_lock = rhs.d_lock;
  92. rhs.d_lock=0;
  93. }
  94. ~WriteLock()
  95. {
  96. if(d_lock) // might have been moved
  97. pthread_rwlock_unlock(d_lock);
  98. }
  99. WriteLock(const WriteLock& rhs) = delete;
  100. WriteLock& operator=(const WriteLock& rhs) = delete;
  101. private:
  102. WriteLock(pthread_rwlock_t *lock) : d_lock(lock)
  103. {
  104. int err;
  105. if((err = pthread_rwlock_wrlock(d_lock))) {
  106. throw PDNSException("error acquiring rwlock wrlock: "+stringerror(err));
  107. }
  108. }
  109. pthread_rwlock_t *d_lock;
  110. };
  111. class TryReadLock
  112. {
  113. public:
  114. TryReadLock(ReadWriteLock& lock): TryReadLock(lock.getLock())
  115. {
  116. }
  117. TryReadLock(ReadWriteLock* lock): TryReadLock(lock->getLock())
  118. {
  119. }
  120. TryReadLock(TryReadLock&& rhs)
  121. {
  122. d_lock = rhs.d_lock;
  123. rhs.d_lock = nullptr;
  124. d_havelock = rhs.d_havelock;
  125. rhs.d_havelock = false;
  126. }
  127. ~TryReadLock()
  128. {
  129. if(d_havelock && d_lock)
  130. pthread_rwlock_unlock(d_lock);
  131. }
  132. TryReadLock(const TryReadLock& rhs) = delete;
  133. TryReadLock& operator=(const TryReadLock& rhs) = delete;
  134. bool gotIt()
  135. {
  136. return d_havelock;
  137. }
  138. private:
  139. TryReadLock(pthread_rwlock_t *lock) : d_lock(lock)
  140. {
  141. int err;
  142. if((err = pthread_rwlock_tryrdlock(d_lock)) && err!=EBUSY) {
  143. throw PDNSException("error acquiring rwlock tryrdlock: "+stringerror(err));
  144. }
  145. d_havelock=(err==0);
  146. }
  147. pthread_rwlock_t *d_lock;
  148. bool d_havelock;
  149. };
  150. class TryWriteLock
  151. {
  152. public:
  153. TryWriteLock(ReadWriteLock& lock): TryWriteLock(lock.getLock())
  154. {
  155. }
  156. TryWriteLock(ReadWriteLock* lock): TryWriteLock(lock->getLock())
  157. {
  158. }
  159. TryWriteLock(TryWriteLock&& rhs)
  160. {
  161. d_lock = rhs.d_lock;
  162. rhs.d_lock = nullptr;
  163. d_havelock = rhs.d_havelock;
  164. rhs.d_havelock = false;
  165. }
  166. ~TryWriteLock()
  167. {
  168. if(d_havelock && d_lock) // we might be moved
  169. pthread_rwlock_unlock(d_lock);
  170. }
  171. TryWriteLock(const TryWriteLock& rhs) = delete;
  172. TryWriteLock& operator=(const TryWriteLock& rhs) = delete;
  173. bool gotIt()
  174. {
  175. return d_havelock;
  176. }
  177. private:
  178. TryWriteLock(pthread_rwlock_t *lock) : d_lock(lock)
  179. {
  180. d_havelock=false;
  181. int err;
  182. if((err = pthread_rwlock_trywrlock(d_lock)) && err!=EBUSY) {
  183. throw PDNSException("error acquiring rwlock tryrwlock: "+stringerror(err));
  184. }
  185. d_havelock=(err==0);
  186. }
  187. pthread_rwlock_t *d_lock;
  188. bool d_havelock;
  189. };