All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jogamp.newt.util.MainThread Maven / Gradle / Ivy

/*
 * Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved.
 * Copyright (c) 2010 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:
 *
 * - Redistribution of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistribution 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.
 *
 * Neither the name of Sun Microsystems, Inc. or the names of
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
 * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
 * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
 * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
 * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
 * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
 * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that this software is not designed or intended for use
 * in the design, construction, operation or maintenance of any nuclear
 * facility.
 */

package com.jogamp.newt.util;

import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

import javax.media.nativewindow.NativeWindowFactory;

import com.jogamp.common.os.Platform;
import com.jogamp.common.util.ReflectionUtil;

import jogamp.newt.Debug;
import jogamp.newt.NEWTJNILibLoader;

/**
 * NEWT Utility class MainThread

* *

* FIXME: Update this documentation! * This class just provides a main-thread utility, forking of a main java class * on another thread while being able to continue doing platform specific things * on the main-thread. The latter is essential for eg. MacOSX, where we continue * to run NSApp.run(). *

* * This class provides a startup singleton main thread, * from which a new thread with the users main class is launched.
* * Such behavior is necessary for native windowing toolkits, * where the windowing management must happen on the so called * main thread e.g. for Mac OS X !
* * Utilizing this class as a launchpad, now you are able to * use a NEWT multithreaded application with window handling within the different threads, * even on these restricted platforms.
* * To support your NEWT Window platform, * you have to pass your main thread actions to {@link #invoke invoke(..)}, * have a look at the {@link jogamp.newt.driver.macosx.WindowDriver NEWT Mac OSX Window} driver implementation.
* TODO: Some hardcoded dependencies exist in this implementation, * where you have to patch this code or factor it out.

* * If your platform is not Mac OS X, but you want to test your code without modifying * this class, you have to set the system property newt.MainThread.force to true.

* * The code is compatible with all other platform, which support multithreaded windowing handling. * Since those platforms won't trigger the main thread serialization, the main method * will be simply executed, in case you haven't set newt.MainThread.force to true.

* * Test case on Mac OS X (or any other platform):

    java -XstartOnFirstThread com.jogamp.newt.util.MainThread demos.es1.RedSquare -GL2 -GL2 -GL2 -GL2
 
* Which starts 4 threads, each with a window and OpenGL rendering.
*/ public class MainThread { private static final String MACOSXDisplayClassName = "jogamp.newt.driver.macosx.DisplayDriver"; private static final Platform.OSType osType; private static final boolean isMacOSX; private static final ThreadGroup rootThreadGroup; /** if true, use the main thread EDT, otherwise AWT's EDT */ public static final boolean HINT_USE_MAIN_THREAD; static { NativeWindowFactory.initSingleton(); NEWTJNILibLoader.loadNEWT(); HINT_USE_MAIN_THREAD = !NativeWindowFactory.isAWTAvailable() || Debug.getBooleanProperty("newt.MainThread.force", true); osType = Platform.getOSType(); isMacOSX = osType == Platform.OSType.MACOS; rootThreadGroup = getRootThreadGroup(); } public static boolean useMainThread = false; protected static final boolean DEBUG = Debug.debug("MainThread"); private static final MainThread singletonMainThread = new MainThread(); // one singleton MainThread private static final ThreadGroup getRootThreadGroup() { ThreadGroup rootGroup = Thread.currentThread( ).getThreadGroup( ); ThreadGroup parentGroup; while ( ( parentGroup = rootGroup.getParent() ) != null ) { rootGroup = parentGroup; } return rootGroup; } private static final Thread[] getAllThreads(int[] count) { int tn; Thread[] threads = new Thread[ rootThreadGroup.activeCount() ]; while ( ( tn = rootThreadGroup.enumerate( threads, true ) ) == threads.length ) { threads = new Thread[ threads.length * 2 ]; } count[0] = tn; return threads; } private static final List getNonDaemonThreads() { List res = new ArrayList(); int[] tn = { 0 }; Thread[] threads = getAllThreads(tn); for(int i = tn[0] - 1; i >= 0; i--) { final Thread thread = threads[i]; try { if(thread.isAlive() && !thread.isDaemon()) { res.add(thread); if(DEBUG) System.err.println("XXX0: "+thread.getName()+", "+thread); } } catch (Throwable t) { t.printStackTrace(); } } return res; } private static final int getNonDaemonThreadCount(List ignoreThreads) { int res = 0; int[] tn = { 0 }; Thread[] threads = getAllThreads(tn); for(int i = tn[0] - 1; i >= 0; i--) { final Thread thread = threads[i]; try { if(thread.isAlive() && !thread.isDaemon() && !ignoreThreads.contains(thread)) { res++; if(DEBUG) System.err.println("MainAction.run(): non daemon thread: "+thread); } } catch (Throwable t) { t.printStackTrace(); } } return res; } static class UserApp extends Thread { private final String mainClassNameShort; private final String mainClassName; private final String[] mainClassArgs; private final Method mainClassMain; private List nonDaemonThreadsAtStart; public UserApp(String mainClassName, String[] mainClassArgs) throws SecurityException, NoSuchMethodException, ClassNotFoundException { super(); this.mainClassName=mainClassName; this.mainClassArgs=mainClassArgs; final Class mainClass = ReflectionUtil.getClass(mainClassName, true, getClass().getClassLoader()); if(null==mainClass) { throw new ClassNotFoundException("MainAction couldn't find main class "+mainClassName); } mainClassNameShort = mainClass.getSimpleName(); mainClassMain = mainClass.getDeclaredMethod("main", new Class[] { String[].class }); mainClassMain.setAccessible(true); setName(getName()+"-UserApp-"+mainClassNameShort); setDaemon(false); if(DEBUG) System.err.println("MainAction(): instantiated: "+getName()+", is daemon "+isDaemon()+", main-class: "+mainClass.getName()); } @Override public void run() { nonDaemonThreadsAtStart = getNonDaemonThreads(); if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" start, nonDaemonThreadsAtStart "+nonDaemonThreadsAtStart); // start user app .. try { if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" invoke "+mainClassName); mainClassMain.invoke(null, new Object[] { mainClassArgs } ); } catch (InvocationTargetException ite) { ite.getTargetException().printStackTrace(); return; } catch (Throwable t) { t.printStackTrace(); return; } // wait until no more active non-daemon threads are running { int ndtr; while( 0 < ( ndtr = getNonDaemonThreadCount(nonDaemonThreadsAtStart) ) ) { if(DEBUG) System.err.println("MainAction.run(): post user app, non daemon threads alive: "+ndtr); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" user app fin: "+ndtr); } if ( useMainThread ) { if(isMacOSX) { try { if(DEBUG) { System.err.println("MainAction.main(): "+Thread.currentThread()+" MainAction fin - stopNSApp.0"); } ReflectionUtil.callStaticMethod(MACOSXDisplayClassName, "stopNSApplication", null, null, MainThread.class.getClassLoader()); if(DEBUG) { System.err.println("MainAction.main(): "+Thread.currentThread()+" MainAction fin - stopNSApp.X"); } } catch (Exception e) { e.printStackTrace(); } } else { if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" MainAction fin - System.exit(0)"); System.exit(0); } } } } private static UserApp mainAction; /** Your new java application main entry, which pipelines your application * @throws ClassNotFoundException * @throws NoSuchMethodException * @throws SecurityException */ public static void main(String[] args) throws SecurityException, NoSuchMethodException, ClassNotFoundException { final Thread cur = Thread.currentThread(); useMainThread = HINT_USE_MAIN_THREAD; if(DEBUG) { System.err.println("MainThread.main(): "+cur.getName()+ ", useMainThread "+ useMainThread + ", HINT_USE_MAIN_THREAD "+ HINT_USE_MAIN_THREAD + ", isAWTAvailable " + NativeWindowFactory.isAWTAvailable() + ", ostype "+osType+", isMacOSX "+isMacOSX); } if(!useMainThread && !NativeWindowFactory.isAWTAvailable()) { throw new RuntimeException("!USE_MAIN_THREAD and no AWT available"); } if(args.length==0) { return; } String mainClassName=args[0]; String[] mainClassArgs=new String[args.length-1]; if(args.length>1) { System.arraycopy(args, 1, mainClassArgs, 0, args.length-1); } mainAction = new UserApp(mainClassName, mainClassArgs); if(isMacOSX) { ReflectionUtil.callStaticMethod(MACOSXDisplayClassName, "initSingleton", null, null, MainThread.class.getClassLoader()); } if ( useMainThread ) { try { cur.setName(cur.getName()+"-MainThread"); } catch (Exception e) {} // dispatch user's main thread .. mainAction.start(); if(isMacOSX) { try { if(DEBUG) { System.err.println("MainThread.main(): "+cur.getName()+"- runNSApp"); } ReflectionUtil.callStaticMethod(MACOSXDisplayClassName, "runNSApplication", null, null, MainThread.class.getClassLoader()); } catch (Exception e) { e.printStackTrace(); } } if(DEBUG) { System.err.println("MainThread - wait until last non daemon thread ends ..."); } } else { // run user's main in this thread mainAction.run(); } } public static MainThread getSingleton() { return singletonMainThread; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy