001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: * The Original Software is NetBeans. The Initial Developer of the Original
026: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
027: * Microsystems, Inc. All Rights Reserved.
028: *
029: * If you wish your version of this file to be governed by only the CDDL
030: * or only the GPL Version 2, indicate your decision by adding
031: * "[Contributor] elects to include this software in this distribution
032: * under the [CDDL or GPL Version 2] license." If you do not indicate a
033: * single choice of license, a recipient has the option to distribute
034: * your version of this file under either the CDDL, the GPL Version 2 or
035: * to extend the choice of license to its licensees as provided above.
036: * However, if you add GPL Version 2 code and therefore, elected the GPL
037: * Version 2 license, then the option applies only if the new code is
038: * made subject to such option by the copyright holder.
039: */
040:
041: package org.netbeans.lib.profiler.utils;
042:
043: import java.util.HashMap;
044: import java.util.Hashtable;
045: import java.util.Map;
046:
047: /**
048: *
049: * @author Jaroslav Bachorik
050: */
051: public class Guard {
052: //~ Static fields/initializers -----------------------------------------------------------------------------------------------
053:
054: private static final int READ_INDEX = 0;
055: private static final int WRITE_INDEX = 1;
056:
057: //~ Instance fields ----------------------------------------------------------------------------------------------------------
058:
059: private final Map readLocks = new HashMap();
060: private Thread owner = null;
061: private boolean flag = false;
062: private boolean starving = false;
063: private int xLockCounter = 0;
064:
065: //~ Methods ------------------------------------------------------------------------------------------------------------------
066:
067: public synchronized boolean isDemanded() {
068: return starving;
069: }
070:
071: public synchronized Thread getOwner() {
072: return owner;
073: }
074:
075: public synchronized boolean enter(final boolean exclusive) {
076: if (exclusive) {
077: return enterExclusive(-1);
078: } else {
079: return enterShared(-1);
080: }
081: }
082:
083: public synchronized boolean enter(final boolean exclusive,
084: final long timeout) {
085: if (exclusive) {
086: return enterExclusive(timeout);
087: } else {
088: return enterShared(timeout);
089: }
090: }
091:
092: public synchronized void exit() {
093: Long threadId = Long.valueOf(Thread.currentThread().getId());
094:
095: try {
096: if (owner == Thread.currentThread()) {
097: if (--xLockCounter == 0) {
098: owner = null;
099:
100: return;
101: }
102: }
103:
104: if (readLocks.containsKey(threadId)) {
105: Long lockCnt = Long.valueOf(((Long) readLocks
106: .get(threadId)).longValue() - 1);
107:
108: if (lockCnt.longValue() <= 0L) {
109: readLocks.remove(threadId);
110: } else {
111: readLocks.put(threadId, lockCnt);
112: }
113: }
114: } finally {
115: this .notifyAll();
116: }
117: }
118:
119: private synchronized void setStarving(final boolean value) {
120: starving = value;
121: }
122:
123: private synchronized boolean enterExclusive(final long timeout) {
124: try {
125: if (owner != Thread.currentThread()) {
126: boolean firstTry = true;
127: Long threadId = Long.valueOf(Thread.currentThread()
128: .getId());
129:
130: while (((xLockCounter > 0)
131: || ((readLocks.size() > 0) && !readLocks
132: .containsKey(threadId)) || (readLocks
133: .size() > 1))
134: && firstTry) {
135: setStarving(true);
136:
137: try {
138: if (timeout > -1) {
139: this .wait(timeout);
140: } else if (timeout > 0) {
141: this .wait();
142: }
143: } catch (InterruptedException e) {
144: }
145:
146: firstTry = false;
147: }
148:
149: if ((xLockCounter > 0) && (readLocks.size() > 0)) {
150: return false;
151: }
152:
153: readLocks.remove(threadId); // promote an already existing shared lock
154: owner = Thread.currentThread();
155: }
156:
157: xLockCounter++;
158: } finally {
159: setStarving(false);
160: this .notifyAll();
161: }
162: assert ((owner == Thread.currentThread()) && (xLockCounter > 0) && (readLocks
163: .size() == 0)); // postocondition
164:
165: return true;
166: }
167:
168: private synchronized boolean enterShared(final long timeout) {
169: try {
170: if (owner != null) {
171: if (owner == Thread.currentThread()) {
172: return true;
173: }
174:
175: boolean firstTry = true;
176:
177: while ((owner != null)
178: && (owner != Thread.currentThread())
179: && firstTry) {
180: setStarving(true);
181:
182: try {
183: if (timeout > -1) {
184: this .wait(timeout);
185: } else if (timeout > 0) {
186: this .wait();
187: }
188: } catch (InterruptedException e) {
189: }
190:
191: firstTry = false;
192: }
193:
194: if ((owner != null)
195: && (owner != Thread.currentThread())) {
196: return false;
197: }
198: }
199:
200: Long threadId = Long
201: .valueOf(Thread.currentThread().getId());
202:
203: if (readLocks.containsKey(threadId)) {
204: readLocks.put(threadId, Long.valueOf(((Long) readLocks
205: .get(threadId)).longValue() + 1));
206: } else {
207: readLocks.put(threadId, Long.valueOf(1L));
208: }
209: } finally {
210: setStarving(false);
211: this .notifyAll();
212: }
213: assert ((owner == null) && (readLocks.size() > 0));
214:
215: return true;
216: }
217: }
|