Skip to content

Commit

Permalink
Bug628: Adding unit-test 'TestNewtCanvasSWTBug628ResizeDeadlock' expo…
Browse files Browse the repository at this point in the history
…sing NewtCanvasSWT asyncExec(..) bug w/ native parenting

The unit test shows, that while using JOGL's SWT GLCanvas Display's asyncExec(..) works properly,
but w/ NewtCanvasSWT on Windows does not.

NewtCanvasSWT differs w/:
  - Using native parenting [Newt GLWindow to SWT Canvas]
  - Processing native events in own NEWT EDT, w/ own Windows dispatch hook [For the child GLWindow only]
  • Loading branch information
sgothel committed Nov 29, 2012
1 parent 03d7433 commit 0bb202f
Show file tree
Hide file tree
Showing 4 changed files with 292 additions and 9 deletions.
3 changes: 2 additions & 1 deletion make/scripts/tests-x64.bat
Expand Up @@ -54,9 +54,10 @@ REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestP
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParenting04SWT %*

REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestSWTAccessor03AWTGLn %*
scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestSWTJOGLGLCanvas01GLn %*
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestSWTJOGLGLCanvas01GLn %*
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestNewtCanvasSWTGLn %*
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestNewtCanvasSWTBug628ResizeDeadlock %*
scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.swt.TestSWTBug643AsyncExec %*

REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestWindows01NEWT
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestGLWindows01NEWT
Expand Down
3 changes: 2 additions & 1 deletion make/scripts/tests.sh
Expand Up @@ -370,9 +370,10 @@ function testawtswt() {
#
#testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestSWTEclipseGLCanvas01GLn $*
#testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestSWTAccessor03AWTGLn $*
testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestSWTJOGLGLCanvas01GLn $*
#testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestSWTJOGLGLCanvas01GLn $*
#testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestNewtCanvasSWTGLn $*
#testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestNewtCanvasSWTBug628ResizeDeadlock $*
testawtswt com.jogamp.opengl.test.junit.jogl.swt.TestSWTBug643AsyncExec $*

#
# newt.awt (testawt)
Expand Down
Expand Up @@ -65,7 +65,7 @@

public class TestNewtCanvasSWTBug628ResizeDeadlock extends UITestCase {

static int duration = 1000;
static int duration = 500;

static class BigFlashingX implements GLEventListener
{
Expand Down Expand Up @@ -262,7 +262,7 @@ public void run() {
shell = new Shell( display );
Assert.assertNotNull( shell );
shell.setLayout( new FillLayout() );
composite = new Composite( shell, SWT.NONE );
composite = new Composite( shell, SWT.NO_BACKGROUND );
composite.setLayout( new FillLayout() );
Assert.assertNotNull( composite );
}});
Expand Down Expand Up @@ -301,10 +301,9 @@ public void test() throws InterruptedException, AWTException, InvocationTargetEx
dsc.init();

final GLWindow glWindow;
final NewtCanvasSWT canvas;
{
final GLProfile gl2Profile = GLProfile.get( GLProfile.GL2 ) ;
GLCapabilities caps = new GLCapabilities( gl2Profile ) ;
final GLCapabilities caps = new GLCapabilities( gl2Profile ) ;
glWindow = GLWindow.create( caps ) ;
glWindow.addGLEventListener( new BigFlashingX() ) ;
glWindow.addKeyListener(new KeyAdapter() {
Expand All @@ -314,7 +313,7 @@ public void keyTyped(com.jogamp.newt.event.KeyEvent e) {
glWindow.display();
}
});
canvas = NewtCanvasSWT.create( dsc.composite, 0, glWindow ) ;
NewtCanvasSWT.create( dsc.composite, 0, glWindow ) ;
}

dsc.display.syncExec( new Runnable() {
Expand Down Expand Up @@ -374,8 +373,7 @@ public void run() {
Assert.assertTrue("Deadlock @ dispatch: "+e0, false);
}

System.err.println("NewtCanvasAWT Dispose");
canvas.dispose();
// canvas is disposed implicit, due to it's disposed listener !

dsc.dispose();
}
Expand Down
@@ -0,0 +1,283 @@
/**
* Copyright 2012 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of JogAmp Community.
*/

package com.jogamp.opengl.test.junit.jogl.swt;

import java.awt.AWTException;
import java.lang.reflect.InvocationTargetException;

import org.eclipse.swt.SWT ;

import org.eclipse.swt.layout.FillLayout ;

import org.eclipse.swt.widgets.Composite ;
import org.eclipse.swt.widgets.Display ;
import org.eclipse.swt.widgets.Shell ;
import org.junit.Assume;
import org.junit.Test;

import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities ;
import javax.media.opengl.GLProfile;

import junit.framework.Assert;

import com.jogamp.nativewindow.swt.SWTAccessor;
import com.jogamp.newt.opengl.GLWindow ;
import com.jogamp.newt.swt.NewtCanvasSWT ;
import com.jogamp.opengl.swt.GLCanvas;
import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
import com.jogamp.opengl.test.junit.util.MiscUtils;
import com.jogamp.opengl.test.junit.util.UITestCase;

////////////////////////////////////////////////////////////////////////////////


public class TestSWTBug643AsyncExec extends UITestCase {

static int duration = 500;

////////////////////////////////////////////////////////////////////////////////

static void resetAsyncExecCount() {
synchronized(asyncExecCountSync) {
asyncExecCount=0;
}
}
static int incrAsyncExecCount() {
synchronized(asyncExecCountSync) {
asyncExecCount++;
return asyncExecCount;
}
}
static int getAsyncExecCount() {
synchronized(asyncExecCountSync) {
return asyncExecCount;
}
}
static Object asyncExecCountSync = new Object();
static int asyncExecCount = 0;

////////////////////////////////////////////////////////////////////////////////

static class AsyncExecFeederThread extends Thread {
volatile boolean shallStop = false;
private Display display ;
private int n ;

public AsyncExecFeederThread( Display display )
{
super();
this.display = display ;
}

final Runnable asyncAction = new Runnable() {
public void run()
{
++n ;
System.err.println("[A-i shallStop "+shallStop+", disposed "+display.isDisposed()+"]: Counter[loc "+n+", glob: "+incrAsyncExecCount()+"]");
} };

public void run()
{
System.err.println("[A-0 shallStop "+shallStop+", disposed "+display.isDisposed()+"]");

// final Display d = Display.getDefault();
final Display d = this.display;

while( !shallStop && !d.isDisposed() )
{
try
{
System.err.println("[A-n shallStop "+shallStop+", disposed "+d.isDisposed()+"]");
d.asyncExec( asyncAction );
d.wake();

Thread.sleep( 50L ) ;
} catch( InterruptedException e ) {
break ;
}
}
System.err.println("*R-Exit* shallStop "+shallStop+", disposed "+d.isDisposed());
}
}

////////////////////////////////////////////////////////////////////////////////

private volatile boolean shallStop = false;

static class SWT_DSC {
Display display;
Shell shell;
Composite composite;

public void init() {
SWTAccessor.invoke(true, new Runnable() {
public void run() {
display = new Display();
Assert.assertNotNull( display );
}});

display.syncExec(new Runnable() {
public void run() {
shell = new Shell( display );
Assert.assertNotNull( shell );
shell.setLayout( new FillLayout() );
composite = new Composite( shell, SWT.NO_BACKGROUND );
composite.setLayout( new FillLayout() );
Assert.assertNotNull( composite );
}});
}

public void dispose() {
Assert.assertNotNull( display );
Assert.assertNotNull( shell );
Assert.assertNotNull( composite );
try {
display.syncExec(new Runnable() {
public void run() {
composite.dispose();
shell.dispose();
}});
SWTAccessor.invoke(true, new Runnable() {
public void run() {
display.dispose();
}});
}
catch( Throwable throwable ) {
throwable.printStackTrace();
Assume.assumeNoException( throwable );
}
display = null;
shell = null;
composite = null;
}
}

private void testImpl(boolean useJOGLGLCanvas, boolean useNewtCanvasSWT) throws InterruptedException, AWTException, InvocationTargetException {
resetAsyncExecCount();

final SWT_DSC dsc = new SWT_DSC();
dsc.init();

{
final GLProfile gl2Profile = GLProfile.get( GLProfile.GL2 ) ;
final GLCapabilities caps = new GLCapabilities( gl2Profile ) ;

final GLAutoDrawable glad;
if( useJOGLGLCanvas ) {
glad = GLCanvas.create(dsc.composite, 0, caps, null, null);
} else if( useNewtCanvasSWT ) {
final GLWindow glWindow = GLWindow.create( caps ) ;
glad = glWindow;
NewtCanvasSWT.create( dsc.composite, 0, glWindow ) ;
} else {
throw new InternalError("XXX");
}
glad.addGLEventListener( new GearsES2() ) ;
}

dsc.display.syncExec( new Runnable() {
public void run() {
dsc.shell.setText( "NewtCanvasSWT Resize Bug Demo" ) ;
dsc.shell.setSize( 400, 450 ) ;
dsc.shell.open() ;
} } );

shallStop = false;

final int[] ayncExecCountBeforeExit = new int[] { 0 };

final AsyncExecFeederThread asyncExecFeeder;
{
asyncExecFeeder = new AsyncExecFeederThread( dsc.display) ;
asyncExecFeeder.start() ;
}

{
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(duration);
} catch (InterruptedException e) {}

ayncExecCountBeforeExit[0] = getAsyncExecCount();
asyncExecFeeder.shallStop = true;
try
{
asyncExecFeeder.join();
} catch( InterruptedException e ) { }
shallStop = true;
dsc.display.wake();
} } ).start();
}

try {
final Display d = dsc.display;
while( !shallStop && !d.isDisposed() ) {
final boolean r = d.readAndDispatch();
System.err.print(",");
if( !r ) {
dsc.display.sleep();
}
}
} catch (Exception e0) {
e0.printStackTrace();
Assert.assertTrue("Deadlock @ dispatch: "+e0, false);
}

// canvas is disposed implicit, due to it's disposed listener !

dsc.dispose();

System.err.println("AsyncExecCount before exit: " + ayncExecCountBeforeExit[0]);
Assert.assertTrue("AsyncExecCount not greater zero before dispose!", 0 < ayncExecCountBeforeExit[0]);
}

@Test
public void test01JOGLGLCanvas() throws InterruptedException, AWTException, InvocationTargetException {
testImpl(true /* useJOGLGLCanvas */, false /* useNewtCanvasSWT */);
}

@Test
public void test02NewtCanvasSWT() throws InterruptedException, AWTException, InvocationTargetException {
testImpl(false /* useJOGLGLCanvas */, true /* useNewtCanvasSWT */);
}

public static void main( String[] args ) {
for(int i=0; i<args.length; i++) {
if(args[i].equals("-time")) {
duration = MiscUtils.atoi(args[++i], duration);
}
}
System.out.println("durationPerTest: "+duration);
org.junit.runner.JUnitCore.main(TestSWTBug643AsyncExec.class.getName());
}

}

0 comments on commit 0bb202f

Please sign in to comment.