Opened 14 years ago

Closed 13 years ago

#69 closed defect (fixed)

No output from java.exe -? if another Java app is already running.

Reported by: Yoda_Java6 Owned by:
Priority: minor Milestone: GA
Component: general Version: 1.6.0-b22 RC2
Severity: low Keywords:
Cc:

Description

Start any java app, and try:

Java.exe -?
(no output - that is annoying)

Java.exe -version

(no output)

but

Java -fullversion

gives normal output

At least the help is needed :-)

Change History (10)

comment:1 by dmik, 14 years ago

Resolution: worksforme
Status: newclosed

Works here. Must be your local environment mix-up.

comment:2 by Yoda_Java6, 14 years ago

Milestone: RCGA
Priority: minormajor
Resolution: worksforme
Severity: highest
Status: closedreopened
Version: 1.6.0-b19 Beta 21.6.0-b22 RC2

After testing further......

When one app is started in -server mode
ex "java.exe -server -jar Font2DTest.jar"

Then it is not possible to start any other java app,
and simple output from java.exe doesn't work, as described
above.

comment:3 by Yoda_Java6, 14 years ago

There is a report in POPUPLOG.OS2 when this happens:

04-15-2011 17:07:24 SYS3171 PID 0082 TID 0006 Slot 00c4
L:\JAVA6RC2\BIN\JAVA.EXE
c0010001
1ffde3e1
EAX=00000000 EBX=000005a8 ECX=053729bf EDX=054a0280
ESI=054a05e4 EDI=297a0000
DS=0053 DSACC=d0f3 DSLIM=3fffffff
ES=0053 ESACC=d0f3 ESLIM=3fffffff
FS=29bf FSACC=00f3 FSLIM=00000fff
GS=0000 GSACC= GSLIM=
CS:EIP=005b:1c5b13ab CSACC=d0df CSLIM=3fffffff
SS:ESP=0053:0549fee8 SSACC=d0f3 SSLIM=3fffffff
EBP=054a0064 FLG=00010216

DOSCALL1.DLL 0003:0000e3e1

comment:4 by Yoda_Java6, 14 years ago

I just found a corresponding exception in Odin dir:

JAVA.EXE
Fri Apr 15 17:07:23 2011

---[Exception Information]------------

Access Violation (hardware generated,portable,fatal)
Read Access at address 00000000h
Exception Address = 15f51f81 < JVM> (1A92) obj 0001:00291F81
Thread: Ordinal TID: 195, TID: 4, Priority: 0200h
Process: PID: 130, Parent: 129, Status: 16
SS:ESP=0053:0521f484 EFLAGS=00010246
CS:EIP=005b:15f51f81 EBP =0521f49c
EAX=00000000 EBX=00000000 ESI=0521f4d0
ECX=ffffffe8 EDX=0521f4d0 EDI=0521f6c0
DS=0053 ES=00000053 FS=288f GS=0000

---[End Of Exception Information]-----

comment:5 by dmik, 14 years ago

Priority: majorminor
Severity: highestlow

I can confirm the problem. Looks like when the server version of JVM.DLL is loaded, the client version can't load. I will check if it's easy to fix for the GA after the tickets with a higher priority are done.

The workaround for the time being is to use the -server switch for all applications (or use it for none of them) -- which actually makes sense since:

  1. JVM is intended to be shared by all running Java applications on a given machine.
  2. If you run an application in server mode, this implies you expect server-type load for it. Which implies your machine is the server and the same type of load is expected for all other applications.

Please note that using the -server switch for desktop applications (or for applications running on a desktop machine) just to increase the default heap size etc. is a clear abuse (even though the application developers may recommend so) -- it is not designed for that purpose and there are other ways to control the heap size and other important runtime parameters.

comment:6 by dmik, 13 years ago

Okay, the source of the problem is clear now. When a Java application starts, it loads the corresponding version of JVM.DLL (e.g. client or server) manually by full path [1] and then loads a bunch of other DLLs (e.g. JZIP.DLL) that have the JVM module as a dependency in the imported module list [2].

If there is only one version of JVM.DLL currently loaded into the system at step 1, everything is fine: when DosLoadModule() resolves the dependencies of JZIP.DLL at step 2, it finds this already loaded instance of JVM and uses it. But if there are two different versions of JVM.DLL already in memory, DosLoadModule() seems to simply pick up the one loaded first which is not always right.

For example, if there is a Java application running in -server mode, it has already loaded the server verison of JVM.DLL. When you then attempt to start another application in -client mode, the client version of JVM.DLL gets manually loaded at step 1, but when it comes to step 2, OS/2 picks up the server version of JVM.DLL (which was loaded first). This is obviously wrong because the second application clearly wants the client version (e.g. the one it loaded at step 1). Using the wrong DLL eventually leads to crashes when the server version of the DLL gets used in the second process (through JZIP and other libraries) because lots of the private DLL data objects of this server version are uninitialized in there (as the second process has already performed JVM initialization but on the client version of the DLL when first loading it).

Last edited 13 years ago by dmik (previous) (diff)

comment:7 by dmik, 13 years ago

Note that even LIBPATHSTRICT=T doesn't help here and I guess I know why: JZIP.DLL is already loaded by the first process as well when the second process loads it. And since it is already loaded, OS/2 simply takes the loaded instance with all its already resolved dependencies (instead of resolving them again and taking the ones that were loaded first as I guessed above).

I wonder how Win32 behaves in this situation.

comment:8 by dmik, 13 years ago

In Windows it works well. I found in the debugger that Windows maintains local copies of all import address tables of all modules loaded into the process so that the same module (ZIP.DLL in case of Java) may import functions from different versions of the DLL it depends on (server/JVM.DLL or client/JVM.DLL, depending on which is found first according to normal DLL rules).

OS/2 doesn't seem to have anything like that -- each import address table seems to be global for each module, so that once the JZIP.DLL's table is filled with pointers to functions from server/JVM.DLL, it remains constant and all processes have to stick to this table.

I see no solution for the problem other than:

  1. Ignore the JVM selection switch (-server, -client, whatever) and use the already loaded JVM instead.
  2. Fail with an error if the JVM requested differs from the JVM already loaded.

I would prefer option 2 since it's more explicit.

comment:9 by dmik, 13 years ago

BTW, the information about Win32 import address tables I found here.

Regarding OS/2, it's not a surprise that it doesn't support this behavior -- imports are resolved there through relocation fixups AFAIR. Which basically means that imported functions are called directly using their real addresses (not through the function pointer table like in PE on Windows) which are written next the CALL instructions all over in the code segment when doing fixups at load time. It is obviously not possible to have the same shared DLL code call different functions -- it would require to have two otherwise identical copies of the DLL in memory which beats the whole purpose of a DLL.

comment:10 by dmik, 13 years ago

Resolution: fixed
Status: reopenedclosed

Fixed in r294. When the conflicting JVMs are detected, it will now terminate the second process with the following message:

Error: <path_to_jvm>: this JVM conflicts with a different type of JVM loaded
by another process. You may only use one JVM type of a given Java installation
at a time
Note: See TracTickets for help on using tickets.