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