Source Code Cross Referenced for Mutex.java in  » IDE-Netbeans » openide » org » openide » util » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Netbeans » openide » org.openide.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common
0008:         * Development and Distribution License("CDDL") (collectively, the
0009:         * "License"). You may not use this file except in compliance with the
0010:         * License. You can obtain a copy of the License at
0011:         * http://www.netbeans.org/cddl-gplv2.html
0012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013:         * specific language governing permissions and limitations under the
0014:         * License.  When distributing the software, include this License Header
0015:         * Notice in each file and include the License file at
0016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
0017:         * particular file as subject to the "Classpath" exception as provided
0018:         * by Sun in the GPL Version 2 section of the License file that
0019:         * accompanied this code. If applicable, add the following below the
0020:         * License Header, with the fields enclosed by brackets [] replaced by
0021:         * your own identifying information:
0022:         * "Portions Copyrighted [year] [name of copyright owner]"
0023:         *
0024:         * Contributor(s):
0025:         *
0026:         * The Original Software is NetBeans. The Initial Developer of the Original
0027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028:         * Microsystems, Inc. All Rights Reserved.
0029:         *
0030:         * If you wish your version of this file to be governed by only the CDDL
0031:         * or only the GPL Version 2, indicate your decision by adding
0032:         * "[Contributor] elects to include this software in this distribution
0033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034:         * single choice of license, a recipient has the option to distribute
0035:         * your version of this file under either the CDDL, the GPL Version 2 or
0036:         * to extend the choice of license to its licensees as provided above.
0037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
0038:         * Version 2 license, then the option applies only if the new code is
0039:         * made subject to such option by the copyright holder.
0040:         */
0041:
0042:        package org.openide.util;
0043:
0044:        import java.awt.EventQueue;
0045:        import java.lang.reflect.InvocationTargetException;
0046:        import java.util.ArrayList;
0047:        import java.util.HashMap;
0048:        import java.util.LinkedList;
0049:        import java.util.List;
0050:        import java.util.Map;
0051:        import java.util.concurrent.Executor;
0052:        import java.util.logging.Level;
0053:        import java.util.logging.Logger;
0054:
0055:        /** Read-many/write-one lock.
0056:         * Allows control over resources that
0057:         * can be read by several readers at once but only written by one writer.
0058:         * <P>
0059:         * It is guaranteed that if you are a writer you can also enter the
0060:         * mutex as a reader. Conversely, if you are the <em>only</em> reader you
0061:         * can enter the mutex as a writer, but you'll be warned because it is very
0062:         * deadlock prone (two readers trying to get write access concurently).
0063:         * <P>
0064:         * If the mutex is used only by one thread, the thread can repeatedly
0065:         * enter it as a writer or reader. So one thread can never deadlock itself,
0066:         * whichever order operations are performed in.
0067:         * <P>
0068:         * There is no strategy to prevent starvation.
0069:         * Even if there is a writer waiting to enter, another reader might enter
0070:         * the section instead.
0071:         * <P>
0072:         * Examples of use:
0073:         *
0074:         * <p><code><PRE>
0075:         * Mutex m = new Mutex ();
0076:         *
0077:         * // Grant write access, compute an integer and return it:
0078:         * return (Integer)m.writeAccess (new Mutex.Action () {
0079:         *   public Object run () {
0080:         *     return new Integer (1);
0081:         *   }
0082:         * });
0083:         *
0084:         * // Obtain read access, do some computation, possibly throw an IOException:
0085:         * try {
0086:         *   m.readAccess (new Mutex.ExceptionAction () {
0087:         *     public Object run () throws IOException {
0088:         *       if (...) throw new IOException ();
0089:         *
0090:         *       return null;
0091:         *     }
0092:         *   });
0093:         * } catch (MutexException ex) {
0094:         *   throw (IOException)ex.getException ();
0095:         * }
0096:         *
0097:         * // check whether you are already in read access
0098:         * if (m.isReadAccess ()) {
0099:         *   // do your work
0100:         * }
0101:         * </PRE></code>
0102:         *
0103:         * @author Ales Novak
0104:         */
0105:        public final class Mutex extends Object {
0106:            /** counter of created mutexes */
0107:            private static int counter;
0108:
0109:            /** logger for things that happen in mutex */
0110:            private static Logger LOG = Logger.getLogger(Mutex.class.getName());
0111:
0112:            /** Mutex that allows code to be synchronized with the AWT event dispatch thread.
0113:             * <P>
0114:             * When the Mutex methods are invoked on this mutex, the methods' semantics 
0115:             * change as follows:
0116:             * <UL>
0117:             * <LI>The {@link #isReadAccess} and {@link #isWriteAccess} methods
0118:             *  return <code>true</code> if the current thread is the event dispatch thread
0119:             *  and false otherwise.
0120:             * <LI>The {@link #postReadRequest} and {@link #postWriteRequest} methods
0121:             *  asynchronously execute the {@link java.lang.Runnable} passed in their 
0122:             *  <code>run</code> parameter on the event dispatch thead.
0123:             * <LI>The {@link #readAccess(java.lang.Runnable)} and 
0124:             *  {@link #writeAccess(java.lang.Runnable)} methods asynchronously execute the 
0125:             *  {@link java.lang.Runnable} passed in their <code>run</code> parameter 
0126:             *  on the event dispatch thread, unless the current thread is 
0127:             *  the event dispatch thread, in which case 
0128:             *  <code>run.run()</code> is immediately executed.
0129:             * <LI>The {@link #readAccess(Mutex.Action)},
0130:             *  {@link #readAccess(Mutex.ExceptionAction action)},
0131:             *  {@link #writeAccess(Mutex.Action action)} and
0132:             *  {@link #writeAccess(Mutex.ExceptionAction action)} 
0133:             *  methods synchronously execute the {@link Mutex.ExceptionAction}
0134:             *  passed in their <code>action</code> parameter on the event dispatch thread,
0135:             *  unless the current thread is the event dispatch thread, in which case
0136:             *  <code>action.run()</code> is immediately executed.
0137:             * </UL>
0138:             */
0139:            public static final Mutex EVENT = new Mutex();
0140:
0141:            /** this is used from tests to prevent upgrade from readAccess to writeAccess
0142:             * by strictly throwing exception. Otherwise we just notify that using ErrorManager.
0143:             */
0144:            static boolean beStrict;
0145:
0146:            // lock mode constants
0147:
0148:            /** Lock free */
0149:            private static final int NONE = 0x0;
0150:
0151:            /** Enqueue all requests */
0152:            private static final int CHAIN = 0x1;
0153:
0154:            /** eXclusive */
0155:            private static final int X = 0x2;
0156:
0157:            /** Shared */
0158:            private static final int S = 0x3;
0159:
0160:            /** number of modes */
0161:            private static final int MODE_COUNT = 0x4;
0162:
0163:            /** compatibility matrix */
0164:
0165:            // [requested][granted]
0166:            private static final boolean[][] cmatrix = { null, null, // NONE, CHAIN
0167:                    { true, false, false, false }, { true, false, false, true } };
0168:
0169:            /** granted mode */
0170:            private int grantedMode = NONE;
0171:
0172:            /** The mode the mutex was in before it started chaining */
0173:            private int origMode;
0174:
0175:            /** protects internal data structures */
0176:            private/*final*/Object LOCK;
0177:
0178:            /** wrapper, if any */
0179:            private final Executor wrapper;
0180:
0181:            /** threads that - owns or waits for this mutex */
0182:            private/*final*/Map<Thread, ThreadInfo> registeredThreads;
0183:
0184:            /** number of threads that holds S mode (readersNo == "count of threads in registeredThreads that holds S") */
0185:
0186:            // NOI18N
0187:            private int readersNo = 0;
0188:
0189:            /** a queue of waiting threads for this mutex */
0190:            private List<QueueCell> waiters;
0191:
0192:            /** identification of the mutex */
0193:            private int cnt;
0194:
0195:            /** Enhanced constructor that permits specifying an object to use as a lock.
0196:             * The lock is used on entry and exit to {@link #readAccess} and during the
0197:             * whole execution of {@link #writeAccess}. The ability to specify locks
0198:             * allows several <code>Mutex</code>es to synchronize on one object or to synchronize
0199:             * a mutex with another critical section.
0200:             *
0201:             * @param lock lock to use
0202:             */
0203:            public Mutex(Object lock) {
0204:                init(lock);
0205:                this .wrapper = null;
0206:            }
0207:
0208:            /** Default constructor.
0209:             */
0210:            public Mutex() {
0211:                init(new InternalLock());
0212:                this .wrapper = null;
0213:            }
0214:
0215:            /** @param privileged can enter privileged states of this Mutex
0216:             * This helps avoid creating of custom Runnables.
0217:             */
0218:            public Mutex(Privileged privileged) {
0219:                if (privileged == null) {
0220:                    throw new IllegalArgumentException("privileged == null"); //NOI18N
0221:                } else {
0222:                    init(new InternalLock());
0223:                    privileged.setParent(this );
0224:                }
0225:                this .wrapper = null;
0226:            }
0227:
0228:            /** Constructor for those who wish to do some custom additional tasks
0229:             * whenever an action or runnable is executed in the {@link Mutex}. This
0230:             * may be useful for wrapping all the actions with custom {@link ThreadLocal}
0231:             * value, etc. Just implement the {@link Executor}'s <code>execute(Runnable)</code>
0232:             * method and do pre and post initialization tasks before running the runnable.
0233:             * <p>
0234:             * The {@link Executor#execute} method shall return only when the passed in
0235:             * {@link Runnable} is finished, otherwise methods like {@link Mutex#readAccess(Action)} and co.
0236:             * might not return proper result.
0237:             * 
0238:             * @param privileged can enter privileged states of this Mutex
0239:             *  @param executor allows to wrap the work of the mutex with a custom code
0240:             * @since 7.12
0241:             */
0242:            public Mutex(Privileged privileged, Executor executor) {
0243:                LOCK = new Mutex(privileged);
0244:                this .wrapper = executor;
0245:            }
0246:
0247:            /** Initiates this Mutex */
0248:            private void init(Object lock) {
0249:                this .LOCK = lock;
0250:                this .registeredThreads = new HashMap<Thread, ThreadInfo>(7);
0251:                this .waiters = new LinkedList<QueueCell>();
0252:                this .cnt = counter++;
0253:                if (LOG.isLoggable(Level.FINE)) {
0254:                    LOG.log(Level.FINE, "[" + cnt + "] created here",
0255:                            new Exception());
0256:                }
0257:            }
0258:
0259:            /** Run an action only with read access.
0260:             * See class description re. entering for write access within the dynamic scope.
0261:             * @param action the action to perform
0262:             * @return the object returned from {@link Mutex.Action#run}
0263:             */
0264:            public <T> T readAccess(final Action<T> action) {
0265:                if (this  == EVENT) {
0266:                    try {
0267:                        return doEventAccess(action);
0268:                    } catch (MutexException e) {
0269:                        throw (InternalError) new InternalError(
0270:                                "Exception from non-Exception Action")
0271:                                .initCause(e.getException()); // NOI18N
0272:                    }
0273:                }
0274:                if (wrapper != null) {
0275:                    try {
0276:                        return doWrapperAccess(action, null, true);
0277:                    } catch (MutexException e) {
0278:                        throw (InternalError) new InternalError(
0279:                                "Exception from non-Exception Action")
0280:                                .initCause(e.getException()); // NOI18N
0281:                    }
0282:                }
0283:
0284:                Thread t = Thread.currentThread();
0285:                readEnter(t);
0286:
0287:                try {
0288:                    return action.run();
0289:                } finally {
0290:                    leave(t);
0291:                }
0292:            }
0293:
0294:            /** Run an action with read access and possibly throw a checked exception.
0295:             * The exception if thrown is then encapsulated
0296:             * in a <code>MutexException</code> and thrown from this method. One is encouraged
0297:             * to catch <code>MutexException</code>, obtain the inner exception, and rethrow it.
0298:             * Here is an example:
0299:             * <p><code><PRE>
0300:             * try {
0301:             *   mutex.readAccess (new ExceptionAction () {
0302:             *     public void run () throws IOException {
0303:             *       throw new IOException ();
0304:             *     }
0305:             *   });
0306:             *  } catch (MutexException ex) {
0307:             *    throw (IOException) ex.getException ();
0308:             *  }
0309:             * </PRE></code>
0310:             * Note that <em>runtime exceptions</em> are always passed through, and neither
0311:             * require this invocation style, nor are encapsulated.
0312:             * @param action the action to execute
0313:             * @return the object returned from {@link Mutex.ExceptionAction#run}
0314:             * @exception MutexException encapsulates a user exception
0315:             * @exception RuntimeException if any runtime exception is thrown from the run method
0316:             * @see #readAccess(Mutex.Action)
0317:             */
0318:            public <T> T readAccess(final ExceptionAction<T> action)
0319:                    throws MutexException {
0320:                if (this  == EVENT) {
0321:                    return doEventAccess(action);
0322:                }
0323:                if (wrapper != null) {
0324:                    return doWrapperAccess(action, null, true);
0325:                }
0326:
0327:                Thread t = Thread.currentThread();
0328:                readEnter(t);
0329:
0330:                try {
0331:                    return action.run();
0332:                } catch (RuntimeException e) {
0333:                    throw e;
0334:                } catch (Exception e) {
0335:                    throw new MutexException(e);
0336:                } finally {
0337:                    leave(t);
0338:                }
0339:            }
0340:
0341:            /** Run an action with read access, returning no result.
0342:             * It may be run asynchronously.
0343:             *
0344:             * @param action the action to perform
0345:             * @see #readAccess(Mutex.Action)
0346:             */
0347:            public void readAccess(final Runnable action) {
0348:                if (this  == EVENT) {
0349:                    doEvent(action);
0350:
0351:                    return;
0352:                }
0353:                if (wrapper != null) {
0354:                    try {
0355:                        doWrapperAccess(null, action, true);
0356:                        return;
0357:                    } catch (MutexException ex) {
0358:                        throw (IllegalStateException) new IllegalStateException()
0359:                                .initCause(ex);
0360:                    }
0361:                }
0362:
0363:                Thread t = Thread.currentThread();
0364:                readEnter(t);
0365:
0366:                try {
0367:                    action.run();
0368:                } finally {
0369:                    leave(t);
0370:                }
0371:            }
0372:
0373:            /** Run an action with write access.
0374:             * The same thread may meanwhile reenter the mutex; see the class description for details.
0375:             *
0376:             * @param action the action to perform
0377:             * @return the result of {@link Mutex.Action#run}
0378:             */
0379:            public <T> T writeAccess(Action<T> action) {
0380:                if (this  == EVENT) {
0381:                    try {
0382:                        return doEventAccess(action);
0383:                    } catch (MutexException e) {
0384:                        throw (InternalError) new InternalError(
0385:                                "Exception from non-Exception Action")
0386:                                .initCause(e.getException()); // NOI18N
0387:                    }
0388:                }
0389:                if (wrapper != null) {
0390:                    try {
0391:                        return doWrapperAccess(action, null, false);
0392:                    } catch (MutexException e) {
0393:                        throw (InternalError) new InternalError(
0394:                                "Exception from non-Exception Action")
0395:                                .initCause(e.getException()); // NOI18N
0396:                    }
0397:                }
0398:
0399:                Thread t = Thread.currentThread();
0400:                writeEnter(t);
0401:
0402:                try {
0403:                    return action.run();
0404:                } finally {
0405:                    leave(t);
0406:                }
0407:            }
0408:
0409:            /** Run an action with write access and possibly throw an exception.
0410:             * Here is an example:
0411:             * <p><code><PRE>
0412:             * try {
0413:             *   mutex.writeAccess (new ExceptionAction () {
0414:             *     public void run () throws IOException {
0415:             *       throw new IOException ();
0416:             *     }
0417:             *   });
0418:             *  } catch (MutexException ex) {
0419:             *    throw (IOException) ex.getException ();
0420:             *  }
0421:             * </PRE></code>
0422:             *
0423:             * @param action the action to execute
0424:             * @return the result of {@link Mutex.ExceptionAction#run}
0425:             * @exception MutexException an encapsulated checked exception, if any
0426:             * @exception RuntimeException if a runtime exception is thrown in the action
0427:             * @see #writeAccess(Mutex.Action)
0428:             * @see #readAccess(Mutex.ExceptionAction)
0429:             */
0430:            public <T> T writeAccess(ExceptionAction<T> action)
0431:                    throws MutexException {
0432:                if (this  == EVENT) {
0433:                    return doEventAccess(action);
0434:                }
0435:                if (wrapper != null) {
0436:                    return doWrapperAccess(action, null, false);
0437:                }
0438:
0439:                Thread t = Thread.currentThread();
0440:                writeEnter(t);
0441:
0442:                try {
0443:                    return action.run();
0444:                } catch (RuntimeException e) {
0445:                    throw e;
0446:                } catch (Exception e) {
0447:                    throw new MutexException(e);
0448:                } finally {
0449:                    leave(t);
0450:                }
0451:            }
0452:
0453:            /** Run an action with write access and return no result.
0454:             * It may be run asynchronously.
0455:             *
0456:             * @param action the action to perform
0457:             * @see #writeAccess(Mutex.Action)
0458:             * @see #readAccess(Runnable)
0459:             */
0460:            public void writeAccess(final Runnable action) {
0461:                if (this  == EVENT) {
0462:                    doEvent(action);
0463:
0464:                    return;
0465:                }
0466:                if (wrapper != null) {
0467:                    try {
0468:                        doWrapperAccess(null, action, false);
0469:                    } catch (MutexException ex) {
0470:                        throw (IllegalStateException) new IllegalStateException()
0471:                                .initCause(ex);
0472:                    }
0473:                    return;
0474:                }
0475:
0476:                Thread t = Thread.currentThread();
0477:                writeEnter(t);
0478:
0479:                try {
0480:                    action.run();
0481:                } finally {
0482:                    leave(t);
0483:                }
0484:            }
0485:
0486:            /** Tests whether this thread has already entered the mutex in read access.
0487:             * If it returns true, calling <code>readAccess</code>
0488:             * will be executed immediatelly
0489:             * without any blocking.
0490:             * Calling <code>postWriteAccess</code> will delay the execution
0491:             * of its <code>Runnable</code> until a readAccess section is over
0492:             * and calling <code>writeAccess</code> is strongly prohibited and will
0493:             * result in a warning as a deadlock prone behaviour.
0494:             * <p><strong>Warning:</strong> since a thread with write access automatically
0495:             * has effective read access as well (whether or not explicitly requested), if
0496:             * you want to check whether a thread can read some data, you should check for
0497:             * either kind of access, e.g.:
0498:             * <pre>assert myMutex.isReadAccess() || myMutex.isWriteAccess();</pre>
0499:             *
0500:             * @return true if the thread is in read access section
0501:             * @since 4.48
0502:             */
0503:            public boolean isReadAccess() {
0504:                if (this  == EVENT) {
0505:                    return javax.swing.SwingUtilities.isEventDispatchThread();
0506:                }
0507:                if (wrapper != null) {
0508:                    Mutex m = (Mutex) LOCK;
0509:                    return m.isReadAccess();
0510:                }
0511:
0512:                Thread t = Thread.currentThread();
0513:                ThreadInfo info;
0514:
0515:                synchronized (LOCK) {
0516:                    info = getThreadInfo(t);
0517:
0518:                    if (info != null) {
0519:                        if (info.counts[S] > 0) {
0520:                            return true;
0521:                        }
0522:                    }
0523:                }
0524:
0525:                return false;
0526:            }
0527:
0528:            /** Tests whether this thread has already entered the mutex in write access.
0529:             * If it returns true, calling <code>writeAccess</code> will be executed
0530:             * immediatelly without any other blocking. <code>postReadAccess</code>
0531:             * will be delayed until a write access runnable is over.
0532:             *
0533:             * @return true if the thread is in write access section
0534:             * @since 4.48
0535:             */
0536:            public boolean isWriteAccess() {
0537:                if (this  == EVENT) {
0538:                    return javax.swing.SwingUtilities.isEventDispatchThread();
0539:                }
0540:                if (wrapper != null) {
0541:                    Mutex m = (Mutex) LOCK;
0542:                    return m.isWriteAccess();
0543:                }
0544:
0545:                Thread t = Thread.currentThread();
0546:                ThreadInfo info;
0547:
0548:                synchronized (LOCK) {
0549:                    info = getThreadInfo(t);
0550:
0551:                    if (info != null) {
0552:                        if (info.counts[X] > 0) {
0553:                            return true;
0554:                        }
0555:                    }
0556:                }
0557:
0558:                return false;
0559:            }
0560:
0561:            /** Posts a read request. This request runs immediately iff
0562:             * this Mutex is in the shared mode or this Mutex is not contended
0563:             * at all.
0564:             *
0565:             * This request is delayed if this Mutex is in the exclusive
0566:             * mode and is held by this thread, until the exclusive is left.
0567:             *
0568:             * Finally, this request blocks, if this Mutex is in the exclusive
0569:             * mode and is held by another thread.
0570:             *
0571:             * <p><strong>Warning:</strong> this method blocks.</p>
0572:             *
0573:             * @param run runnable to run
0574:             */
0575:            public void postReadRequest(final Runnable run) {
0576:                postRequest(S, run, null);
0577:            }
0578:
0579:            /** Posts a write request. This request runs immediately iff
0580:             * this Mutex is in the "pure" exclusive mode, i.e. this Mutex
0581:             * is not reentered in shared mode after the exclusive mode
0582:             * was acquired. Otherwise it is delayed until all read requests
0583:             * are executed.
0584:             *
0585:             * This request runs immediately if this Mutex is not contended at all.
0586:             *
0587:             * This request blocks if this Mutex is in the shared mode.
0588:             *
0589:             * <p><strong>Warning:</strong> this method blocks.</p>
0590:             * @param run runnable to run
0591:             */
0592:            public void postWriteRequest(Runnable run) {
0593:                postRequest(X, run, null);
0594:            }
0595:
0596:            /** toString */
0597:            public String toString() {
0598:                if (this  == EVENT) {
0599:                    return "Mutex.EVENT"; // NOI18N
0600:                }
0601:
0602:                String newline = System.getProperty("line.separator");
0603:                StringBuffer sbuff = new StringBuffer(512);
0604:
0605:                synchronized (LOCK) {
0606:                    sbuff.append("threads: ").append(registeredThreads).append(
0607:                            newline); // NOI18N
0608:                    sbuff.append("readersNo: ").append(readersNo).append(
0609:                            newline); // NOI18N
0610:                    sbuff.append("waiters: ").append(waiters).append(newline); // NOI18N
0611:                    sbuff.append("grantedMode: ").append(grantedMode).append(
0612:                            newline); // NOI18N
0613:                }
0614:
0615:                return sbuff.toString();
0616:            }
0617:
0618:            // priv methods  -----------------------------------------
0619:
0620:            /** enters this mutex for writing */
0621:            private void writeEnter(Thread t) {
0622:                enter(X, t, true);
0623:            }
0624:
0625:            /** enters this mutex for reading */
0626:            private void readEnter(Thread t) {
0627:                enter(S, t, true);
0628:            }
0629:
0630:            private void doLog(String action, Object... params) {
0631:                String tid = Integer.toHexString(Thread.currentThread()
0632:                        .hashCode());
0633:                LOG.log(Level.FINE, "[#" + cnt + "@" + tid + "] " + action,
0634:                        params);
0635:            }
0636:
0637:            /** enters this mutex with given mode
0638:             * @param requested one of S, X
0639:             * @param t
0640:             */
0641:            private boolean enter(int requested, Thread t, boolean block) {
0642:                boolean log = LOG.isLoggable(Level.FINE);
0643:
0644:                if (log)
0645:                    doLog("Entering {0}, {1}", requested, block); // NOI18N
0646:
0647:                boolean ret = enterImpl(requested, t, block);
0648:
0649:                if (log)
0650:                    doLog("Entering exit: {0}", ret); // NOI18N
0651:
0652:                return ret;
0653:            }
0654:
0655:            private boolean enterImpl(int requested, Thread t, boolean block) {
0656:                QueueCell cell = null;
0657:                int loopc = 0;
0658:
0659:                for (;;) {
0660:                    loopc++;
0661:                    synchronized (LOCK) {
0662:                        // does the thread reenter this mutex?
0663:                        ThreadInfo info = getThreadInfo(t);
0664:
0665:                        if (info != null) {
0666:                            if (grantedMode == NONE) {
0667:                                // defensive
0668:                                throw new IllegalStateException();
0669:                            }
0670:                            // reenters
0671:                            // requested == S -> always succeeds
0672:                            // info.mode == X -> always succeeds
0673:                            if (((info.mode == S) && (grantedMode == X))
0674:                                    || ((info.mode == X) && (grantedMode == S))) {
0675:                                // defensive
0676:                                throw new IllegalStateException();
0677:                            }
0678:                            if ((info.mode == X) || (info.mode == requested)) {
0679:                                if (info.forced) {
0680:                                    info.forced = false;
0681:                                } else {
0682:                                    if ((requested == X)
0683:                                            && (info.counts[S] > 0)) {
0684:                                        IllegalStateException e = new IllegalStateException(
0685:                                                "WARNING: Going from readAccess to writeAccess, see #10778: http://www.netbeans.org/issues/show_bug.cgi?id=10778 ");
0686:
0687:                                        if (beStrict) {
0688:                                            throw e;
0689:                                        }
0690:                                        Exceptions.printStackTrace(e);
0691:                                    }
0692:                                    info.counts[requested]++;
0693:                                    if ((requested == S)
0694:                                            && (info.counts[requested] == 1)) {
0695:                                        readersNo++;
0696:                                    }
0697:                                }
0698:                                return true;
0699:                            } else if (canUpgrade(info.mode, requested)) {
0700:                                IllegalStateException e = new IllegalStateException(
0701:                                        "WARNING: Going from readAccess to writeAccess, see #10778: http://www.netbeans.org/issues/show_bug.cgi?id=10778 ");
0702:
0703:                                if (beStrict) {
0704:                                    throw e;
0705:                                }
0706:                                Exceptions.printStackTrace(e);
0707:                                info.mode = X;
0708:                                info.counts[requested]++;
0709:                                info.rsnapshot = info.counts[S];
0710:                                if (grantedMode == S) {
0711:                                    setGrantedMode(X);
0712:                                } else if (grantedMode == X) {
0713:                                    // defensive
0714:                                    throw new IllegalStateException();
0715:                                }
0716:                                // else if grantedMode == CHAIN - let it be
0717:                                return true;
0718:                            } else {
0719:                                IllegalStateException e = new IllegalStateException(
0720:                                        "WARNING: Going from readAccess to writeAccess through queue, see #10778: http://www.netbeans.org/issues/show_bug.cgi?id=10778 ");
0721:
0722:                                if (beStrict) {
0723:                                    throw e;
0724:                                }
0725:                                Exceptions.printStackTrace(e);
0726:                            }
0727:                        } else {
0728:                            if (isCompatible(requested)) {
0729:                                setGrantedMode(requested);
0730:                                registeredThreads.put(t, info = new ThreadInfo(
0731:                                        t, requested));
0732:                                if (requested == S) {
0733:                                    readersNo++;
0734:                                }
0735:                                return true;
0736:                            }
0737:                        }
0738:                        if (!block) {
0739:                            return false;
0740:                        }
0741:                        setGrantedMode(CHAIN);
0742:                        cell = chain(requested, t, 0);
0743:                    }
0744:                    // sync
0745:                    cell.sleep();
0746:                }
0747:                // for
0748:            }
0749:
0750:            /** privilegedEnter serves for processing posted requests */
0751:            private boolean reenter(Thread t, int mode) {
0752:                boolean log = LOG.isLoggable(Level.FINE);
0753:
0754:                if (log)
0755:                    doLog("Re-Entering {0}", mode); // NOI18N
0756:
0757:                boolean ret = reenterImpl(t, mode);
0758:
0759:                if (log)
0760:                    doLog("Re-Entering exit: {0}", ret); // NOI18N
0761:
0762:                return ret;
0763:            }
0764:
0765:            private boolean reenterImpl(Thread t, int mode) {
0766:                // from leaveX -> grantedMode is NONE or S
0767:                if (mode == S) {
0768:                    if ((grantedMode != NONE) && (grantedMode != S)) {
0769:                        throw new IllegalStateException(this .toString());
0770:                    }
0771:
0772:                    enter(mode, t, true);
0773:
0774:                    return false;
0775:                }
0776:
0777:                // assert (mode == X)
0778:                ThreadInfo tinfo = getThreadInfo(t);
0779:                boolean chainFromLeaveX = ((grantedMode == CHAIN)
0780:                        && (tinfo != null) && (tinfo.counts[X] > 0));
0781:
0782:                // process grantedMode == X or CHAIN from leaveX OR grantedMode == NONE from leaveS
0783:                if ((grantedMode == X) || (grantedMode == NONE)
0784:                        || chainFromLeaveX) {
0785:                    enter(mode, t, true);
0786:
0787:                    return false;
0788:                } else { // remains grantedMode == CHAIN or S from leaveS, so it will be CHAIN
0789:
0790:                    if (readersNo == 0) {
0791:                        throw new IllegalStateException(this .toString());
0792:                    }
0793:
0794:                    ThreadInfo info = new ThreadInfo(t, mode);
0795:                    registeredThreads.put(t, info);
0796:
0797:                    // prevent from grantedMode == NONE (another thread - leaveS)
0798:                    readersNo += 2;
0799:
0800:                    // prevent from new readers
0801:                    setGrantedMode(CHAIN);
0802:
0803:                    return true;
0804:                }
0805:                // else X means ERROR!!!
0806:            }
0807:
0808:            /** @param t holds S (one entry) and wants X, grantedMode != NONE && grantedMode != X */
0809:            private void privilegedEnter(Thread t, int mode) {
0810:                boolean decrease = true;
0811:
0812:                synchronized (LOCK) {
0813:                    getThreadInfo(t);
0814:                }
0815:
0816:                for (;;) {
0817:                    QueueCell cell;
0818:
0819:                    synchronized (LOCK) {
0820:                        if (decrease) {
0821:                            decrease = false;
0822:                            readersNo -= 2;
0823:                        }
0824:
0825:                        // always chain this thread
0826:                        // since there can be another one
0827:                        // in the queue with higher priority
0828:                        setGrantedMode(CHAIN);
0829:                        cell = chain(mode, t, Integer.MAX_VALUE);
0830:
0831:                        if (readersNo == 0) { // seems I may enter
0832:
0833:                            // no one has higher prio?
0834:                            if (waiters.get(0) == cell) {
0835:                                waiters.remove(0);
0836:
0837:                                setGrantedMode(mode);
0838:
0839:                                return;
0840:                            } else {
0841:                                setGrantedMode(NONE);
0842:                                wakeUpOthers();
0843:                            }
0844:                        }
0845:                    }
0846:                    // synchronized (LOCK)
0847:
0848:                    cell.sleep();
0849:
0850:                    // cell already removed from waiters here
0851:                }
0852:            }
0853:
0854:            /** Leaves this mutex */
0855:            private void leave(Thread t) {
0856:                boolean log = LOG.isLoggable(Level.FINE);
0857:
0858:                if (log)
0859:                    doLog("Leaving {0}", grantedMode); // NOI18N
0860:
0861:                leaveImpl(t);
0862:
0863:                if (log)
0864:                    doLog("Leaving exit: {0}", grantedMode); // NOI18N
0865:            }
0866:
0867:            private void leaveImpl(Thread t) {
0868:                ThreadInfo info;
0869:                int postedMode = NONE;
0870:                boolean needLock = false;
0871:
0872:                synchronized (LOCK) {
0873:                    info = getThreadInfo(t);
0874:
0875:                    switch (grantedMode) {
0876:                    case NONE:
0877:                        throw new IllegalStateException();
0878:
0879:                    case CHAIN:
0880:
0881:                        if (info.counts[X] > 0) {
0882:                            // it matters that X is handled first - see ThreadInfo.rsnapshot
0883:                            postedMode = leaveX(info);
0884:                        } else if (info.counts[S] > 0) {
0885:                            postedMode = leaveS(info);
0886:                        } else {
0887:                            throw new IllegalStateException();
0888:                        }
0889:
0890:                        break;
0891:
0892:                    case X:
0893:                        postedMode = leaveX(info);
0894:
0895:                        break;
0896:
0897:                    case S:
0898:                        postedMode = leaveS(info);
0899:
0900:                        break;
0901:                    } // switch
0902:
0903:                    // do not give up LOCK until queued runnables are run
0904:                    if (postedMode != NONE) {
0905:                        int runsize = info.getRunnableCount(postedMode);
0906:
0907:                        if (runsize != 0) {
0908:                            needLock = reenter(t, postedMode); // grab lock
0909:                        }
0910:                    }
0911:                } // sync
0912:
0913:                // check posted requests
0914:                if ((postedMode != NONE)
0915:                        && (info.getRunnableCount(postedMode) > 0)) {
0916:                    doLog("Processing posted requests: {0}", postedMode); // NOI18N
0917:                    try {
0918:                        if (needLock) { // go from S to X or CHAIN
0919:                            privilegedEnter(t, postedMode);
0920:                        }
0921:
0922:                        // holds postedMode lock here
0923:                        List runnables = info.dequeue(postedMode);
0924:                        final int size = runnables.size();
0925:
0926:                        for (int i = 0; i < size; i++) {
0927:                            try {
0928:                                Runnable r = (Runnable) runnables.get(i);
0929:
0930:                                r.run();
0931:                            } catch (Exception e) {
0932:                                Exceptions.printStackTrace(e);
0933:                            } catch (StackOverflowError e) {
0934:                                // Try as hard as possible to get a real stack trace
0935:                                e.printStackTrace();
0936:                                Exceptions.printStackTrace(e);
0937:                            } catch (ThreadDeath td) {
0938:                                throw td;
0939:                            } catch (Error e) {
0940:                                Exceptions.printStackTrace(e);
0941:                            }
0942:                        }
0943:                        // for
0944:
0945:                        // help gc
0946:                        runnables = null;
0947:                    } finally {
0948:                        leave(t); // release lock grabbed - shared
0949:                    }
0950:                }
0951:                // mode
0952:            }
0953:
0954:            /** Leaves the lock supposing that info.counts[X] is greater than zero */
0955:            private int leaveX(ThreadInfo info) {
0956:                if ((info.counts[X] <= 0) || (info.rsnapshot > info.counts[S])) {
0957:                    // defensive
0958:                    throw new IllegalStateException();
0959:                }
0960:
0961:                if (info.rsnapshot == info.counts[S]) {
0962:                    info.counts[X]--;
0963:
0964:                    if (info.counts[X] == 0) {
0965:                        info.rsnapshot = 0;
0966:
0967:                        // downgrade the lock
0968:                        if (info.counts[S] > 0) {
0969:                            info.mode = S;
0970:                            setGrantedMode(S);
0971:                        } else {
0972:                            info.mode = NONE;
0973:                            setGrantedMode(NONE);
0974:                            registeredThreads.remove(info.t);
0975:                        }
0976:
0977:                        if (info.getRunnableCount(S) > 0) {
0978:                            // wake up other readers of this mutex
0979:                            wakeUpReaders();
0980:
0981:                            return S;
0982:                        }
0983:
0984:                        // mode has changed
0985:                        wakeUpOthers();
0986:                    }
0987:                } else {
0988:                    // rsnapshot < counts[S]
0989:                    if (info.counts[S] <= 0) {
0990:                        // defensive
0991:                        throw new IllegalStateException();
0992:                    }
0993:
0994:                    if (--info.counts[S] == 0) {
0995:                        if (readersNo <= 0) {
0996:                            throw new IllegalStateException();
0997:                        }
0998:
0999:                        readersNo--;
1000:
1001:                        return X;
1002:                    }
1003:                }
1004:
1005:                return NONE;
1006:            }
1007:
1008:            /** Leaves the lock supposing that info.counts[S] is greater than zero */
1009:            private int leaveS(ThreadInfo info) {
1010:                if ((info.counts[S] <= 0) || (info.counts[X] > 0)) {
1011:                    // defensive
1012:                    throw new IllegalStateException();
1013:                }
1014:
1015:                info.counts[S]--;
1016:
1017:                if (info.counts[S] == 0) {
1018:                    // remove the thread
1019:                    info.mode = NONE;
1020:                    registeredThreads.remove(info.t);
1021:
1022:                    // downsize readersNo
1023:                    if (readersNo <= 0) {
1024:                        throw new IllegalStateException();
1025:                    }
1026:
1027:                    readersNo--;
1028:
1029:                    if (readersNo == 0) {
1030:                        // set grantedMode to NONE
1031:                        // and then wakeUp others - either immediately 
1032:                        // or in privelegedEnter()
1033:                        setGrantedMode(NONE);
1034:
1035:                        if (info.getRunnableCount(X) > 0) {
1036:                            return X;
1037:                        }
1038:
1039:                        wakeUpOthers();
1040:                    } else if (info.getRunnableCount(X) > 0) {
1041:                        return X;
1042:                    } else if ((grantedMode == CHAIN) && (readersNo == 1)) {
1043:                        // can be the mode advanced from CHAIN? Examine first item of waiters!
1044:                        for (int i = 0; i < waiters.size(); i++) {
1045:                            QueueCell qc = waiters.get(i);
1046:
1047:                            synchronized (qc) {
1048:                                if (qc.isGotOut()) {
1049:                                    waiters.remove(i--);
1050:
1051:                                    continue;
1052:                                }
1053:
1054:                                ThreadInfo tinfo = getThreadInfo(qc.t);
1055:
1056:                                if (tinfo != null) {
1057:                                    if (tinfo.mode == S) {
1058:                                        if (qc.mode != X) {
1059:                                            // defensive
1060:                                            throw new IllegalStateException();
1061:                                        }
1062:
1063:                                        if (waiters.size() == 1) {
1064:                                            setGrantedMode(X);
1065:                                        }
1066:                                        // else let CHAIN
1067:
1068:                                        tinfo.mode = X;
1069:                                        waiters.remove(i);
1070:                                        qc.wakeMeUp();
1071:                                    }
1072:                                }
1073:                                // else first request is a first X request of some thread
1074:
1075:                                break;
1076:                            }
1077:                            // sync (qc)
1078:                        }
1079:                        // for
1080:                    }
1081:                    // else
1082:                }
1083:                // count[S] == 0
1084:
1085:                return NONE;
1086:            }
1087:
1088:            /** Adds this thread to the queue of waiting threads
1089:             * @warning LOCK must be held
1090:             */
1091:            private QueueCell chain(final int requested, final Thread t,
1092:                    final int priority) {
1093:                //long timeout = 0;
1094:
1095:                /*
1096:                if (killDeadlocksOn) {
1097:                    checkDeadlock(requested, t);
1098:                    timeout = (isDispatchThread() || checkAwtTreeLock() ? TIMEOUT : 0);
1099:                }
1100:                 */
1101:                QueueCell qc = new QueueCell(requested, t);
1102:
1103:                //qc.timeout = timeout;
1104:                qc.priority2 = priority;
1105:
1106:                final int size = waiters.size();
1107:
1108:                if (size == 0) {
1109:                    waiters.add(qc);
1110:                } else if (qc.getPriority() == Integer.MAX_VALUE) {
1111:                    waiters.add(0, qc);
1112:                } else {
1113:                    QueueCell cursor;
1114:                    int i = 0;
1115:
1116:                    do {
1117:                        cursor = waiters.get(i);
1118:
1119:                        if (cursor.getPriority() < qc.getPriority()) {
1120:                            waiters.add(i, qc);
1121:
1122:                            break;
1123:                        }
1124:
1125:                        i++;
1126:                    } while (i < size);
1127:
1128:                    if (i == size) {
1129:                        waiters.add(qc);
1130:                    }
1131:                }
1132:
1133:                return qc;
1134:            }
1135:
1136:            /** Scans through waiters and wakes up them */
1137:            private void wakeUpOthers() {
1138:                if ((grantedMode == X) || (grantedMode == CHAIN)) {
1139:                    // defensive
1140:                    throw new IllegalStateException();
1141:                }
1142:
1143:                if (waiters.size() == 0) {
1144:                    return;
1145:                }
1146:
1147:                for (int i = 0; i < waiters.size(); i++) {
1148:                    QueueCell qc = waiters.get(i);
1149:
1150:                    synchronized (qc) {
1151:                        if (qc.isGotOut()) {
1152:                            // bogus waiter
1153:                            waiters.remove(i--);
1154:
1155:                            continue;
1156:                        }
1157:
1158:                        if (isCompatible(qc.mode)) { // woken S -> should I wake X? -> no
1159:                            waiters.remove(i--);
1160:                            qc.wakeMeUp();
1161:                            setGrantedMode(qc.mode);
1162:
1163:                            if (getThreadInfo(qc.t) == null) {
1164:                                // force to have a record since recorded threads
1165:                                // do not use isCompatible call
1166:                                ThreadInfo ti = new ThreadInfo(qc.t, qc.mode);
1167:                                ti.forced = true;
1168:
1169:                                if (qc.mode == S) {
1170:                                    readersNo++;
1171:                                }
1172:
1173:                                registeredThreads.put(qc.t, ti);
1174:                            }
1175:                        } else {
1176:                            setGrantedMode(CHAIN);
1177:
1178:                            break;
1179:                        }
1180:                    }
1181:                    // sync (qc)
1182:                }
1183:            }
1184:
1185:            private void wakeUpReaders() {
1186:                assert (grantedMode == NONE) || (grantedMode == S);
1187:
1188:                if (waiters.size() == 0) {
1189:                    return;
1190:                }
1191:
1192:                for (int i = 0; i < waiters.size(); i++) {
1193:                    QueueCell qc = waiters.get(i);
1194:
1195:                    synchronized (qc) {
1196:                        if (qc.isGotOut()) {
1197:                            // bogus waiter
1198:                            waiters.remove(i--);
1199:
1200:                            continue;
1201:                        }
1202:
1203:                        if (qc.mode == S) { // readers only
1204:                            waiters.remove(i--);
1205:                            qc.wakeMeUp();
1206:                            setGrantedMode(S);
1207:
1208:                            if (getThreadInfo(qc.t) == null) {
1209:                                // force to have a record since recorded threads
1210:                                // do not use isCompatible call
1211:                                ThreadInfo ti = new ThreadInfo(qc.t, qc.mode);
1212:                                ti.forced = true;
1213:                                readersNo++;
1214:                                registeredThreads.put(qc.t, ti);
1215:                            }
1216:                        }
1217:                    }
1218:                    // sync (qc)
1219:                }
1220:            }
1221:
1222:            /** Posts new request for current thread
1223:             * @param mutexMode mutex mode for which the action is rquested
1224:             * @param run the action
1225:             */
1226:            private void postRequest(final int mutexMode, final Runnable run,
1227:                    Executor exec) {
1228:                if (this  == EVENT) {
1229:                    doEventRequest(run);
1230:
1231:                    return;
1232:                }
1233:                if (wrapper != null) {
1234:                    Mutex m = (Mutex) LOCK;
1235:                    m.postRequest(mutexMode, run, wrapper);
1236:                    return;
1237:                }
1238:
1239:                final Thread t = Thread.currentThread();
1240:                ThreadInfo info;
1241:
1242:                synchronized (LOCK) {
1243:                    info = getThreadInfo(t);
1244:
1245:                    if (info != null) {
1246:                        // the same mode and mutex is not entered in the other mode
1247:                        // assert (mutexMode == S || mutexMode == X)
1248:                        if ((mutexMode == info.mode)
1249:                                && (info.counts[(S + X) - mutexMode] == 0)) {
1250:                            enter(mutexMode, t, true);
1251:                        } else { // the mutex is held but can not be entered in X mode
1252:                            info.enqueue(mutexMode, run);
1253:
1254:                            return;
1255:                        }
1256:                    }
1257:                }
1258:
1259:                // this mutex is not held
1260:                if (info == null) {
1261:                    if (exec != null) {
1262:                        class Exec implements  Runnable {
1263:                            public void run() {
1264:                                enter(mutexMode, t, true);
1265:                                try {
1266:                                    run.run();
1267:                                } finally {
1268:                                    leave(t);
1269:                                }
1270:                            }
1271:                        }
1272:                        exec.execute(new Exec());
1273:                        return;
1274:                    }
1275:
1276:                    enter(mutexMode, t, true);
1277:                    try {
1278:                        run.run();
1279:                    } finally {
1280:                        leave(t);
1281:                    }
1282:
1283:                    return;
1284:                }
1285:
1286:                // run it immediately
1287:                // info != null so enter(...) succeeded
1288:                try {
1289:                    run.run();
1290:                } finally {
1291:                    leave(t);
1292:                }
1293:            }
1294:
1295:            /** @param requested is requested mode of locking
1296:             * @return <tt>true</tt> if and only if current mode and requested mode are compatible
1297:             */
1298:            private boolean isCompatible(int requested) {
1299:                // allow next reader in even in chained mode, if it was read access before
1300:                if (requested == S && grantedMode == CHAIN && origMode == S)
1301:                    return true;
1302:                return cmatrix[requested][grantedMode];
1303:            }
1304:
1305:            private ThreadInfo getThreadInfo(Thread t) {
1306:                return registeredThreads.get(t);
1307:            }
1308:
1309:            private boolean canUpgrade(int threadGranted, int requested) {
1310:                return (threadGranted == S) && (requested == X)
1311:                        && (readersNo == 1);
1312:            }
1313:
1314:            // -------------------------------- WRAPPERS --------------------------------
1315:
1316:            private <T> T doWrapperAccess(final ExceptionAction<T> action,
1317:                    final Runnable runnable, final boolean readOnly)
1318:                    throws MutexException {
1319:                class R implements  Runnable {
1320:                    T ret;
1321:                    MutexException e;
1322:
1323:                    public void run() {
1324:                        Mutex m = (Mutex) LOCK;
1325:                        try {
1326:                            if (readOnly) {
1327:                                if (action != null) {
1328:                                    ret = m.readAccess(action);
1329:                                } else {
1330:                                    m.readAccess(runnable);
1331:                                }
1332:                            } else {
1333:                                if (action != null) {
1334:                                    ret = m.writeAccess(action);
1335:                                } else {
1336:                                    m.writeAccess(runnable);
1337:                                }
1338:                            }
1339:                        } catch (MutexException ex) {
1340:                            this .e = ex;
1341:                        }
1342:                    }
1343:                }
1344:                R run = new R();
1345:                Mutex m = (Mutex) LOCK;
1346:                if (m.isWriteAccess() || m.isReadAccess()) {
1347:                    run.run();
1348:                } else {
1349:                    wrapper.execute(run);
1350:                }
1351:                if (run.e != null) {
1352:                    throw run.e;
1353:                }
1354:                return run.ret;
1355:            }
1356:
1357:            // ------------------------------- EVENT METHODS ----------------------------
1358:
1359:            /** Runs the runnable in event queue, either immediatelly,
1360:             * or it posts it into the queue.
1361:             */
1362:            private static void doEvent(Runnable run) {
1363:                if (EventQueue.isDispatchThread()) {
1364:                    run.run();
1365:                } else {
1366:                    EventQueue.invokeLater(run);
1367:                }
1368:            }
1369:
1370:            /** Methods for access to event queue.
1371:             * @param run runabble to post later
1372:             */
1373:            private static void doEventRequest(Runnable run) {
1374:                EventQueue.invokeLater(run);
1375:            }
1376:
1377:            /** Methods for access to event queue and waiting for result.
1378:             * @param run runnable to post later
1379:             */
1380:            private static <T> T doEventAccess(final ExceptionAction<T> run)
1381:                    throws MutexException {
1382:                if (isDispatchThread()) {
1383:                    try {
1384:                        return run.run();
1385:                    } catch (RuntimeException e) {
1386:                        throw e;
1387:                    } catch (Exception e) {
1388:                        throw new MutexException(e);
1389:                    }
1390:                }
1391:
1392:                final Throwable[] arr = new Throwable[1];
1393:
1394:                try {
1395:                    final List<T> res = new ArrayList<T>(1);
1396:                    class AWTWorker implements  Runnable {
1397:                        public void run() {
1398:                            try {
1399:                                res.add(run.run());
1400:                            } catch (Exception e) {
1401:                                arr[0] = e;
1402:                            } catch (LinkageError e) {
1403:                                // #20467
1404:                                arr[0] = e;
1405:                            } catch (StackOverflowError e) {
1406:                                // #20467
1407:                                arr[0] = e;
1408:                            }
1409:                        }
1410:                    }
1411:
1412:                    AWTWorker w = new AWTWorker();
1413:                    EventQueue.invokeAndWait(w);
1414:
1415:                    if (arr[0] == null) {
1416:                        return res.get(0);
1417:                    }
1418:                } catch (InterruptedException e) {
1419:                    arr[0] = e;
1420:                } catch (InvocationTargetException e) {
1421:                    arr[0] = e;
1422:                }
1423:
1424:                if (arr[0] instanceof  RuntimeException) {
1425:                    throw (RuntimeException) arr[0];
1426:                }
1427:
1428:                throw notifyException(arr[0]);
1429:            }
1430:
1431:            /** @return true iff current thread is EventDispatchThread */
1432:            static boolean isDispatchThread() {
1433:                boolean dispatch = EventQueue.isDispatchThread();
1434:
1435:                if (!dispatch
1436:                        && (Utilities.getOperatingSystem() == Utilities.OS_SOLARIS)) {
1437:                    // on solaris the event queue is not always recognized correctly
1438:                    // => try to guess by name
1439:                    dispatch = (Thread.currentThread().getClass().getName()
1440:                            .indexOf("EventDispatchThread") >= 0); // NOI18N
1441:                }
1442:
1443:                return dispatch;
1444:            }
1445:
1446:            /** Notify exception and returns new MutexException */
1447:            private static final MutexException notifyException(Throwable t) {
1448:                if (t instanceof  InvocationTargetException) {
1449:                    t = unfoldInvocationTargetException((InvocationTargetException) t);
1450:                }
1451:
1452:                if (t instanceof  Error) {
1453:                    annotateEventStack(t);
1454:                    throw (Error) t;
1455:                }
1456:
1457:                if (t instanceof  RuntimeException) {
1458:                    annotateEventStack(t);
1459:                    throw (RuntimeException) t;
1460:                }
1461:
1462:                MutexException exc = new MutexException((Exception) t);
1463:                exc.initCause(t);
1464:
1465:                return exc;
1466:            }
1467:
1468:            private static final void annotateEventStack(Throwable t) {
1469:                //ErrorManager.getDefault().annotate(t, new Exception("Caught here in mutex")); // NOI18N
1470:            }
1471:
1472:            private static final Throwable unfoldInvocationTargetException(
1473:                    InvocationTargetException e) {
1474:                Throwable ret;
1475:
1476:                do {
1477:                    ret = e.getTargetException();
1478:
1479:                    if (ret instanceof  InvocationTargetException) {
1480:                        e = (InvocationTargetException) ret;
1481:                    } else {
1482:                        e = null;
1483:                    }
1484:                } while (e != null);
1485:
1486:                return ret;
1487:            }
1488:
1489:            // --------------------------------------------- END OF EVENT METHODS ------------------------------
1490:
1491:            /** Action to be executed in a mutex without throwing any checked exceptions.
1492:             * Unchecked exceptions will be propagated to calling code.
1493:             * @param T the type of object to return
1494:             */
1495:            public interface Action<T> extends ExceptionAction<T> {
1496:                /** Execute the action.
1497:                 * @return any object, then returned from {@link Mutex#readAccess(Mutex.Action)} or {@link Mutex#writeAccess(Mutex.Action)}
1498:                 */
1499:                T run();
1500:            }
1501:
1502:            /** Action to be executed in a mutex, possibly throwing checked exceptions.
1503:             * May throw a checked exception, in which case calling
1504:             * code should catch the encapsulating exception and rethrow the
1505:             * real one.
1506:             * Unchecked exceptions will be propagated to calling code without encapsulation.
1507:             * @param T the type of object to return
1508:             */
1509:            public interface ExceptionAction<T> {
1510:                /** Execute the action.
1511:                 * Can throw an exception.
1512:                 * @return any object, then returned from {@link Mutex#readAccess(Mutex.ExceptionAction)} or {@link Mutex#writeAccess(Mutex.ExceptionAction)}
1513:                 * @exception Exception any exception the body needs to throw
1514:                 */
1515:                T run() throws Exception;
1516:            }
1517:
1518:            private static final class ThreadInfo {
1519:                /** t is forcibly sent from waiters to enter() by wakeUpOthers() */
1520:                boolean forced;
1521:
1522:                /** ThreadInfo for this Thread */
1523:                final Thread t;
1524:
1525:                /** granted mode */
1526:                int mode;
1527:
1528:                // 0 - NONE, 1 - CHAIN, 2 - X, 3 - S
1529:
1530:                /** enter counter */
1531:                int[] counts;
1532:
1533:                /** queue of runnable rquests that are to be executed (in X mode) right after S mode is left
1534:                 * deadlock avoidance technique
1535:                 */
1536:                List<Runnable>[] queues;
1537:
1538:                /** value of counts[S] when the mode was upgraded
1539:                 * rsnapshot works as follows:
1540:                 * if a thread holds the mutex in the S mode and it reenters the mutex
1541:                 * and requests X and the mode can be granted (no other readers) then this
1542:                 * variable is set to counts[S]. This is used in the leave method in the X branch.
1543:                 * (X mode is granted by other words)
1544:                 * If rsnapshot is less than counts[S] then the counter is decremented etc. If the rsnapshot is
1545:                 * equal to count[S] then count[X] is decremented. If the X counter is zeroed then
1546:                 * rsnapshot is zeroed as well and current mode is downgraded to S mode.
1547:                 * rsnapshot gets less than counts[S] if current mode is X and the mutex is reentered
1548:                 * with S request.
1549:                 */
1550:                int rsnapshot;
1551:
1552:                @SuppressWarnings("unchecked")
1553:                public ThreadInfo(Thread t, int mode) {
1554:                    this .t = t;
1555:                    this .mode = mode;
1556:                    this .counts = new int[MODE_COUNT];
1557:                    this .queues = (List<Runnable>[]) new List[MODE_COUNT];
1558:                    counts[mode] = 1;
1559:                }
1560:
1561:                public String toString() {
1562:                    return super .toString() + " thread: " + t + " mode: "
1563:                            + mode + " X: " + counts[2] + " S: " + counts[3]; // NOI18N
1564:                }
1565:
1566:                /** Adds the Runnable into the queue of waiting requests */
1567:                public void enqueue(int mode, Runnable run) {
1568:                    if (queues[mode] == null) {
1569:                        queues[mode] = new ArrayList<Runnable>(13);
1570:                    }
1571:
1572:                    queues[mode].add(run);
1573:                }
1574:
1575:                /** @return a List of enqueued Runnables - may be null */
1576:                public List dequeue(int mode) {
1577:                    List ret = queues[mode];
1578:                    queues[mode] = null;
1579:
1580:                    return ret;
1581:                }
1582:
1583:                public int getRunnableCount(int mode) {
1584:                    return ((queues[mode] == null) ? 0 : queues[mode].size());
1585:                }
1586:            }
1587:
1588:            /** This class is defined only for better understanding of thread dumps where are informations like
1589:             * java.lang.Object@xxxxxxxx owner thread_x
1590:             *   wait for enter thread_y
1591:             */
1592:            private static final class InternalLock {
1593:                InternalLock() {
1594:                }
1595:            }
1596:
1597:            private static final class QueueCell {
1598:                int mode;
1599:                Thread t;
1600:                boolean signal;
1601:                boolean left;
1602:
1603:                /** priority of the cell */
1604:                int priority2;
1605:
1606:                public QueueCell(int mode, Thread t) {
1607:                    this .mode = mode;
1608:                    this .t = t;
1609:                    this .left = false;
1610:                    this .priority2 = 0;
1611:                }
1612:
1613:                public String toString() {
1614:                    return super .toString() + " mode: " + mode + " thread: "
1615:                            + t; // NOI18N
1616:                }
1617:
1618:                /** @return priority of this cell */
1619:                public long getPriority() {
1620:                    return ((priority2 == 0) ? t.getPriority() : priority2);
1621:                }
1622:
1623:                /** @return true iff the thread left sleep */
1624:                public boolean isGotOut() {
1625:                    return left;
1626:                }
1627:
1628:                /** current thread will sleep until wakeMeUp is called
1629:                 * if wakeMeUp was already called then the thread will not sleep
1630:                 */
1631:                public synchronized void sleep() {
1632:                    try {
1633:                        while (!signal) {
1634:                            try {
1635:                                wait();
1636:
1637:                                return;
1638:                            } catch (InterruptedException e) {
1639:                                Logger.getLogger(Mutex.class.getName()).log(
1640:                                        Level.WARNING, null, e);
1641:                            }
1642:                        }
1643:                    } finally {
1644:                        left = true;
1645:                    }
1646:                }
1647:
1648:                /** sends signal to a sleeper - to a thread that is in the sleep() */
1649:                public void wakeMeUp() {
1650:                    signal = true;
1651:                    notifyAll();
1652:                }
1653:            }
1654:
1655:            /** Provides access to Mutex's internal methods.
1656:             *
1657:             * This class can be used when one wants to avoid creating a
1658:             * bunch of Runnables. Instead,
1659:             * <pre>
1660:             * try {
1661:             *     enterXAccess ();
1662:             *     yourCustomMethod ();
1663:             * } finally {
1664:             *     exitXAccess ();
1665:             * }
1666:             * </pre>
1667:             * can be used.
1668:             *
1669:             * You must, however, control the related Mutex, i.e. you must be creator of
1670:             * the Mutex.
1671:             *
1672:             * @since 1.17
1673:             */
1674:            public static final class Privileged {
1675:                private Mutex parent;
1676:
1677:                final void setParent(Mutex parent) {
1678:                    this .parent = parent;
1679:                }
1680:
1681:                public void enterReadAccess() {
1682:                    parent.readEnter(Thread.currentThread());
1683:                }
1684:
1685:                public void enterWriteAccess() {
1686:                    parent.writeEnter(Thread.currentThread());
1687:                }
1688:
1689:                public void exitReadAccess() {
1690:                    parent.leave(Thread.currentThread());
1691:                }
1692:
1693:                public void exitWriteAccess() {
1694:                    parent.leave(Thread.currentThread());
1695:                }
1696:            }
1697:
1698:            private void setGrantedMode(int mode) {
1699:                if (grantedMode != CHAIN && mode == CHAIN) {
1700:                    origMode = grantedMode;
1701:                }
1702:                grantedMode = mode;
1703:            }
1704:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.