1 /******************************************************************************* 2 * Copyright (c) 2000, 2008 IBM Corporation and others. 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 * Port to the D programming language: 11 * Frank Benoit <benoit@tionex.de> 12 *******************************************************************************/ 13 module org.eclipse.swt.widgets.Synchronizer; 14 15 import org.eclipse.swt.widgets.Display; 16 import org.eclipse.swt.widgets.RunnableLock; 17 import org.eclipse.swt.internal.Compatibility; 18 import java.lang.all; 19 20 import org.eclipse.swt.SWT; 21 import java.lang.Thread; 22 import org.eclipse.swt.graphics.Device; 23 version(Tango){ 24 import tango.core.Exception; 25 } else { // Phobos 26 import java.nonstandard.sync.exception: SyncException; 27 } 28 29 /** 30 * Instances of this class provide synchronization support 31 * for displays. A default instance is created automatically 32 * for each display, and this instance is sufficient for almost 33 * all applications. 34 * <p> 35 * <b>IMPORTANT:</b> Typical application code <em>never</em> 36 * needs to deal with this class. It is provided only to 37 * allow applications which require non-standard 38 * synchronization behavior to plug in the support they 39 * require. <em>Subclasses which override the methods in 40 * this class must ensure that the superclass methods are 41 * invoked in their implementations</em> 42 * </p> 43 * 44 * @see Display#setSynchronizer 45 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> 46 */ 47 public class Synchronizer { 48 Display display; 49 int messageCount; 50 RunnableLock [] messages; 51 Object messageLock; 52 Thread syncThread; 53 static const int GROW_SIZE = 4; 54 static const int MESSAGE_LIMIT = 64; 55 56 /** 57 * Constructs a new instance of this class. 58 * 59 * @param display the display to create the synchronizer on 60 */ 61 public this (Display display) { 62 this.display = display; 63 messageLock = new Object (); 64 } 65 66 void addLast (RunnableLock lock) { 67 bool wake = false; 68 synchronized (messageLock) { 69 if (messages is null) messages = new RunnableLock [GROW_SIZE]; 70 if (messageCount is messages.length) { 71 RunnableLock[] newMessages = new RunnableLock [messageCount + GROW_SIZE]; 72 System.arraycopy (messages, 0, newMessages, 0, messageCount); 73 messages = newMessages; 74 } 75 messages [messageCount++] = lock; 76 wake = messageCount is 1; 77 } 78 if (wake) display.wakeThread (); 79 } 80 81 /** 82 * Causes the <code>run()</code> method of the runnable to 83 * be invoked by the user-interface thread at the next 84 * reasonable opportunity. The caller of this method continues 85 * to run in parallel, and is not notified when the 86 * runnable has completed. 87 * 88 * @param runnable code to run on the user-interface thread. 89 * 90 * @see #syncExec 91 */ 92 public void asyncExec (Runnable runnable) { 93 if (runnable is null) { 94 display.wake (); 95 return; 96 } 97 addLast (new RunnableLock (runnable, false)); 98 } 99 100 int getMessageCount () { 101 synchronized (messageLock) { 102 return messageCount; 103 } 104 } 105 106 void releaseSynchronizer () { 107 display = null; 108 messages = null; 109 messageLock = null; 110 syncThread = null; 111 } 112 113 RunnableLock removeFirst () { 114 synchronized (messageLock) { 115 if (messageCount is 0) return null; 116 RunnableLock lock = messages [0]; 117 System.arraycopy (messages, 1, messages, 0, --messageCount); 118 messages [messageCount] = null; 119 if (messageCount is 0) { 120 if (messages.length > MESSAGE_LIMIT) messages = null; 121 } 122 return lock; 123 } 124 } 125 126 bool runAsyncMessages () { 127 return runAsyncMessages (false); 128 } 129 130 bool runAsyncMessages (bool all) { 131 bool run = false; 132 do { 133 RunnableLock lock = removeFirst (); 134 if (lock is null) return run; 135 run = true; 136 scope (exit) { 137 if (!lock.syncExec) { 138 // Release handle of lock#cond. 139 // If not released here, the handle will not be released until the next GC works. 140 destroy(lock); 141 } 142 } 143 synchronized (lock) { 144 syncThread = lock.thread; 145 try { 146 lock.run (); 147 } catch (Exception t) { 148 lock.throwable = t; 149 SWT.error (SWT.ERROR_FAILED_EXEC, t); 150 } finally { 151 syncThread = null; 152 lock.notifyAll (); 153 } 154 } 155 } while (all); 156 return run; 157 } 158 159 /** 160 * Causes the <code>run()</code> method of the runnable to 161 * be invoked by the user-interface thread at the next 162 * reasonable opportunity. The thread which calls this method 163 * is suspended until the runnable completes. 164 * 165 * @param runnable code to run on the user-interface thread. 166 * 167 * @exception SWTException <ul> 168 * <li>ERROR_FAILED_EXEC - if an exception occurred when executing the runnable</li> 169 * </ul> 170 * 171 * @see #asyncExec 172 */ 173 public void syncExec (Runnable runnable) { 174 RunnableLock lock = null; 175 synchronized (Device.classinfo) { 176 if (display is null || display.isDisposed ()) SWT.error (SWT.ERROR_DEVICE_DISPOSED); 177 if (!display.isValidThread ()) { 178 if (runnable is null) { 179 display.wake (); 180 return; 181 } 182 lock = new RunnableLock (runnable, true); 183 /* 184 * Only remember the syncThread for syncExec. 185 */ 186 lock.thread = Thread.currentThread(); 187 addLast (lock); 188 } 189 } 190 if (lock is null) { 191 if (runnable !is null) runnable.run (); 192 return; 193 } 194 scope (exit) { 195 // Release handle of lock#cond. 196 // If not released here, the handle will not be released until the next GC works. 197 destroy(lock); 198 } 199 synchronized (lock) { 200 bool interrupted = false; 201 while (!lock.done ()) { 202 try { 203 lock.wait (); 204 } catch (SyncException e) { 205 interrupted = true; 206 } 207 } 208 if (interrupted) { 209 Compatibility.interrupt(); 210 } 211 if (lock.throwable !is null) { 212 SWT.error (SWT.ERROR_FAILED_EXEC, lock.throwable); 213 } 214 } 215 } 216 217 }