SkSharedMutex.h 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. /*
  2. * Copyright 2015 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #ifndef SkSharedLock_DEFINED
  8. #define SkSharedLock_DEFINED
  9. #include "include/core/SkTypes.h"
  10. #include "include/private/SkMacros.h"
  11. #include "include/private/SkSemaphore.h"
  12. #include "include/private/SkThreadAnnotations.h"
  13. #include <atomic>
  14. #ifdef SK_DEBUG
  15. #include "include/private/SkMutex.h"
  16. #include <memory>
  17. #endif // SK_DEBUG
  18. // There are two shared lock implementations one debug the other is high performance. They implement
  19. // an interface similar to pthread's rwlocks.
  20. // This is a shared lock implementation similar to pthreads rwlocks. The high performance
  21. // implementation is cribbed from Preshing's article:
  22. // http://preshing.com/20150316/semaphores-are-surprisingly-versatile/
  23. //
  24. // This lock does not obey strict queue ordering. It will always alternate between readers and
  25. // a single writer.
  26. class SK_CAPABILITY("mutex") SkSharedMutex {
  27. public:
  28. SkSharedMutex();
  29. ~SkSharedMutex();
  30. // Acquire lock for exclusive use.
  31. void acquire() SK_ACQUIRE();
  32. // Release lock for exclusive use.
  33. void release() SK_RELEASE_CAPABILITY();
  34. // Fail if exclusive is not held.
  35. void assertHeld() const SK_ASSERT_CAPABILITY(this);
  36. // Acquire lock for shared use.
  37. void acquireShared() SK_ACQUIRE_SHARED();
  38. // Release lock for shared use.
  39. void releaseShared() SK_RELEASE_SHARED_CAPABILITY();
  40. // Fail if shared lock not held.
  41. void assertHeldShared() const SK_ASSERT_SHARED_CAPABILITY(this);
  42. private:
  43. #ifdef SK_DEBUG
  44. class ThreadIDSet;
  45. std::unique_ptr<ThreadIDSet> fCurrentShared;
  46. std::unique_ptr<ThreadIDSet> fWaitingExclusive;
  47. std::unique_ptr<ThreadIDSet> fWaitingShared;
  48. int fSharedQueueSelect{0};
  49. mutable SkMutex fMu;
  50. SkSemaphore fSharedQueue[2];
  51. SkSemaphore fExclusiveQueue;
  52. #else
  53. std::atomic<int32_t> fQueueCounts;
  54. SkSemaphore fSharedQueue;
  55. SkSemaphore fExclusiveQueue;
  56. #endif // SK_DEBUG
  57. };
  58. #ifndef SK_DEBUG
  59. inline void SkSharedMutex::assertHeld() const {};
  60. inline void SkSharedMutex::assertHeldShared() const {};
  61. #endif // SK_DEBUG
  62. class SK_SCOPED_CAPABILITY SkAutoSharedMutexExclusive {
  63. public:
  64. explicit SkAutoSharedMutexExclusive(SkSharedMutex& lock) SK_ACQUIRE(lock)
  65. : fLock(lock) {
  66. lock.acquire();
  67. }
  68. ~SkAutoSharedMutexExclusive() SK_RELEASE_CAPABILITY() { fLock.release(); }
  69. private:
  70. SkSharedMutex& fLock;
  71. };
  72. #define SkAutoSharedMutexExclusive(...) SK_REQUIRE_LOCAL_VAR(SkAutoSharedMutexExclusive)
  73. class SK_SCOPED_CAPABILITY SkAutoSharedMutexShared {
  74. public:
  75. explicit SkAutoSharedMutexShared(SkSharedMutex& lock) SK_ACQUIRE_SHARED(lock)
  76. : fLock(lock) {
  77. lock.acquireShared();
  78. }
  79. // You would think this should be SK_RELEASE_SHARED_CAPABILITY, but SK_SCOPED_CAPABILITY
  80. // doesn't fully understand the difference between shared and exclusive.
  81. // Please review https://reviews.llvm.org/D52578 for more information.
  82. ~SkAutoSharedMutexShared() SK_RELEASE_CAPABILITY() { fLock.releaseShared(); }
  83. private:
  84. SkSharedMutex& fLock;
  85. };
  86. #define SkAutoSharedMutexShared(...) SK_REQUIRE_LOCAL_VAR(SkAutoSharedMutexShared)
  87. #endif // SkSharedLock_DEFINED