Source code: org/eclipse/swt/widgets/Synchronizer.java
1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.swt.widgets;
12
13
14 import org.eclipse.swt.*;
15 import org.eclipse.swt.internal.Compatibility;
16
17 /**
18 * Instances of this class provide synchronization support
19 * for displays. A default instance is created automatically
20 * for each display, and this instance is sufficient for almost
21 * all applications.
22 * <p>
23 * <b>IMPORTANT:</b> Typical application code <em>never</em>
24 * needs to deal with this class. It is provided only to
25 * allow applications which require non-standard
26 * synchronization behavior to plug in the support they
27 * require. <em>Subclasses which override the methods in
28 * this class must ensure that the superclass methods are
29 * invoked in their implementations</em>
30 * </p>
31 *
32 * @see Display#setSynchronizer
33 */
34 public class Synchronizer {
35 Display display;
36 int messageCount;
37 RunnableLock [] messages;
38 Object messageLock = new Object ();
39 Thread syncThread;
40
41 public Synchronizer (Display display) {
42 this.display = display;
43 }
44
45 void addLast (RunnableLock lock) {
46 synchronized (messageLock) {
47 if (messages == null) messages = new RunnableLock [4];
48 if (messageCount == messages.length) {
49 RunnableLock[] newMessages = new RunnableLock [messageCount + 4];
50 System.arraycopy (messages, 0, newMessages, 0, messageCount);
51 messages = newMessages;
52 }
53 messages [messageCount++] = lock;
54 if (messageCount == 1) display.wakeThread ();
55 }
56 }
57
58 /**
59 * Causes the <code>run()</code> method of the runnable to
60 * be invoked by the user-interface thread at the next
61 * reasonable opportunity. The caller of this method continues
62 * to run in parallel, and is not notified when the
63 * runnable has completed.
64 *
65 * @param runnable code to run on the user-interface thread.
66 *
67 * @see #syncExec
68 */
69 protected void asyncExec (Runnable runnable) {
70 if (runnable == null) {
71 display.wake ();
72 return;
73 }
74 addLast (new RunnableLock (runnable));
75 }
76
77 int getMessageCount () {
78 return messageCount;
79 }
80
81 void releaseSynchronizer () {
82 display = null;
83 messages = null;
84 messageLock = null;
85 syncThread = null;
86 }
87
88 RunnableLock removeFirst () {
89 synchronized (messageLock) {
90 if (messageCount == 0) return null;
91 RunnableLock lock = messages [0];
92 System.arraycopy (messages, 1, messages, 0, --messageCount);
93 messages [messageCount] = null;
94 if (messageCount == 0) messages = null;
95 return lock;
96 }
97 }
98
99 boolean runAsyncMessages () {
100 if (messageCount == 0) return false;
101 RunnableLock lock = removeFirst ();
102 if (lock == null) return true;
103 synchronized (lock) {
104 syncThread = lock.thread;
105 try {
106 lock.run ();
107 } catch (Throwable t) {
108 lock.throwable = t;
109 SWT.error (SWT.ERROR_FAILED_EXEC, t);
110 } finally {
111 syncThread = null;
112 lock.notifyAll ();
113 }
114 }
115 return true;
116 }
117
118
119 /**
120 * Causes the <code>run()</code> method of the runnable to
121 * be invoked by the user-interface thread at the next
122 * reasonable opportunity. The thread which calls this method
123 * is suspended until the runnable completes.
124 *
125 * @param runnable code to run on the user-interface thread.
126 *
127 * @exception SWTException <ul>
128 * <li>ERROR_FAILED_EXEC - if an exception occured when executing the runnable</li>
129 * </ul>
130 *
131 * @see #asyncExec
132 */
133 protected void syncExec (Runnable runnable) {
134 if (display.isValidThread ()) {
135 if (runnable != null) runnable.run ();
136 return;
137 }
138 if (runnable == null) {
139 display.wake ();
140 return;
141 }
142 RunnableLock lock = new RunnableLock (runnable);
143 /*
144 * Only remember the syncThread for syncExec.
145 */
146 lock.thread = Thread.currentThread();
147 synchronized (lock) {
148 addLast (lock);
149 boolean interrupted = false;
150 while (!lock.done ()) {
151 try {
152 lock.wait ();
153 } catch (InterruptedException e) {
154 interrupted = true;
155 }
156 }
157 if (interrupted) {
158 Compatibility.interrupt();
159 }
160 if (lock.throwable != null) {
161 SWT.error (SWT.ERROR_FAILED_EXEC, lock.throwable);
162 }
163 }
164 }
165
166 }