1/* GENERATED SOURCE. DO NOT MODIFY. */
2// © 2016 and later: Unicode, Inc. and others.
3// License & terms of use: http://www.unicode.org/copyright.html#License
4/**
5 *******************************************************************************
6 * Copyright (C) 2001-2013, International Business Machines Corporation and    *
7 * others. All Rights Reserved.                                                *
8 *******************************************************************************
9 */
10package android.icu.impl;
11
12import java.util.concurrent.locks.ReentrantReadWriteLock;
13
14
15/**
16 * <p>A Reader/Writer lock originally written for ICU service
17 * implementation. The internal implementation was replaced
18 * with the JDK's stock read write lock (ReentrantReadWriteLock)
19 * for ICU 52.</p>
20 *
21 * <p>This assumes that there will be little writing contention.
22 * It also doesn't allow active readers to acquire and release
23 * a write lock, or deal with priority inversion issues.</p>
24 *
25 * <p>Access to the lock should be enclosed in a try/finally block
26 * in order to ensure that the lock is always released in case of
27 * exceptions:<br><pre>
28 * try {
29 *     lock.acquireRead();
30 *     // use service protected by the lock
31 * }
32 * finally {
33 *     lock.releaseRead();
34 * }
35 * </pre></p>
36 *
37 * <p>The lock provides utility methods getStats and clearStats
38 * to return statistics on the use of the lock.</p>
39 * @hide Only a subset of ICU is exposed in Android
40 */
41public class ICURWLock {
42    private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
43
44    private Stats stats = null;
45
46    /**
47     * Internal class used to gather statistics on the RWLock.
48     */
49    public final static class Stats {
50        /**
51         * Number of times read access granted (read count).
52         */
53        public int _rc;
54
55        /**
56         * Number of times concurrent read access granted (multiple read count).
57         */
58        public int _mrc;
59
60        /**
61         * Number of times blocked for read (waiting reader count).
62         */
63        public int _wrc; // wait for read
64
65        /**
66         * Number of times write access granted (writer count).
67         */
68        public int _wc;
69
70        /**
71         * Number of times blocked for write (waiting writer count).
72         */
73        public int _wwc;
74
75        private Stats() {
76        }
77
78        private Stats(int rc, int mrc, int wrc, int wc, int wwc) {
79            this._rc = rc;
80            this._mrc = mrc;
81            this._wrc = wrc;
82            this._wc = wc;
83            this._wwc = wwc;
84        }
85
86        private Stats(Stats rhs) {
87            this(rhs._rc, rhs._mrc, rhs._wrc, rhs._wc, rhs._wwc);
88        }
89
90        /**
91         * Return a string listing all the stats.
92         */
93        @Override
94        public String toString() {
95            return " rc: " + _rc +
96                " mrc: " + _mrc +
97                " wrc: " + _wrc +
98                " wc: " + _wc +
99                " wwc: " + _wwc;
100        }
101    }
102
103    /**
104     * Reset the stats.  Returns existing stats, if any.
105     */
106    public synchronized Stats resetStats() {
107        Stats result = stats;
108        stats = new Stats();
109        return result;
110    }
111
112    /**
113     * Clear the stats (stop collecting stats).  Returns existing stats, if any.
114     */
115    public synchronized Stats clearStats() {
116        Stats result = stats;
117        stats = null;
118        return result;
119    }
120
121    /**
122     * Return a snapshot of the current stats.  This does not reset the stats.
123     */
124    public synchronized Stats getStats() {
125        return stats == null ? null : new Stats(stats);
126    }
127
128    /**
129     * <p>Acquire a read lock, blocking until a read lock is
130     * available.  Multiple readers can concurrently hold the read
131     * lock.</p>
132     *
133     * <p>If there's a writer, or a waiting writer, increment the
134     * waiting reader count and block on this.  Otherwise
135     * increment the active reader count and return.  Caller must call
136     * releaseRead when done (for example, in a finally block).</p>
137     */
138    public void acquireRead() {
139        if (stats != null) {    // stats is null by default
140            synchronized (this) {
141                stats._rc++;
142                if (rwl.getReadLockCount() > 0) {
143                    stats._mrc++;
144                }
145                if (rwl.isWriteLocked()) {
146                    stats._wrc++;
147                }
148            }
149        }
150        rwl.readLock().lock();
151    }
152
153    /**
154     * <p>Release a read lock and return.  An error will be thrown
155     * if a read lock is not currently held.</p>
156     *
157     * <p>If this is the last active reader, notify the oldest
158     * waiting writer.  Call when finished with work
159     * controlled by acquireRead.</p>
160     */
161    public void releaseRead() {
162        rwl.readLock().unlock();
163    }
164
165    /**
166     * <p>Acquire the write lock, blocking until the write lock is
167     * available.  Only one writer can acquire the write lock, and
168     * when held, no readers can acquire the read lock.</p>
169     *
170     * <p>If there are no readers and no waiting writers, mark as
171     * having an active writer and return.  Otherwise, add a lock to the
172     * end of the waiting writer list, and block on it.  Caller
173     * must call releaseWrite when done (for example, in a finally
174     * block).<p>
175     */
176    public void acquireWrite() {
177        if (stats != null) {    // stats is null by default
178            synchronized (this) {
179                stats._wc++;
180                if (rwl.getReadLockCount() > 0 || rwl.isWriteLocked()) {
181                    stats._wwc++;
182                }
183            }
184        }
185        rwl.writeLock().lock();
186    }
187
188    /**
189     * <p>Release the write lock and return.  An error will be thrown
190     * if the write lock is not currently held.</p>
191     *
192     * <p>If there are waiting readers, make them all active and
193     * notify all of them.  Otherwise, notify the oldest waiting
194     * writer, if any.  Call when finished with work controlled by
195     * acquireWrite.</p>
196     */
197    public void releaseWrite() {
198        rwl.writeLock().unlock();
199    }
200}
201