Runtime.exec() problem

Hello,

I have written a separate GUI part in Swing for my game. So when the player sets his user name and other settings, this Java application starts the other one using the exec() method. The problem is my game crashes immediately after startup, throwing out messages I only saw when binding native DLLs with JNI.

My other application (the game) does this: it loads all the settings and other stuff, then it creates a JFrame. The error occurs in the JFrame constructor, right before I call super():

public Game() { super("My game");

This is the code I’m using to start the game:
`
Process proc = Runtime.getRuntime().exec(
new String[] {“javaw”, “-cp”, “bin;.”, “com.mygame.Game”},
new String[] {“dd”},
new File(“D:\Tgame2”));

BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line = null;
while ((line = in.readLine()) != null)
System.out.println(line);
`

This is the same as if I had written
javaw -cp bin;. com.mygame.Game dd
while being in the D:\Tgame2 directory.

This is the output I retrieved through the BufferedReader:

`Starting the game, press ESC to quit…
Loading settings… OK

An unexpected exception has been detected in native code outside the VM.
Unexpected Signal : EXCEPTION_ACCESS_VIOLATION (0xc0000005) occurred at PC=0x3284C7D
Function=AWTIsHeadless+0x17AD
Library=D:\Java\jre\bin\awt.dll

Current Java thread:
at sun.awt.windows.WToolkit.init(Native Method)
at sun.awt.windows.WToolkit.run(WToolkit.java:231)
at java.lang.Thread.run(Thread.java:534)

Dynamic libraries:
0x00400000 - 0x00407000 D:\Java\bin\javaw.exe
0x77F50000 - 0x77FF7000 C:\WINDOWS\System32\ntdll.dll
0x77E60000 - 0x77F47000 C:\WINDOWS\system32\kernel32.dll
0x77DD0000 - 0x77E5D000 C:\WINDOWS\system32\ADVAPI32.dll
0x78000000 - 0x78087000 C:\WINDOWS\system32\RPCRT4.dll
0x77D40000 - 0x77DCD000 C:\WINDOWS\system32\USER32.dll
0x7F000000 - 0x7F042000 C:\WINDOWS\system32\GDI32.dll
0x77C10000 - 0x77C63000 C:\WINDOWS\system32\MSVCRT.dll
0x76390000 - 0x763AC000 C:\WINDOWS\System32\IMM32.DLL
0x629C0000 - 0x629C8000 C:\WINDOWS\System32\LPK.DLL
0x72FA0000 - 0x72FFA000 C:\WINDOWS\System32\USP10.dll
0x5A800000 - 0x5A817000 C:\Program Files\Spyware Doctor\Tools\eg.dat
0x77120000 - 0x771AB000 C:\WINDOWS\system32\oleaut32.dll
0x4FEC0000 - 0x4FFE6000 C:\WINDOWS\system32\OLE32.DLL
0x5A000000 - 0x5A018000 C:\Program Files\Spyware Doctor\Tools\klg.dat
0x00A30000 - 0x00A4F000 C:\Program Files\Spyware Doctor\tools\swpg.dat
0x76BF0000 - 0x76BFB000 C:\WINDOWS\System32\PSAPI.DLL
0x08000000 - 0x08138000 D:\Java\jre\bin\client\jvm.dll
0x76B40000 - 0x76B6C000 C:\WINDOWS\System32\WINMM.dll
0x10000000 - 0x10007000 D:\Java\jre\bin\hpi.dll
0x76F90000 - 0x76FA0000 C:\WINDOWS\System32\Secur32.dll
0x003F0000 - 0x003FE000 D:\Java\jre\bin\verify.dll
0x00BF0000 - 0x00C09000 D:\Java\jre\bin\java.dll
0x00820000 - 0x0082D000 D:\Java\jre\bin\zip.dll
0x031F0000 - 0x032FF000 D:\Java\jre\bin\awt.dll
0x73000000 - 0x73023000 C:\WINDOWS\System32\WINSPOOL.DRV
0x03310000 - 0x03360000 D:\Java\jre\bin\fontmanager.dll
0x51000000 - 0x5104D000 C:\WINDOWS\System32\ddraw.dll
0x73BC0000 - 0x73BC6000 C:\WINDOWS\System32\DCIMAN32.dll
0x5C000000 - 0x5C0C8000 C:\WINDOWS\System32\D3DIM700.DLL
0x74720000 - 0x74764000 C:\WINDOWS\System32\MSCTF.dll
0x07450000 - 0x0747B000 C:\WINDOWS\System32\msctfime.ime
0x76C90000 - 0x76CB2000 C:\WINDOWS\system32\imagehlp.dll
0x6D510000 - 0x6D58D000 C:\WINDOWS\system32\DBGHELP.dll
0x77C00000 - 0x77C07000 C:\WINDOWS\system32\VERSION.dll

Heap at VM Abort:
Heap
def new generation total 576K, used 226K [0x10010000, 0x100b0000, 0x104f0000)
eden space 512K, 31% used [0x10010000, 0x10038998, 0x10090000)
from space 64K, 100% used [0x100a0000, 0x100b0000, 0x100b0000)
to space 64K, 0% used [0x10090000, 0x10090000, 0x100a0000)
tenured generation total 1408K, used 85K [0x104f0000, 0x10650000, 0x14010000)
the space 1408K, 6% used [0x104f0000, 0x10505628, 0x10505800, 0x10650000)
compacting perm gen total 4096K, used 2309K [0x14010000, 0x14410000, 0x18010000)
the space 4096K, 56% used [0x14010000, 0x14251400, 0x14251400, 0x14410000)

Local Time = Tue Sep 12 18:10:56 2006
Elapsed Time = 1

The exception above was detected in native code outside the VM

Java VM: Java HotSpot™ Client VM (1.4.2_04-b05 mixed mode)

An error report file has been saved as hs_err_pid4144.log.

Please refer to the file for further information.

#`

As you can see from the first two lines, the game is working in the beginning (loading settings), but then it crashes when it needs to create a new JFrame. Also, the error is apparently in D:\Java\jre\bin\awt.dll

Any idea how I can fix this? Is there something special regarding to loading other Java GUI applications?

Why are you running these as two different processes? Why not have the initial gui be part of the same process as your game? If you need to, run them in different threads. Generally speaking you’re heading down the wrong path if your internally developed app is two different processes running at the same time.

I’ve tried the same thing before. Runtime.exec() seemed to work for non-Java programs, but not for Java or any program that used Java’s VM.

I don’t know what the problem is. Maybe both processes are trying to use the same instance of the virtual machine. Different windows of an Internet browser share the VM for multiple instances of the same applet, so maybe this is a similar issue.

I never resolved the problem when I was using Runtime.exec, but I did figure out that if I didn’t use any static variables to store game state in the applet that I could run multiple instances of the same applet at the same time.

The point is that you are going to spend a lot of time trying to do something that is completely unnecessary. I doubt anyone here has run into this problem, because it is not something that would be tried. You can just put Game game = new Game(); game.run(); instead of trying to invoke a new process.

Actually, no, I cannot do that. The reason why I started this whole process thing was because I couldn’t start the game frame with Game game = new Game(); because then the newly created frame never becomes the focusOwner(), and my code requires that to be able to draw.

The following is the process:

  • I start the GUI frame
  • The GUI frame creates the Game frame with Game g = new Game();
  • Game creates a frame and does some initialization
  • Game enters the loop() method
    [li]The loop method goes like this:
public void loop() {
	while (gameRunning) {
		if (isFocusOwner()) {           // ------------- notice this line --------------
			if (now - Globals.timer >= Globals.frameDiff) {
				Globals.timer = now;
				doAction();   // do logic
			}
			doDraw();
		} else
			try { Thread.sleep(100); } catch (Exception ex) {}
	}
}

]Notice the line where it says if (isFocusOwner()); this will never be true. For some reason Swing needs a few seconds to initialize the JFrame, and only then it will become the focus owner. So if I comment out the loop() the window will show up and actions will be handled properly. But the loop() won’t get started and the game is not played.
If the loop() is not commented out, it will just continue forever, and the window will never be drawn

I also tried like this: in the Game constructor, I wrote

Thread t = new Thread(new Runnable() {
  public void run() {
    try {
       while (!mainFrame.isFocusOwner())
             Thread.sleep(100);
    } catch (Exception ex) {}
    mainFrame.loop();
  }
});
t.start();

This way it will work, but since loop() is called from another thread, the drawing is slow, it stops from time to time etc.

I even tried EventQueue.invokeLater(), and it again worked like this, but now the mouse and the keyboard weren’t reacting.

As it stands now, the game only works when it is started as a stand-alone application. Then it is the focusOwner() and the keyboard and the mouse are reacting properly. It didn’t help that after the game was started I disposed of the Swing window, or that I’ve set the Game frame toFront()

So the only option I could think of was starting the game as a stand-alone application by another Java application, but it seems I can’t do that either >:(

I know one solution would be to draw everything on the same JFrame, but I would really rather like to have separate code. One where I setup the game, and another one where I play it.

I also tried like this:

startBtn.addActionListener(new ActionListener() {
	public void actionPerformed(ActionEvent ae) {
		Game.SINGLE_PLAYER = true;
		Game.IS_SERVER = true;
		Game.showWindow = true;
		Game.userName = (String)nameText.getSelectedItem();
		Game.password = "";
		Game.map = (byte)mapList.getSelectedIndex();
		self.dispose();
		
		Thread t = new Thread(new Runnable() {
			public void run() {
				Game.start();
			}
		});
		t.start();
	}
});

The FPS is 0, and when I hit a key on my keyboard it takes around 10 seconds for it to react. I tried setting the thread priority to max but this didn’t do a thing.

It’s hard to say what you’ve really got going without taking a hard look at your code. But my hunch is you’ve kinda dug yourself into a hole. Anytime you find yourself doing something unusual like trying to launch another process, that’s usually a red flag that your in trouble.

Getting Java2D to work with games can be difficult. You might consider backing off a bit. Taking your core logic code and building a new framework around it. Try to keep it simple.

One of the few instances where a second VM is needed, would be a configuration dialog, where you choose which java2d properties you want set.

Well I can provide the entire game code in a ZIP file if anyone’s interested in taking a look at it :wink:

There’s really no reason for me to back off now. The game as it is works fine. I even started writing the client/server part. It draws out whatever I want the way I want. In other words, the “engine” is almost finished. From now on I can just add elements to the game and it would work.

I always have problems with Swing in situations like this. I remember once in a client/server application I had the login dialog, which would then create a thread which would display the logo and do additional checks, and then create another thread which would display the main application frame. Except that in that case I wasn’t worried about FPS’s :slight_smile:

One of the reasons why I decided to make a game in Java was the thought of not having problems with making my own GUI, because I could simply relly on Swing… and now I’ve lost a whole day trying to figure this out… >:(

Did you try isActive(); on the JFrame instead of isFocusOwner(); ?

There is also a method requestFocus() , I remember I needed to do that before registering a keylistener on a component.

Koen

why focus owner? why not just isFocused?

Swing is tricky, I’m quite sure that there’s a good solution to this, and not starting more VMs.

I think you mean Swing, all I use to make games is Java2D and it works great ;). Swing, on the other hand, is hard since it introduces EDT threading headaches.

I got Runtime.exec() to work on windows, I think what you’re missing is the ‘.exe’ part after ‘bin/java’. You can check out my code here: http://www.java-gaming.org/forums/index.php?topic=14092.0

Beware that it only works on Windows and doesn’t even work with WebStart (can’t find the jar files since they’re cached). For what you’re doing though, its doesn’t sound necessary to launch a new VM.

Keith

I had similar (?) problem some time ago. I was writing an eclipse plugin, and I needed to launch an external program from it. In fact I needed to launch a batch file (".bat"), containing just a line like:

java -jar something.jar

I launched it like this:

Process process = Runtime.getRuntime().exec("...something...", null, dir);
process.waitFor();

It always simple froze, and I have no idea why. I AGREE that there are better ways to do same thing, but still I don’t understand why it didn’t work.

It could be because of a space character in a directory name which screws things up unless you use double quotes (""), see swpalmer’s last post in the thread I linked to.

isActive() and isFocus() didn’t change anything. I tried putting requestFocus() at several places, I even made a separate thread which would invoke it every second, with no result.

If I put true in the condition, then the map will be drawn out, but the cursor and mouse won’t react, and it says the FPS is 0…

`public void loop() {
oneSecond = System.currentTimeMillis();

while (gameRunning) {
	if ([b]true[/b]) {
		long now = System.currentTimeMillis();
		if (now - oneSecond >= 1000) {
			oneSecond += 1000;
			fps = fpsCounter;
			fpsCounter = 0;
		}
		System.err.println("fps = " + fps);
		if (now - Globals.timer >= Globals.frameDiff) {
			Globals.timer = now;
			doAction();   // do logic
		}
		doDraw();
	} else
		try { Thread.sleep(100); } catch (Exception ex) {}
}

}`

Anyway I decided that wasting one day on this was enough. Now I start the game with parameters like this:
game --mode single --server yes --user csaba --password 12345 --window yes --map 3
In the end I’ll write a GUI in Delphi or C++ which will then just pass the parameters to the game and that’s it.

Oh yeah, and I noticed there was an error in the code I posted previously. I must have accidentally deleted fpsCounter++ beneath the while (gameRunning) line. Anyway, it didn’t change a thing.

[quote=“gcsaba2,post:9,topic:28317”]
Unless you’re using active rendering, multiple threads in combination with awt/swing is a recipe for disaster. Since neither is tread safe, you’re bound to bump into race conditions and/or deadlocks sooner or later. Btw, I don’t see why you would need to create a thread to show a splash screen or new window.
As someone already said, it’s hard to give more constructive feedback without knowing exactly what you’re doing. My gut feeling says threading issues. You might be blocking the EDT by starting the game loop on it. You might be drawing to a Graphics object from a non-EDT thread, which gives kind of unpredictable results, …