Bug 4521 - Display.syncExec or Display.asyncExec can block processing of native events (1G03DF0)
Summary: Display.syncExec or Display.asyncExec can block processing of native events (...
Status: RESOLVED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: SWT (show other bugs)
Version: 2.0   Edit
Hardware: All All
: P4 normal (vote)
Target Milestone: ---   Edit
Assignee: Silenio Quarti CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2001-10-11 14:18 EDT by Dirk Baeumer CLA
Modified: 2002-07-31 16:55 EDT (History)
0 users

See Also:


Attachments
Example code (1.91 KB, text/plain)
2002-07-24 04:54 EDT, Dirk Baeumer CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Dirk Baeumer CLA 2001-10-11 14:18:16 EDT
Run the attached test case. I tested it on a Sun JDK 1.2.2.

	Some notes:
		- the problem occures with both syncExec and asyncExec.
		- the problem even showed up on my system if both threads have the same priority (NORM_PRIORITY). I only
		  changed to priority to make sure that the problem shows up.


=================== Test Case =====================================
package com.oti.dbaeumer.swt.prs;

import com.ibm.swt.*;
import com.ibm.swt.events.*;
import com.ibm.swt.layout.*;
import com.ibm.swt.widgets.*;

public class PR_1G03DF0 {
	Shell shell;
	Table table;
	Button button;
	
	public PR_1G03DF0() {
	}
	
	public PR_1G03DF0 close () {
		if ((shell != null) && (!shell.isDisposed ())) shell.dispose ();
		shell= null;
		table= null;
		return this;
	}
	
	public PR_1G03DF0 open () {
		shell = new Shell ();
		shell.setText ("Block Example");
		shell.setSize (300, 200);
		shell.setLayout(new GridLayout());
	
		table= new Table(shell, SWT.FULL_SELECTION | SWT.HIDE_SELECTION | SWT.BORDER);
		GridData gd= new GridData();
		gd.horizontalAlignment= gd.FILL; gd.grabExcessHorizontalSpace= true;
		gd.verticalAlignment= gd.FILL; gd.grabExcessVerticalSpace= true;
		table.setLayoutData(gd);
		
		table.setHeaderVisible(true);
		table.setLinesVisible(true);
		TableColumn tc1= new TableColumn(table, SWT.NONE);
		tc1.setWidth(80);
		tc1.setText("Column 1");
		TableColumn tc2= new TableColumn(table, SWT.NONE);
		tc2.setWidth(80);
		tc2.setText("Column 2");
		
		for (int i= 0; i < 2; i++) {
			TableItem item= new TableItem(table, SWT.NONE);
			item.setText(0, "Item " + i);
			item.setText(1, "Item " + i);
		}
		
		table.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				System.out.println("Element selected");
			}
		});
		
		shell.open ();
		return this;
	}
	
	public PR_1G03DF0 run () {
		Display display = shell.getDisplay ();
		while (!shell.isDisposed ()) {
			if (!display.readAndDispatch ()) display.sleep ();
		}
		return this;
	}
	
	public static void main(java.lang.String[] args) {
		PR_1G03DF0 window= new PR_1G03DF0().open();
		final Display display= window.shell.getDisplay();
		
		// Only need to make sure the problem shows up.
		Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
		
		Thread thread= new Thread(new Runnable() {
			public void run() {
				int counter= 0;
				do {
					// display.asyncExec(new Runnable() {
					display.syncExec(new Runnable() {
						public void run() {
						}
					});
					counter++;
					if (counter == 10000) {
						System.out.println("10000 items produced");
						counter= 0;
					}
				} while (true);	
			}
		}, "Producer");


		// Only need to make sure the problem shows up.
		thread.setPriority(Thread.MAX_PRIORITY);		
		thread.start();
		
		window.run().close();
	}
}

NOTES:

	VI (8/28/00 4:10:21 PM)
	I have tried this example on Windows 98.  With the priorities as set above, I get the behaviour that the table selection events are not
	getting processed but this is what I would expect to happen because the UI thread has been given such a low relative priority.
	When I changed the example so that both threads have the NORM_PRIORITY thread priority, the UI events get processed regularly.
	I tried this both under J9 and JDK 1.2.2.  Is there something I am missing?

DB (8/29/00 10:21:14 AM)
	I sometimes get the behavior on my machine even if I set the priority of both threads to NORM_PRIORITY. In general I
	have the following problem with the example from above:

	- I start a thread having a display. This thread processes UI events. Lets call the thread the UI thread.
	- I start a second thread that post runnable synchronously into the UI thread. Lets call the thread the producer thread.

	Now you get the following behavior: 
		- the UI thread gets activated every time the producer thread post the runnable into the UI thread, because the
		  runnable is posted using syncExec. At this point the producer thread waits until the runnable is executed.
		- the UI thread executes the event in the method runAsyncMessages(). So the UI thread is active. After the
		  runnable is executed via the call "look.run()"  the "synchronized (lock)" block is finished and a thread scheduling
		  can occur (which is very probably since most VM schedule threads after a synchronized block of after a notifyAll() 
		  call). If the producer thread gets activated then it produces a new runnable and post it synchronously into the event
		  queue.
		- This again activates the UI thread. Since it is still in the do-while(true)  loop in runAsyncMessages it removes the
		  first runnable form the message queue (and there is one since the produces thread has just created one) and executes
		  the runnable. This produces the blocking of the native UI events since the runAsyncMessages method is never left.

	The problem that I have with this behaviour is, that 
		1.) although there are native events created long before the runnables have been posted into the event queue, and 
		2.) I guarantee the activation of the UI thread by using syncExec 

	the native UI events from the native event queue get never "worked off" because the UI thread never leaves the 
	runAsyncMessages method. In my opinion that should not happen even if the UI thread runs on LOW_PRIORITY.

	Using asyncExec instead of syncExec doesn't change anything in general. If I use asyncExec the event thread gets activated
	from time to time and should also check in runAsyncMessages if there are new native UI events which wait for processing.

SN (2/5/01 2:46:40 PM)
	No further action.  We were unable to get the code to fail.

DB (06.02.2001 12:19:33)
	This is still an open issue in Eclipse and it seems that VI was able to reproduce the problem.

	McQ (26/06/2001 10:37:38 AM) -
		VI claims that she was *unable* to reproduce the problem.
		SSQ should read this to see if he understands what's going on.
Comment 1 DJ Houghton CLA 2001-10-29 16:19:06 EST
PRODUCT VERSION:
	SWT 0.45.

Comment 2 Steve Northover CLA 2002-07-18 11:18:40 EDT
Dirk, we fixed a bug recently where repeately asyncExec'ing caused the UI 
thread to block.  What this what you were seeing?

Can we close this PR?  It seems that when you set the thread priority low for 
the UI thread, the UI becomes unresponsive but this is expected.
Comment 3 Dirk Baeumer CLA 2002-07-24 04:53:52 EDT
The problem still exists. The code has been moved to a new class but still has 
the same characteristics. If a thread produces more runnables and post them to 
the UI thread using async or sync exec than the UI thread can process, then the 
do {....} while(true) loop in Synchronizer is never left and therefore no 
native events are processed.

I created a smaller example that demonstrates this. It is attached to the PR. 
Run it and try to press the button or the shell's close box. Nothing happens. 
Clicking on the close box several times opens a dialog saying that the 
application is not responding to user events.
Comment 4 Dirk Baeumer CLA 2002-07-24 04:54:26 EDT
Created attachment 1728 [details]
Example code
Comment 5 Steve Northover CLA 2002-07-31 16:55:22 EDT
Fixed > 20020731.  Note that then old example code hangs Windows 98 because the 
UI thread exits and the producer thread keeps going, adding work to the queue 
which is no longer getting taken off.

Here is new DB example code that does not hang Windows 98 and works:

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;

public class PR_4521 {

	Shell shell;
	Button button;
	
	public PR_4521() {
	}
	
	public PR_4521 close () {
		if ((shell != null) && (!shell.isDisposed ())) shell.dispose ();
		shell= null;
		return this;
	}
	
	public PR_4521 open () {
		shell = new Shell ();
		shell.setText ("Block Example");
		shell.setSize (300, 200);
		shell.setLayout(new GridLayout());
	
		button= new Button(shell, SWT.PUSH);
		button.setText("Press Me");
		button.addSelectionListener(new SelectionListener() {
			public void widgetSelected(SelectionEvent e) {
				System.out.println("Button pressed");
			}
			public void widgetDefaultSelected(SelectionEvent e) {
			}
		});
			
		shell.open ();
		return this;
	}
	
	public PR_4521 run () {
		Display display = shell.getDisplay ();
		while (!shell.isDisposed ()) {
			if (!display.readAndDispatch ()) display.sleep ();
		}
		return this;
	}
	
	public static void main(java.lang.String[] args) {
		PR_4521 window= new PR_4521().open();
		final Display display= window.shell.getDisplay();
		final Shell shell = window.shell;
				
		Thread producer= new Thread(new Runnable() {
			public void run() {
				do {
					if (shell.isDisposed()) break;
					display.asyncExec(new Runnable() {
						public void run() {
							try {
							
	Thread.currentThread().sleep(10);
							} catch 
(InterruptedException e) {
							}
						}
					});
				} while (true);	
			}
		}, "Producer");


		producer.start();
		
		window.run().close();
	}
}