Invalid thread access even with XstartOnFirstThread in vm args

I have an embryonic Java Web Start application with one class. It works on Windows and Linux, but it gets a terrible error accessing an invalid stream on Mac OS X. I understand that this has been addressed elsewhere. I spent two full days cleaning the Internet and implemented all the solutions, but the problem persists.

I understand that SWT calls must be made from the main thread that takes place here. Correct me if I am wrong about this.

I will post 3 snippets below, the application source code, the corresponding part of the jnlp file, and the error message on Mac. The question is at the end.


JAVA SOURCE CODE

package client; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; public class AccountWindow { public static void main(String[] args) { Display display = new Display(); **// error occurs here** Shell shell = new Shell(display); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose(); } } 

JNLP SNIPPET

 <resources os="Mac\ OS\ X" arch="x86_64"> <j2se version="1.5+" java-vm-args="-XstartOnFirstThread" /> <nativelib href="swt-4.2-cocoa-macosx-x86_64.jar" /> </resources> 

ERROR MESSAGE

 org.eclipse.swt.SWTException: Invalid thread access at org.eclipse.swt.SWT.error(Unknown Source) at org.eclipse.swt.SWT.error(Unknown Source) at org.eclipse.swt.SWT.error(Unknown Source) at org.eclipse.swt.widgets.Display.error(Unknown Source) at org.eclipse.swt.widgets.Display.createDisplay(Unknown Source) at org.eclipse.swt.widgets.Display.create(Unknown Source) at org.eclipse.swt.graphics.Device.<init>(Unknown Source) at org.eclipse.swt.widgets.Display.<init>(Unknown Source) at org.eclipse.swt.widgets.Display.<init>(Unknown Source) at client.AccountWindow.main(AccountWindow.java:16) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at com.sun.javaws.Launcher.executeApplication(Launcher.java:1550) at com.sun.javaws.Launcher.executeMainClass(Launcher.java:1488) at com.sun.javaws.Launcher.doLaunchApp(Launcher.java:1299) at com.sun.javaws.Launcher.run(Launcher.java:114) at java.lang.Thread.run(Thread.java:637) 

PLEASE NOTE
- The display.syncExec solution, available at http://www.eclipse.org/swt/faq.php#javawebstart , is not applicable since you need a display before calling it. An error occurs when I try to create a mapping.
- I used JaNeLa to check the jnlp file and there are no red errors.
- <resources os = "Mac \ OS \ X" arch = "i386"> is interpreted correctly because the correct swt library is loading.
- You can reproduce the error at http://thelinkjuicer.com/gannonline/client.jnlp


AND NOW QUESTION
Can anyone see anything in the source code or jnlp fragment that will lead to an error?
Secondary question: how can you determine if the -XstartOnFirstThread argument is actually being read by the VM?

+4
source share
2 answers

Obviously, your main method is not executing in the main thread. In the stack trace, you can see that the launcher starts in another thread, and then Launcher indirectly calls main . This, unfortunately, is just a diagnosis, I'm not sure about the solution. I did a similar thing (SWT application via Java Web Start), but I donโ€™t remember how we decided, if at all.

After checking the com.sun.javaws.Launcher source code, it is completely unclear how this could be made to work. The Launcher.launch method launches a new thread in which your main method runs. You can follow the code to recreate the exact stack you get.

The main entry point to Java Web Start shows that the main thread dies shortly after launch.

Update

I dug up something: this Eclipse error report suggests that the problem may be related to this:

 <resources> <j2se version="1.4+" /> <jar href="client.jar" /> </resources> 

The parser uses the j2se specification here and ignores the later, more specific ones. Try deleting the line <j2se...

Update 2

Now I dug this from here :

 com.apple.concurrent.Dispatch.getInstance().getNonBlockingMainQueueExecutor().execute( new Runnable() { public void run() { final Display display = Display.getDefault(); while (!display.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } }); 

It actually looks like something workable. It does exactly what I described in my comment below: fixes to the main thread through a mechanism specifically created for this purpose. Try to adapt this to your needs. You might not even need -XstartOnFirstThread with this.

Update 3

I finally found my old SWT-JWS project. He got it in him:

 <resources os="Mac OS X" arch="x86_64"> <j2se version="1.6+" java-vm-args="-XstartOnFirstThread"/> <jar href="swt-cocoa-macosx-x86-64-3.6.2.jar" /> </resources> 

and it works. It does not have a j2se default j2se , this element is only displayed in an OSX-specific entry.

+5
source

This is the answer to the secondary question: "How can you determine if the -XstartOnFirstThread argument is actually being read by the VM?" (or related question): "How can you detect if a -XstartOnFirstThread VM has been transferred?" ) I looked at java.lang.management.RuntimeMXBean.getInputArguments() , but -XstartOnFirstThread not included in the returned List . After some research, I was able to find out something, so I hope this helps someone else who was in my shoes.

According to this link , there are several environment variables set by the launcher. Among them:

 JAVA_MAIN_CLASS_pid JAVA_STARTED_ON_FIRST_THREAD_pid 

Use System.getenv() to get Map environment variables. From there, you can iterate through entrySet() until you find Entry with getKey() whose return value starts with "JAVA_MAIN_CLASS_" . If the detected Entry getValue() contains the name of your main class, you can use the rest of the key to determine pid.

Once you have the pid, find the line "JAVA_STARTED_ON_FIRST_THREAD_pid" in the Map environment. If it exists and has a value of "1" , the process was started with -XstartOnFirstThread . Otherwise, the process was started without a flag.

This probably will not work in an unsigned WebStart application, as the System.getenv() method is disabled by default. But in a signed webstart application or in a regular Java application, this works.

Hope this helps,

0
source

Source: https://habr.com/ru/post/981545/


All Articles