1/*
2 * Copyright (C) 2017 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include <wtf/Condition.h>
29#include <wtf/Lock.h>
30
31namespace WTF {
32
33// This is a traditional read-write lock implementation that enables concurrency between readers so long as
34// the read critical section is long. Concurrent readers will experience contention on read().lock() and
35// read().unlock() if the work inside the critical section is short. The more cores participate in reading,
36// the longer the read critical section has to be for this locking scheme to be profitable.
37
38class ReadWriteLock {
39 WTF_MAKE_NONCOPYABLE(ReadWriteLock);
40 WTF_MAKE_FAST_ALLOCATED;
41public:
42 ReadWriteLock() = default;
43
44 // It's easiest to read lock like this:
45 //
46 // auto locker = holdLock(rwLock.read());
47 //
48 // It's easiest to write lock like this:
49 //
50 // auto locker = holdLock(rwLock.write());
51 //
52 WTF_EXPORT_PRIVATE void readLock();
53 WTF_EXPORT_PRIVATE void readUnlock();
54 WTF_EXPORT_PRIVATE void writeLock();
55 WTF_EXPORT_PRIVATE void writeUnlock();
56
57 class ReadLock;
58 class WriteLock;
59
60 ReadLock& read();
61 WriteLock& write();
62
63private:
64 Lock m_lock;
65 Condition m_cond;
66 bool m_isWriteLocked { false };
67 unsigned m_numReaders { 0 };
68 unsigned m_numWaitingWriters { 0 };
69};
70
71class ReadWriteLock::ReadLock : public ReadWriteLock {
72public:
73 bool tryLock() { return false; }
74 void lock() { readLock(); }
75 void unlock() { readUnlock(); }
76};
77
78class ReadWriteLock::WriteLock : public ReadWriteLock {
79public:
80 bool tryLock() { return false; }
81 void lock() { writeLock(); }
82 void unlock() { writeUnlock(); }
83};
84
85inline ReadWriteLock::ReadLock& ReadWriteLock::read() { return *static_cast<ReadLock*>(this); }
86inline ReadWriteLock::WriteLock& ReadWriteLock::write() { return *static_cast<WriteLock*>(this); }
87
88} // namespace WTF
89
90using WTF::ReadWriteLock;
91