Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[generator] Use the *real* Mono.Options. #37

Merged
merged 1 commit into from
May 26, 2016

Conversation

jonpryor
Copy link
Member

The Mono.Options-PCL package not only doesn't support enumerations,
but it doesn't support nullable types either!

Consequently, when running generator --product-version=6, it would
error out with:

System.IndexOutOfRangeException: Index was outside the bounds of the array.
  at Mono.Options.Option.Parse[T] (System.String value, Mono.Options.OptionContext c) [0x00059] in .../Java.Interop/tools/generator/Mono.Options-PCL.cs:533
  at Mono.Options.OptionSet+ActionOption`1[T].OnParseComplete (Mono.Options.OptionContext c) [0x00014] in .../Java.Interop/tools/generator/Mono.Options-PCL.cs:936
  at Mono.Options.Option.Invoke (Mono.Options.OptionContext c) [0x00003] in .../Java.Interop/tools/generator/Mono.Options-PCL.cs:631
  at Mono.Options.OptionSet.ParseValue (System.String option, Mono.Options.OptionContext c) [0x000aa] in .../Java.Interop/tools/generator/Mono.Options-PCL.cs:1150
  at Mono.Options.OptionSet.Parse (System.String argument, Mono.Options.OptionContext c) [0x000a8] in .../Java.Interop/tools/generator/Mono.Options-PCL.cs:1125
  at Mono.Options.OptionSet.Parse (IEnumerable`1 arguments) [0x000c1] in .../Java.Interop/tools/generator/Mono.Options-PCL.cs:1015
  at Xamarin.Android.Binder.CodeGeneratorOptions.Parse (System.String[] args) [0x0034c] in .../Java.Interop/tools/generator/CodeGenerator.cs:146
  at Xamarin.Android.Binder.CodeGenerator.Main (System.String[] args) [0x00002] in .../Java.Interop/tools/generator/CodeGenerator.cs:191

Dump Mono.Options-PCL and use the "real" Mono.Options Nuget package.
That allows proper parsing of nullable types and enumerations and...

The Mono.Options-PCL package not only doesn't support enumerations,
but it doesn't support nullable types either!

Consequently, when running `generator --product-version=6`, it would
error out with:

	System.IndexOutOfRangeException: Index was outside the bounds of the array.
	  at Mono.Options.Option.Parse[T] (System.String value, Mono.Options.OptionContext c) [0x00059] in .../Java.Interop/tools/generator/Mono.Options-PCL.cs:533
	  at Mono.Options.OptionSet+ActionOption`1[T].OnParseComplete (Mono.Options.OptionContext c) [0x00014] in .../Java.Interop/tools/generator/Mono.Options-PCL.cs:936
	  at Mono.Options.Option.Invoke (Mono.Options.OptionContext c) [0x00003] in .../Java.Interop/tools/generator/Mono.Options-PCL.cs:631
	  at Mono.Options.OptionSet.ParseValue (System.String option, Mono.Options.OptionContext c) [0x000aa] in .../Java.Interop/tools/generator/Mono.Options-PCL.cs:1150
	  at Mono.Options.OptionSet.Parse (System.String argument, Mono.Options.OptionContext c) [0x000a8] in .../Java.Interop/tools/generator/Mono.Options-PCL.cs:1125
	  at Mono.Options.OptionSet.Parse (IEnumerable`1 arguments) [0x000c1] in .../Java.Interop/tools/generator/Mono.Options-PCL.cs:1015
	  at Xamarin.Android.Binder.CodeGeneratorOptions.Parse (System.String[] args) [0x0034c] in .../Java.Interop/tools/generator/CodeGenerator.cs:146
	  at Xamarin.Android.Binder.CodeGenerator.Main (System.String[] args) [0x00002] in .../Java.Interop/tools/generator/CodeGenerator.cs:191

Dump Mono.Options-PCL and use the "real" Mono.Options Nuget package.
That allows proper parsing of nullable types and enumerations and...
@grendello grendello merged commit 175ee89 into dotnet:master May 26, 2016
jonpryor added a commit to jonpryor/java.interop that referenced this pull request Aug 17, 2016
When `JniRuntime.CreationOptions.DestroyRuntimeOnDispose` is true,
`JavaVM::DestroyJavaVM()` will be invoked when the `JniRuntime`
instance is disposed *or* finalized.

`JreRuntime.CreateJreVM()` would *always* set
`DestroyRuntimeOnDispose` to true, because it called
`JNI_CreateJavaVM()`, so *of course* you'd want to destroy the
Java VM, right?

Which brings us to unit tests. I don't know of any "before all test
fixtures run" and "after all test fixtures run" extension points,
which means:

1. The JVM needs to be created implicitly, "on demand."
2. There's no good way to destroy the JVM created in (1) after all
    tests have finished executing.

Which *really* means that the `JreRuntime` instance is *finalized*,
which sets us up for the unholy trifecta of AppDomain unloads,
finalizers, and JVM shutdown:

For unknown reasons, ~randomly, when running the unit tests (e.g.
`make run-tests`), the test runner will *hang*, indefinitely.

Attaching `lldb` and triggering a backtrace shows the unholy trifecta:

Finalization:

	thread dotnet#4: tid = 0x403831, 0x00007fff9656bdb6 libsystem_kernel.dylib`__psynch_cvwait + 10, name = 'tid_1403'
	  ...
	  frame dotnet#10: 0x00000001001ccb4a mono64`mono_gc_run_finalize(obj=<unavailable>, data=<unavailable>) + 938 at gc.c:256 [opt]
	  frame dotnet#11: 0x00000001001cdd4a mono64`finalizer_thread [inlined] finalize_domain_objects + 51 at gc.c:681 [opt]
	  frame dotnet#12: 0x00000001001cdd17 mono64`finalizer_thread(unused=<unavailable>) + 295 at gc.c:730 [opt]

JVM destruction:

	thread dotnet#4: tid = 0x403831, 0x00007fff9656bdb6 libsystem_kernel.dylib`__psynch_cvwait + 10, name = 'tid_1403'
	  frame #0: 0x00007fff9656bdb6 libsystem_kernel.dylib`__psynch_cvwait + 10
	  frame dotnet#1: 0x00007fffa04d4728 libsystem_pthread.dylib`_pthread_cond_wait + 767
	  frame dotnet#2: 0x000000010ba5bc76 libjvm.dylib`os::PlatformEvent::park() + 192
	  frame dotnet#3: 0x000000010ba38e32 libjvm.dylib`ParkCommon(ParkEvent*, long) + 42
	  frame dotnet#4: 0x000000010ba39708 libjvm.dylib`Monitor::IWait(Thread*, long) + 168
	  frame dotnet#5: 0x000000010ba398f0 libjvm.dylib`Monitor::wait(bool, long, bool) + 246
	  frame dotnet#6: 0x000000010bb3dca2 libjvm.dylib`Threads::destroy_vm() + 80
	  frame dotnet#7: 0x000000010b8fd665 libjvm.dylib`jni_DestroyJavaVM + 254

AppDomain unload:

	thread dotnet#37: tid = 0x4038fb, 0x00007fff9656bdb6 libsystem_kernel.dylib`__psynch_cvwait + 10
	  frame #0: 0x00007fff9656bdb6 libsystem_kernel.dylib`__psynch_cvwait + 10
	  frame dotnet#1: 0x00007fffa04d4728 libsystem_pthread.dylib`_pthread_cond_wait + 767
	  frame dotnet#2: 0x0000000100234a7f mono64`mono_os_cond_timedwait [inlined] mono_os_cond_wait(cond=0x0000000102016e50, mutex=0x0000000102016e10) + 11 at mono-os-mutex.h:105 [opt]
	  frame dotnet#3: 0x0000000100234a74 mono64`mono_os_cond_timedwait(cond=0x0000000102016e50, mutex=0x0000000102016e10, timeout_ms=<unavailable>) + 164 at mono-os-mutex.h:120 [opt]
	  frame dotnet#4: 0x0000000100234828 mono64`_wapi_handle_timedwait_signal_handle(handle=0x0000000000000440, timeout=4294967295, alertable=1, poll=<unavailable>, alerted=0x0000700000a286f4) + 536 at handles.c:1554 [opt]
	  frame dotnet#5: 0x0000000100246370 mono64`wapi_WaitForSingleObjectEx(handle=<unavailable>, timeout=<unavailable>, alertable=<unavailable>) + 592 at wait.c:189 [opt]
	  frame dotnet#6: 0x00000001001c832e mono64`mono_domain_try_unload [inlined] guarded_wait(timeout=4294967295, alertable=1) + 30 at appdomain.c:2390 [opt]
	  frame dotnet#7: 0x00000001001c8310 mono64`mono_domain_try_unload(domain=0x000000010127ccb0, exc=0x0000700000a287a0) + 416 at appdomain.c:2482 [opt]
	  frame dotnet#8: 0x00000001001c7db2 mono64`ves_icall_System_AppDomain_InternalUnload [inlined] mono_domain_unload(domain=<unavailable>) + 20 at appdomain.c:2379 [opt]
	  frame dotnet#9: 0x00000001001c7d9e mono64`ves_icall_System_AppDomain_InternalUnload(domain_id=<unavailable>) + 46 at appdomain.c:2039 [opt]

This randomly results in deadlock, and hung Jenkins bots.

Fix this behavior by altering `JreRuntime.CreateJreVM()` to *not*
override the value of
`JniRuntime.CreationOptions.DestroyRuntimeOnDispose`. This allows the
constructor of the `JreRuntime` instance to decide whether or not the
JVM is destroyed.

In the case of TestJVM, we *don't* want to destroy the JVM.

This prevents the JVM from being destroyed, which in turn prevents the
hang during process shutdown.
jonpryor added a commit that referenced this pull request Aug 17, 2016
When `JniRuntime.CreationOptions.DestroyRuntimeOnDispose` is true,
`JavaVM::DestroyJavaVM()` will be invoked when the `JniRuntime`
instance is disposed *or* finalized.

`JreRuntime.CreateJreVM()` would *always* set
`DestroyRuntimeOnDispose` to true, because it called
`JNI_CreateJavaVM()`, so *of course* you'd want to destroy the
Java VM, right?

Which brings us to unit tests. I don't know of any "before all test
fixtures run" and "after all test fixtures run" extension points,
which means:

1. The JVM needs to be created implicitly, "on demand."
2. There's no good way to destroy the JVM created in (1) after all
    tests have finished executing.

Which *really* means that the `JreRuntime` instance is *finalized*,
which sets us up for the unholy trifecta of AppDomain unloads,
finalizers, and JVM shutdown:

For unknown reasons, ~randomly, when running the unit tests (e.g.
`make run-tests`), the test runner will *hang*, indefinitely.

Attaching `lldb` and triggering a backtrace shows the unholy trifecta:

Finalization:

	thread #4: tid = 0x403831, 0x00007fff9656bdb6 libsystem_kernel.dylib`__psynch_cvwait + 10, name = 'tid_1403'
	  ...
	  frame #10: 0x00000001001ccb4a mono64`mono_gc_run_finalize(obj=<unavailable>, data=<unavailable>) + 938 at gc.c:256 [opt]
	  frame #11: 0x00000001001cdd4a mono64`finalizer_thread [inlined] finalize_domain_objects + 51 at gc.c:681 [opt]
	  frame #12: 0x00000001001cdd17 mono64`finalizer_thread(unused=<unavailable>) + 295 at gc.c:730 [opt]

JVM destruction:

	thread #4: tid = 0x403831, 0x00007fff9656bdb6 libsystem_kernel.dylib`__psynch_cvwait + 10, name = 'tid_1403'
	  frame #0: 0x00007fff9656bdb6 libsystem_kernel.dylib`__psynch_cvwait + 10
	  frame #1: 0x00007fffa04d4728 libsystem_pthread.dylib`_pthread_cond_wait + 767
	  frame #2: 0x000000010ba5bc76 libjvm.dylib`os::PlatformEvent::park() + 192
	  frame #3: 0x000000010ba38e32 libjvm.dylib`ParkCommon(ParkEvent*, long) + 42
	  frame #4: 0x000000010ba39708 libjvm.dylib`Monitor::IWait(Thread*, long) + 168
	  frame #5: 0x000000010ba398f0 libjvm.dylib`Monitor::wait(bool, long, bool) + 246
	  frame #6: 0x000000010bb3dca2 libjvm.dylib`Threads::destroy_vm() + 80
	  frame #7: 0x000000010b8fd665 libjvm.dylib`jni_DestroyJavaVM + 254

AppDomain unload:

	thread #37: tid = 0x4038fb, 0x00007fff9656bdb6 libsystem_kernel.dylib`__psynch_cvwait + 10
	  frame #0: 0x00007fff9656bdb6 libsystem_kernel.dylib`__psynch_cvwait + 10
	  frame #1: 0x00007fffa04d4728 libsystem_pthread.dylib`_pthread_cond_wait + 767
	  frame #2: 0x0000000100234a7f mono64`mono_os_cond_timedwait [inlined] mono_os_cond_wait(cond=0x0000000102016e50, mutex=0x0000000102016e10) + 11 at mono-os-mutex.h:105 [opt]
	  frame #3: 0x0000000100234a74 mono64`mono_os_cond_timedwait(cond=0x0000000102016e50, mutex=0x0000000102016e10, timeout_ms=<unavailable>) + 164 at mono-os-mutex.h:120 [opt]
	  frame #4: 0x0000000100234828 mono64`_wapi_handle_timedwait_signal_handle(handle=0x0000000000000440, timeout=4294967295, alertable=1, poll=<unavailable>, alerted=0x0000700000a286f4) + 536 at handles.c:1554 [opt]
	  frame #5: 0x0000000100246370 mono64`wapi_WaitForSingleObjectEx(handle=<unavailable>, timeout=<unavailable>, alertable=<unavailable>) + 592 at wait.c:189 [opt]
	  frame #6: 0x00000001001c832e mono64`mono_domain_try_unload [inlined] guarded_wait(timeout=4294967295, alertable=1) + 30 at appdomain.c:2390 [opt]
	  frame #7: 0x00000001001c8310 mono64`mono_domain_try_unload(domain=0x000000010127ccb0, exc=0x0000700000a287a0) + 416 at appdomain.c:2482 [opt]
	  frame #8: 0x00000001001c7db2 mono64`ves_icall_System_AppDomain_InternalUnload [inlined] mono_domain_unload(domain=<unavailable>) + 20 at appdomain.c:2379 [opt]
	  frame #9: 0x00000001001c7d9e mono64`ves_icall_System_AppDomain_InternalUnload(domain_id=<unavailable>) + 46 at appdomain.c:2039 [opt]

This randomly results in deadlock, and hung Jenkins bots.

Fix this behavior by altering `JreRuntime.CreateJreVM()` to *not*
override the value of
`JniRuntime.CreationOptions.DestroyRuntimeOnDispose`. This allows the
constructor of the `JreRuntime` instance to decide whether or not the
JVM is destroyed.

In the case of TestJVM, we *don't* want to destroy the JVM.

This prevents the JVM from being destroyed, which in turn prevents the
hang during process shutdown.
radekdoulik added a commit to radekdoulik/java.interop that referenced this pull request Aug 27, 2018
Changes in xamarin-android-tools between 75530565b6aa903b3a0e52b61df4dd94475a19fc and 9e78d6ee586b498d0ea082b3bc00432c23583dd1:

9e78d6e (HEAD, origin/master, origin/HEAD, master) [tests] fix test failures on Windows (dotnet#47)
bdf0158 Better support no installed JDKs on macOS (dotnet#48)
6353659 Log what is happening during path selection (dotnet#46)
3ef860b Take BUILD_NUMBER into consideration for Version sorting (dotnet#45)
d3de054 Allow an optional locator to be provided to JdkInfo (dotnet#43)
917d3b3 Don't require quotes around `release` values (dotnet#41)
7427692 [tests] Unit tests for finding NDK location based on $PATH (dotnet#40)
dbc517b Merge pull request dotnet#38 from jonpryor/jonp-ndk-via-path
511d580 Allow finding NDK location based on $PATH
b42c217 [tests] Fix DetectAndSetPreferredJavaSdkPathToLatest() test (dotnet#37)
a4aad18 Add AndroidSdkInfo.DetectAndSetPreferredJavaSdkPathToLatest() (dotnet#35)
fae7e0a [tests] Remove temporary directories (dotnet#36)
07c4c2b [Xamarin.Android.Tools.AndroidSdk] Revert JDK validation (dotnet#34)
radekdoulik added a commit that referenced this pull request Aug 27, 2018
Changes in xamarin-android-tools between 75530565b6aa903b3a0e52b61df4dd94475a19fc and 9e78d6ee586b498d0ea082b3bc00432c23583dd1:

9e78d6e (HEAD, origin/master, origin/HEAD, master) [tests] fix test failures on Windows (#47)
bdf0158 Better support no installed JDKs on macOS (#48)
6353659 Log what is happening during path selection (#46)
3ef860b Take BUILD_NUMBER into consideration for Version sorting (#45)
d3de054 Allow an optional locator to be provided to JdkInfo (#43)
917d3b3 Don't require quotes around `release` values (#41)
7427692 [tests] Unit tests for finding NDK location based on $PATH (#40)
dbc517b Merge pull request #38 from jonpryor/jonp-ndk-via-path
511d580 Allow finding NDK location based on $PATH
b42c217 [tests] Fix DetectAndSetPreferredJavaSdkPathToLatest() test (#37)
a4aad18 Add AndroidSdkInfo.DetectAndSetPreferredJavaSdkPathToLatest() (#35)
fae7e0a [tests] Remove temporary directories (#36)
07c4c2b [Xamarin.Android.Tools.AndroidSdk] Revert JDK validation (#34)
@github-actions github-actions bot locked and limited conversation to collaborators Apr 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants