Home | History | Annotate | Download | only in core
      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 
      8 #ifndef SkSharedLock_DEFINED
      9 #define SkSharedLock_DEFINED
     10 
     11 #include "SkAtomics.h"
     12 #include "SkSemaphore.h"
     13 #include "SkTypes.h"
     14 
     15 #ifdef SK_DEBUG
     16     #include "SkMutex.h"
     17     #include <memory>
     18 #endif  // SK_DEBUG
     19 
     20 // There are two shared lock implementations one debug the other is high performance. They implement
     21 // an interface similar to pthread's rwlocks.
     22 // This is a shared lock implementation similar to pthreads rwlocks. The high performance
     23 // implementation is cribbed from Preshing's article:
     24 // http://preshing.com/20150316/semaphores-are-surprisingly-versatile/
     25 //
     26 // This lock does not obey strict queue ordering. It will always alternate between readers and
     27 // a single writer.
     28 class SkSharedMutex {
     29 public:
     30     SkSharedMutex();
     31     ~SkSharedMutex();
     32     // Acquire lock for exclusive use.
     33     void acquire();
     34 
     35     // Release lock for exclusive use.
     36     void release();
     37 
     38     // Fail if exclusive is not held.
     39     void assertHeld() const;
     40 
     41     // Acquire lock for shared use.
     42     void acquireShared();
     43 
     44     // Release lock for shared use.
     45     void releaseShared();
     46 
     47     // Fail if shared lock not held.
     48     void assertHeldShared() const;
     49 
     50 private:
     51 #ifdef SK_DEBUG
     52     class ThreadIDSet;
     53     std::unique_ptr<ThreadIDSet> fCurrentShared;
     54     std::unique_ptr<ThreadIDSet> fWaitingExclusive;
     55     std::unique_ptr<ThreadIDSet> fWaitingShared;
     56     int fSharedQueueSelect{0};
     57     mutable SkMutex fMu;
     58     SkSemaphore fSharedQueue[2];
     59     SkSemaphore fExclusiveQueue;
     60 #else
     61     SkAtomic<int32_t> fQueueCounts;
     62     SkSemaphore       fSharedQueue;
     63     SkSemaphore       fExclusiveQueue;
     64 #endif  // SK_DEBUG
     65 };
     66 
     67 #ifndef SK_DEBUG
     68 inline void SkSharedMutex::assertHeld() const {};
     69 inline void SkSharedMutex::assertHeldShared() const {};
     70 #endif  // SK_DEBUG
     71 
     72 class SkAutoSharedMutexShared {
     73 public:
     74     SkAutoSharedMutexShared(SkSharedMutex& lock) : fLock(lock) { lock.acquireShared(); }
     75     ~SkAutoSharedMutexShared() { fLock.releaseShared(); }
     76 private:
     77     SkSharedMutex& fLock;
     78 };
     79 
     80 #define SkAutoSharedMutexShared(...) SK_REQUIRE_LOCAL_VAR(SkAutoSharedMutexShared)
     81 
     82 #endif // SkSharedLock_DEFINED
     83