From: Alexander Köplinger Date: Tue, 8 Nov 2016 12:57:16 +0000 (+0100) Subject: Merge pull request #3913 from omwok/master X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=8784e2e1cbbd88b4872536d3a8077702dc547216;hp=a74188235918e65e1db41790409019c5a79c7614;p=mono.git Merge pull request #3913 from omwok/master column name and ordinal fix. --- diff --git a/configure.ac b/configure.ac index 43111ecc3ca..45dbacccdb6 100644 --- a/configure.ac +++ b/configure.ac @@ -763,7 +763,7 @@ DISABLED_FEATURES=none # Set the build profiles and options before things which use them # -AC_ARG_WITH(profile4_x, [ --with-profile4=yes,no If you want to install the 4.x FX (defaults to yes)], [], [with_profile4_x=default]) +AC_ARG_WITH(profile4_x, [ --with-profile4_x=yes,no If you want to install the 4.x FX (defaults to yes)], [], [with_profile4_x=default]) AC_ARG_WITH(monodroid, [ --with-monodroid=yes,no If you want to build the MonoDroid assemblies (defaults to no)], [], [with_monodroid=default]) AC_ARG_WITH(monotouch, [ --with-monotouch=yes,no If you want to build the Xamarin.iOS assemblies (defaults to no)], [], [with_monotouch=default]) AC_ARG_WITH(monotouch_watch, [ --with-monotouch_watch=yes,no If you want to build the Xamarin.WatchOS assemblies (defaults to no)],[], [with_monotouch_watch=default]) diff --git a/eglib/src/goutput.c b/eglib/src/goutput.c index ef80cff0347..2dcf8746e08 100644 --- a/eglib/src/goutput.c +++ b/eglib/src/goutput.c @@ -47,8 +47,10 @@ g_print (const gchar *format, ...) va_list args; va_start (args, format); - if (g_vasprintf (&msg, format, args) < 0) + if (g_vasprintf (&msg, format, args) < 0) { + va_end (args); return; + } va_end (args); if (!stdout_handler) @@ -65,8 +67,10 @@ g_printerr (const gchar *format, ...) va_list args; va_start (args, format); - if (g_vasprintf (&msg, format, args) < 0) + if (g_vasprintf (&msg, format, args) < 0) { + va_end (args); return; + } va_end (args); if (!stderr_handler) diff --git a/external/boringssl b/external/boringssl index 432738a3c93..c06ac6b33d3 160000 --- a/external/boringssl +++ b/external/boringssl @@ -1 +1 @@ -Subproject commit 432738a3c938b4f751307301c6aa07f2027a8864 +Subproject commit c06ac6b33d3e7442ad878488b9d1100127eff998 diff --git a/external/nunit-lite b/external/nunit-lite index 4bc79a6da1f..dda48cd0343 160000 --- a/external/nunit-lite +++ b/external/nunit-lite @@ -1 +1 @@ -Subproject commit 4bc79a6da1f0ee538560b7e4d0caff46d3c86e4f +Subproject commit dda48cd0343bddac6b3faf0c0498b680468cc3fd diff --git a/mcs/build/Makefile b/mcs/build/Makefile index f33fcccf2d7..14ad0cbd10c 100644 --- a/mcs/build/Makefile +++ b/mcs/build/Makefile @@ -41,7 +41,6 @@ DISTFILES = \ executable.make \ gensources.sh \ library.make \ - nunit-summary.xsl \ rules.make \ tests.make \ $(COMMON_SRCS:%=common/%) \ diff --git a/mcs/build/config-default.make b/mcs/build/config-default.make index 145665799cc..9e4fcf64a30 100644 --- a/mcs/build/config-default.make +++ b/mcs/build/config-default.make @@ -10,7 +10,7 @@ CODEPAGE = 65001 RUNTIME_FLAGS = -TEST_HARNESS = $(topdir)/class/lib/$(PROFILE)/$(PARENT_PROFILE)nunit-console.exe +TEST_HARNESS = $(topdir)/class/lib/$(PROFILE)/$(PARENT_PROFILE)nunit-lite-console.exe MCS_FLAGS = MBAS_FLAGS = $(PLATFORM_DEBUG_FLAGS) LIBRARY_FLAGS = /noconfig diff --git a/mcs/build/nunit-summary.xsl b/mcs/build/nunit-summary.xsl deleted file mode 100644 index 70972ad3bc0..00000000000 --- a/mcs/build/nunit-summary.xsl +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - -Tests run: - -, Failures: - -, Not run: - -, Time: - - seconds - - - - -Test Fixture SetUp Failures: - - -Test Case Failures: - - -Tests not run: - - - - - - - ) - - : - - - - - - - - - - diff --git a/mcs/build/platforms/win32.make b/mcs/build/platforms/win32.make index bed99f53387..4f34c924f03 100644 --- a/mcs/build/platforms/win32.make +++ b/mcs/build/platforms/win32.make @@ -7,7 +7,7 @@ PLATFORM_DEBUG_FLAGS = /debug+ /debug:full PLATFORM_MCS_FLAGS = /nologo PLATFORM_RUNTIME = PLATFORM_CORLIB = mscorlib.dll -PLATFORM_TEST_HARNESS_EXCLUDES = +PLATFORM_TEST_HARNESS_EXCLUDES = NotOnWindows, EXTERNAL_MCS = mcs EXTERNAL_MBAS = vbc.exe diff --git a/mcs/build/profiles/mobile_static.make b/mcs/build/profiles/mobile_static.make index d9ff3b67dc9..bf52c7e791e 100644 --- a/mcs/build/profiles/mobile_static.make +++ b/mcs/build/profiles/mobile_static.make @@ -32,7 +32,6 @@ PROFILE_MCS_FLAGS = \ $(PLATFORM_DEBUG_FLAGS) FRAMEWORK_VERSION = 2.1 -NUNIT_LITE = yes # the tuner takes care of the install NO_INSTALL = yes diff --git a/mcs/build/profiles/monotouch_runtime.make b/mcs/build/profiles/monotouch_runtime.make index 1603d123c72..ff9e0fd4536 100644 --- a/mcs/build/profiles/monotouch_runtime.make +++ b/mcs/build/profiles/monotouch_runtime.make @@ -31,7 +31,8 @@ PROFILE_MCS_FLAGS = \ -nowarn:1699 \ -nostdlib \ $(DEFAULT_REFERENCES) \ - $(PLATFORM_DEBUG_FLAGS) + $(PLATFORM_DEBUG_FLAGS) \ + $(MONOTOUCH_MCS_FLAGS) FRAMEWORK_VERSION = 2.1 diff --git a/mcs/build/profiles/xammac.make b/mcs/build/profiles/xammac.make index 50e8214884d..ab1aa6fa071 100644 --- a/mcs/build/profiles/xammac.make +++ b/mcs/build/profiles/xammac.make @@ -28,10 +28,13 @@ PROFILE_MCS_FLAGS = \ -nowarn:1699 \ -nostdlib \ $(DEFAULT_REFERENCES) \ - $(PLATFORM_DEBUG_FLAGS) + $(PLATFORM_DEBUG_FLAGS) \ + $(XAMMAC_MCS_FLAGS) FRAMEWORK_VERSION = 2.1 NO_TEST = yes NO_INSTALL = yes MOBILE_DYNAMIC = yes MOBILE_PROFILE = yes + +PROFILE_DISABLE_BTLS=1 diff --git a/mcs/build/profiles/xammac_net_4_5.make b/mcs/build/profiles/xammac_net_4_5.make index 83bfc92fcb2..b9881fe64de 100644 --- a/mcs/build/profiles/xammac_net_4_5.make +++ b/mcs/build/profiles/xammac_net_4_5.make @@ -1,11 +1,14 @@ include $(topdir)/build/profiles/net_4_x.make + PROFILE_MCS_FLAGS += \ -d:FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK \ -d:NO_SYSTEM_DRAWING_DEPENDENCY \ -d:NO_WINFORMS_DEPENDENCY \ -d:NO_SYSTEM_WEB_DEPENDENCY \ -d:XAMMAC_4_5 \ - -d:XAMARIN_MODERN + -d:XAMARIN_MODERN \ + $(XAMMAC_MCS_FLAGS) + XAMMAC_4_5=1 NO_WINDOWS_BASE=1 NO_SYSTEM_WEB_DEPENDENCY=1 @@ -15,3 +18,5 @@ NO_SYSTEM_DRAWING_DEPENDENCY=1 NO_SYSTEM_SERVICEMODEL_ACTIVATION_DEPENDENCY=1 NO_SYSTEM_DESIGN_DEPENDENCY=1 NO_SYSTEM_DIRECTORY_SERVICES_DEPENDENCY=1 + +PROFILE_DISABLE_BTLS=1 diff --git a/mcs/build/rules.make b/mcs/build/rules.make index ac3a476dfb1..d25eb35f6e8 100644 --- a/mcs/build/rules.make +++ b/mcs/build/rules.make @@ -116,22 +116,6 @@ endif include $(topdir)/build/profiles/$(PROFILE).make -# If the profile is using nunit-lite, use it -ifdef NUNIT_LITE -TEST_HARNESS=$(topdir)/class/lib/$(PROFILE)/nunit-lite-console.exe -endif - -# Make sure propagates -export TEST_HARNESS - -# If the profile is using nunit-lite, use it -ifdef NUNIT_LITE -TEST_HARNESS=$(topdir)/class/lib/$(PROFILE)/nunit-lite-console.exe -endif - -# Make sure propagates -export TEST_HARNESS - ifdef BCL_OPTIMIZE PROFILE_MCS_FLAGS += -optimize endif diff --git a/mcs/build/tests.make b/mcs/build/tests.make index 749b5a0faf4..d9f6a95ff72 100644 --- a/mcs/build/tests.make +++ b/mcs/build/tests.make @@ -19,11 +19,7 @@ TEST_RUNTIME_WRAPPERS_PATH = $(shell dirname $(RUNTIME))/_tmpinst/bin ## Unit test support ifndef NO_TEST -ifdef NUNIT_LITE test_nunit_lib = nunitlite.dll -else -test_nunit_lib = nunit.framework.dll nunit.core.dll nunit.util.dll nunit.mocks.dll -endif TEST_LIB_MCS_FLAGS = $(patsubst %,-r:$(topdir)/class/lib/$(PROFILE)/%.dll,$(TEST_LIB_REFS)) @@ -58,19 +54,11 @@ ifndef NO_TEST $(test_nunit_dep): $(topdir)/build/deps/nunit-$(PROFILE).stamp @if test -f $@; then :; else rm -f $<; $(MAKE) $<; fi -ifdef NUNIT_LITE $(topdir)/build/deps/nunit-$(PROFILE).stamp: ifndef PARENT_PROFILE cd ${topdir}/tools/nunit-lite && $(MAKE) endif echo "stamp" >$@ -else -$(topdir)/build/deps/nunit-$(PROFILE).stamp: -ifndef PARENT_PROFILE - cd ${topdir}/nunit24 && $(MAKE) -endif - echo "stamp" >$@ -endif tests_CLEAN_FILES += $(topdir)/build/deps/nunit-$(PROFILE).stamp endif @@ -90,52 +78,18 @@ run-test-ondotnet-local: run-test-ondotnet-lib TEST_HARNESS_EXCLUDES = -exclude=$(PLATFORM_TEST_HARNESS_EXCLUDES)$(PROFILE_TEST_HARNESS_EXCLUDES)NotWorking,ValueAdd,CAS,InetAccess TEST_HARNESS_EXCLUDES_ONDOTNET = /exclude:$(PLATFORM_TEST_HARNESS_EXCLUDES)$(PROFILE_TEST_HARNESS_EXCLUDES)NotDotNet,CAS -ifdef NUNIT_LITE NOSHADOW_FLAG = -NUNIT_XML_FLAG = -format:nunit2 -result: -OUTPUT_FILE_FLAG=-out -else -OUTPUT_FILE_FLAG=-output -NOSHADOW_FLAG = -noshadow -NUNIT_XML_FLAG = -xml= -endif - -ifdef NUNIT_LITE -NOSHADOW_FLAG = -NUNIT_XML_FLAG = -format:nunit2 -result: -OUTPUT_FILE_FLAG=-out -else -OUTPUT_FILE_FLAG=-output -NOSHADOW_FLAG = -noshadow -NUNIT_XML_FLAG = -xml= -endif - -ifdef TEST_HARNESS_VERBOSE -TEST_HARNESS_OUTPUT = -labels -TEST_HARNESS_OUTPUT_ONDOTNET = -labels -TEST_HARNESS_POSTPROC = : -TEST_HARNESS_POSTPROC_ONDOTNET = : -else -TEST_HARNESS_OUTPUT = $(OUTPUT_FILE_FLAG)=TestResult-$(PROFILE).log -TEST_HARNESS_OUTPUT_ONDOTNET = $(OUTPUT_FILE_FLAG)=TestResult-ondotnet-$(PROFILE).log -TEST_HARNESS_POSTPROC = (echo ''; cat TestResult-$(PROFILE).log) | sed '1,/^Tests run: /d'; xsltproc $(topdir)/build/nunit-summary.xsl TestResult-$(PROFILE).xml >> TestResult-$(PROFILE).log -TEST_HARNESS_POSTPROC_ONDOTNET = (echo ''; cat TestResult-ondotnet-$(PROFILE).log) | sed '1,/^Tests run: /d'; xsltproc $(topdir)/build/nunit-summary.xsl TestResult-ondotnet-$(PROFILE).xml >> TestResult-ondotnet-$(PROFILE).log -endif ifdef FIXTURE -ifdef NUNIT_LITE FIXTURE_ARG = -test=MonoTests.$(FIXTURE) -else -FIXTURE_ARG = -fixture=MonoTests.$(FIXTURE) -endif endif ifdef TESTNAME -ifdef NUNIT_LITE TESTNAME_ARG = -test=MonoTests.$(TESTNAME) -else -TESTNAME_ARG = -run=MonoTests.$(TESTNAME) endif + +ifdef TEST_HARNESS_VERBOSE +LABELS_ARG = -labels endif ifdef ALWAYS_AOT @@ -147,19 +101,30 @@ test-local-aot-compile: $(topdir)/build/deps/nunit-$(PROFILE).stamp endif # ALWAYS_AOT +NUNITLITE_CONFIG_FILE=$(topdir)/class/lib/$(PROFILE)/$(PARENT_PROFILE)nunit-lite-console.exe.config + +patch-nunitlite-appconfig: + cp -f $(topdir)/tools/nunit-lite/nunit-lite-console/nunit-lite-console.exe.config.tmpl $(NUNITLITE_CONFIG_FILE) +ifdef TEST_NUNITLITE_APP_CONFIG_GLOBAL + sed -i -e "/__INSERT_CUSTOM_APP_CONFIG_GLOBAL__/r $(TEST_NUNITLITE_APP_CONFIG_GLOBAL)" $(NUNITLITE_CONFIG_FILE) +endif +ifdef TEST_NUNITLITE_APP_CONFIG_RUNTIME + sed -i -e "/__INSERT_CUSTOM_APP_CONFIG_RUNTIME__/r $(TEST_NUNITLITE_APP_CONFIG_RUNTIME)" $(NUNITLITE_CONFIG_FILE) +endif + ## FIXME: i18n problem in the 'sed' command below -run-test-lib: test-local test-local-aot-compile +run-test-lib: test-local test-local-aot-compile patch-nunitlite-appconfig ok=:; \ - PATH="$(TEST_RUNTIME_WRAPPERS_PATH):$(PATH)" MONO_REGISTRY_PATH="$(HOME)/.mono/registry" MONO_TESTS_IN_PROGRESS="yes" $(TEST_RUNTIME) $(RUNTIME_FLAGS) $(AOT_RUN_FLAGS) $(TEST_HARNESS) $(test_assemblies) $(NOSHADOW_FLAG) $(TEST_HARNESS_FLAGS) $(LOCAL_TEST_HARNESS_FLAGS) $(TEST_HARNESS_EXCLUDES) $(TEST_HARNESS_OUTPUT) $(NUNIT_XML_FLAG)TestResult-$(PROFILE).xml $(FIXTURE_ARG) $(TESTNAME_ARG)|| ok=false; \ + PATH="$(TEST_RUNTIME_WRAPPERS_PATH):$(PATH)" MONO_REGISTRY_PATH="$(HOME)/.mono/registry" MONO_TESTS_IN_PROGRESS="yes" $(TEST_RUNTIME) $(RUNTIME_FLAGS) $(AOT_RUN_FLAGS) $(TEST_HARNESS) $(test_assemblies) $(NOSHADOW_FLAG) $(TEST_HARNESS_FLAGS) $(LOCAL_TEST_HARNESS_FLAGS) $(TEST_HARNESS_EXCLUDES) $(LABELS_ARG) -format:nunit2 -result:TestResult-$(PROFILE).xml $(FIXTURE_ARG) $(TESTNAME_ARG)|| ok=false; \ if [ ! -f "TestResult-$(PROFILE).xml" ]; then echo "The test runner didn't produce a test result XML, probably due to a crash of the runtime. Check the log for more details." > TestResult-$(PROFILE).xml; fi; \ - $(TEST_HARNESS_POSTPROC) ; $$ok + $$ok ## Instructs compiler to compile to target .net execution, it can be usefull in rare cases when runtime detection is not possible run-test-ondotnet-lib: LOCAL_TEST_COMPILER_ONDOTNET_FLAGS:=-d:RUN_ONDOTNET run-test-ondotnet-lib: test-local ok=:; \ - $(TEST_HARNESS) $(test_assemblies) $(NOSHADOW_FLAG) $(TEST_HARNESS_FLAGS) $(LOCAL_TEST_HARNESS_ONDOTNET_FLAGS) $(TEST_HARNESS_EXCLUDES_ONDOTNET) $(TEST_HARNESS_OUTPUT_ONDOTNET) $(NUNIT_XML_FLAG)=TestResult-ondotnet-$(PROFILE).xml $(FIXTURE_ARG) $(TESTNAME_ARG) || ok=false; \ - $(TEST_HARNESS_POSTPROC_ONDOTNET) ; $$ok + $(TEST_HARNESS) $(test_assemblies) $(NOSHADOW_FLAG) $(TEST_HARNESS_FLAGS) $(LOCAL_TEST_HARNESS_ONDOTNET_FLAGS) $(TEST_HARNESS_EXCLUDES_ONDOTNET) $(LABELS_ARG) -format:nunit2 -result:TestResult-ondotnet-$(PROFILE).xml $(FIXTURE_ARG) $(TESTNAME_ARG) || ok=false; \ + $$ok endif # test_assemblies @@ -194,3 +159,4 @@ $(test_makefrag): $(test_response) endif +.PHONY: patch-nunitlite-appconfig diff --git a/mcs/class/Microsoft.Build.Engine/.gitignore b/mcs/class/Microsoft.Build.Engine/.gitignore index bfa54497303..887bc47e19e 100644 --- a/mcs/class/Microsoft.Build.Engine/.gitignore +++ b/mcs/class/Microsoft.Build.Engine/.gitignore @@ -1 +1,2 @@ /Test/resources/*.proj +Test/test-config-file-* diff --git a/mcs/class/Microsoft.Build.Engine/Makefile b/mcs/class/Microsoft.Build.Engine/Makefile index 9aed8120654..9acd2e184d4 100644 --- a/mcs/class/Microsoft.Build.Engine/Makefile +++ b/mcs/class/Microsoft.Build.Engine/Makefile @@ -12,6 +12,7 @@ LIB_MCS_FLAGS = TEST_MCS_FLAGS = TEST_LIB_REFS = $(XBUILD_FRAMEWORK) $(XBUILD_UTILITIES) $(PARENT_PROFILE)System.Xml +TEST_NUNITLITE_APP_CONFIG_RUNTIME=Test/test-config-file-$(PROFILE) EXTRA_DISTFILES = \ Test/resources/TestTasks.cs \ diff --git a/mcs/class/Microsoft.Build.Framework/.gitignore b/mcs/class/Microsoft.Build.Framework/.gitignore new file mode 100644 index 00000000000..c8cb7179505 --- /dev/null +++ b/mcs/class/Microsoft.Build.Framework/.gitignore @@ -0,0 +1 @@ +Test/test-config-file-* diff --git a/mcs/class/Microsoft.Build.Framework/Makefile b/mcs/class/Microsoft.Build.Framework/Makefile index f31f5a5835e..edd7cc2e8eb 100644 --- a/mcs/class/Microsoft.Build.Framework/Makefile +++ b/mcs/class/Microsoft.Build.Framework/Makefile @@ -10,6 +10,8 @@ LIBRARY = Microsoft.Build.Framework.dll LIB_REFS = $(PARENT_PROFILE)System LIB_MCS_FLAGS = +TEST_NUNITLITE_APP_CONFIG_RUNTIME=Test/test-config-file-$(PROFILE) + EXTRA_DISTFILES = \ Mono.XBuild.Framework/AssemblyLoadInfo.cs diff --git a/mcs/class/Microsoft.Build.Tasks/.gitignore b/mcs/class/Microsoft.Build.Tasks/.gitignore index bfa54497303..887bc47e19e 100644 --- a/mcs/class/Microsoft.Build.Tasks/.gitignore +++ b/mcs/class/Microsoft.Build.Tasks/.gitignore @@ -1 +1,2 @@ /Test/resources/*.proj +Test/test-config-file-* diff --git a/mcs/class/Microsoft.Build.Tasks/Makefile b/mcs/class/Microsoft.Build.Tasks/Makefile index d451c754e74..a919129b083 100644 --- a/mcs/class/Microsoft.Build.Tasks/Makefile +++ b/mcs/class/Microsoft.Build.Tasks/Makefile @@ -15,6 +15,8 @@ LIB_REFS = $(PARENT_PROFILE)System $(PARENT_PROFILE)System.Core $(PARENT_PROFILE TEST_MCS_FLAGS = TEST_LIB_REFS = $(PARENT_PROFILE)System.Xml $(XBUILD_ENGINE) $(XBUILD_FRAMEWORK) $(XBUILD_TASKS) $(XBUILD_UTILITIES) $(PARENT_PROFILE)System.Core +TEST_NUNITLITE_APP_CONFIG_RUNTIME=Test/test-config-file-$(PROFILE) + ifeq (4, $(FRAMEWORK_VERSION_MAJOR)) TEST_LIB_REFS += Microsoft.Build endif @@ -23,8 +25,7 @@ EXTRA_DISTFILES = \ Test/resources/test.cs \ Test/resources/Sample.cs \ Test/resources/Sample.vb \ - Test/resources/junk.txt \ - Test/test-config-file* + Test/resources/junk.txt Test/resources/test.dll: Test/resources/test.cs $(CSCOMPILE) -target:library /out:$@ $< diff --git a/mcs/class/Microsoft.Build.Tasks/Test/test-config-file-net-4.0 b/mcs/class/Microsoft.Build.Tasks/Test/test-config-file-net-4.0 deleted file mode 100644 index 3c78f3b4ec8..00000000000 --- a/mcs/class/Microsoft.Build.Tasks/Test/test-config-file-net-4.0 +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/mcs/class/Microsoft.Build.Utilities/.gitignore b/mcs/class/Microsoft.Build.Utilities/.gitignore new file mode 100644 index 00000000000..c8cb7179505 --- /dev/null +++ b/mcs/class/Microsoft.Build.Utilities/.gitignore @@ -0,0 +1 @@ +Test/test-config-file-* diff --git a/mcs/class/Microsoft.Build.Utilities/Makefile b/mcs/class/Microsoft.Build.Utilities/Makefile index 10ef6780d4a..2c644346e2c 100644 --- a/mcs/class/Microsoft.Build.Utilities/Makefile +++ b/mcs/class/Microsoft.Build.Utilities/Makefile @@ -15,6 +15,7 @@ TEST_RESX_RESOURCES = Test/Microsoft.Build.Utilities/Strings.resources TEST_LIB_REFS = $(XBUILD_ENGINE) $(XBUILD_FRAMEWORK) $(PARENT_PROFILE)System $(PARENT_PROFILE)System.Core TEST_MCS_FLAGS = $(TEST_RESX_RESOURCES:%=-resource:%) +TEST_NUNITLITE_APP_CONFIG_RUNTIME=Test/test-config-file-$(PROFILE) include $(XBUILD_DIR)/xbuild_test.make include ../../build/library.make diff --git a/mcs/class/Microsoft.Build/.gitignore b/mcs/class/Microsoft.Build/.gitignore index bc686cf9c83..07547b0fc20 100644 --- a/mcs/class/Microsoft.Build/.gitignore +++ b/mcs/class/Microsoft.Build/.gitignore @@ -6,3 +6,4 @@ bin/ Microsoft.Build.Internal/ExpressionParser.cs Microsoft.Build.Internal/y.output Test/FunctionalTestProject*.csproj +Test/test-config-file-* diff --git a/mcs/class/Microsoft.Build/Makefile b/mcs/class/Microsoft.Build/Makefile index 933782ff268..47e9cf9ad41 100644 --- a/mcs/class/Microsoft.Build/Makefile +++ b/mcs/class/Microsoft.Build/Makefile @@ -10,9 +10,10 @@ LIBRARY = Microsoft.Build.dll LIB_REFS = $(PARENT_PROFILE)System $(PARENT_PROFILE)System.Core $(PARENT_PROFILE)System.Xml Microsoft.Build.Engine Microsoft.Build.Framework LIB_MCS_FLAGS = \ /d:MICROSOFT_BUILD_DLL - + TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) TEST_LIB_REFS = $(XBUILD_UTILITIES) +TEST_NUNITLITE_APP_CONFIG_RUNTIME=Test/test-config-file-$(PROFILE) EXTRA_DISTFILES = \ Microsoft.Build.Internal/ExpressionParser.jay \ diff --git a/mcs/class/Microsoft.Build/Microsoft.Build.Internal/BuildNodeManager.cs b/mcs/class/Microsoft.Build/Microsoft.Build.Internal/BuildNodeManager.cs index 322006a4e84..135734fb030 100644 --- a/mcs/class/Microsoft.Build/Microsoft.Build.Internal/BuildNodeManager.cs +++ b/mcs/class/Microsoft.Build/Microsoft.Build.Internal/BuildNodeManager.cs @@ -80,6 +80,9 @@ namespace Microsoft.Build.Internal if (!queued_builds.TryDequeue (out build)) continue; StartOneBuild (build); + } catch (ThreadAbortException) { + // do nothing + break; } catch (Exception ex) { // FIXME: I guess INodeLogger should be used instead. Console.Error.WriteLine ("Uncaught build node exception occured"); diff --git a/mcs/class/Microsoft.Build/Microsoft.Build_test.dll.sources b/mcs/class/Microsoft.Build/Microsoft.Build_test.dll.sources index 7b65749c86a..28c4af1277a 100644 --- a/mcs/class/Microsoft.Build/Microsoft.Build_test.dll.sources +++ b/mcs/class/Microsoft.Build/Microsoft.Build_test.dll.sources @@ -1,3 +1,4 @@ +../../test-helpers/NunitHelpers.cs FunctionalTest.cs Microsoft.Build.Construction/ProjectItemElementTest.cs Microsoft.Build.Construction/ProjectRootElementTest.cs diff --git a/mcs/class/Mono.CodeContracts/Mono.CodeContracts_test.dll.sources b/mcs/class/Mono.CodeContracts/Mono.CodeContracts_test.dll.sources index 984809180a1..9e77c38bdf1 100644 --- a/mcs/class/Mono.CodeContracts/Mono.CodeContracts_test.dll.sources +++ b/mcs/class/Mono.CodeContracts/Mono.CodeContracts_test.dll.sources @@ -1,2 +1,3 @@ +../../test-helpers/NunitHelpers.cs RewriteAndLoad.cs TestCCRewrite.cs diff --git a/mcs/class/Mono.CompilerServices.SymbolWriter/SourceMethodBuilder.cs b/mcs/class/Mono.CompilerServices.SymbolWriter/SourceMethodBuilder.cs index 89763f52ec9..816fb68dc5f 100644 --- a/mcs/class/Mono.CompilerServices.SymbolWriter/SourceMethodBuilder.cs +++ b/mcs/class/Mono.CompilerServices.SymbolWriter/SourceMethodBuilder.cs @@ -187,13 +187,54 @@ namespace Mono.CompilerServices.SymbolWriter public void DefineMethod (MonoSymbolFile file, int token) { var blocks = Blocks; + if (blocks.Length > 0) { + // + // When index is provided by user it can be inserted in + // any order but mdb format does not store its value. It + // uses stored order as the index instead. + // + var sorted = new List (blocks.Length); + int max_index = 0; + for (int i = 0; i < blocks.Length; ++i) { + max_index = System.Math.Max (max_index, blocks [i].Index); + } + + for (int i = 0; i < max_index; ++i) { + var scope_index = i + 1; + + // + // Common fast path + // + if (i < blocks.Length && blocks [i].Index == scope_index) { + sorted.Add (blocks [i]); + continue; + } + + bool found = false; + for (int ii = 0; ii < blocks.Length; ++ii) { + if (blocks [ii].Index == scope_index) { + sorted.Add (blocks [ii]); + found = true; + break; + } + } + + if (found) + continue; + + // + // Ideally this should never happen but with current design we can + // generate scope index for unreachable code before reachable code + // + sorted.Add (new CodeBlockEntry (scope_index, -1, CodeBlockEntry.Type.CompilerGenerated, 0)); + } - // - // When index is provided by user it can be inserted in - // any order but mdb format does not store its value. It - // uses store order instead as the index. - // - Array.Sort (blocks, (x, y) => x.Index.CompareTo (y.Index)); + blocks = sorted.ToArray (); + //for (int i = 0; i < blocks.Length; ++i) { + // if (blocks [i].Index - 1 != i) + // throw new ArgumentException ("CodeBlocks cannot be converted to mdb format"); + //} + } var entry = new MethodEntry ( file, _comp_unit.Entry, token, ScopeVariables, diff --git a/mcs/class/Mono.Parallel/Mono.Parallel_test.dll.sources b/mcs/class/Mono.Parallel/Mono.Parallel_test.dll.sources index 1eb8276dbde..c187abfe371 100644 --- a/mcs/class/Mono.Parallel/Mono.Parallel_test.dll.sources +++ b/mcs/class/Mono.Parallel/Mono.Parallel_test.dll.sources @@ -1,3 +1,4 @@ +../../test-helpers/NunitHelpers.cs Mono.Collections.Concurrent/CollectionStressTestHelper.cs Mono.Collections.Concurrent/ConcurrentSkipListTests.cs Mono.Threading/ParallelTestHelper.cs diff --git a/mcs/class/Mono.Posix/Mono.Posix_test.dll.sources b/mcs/class/Mono.Posix/Mono.Posix_test.dll.sources index a2f290f8656..55773333f78 100644 --- a/mcs/class/Mono.Posix/Mono.Posix_test.dll.sources +++ b/mcs/class/Mono.Posix/Mono.Posix_test.dll.sources @@ -1,3 +1,4 @@ +../../test-helpers/NunitHelpers.cs Mono.Unix/ReadlinkTest.cs Mono.Unix/StdioFileStreamTest.cs Mono.Unix/UnixEncodingTest.cs diff --git a/mcs/class/Mono.Posix/Test/Mono.Unix.Native/RealTimeSignumTests.cs b/mcs/class/Mono.Posix/Test/Mono.Unix.Native/RealTimeSignumTests.cs index f68fe53b8ce..892f087e48f 100644 --- a/mcs/class/Mono.Posix/Test/Mono.Unix.Native/RealTimeSignumTests.cs +++ b/mcs/class/Mono.Posix/Test/Mono.Unix.Native/RealTimeSignumTests.cs @@ -8,9 +8,7 @@ // using NUnit.Framework; -#if !MONODROID -using NUnit.Framework.SyntaxHelpers; -#endif + using System; using System.Text; using System.Threading; @@ -21,7 +19,7 @@ using Mono.Unix.Native; namespace MonoTests.Mono.Unix.Native { [TestFixture] - [Category ("NotOnMac")] + [Category ("NotOnMac"), Category ("NotOnWindows")] public class RealTimeSignumTest { [Test] diff --git a/mcs/class/Mono.Posix/Test/Mono.Unix.Native/SocketTest.cs b/mcs/class/Mono.Posix/Test/Mono.Unix.Native/SocketTest.cs index 3ec10f916ce..31c4549dd6e 100644 --- a/mcs/class/Mono.Posix/Test/Mono.Unix.Native/SocketTest.cs +++ b/mcs/class/Mono.Posix/Test/Mono.Unix.Native/SocketTest.cs @@ -20,7 +20,7 @@ using NUnit.Framework; namespace MonoTests.Mono.Unix.Native { - [TestFixture, Category ("NotDotNet")] + [TestFixture, Category ("NotDotNet"), Category ("NotOnWindows")] public class SocketTest { string TempFolder; diff --git a/mcs/class/Mono.Posix/Test/Mono.Unix.Native/StdlibTest.cs b/mcs/class/Mono.Posix/Test/Mono.Unix.Native/StdlibTest.cs index 1b7b77d5aca..aa0c06b76c6 100644 --- a/mcs/class/Mono.Posix/Test/Mono.Unix.Native/StdlibTest.cs +++ b/mcs/class/Mono.Posix/Test/Mono.Unix.Native/StdlibTest.cs @@ -17,7 +17,7 @@ using Mono.Unix.Native; namespace MonoTests.Mono.Unix.Native { - [TestFixture] + [TestFixture, Category ("NotOnWindows")] public class StdlibTest { private class SignalTest { diff --git a/mcs/class/Mono.Posix/Test/Mono.Unix/ReadlinkTest.cs b/mcs/class/Mono.Posix/Test/Mono.Unix/ReadlinkTest.cs index 608127b568c..2f286d49b81 100644 --- a/mcs/class/Mono.Posix/Test/Mono.Unix/ReadlinkTest.cs +++ b/mcs/class/Mono.Posix/Test/Mono.Unix/ReadlinkTest.cs @@ -18,7 +18,7 @@ using NUnit.Framework; namespace MonoTests.Mono.Unix { - [TestFixture, Category ("NotDotNet")] + [TestFixture, Category ("NotDotNet"), Category ("NotOnWindows")] public class ReadlinkTest { static string[] Targets = { @@ -173,7 +173,7 @@ namespace MonoTests.Mono.Unix long r = Syscall.readlink (link, buf); if (r < 0) UnixMarshal.ThrowExceptionForLastError (); - Assert.GreaterOrEqual (buf.Length, r); + AssertHelper.GreaterOrEqual (buf.Length, r); if (r == buf.Length) buf = new byte[checked (buf.Length * 2)]; else @@ -199,7 +199,7 @@ namespace MonoTests.Mono.Unix long r = Syscall.readlinkat (TempFD, "link", buf); if (r < 0) UnixMarshal.ThrowExceptionForLastError (); - Assert.GreaterOrEqual (buf.Length, r); + AssertHelper.GreaterOrEqual (buf.Length, r); if (r == buf.Length) buf = new byte[checked (buf.Length * 2)]; else @@ -226,7 +226,7 @@ namespace MonoTests.Mono.Unix if (r < 0) UnixMarshal.ThrowExceptionForLastError (); Assert.AreEqual (r, sb.Length); - Assert.GreaterOrEqual (sb.Capacity, r); + AssertHelper.GreaterOrEqual (sb.Capacity, r); if (r == sb.Capacity) checked { sb.Capacity *= 2; } else @@ -255,7 +255,7 @@ namespace MonoTests.Mono.Unix if (r < 0) UnixMarshal.ThrowExceptionForLastError (); Assert.AreEqual (r, sb.Length); - Assert.GreaterOrEqual (sb.Capacity, r); + AssertHelper.GreaterOrEqual (sb.Capacity, r); if (r == sb.Capacity) checked { sb.Capacity *= 2; } else diff --git a/mcs/class/Mono.Posix/Test/Mono.Unix/UnixEndPointTest.cs b/mcs/class/Mono.Posix/Test/Mono.Unix/UnixEndPointTest.cs index 21e5b791636..837fe4ec263 100644 --- a/mcs/class/Mono.Posix/Test/Mono.Unix/UnixEndPointTest.cs +++ b/mcs/class/Mono.Posix/Test/Mono.Unix/UnixEndPointTest.cs @@ -17,7 +17,7 @@ using Mono.Unix; namespace MonoTests.Mono.Unix { - [TestFixture] + [TestFixture, Category ("NotOnWindows")] public class UnixEndPointTest { // Regression test for https://bugzilla.xamarin.com/show_bug.cgi?id=35004 diff --git a/mcs/class/Mono.Posix/Test/Mono.Unix/UnixGroupTest.cs b/mcs/class/Mono.Posix/Test/Mono.Unix/UnixGroupTest.cs index 81e775e64b0..da6bbe08372 100644 --- a/mcs/class/Mono.Posix/Test/Mono.Unix/UnixGroupTest.cs +++ b/mcs/class/Mono.Posix/Test/Mono.Unix/UnixGroupTest.cs @@ -21,7 +21,7 @@ using Syscall = Mono.Unix.Native.Syscall; namespace MonoTests.Mono.Unix { - [TestFixture, Category ("NotDotNet")] + [TestFixture, Category ("NotDotNet"), Category ("NotOnWindows")] public class UnixGroupTest { [Test] diff --git a/mcs/class/Mono.Posix/Test/Mono.Unix/UnixListenerTest.cs b/mcs/class/Mono.Posix/Test/Mono.Unix/UnixListenerTest.cs index b2312b5590f..ad2d3089a42 100644 --- a/mcs/class/Mono.Posix/Test/Mono.Unix/UnixListenerTest.cs +++ b/mcs/class/Mono.Posix/Test/Mono.Unix/UnixListenerTest.cs @@ -14,7 +14,7 @@ using Mono.Unix; namespace MonoTests.Mono.Unix { - [TestFixture] + [TestFixture, Category ("NotOnWindows")] public class UnixListenerTest { // test that a socket file is created and deleted by the UnixListener diff --git a/mcs/class/Mono.Posix/Test/Mono.Unix/UnixMarshalTest.cs b/mcs/class/Mono.Posix/Test/Mono.Unix/UnixMarshalTest.cs index e27a5dd246c..8ae50b98c97 100644 --- a/mcs/class/Mono.Posix/Test/Mono.Unix/UnixMarshalTest.cs +++ b/mcs/class/Mono.Posix/Test/Mono.Unix/UnixMarshalTest.cs @@ -28,7 +28,7 @@ namespace MonoTests.Mono.Unix { } } - [TestFixture] + [TestFixture, Category ("NotOnWindows")] public class UnixMarshalTest { #if false public static void Main () diff --git a/mcs/class/Mono.Posix/Test/Mono.Unix/UnixPathTest.cs b/mcs/class/Mono.Posix/Test/Mono.Unix/UnixPathTest.cs index c21348748dc..6c10225dfe7 100644 --- a/mcs/class/Mono.Posix/Test/Mono.Unix/UnixPathTest.cs +++ b/mcs/class/Mono.Posix/Test/Mono.Unix/UnixPathTest.cs @@ -16,7 +16,7 @@ using Mono.Unix; namespace MonoTests.Mono.Unix { - [TestFixture, Category ("NotDotNet")] + [TestFixture, Category ("NotDotNet"), Category ("NotOnWindows")] public class UnixPathTest { private static readonly char DSC = UnixPath.DirectorySeparatorChar; diff --git a/mcs/class/Mono.Posix/Test/Mono.Unix/UnixSignalTest.cs b/mcs/class/Mono.Posix/Test/Mono.Unix/UnixSignalTest.cs index 9abc27094c9..5dc422d5a34 100644 --- a/mcs/class/Mono.Posix/Test/Mono.Unix/UnixSignalTest.cs +++ b/mcs/class/Mono.Posix/Test/Mono.Unix/UnixSignalTest.cs @@ -8,21 +8,17 @@ // using NUnit.Framework; -#if !MONODROID -using NUnit.Framework.SyntaxHelpers; -#endif + using System; using System.Text; using System.Threading; using Mono.Unix; using Mono.Unix.Android; using Mono.Unix.Native; -#if !MONODROID -namespace NUnit.Framework.SyntaxHelpers { class Dummy {} } -#endif + namespace MonoTests.Mono.Unix { - [TestFixture] + [TestFixture, Category ("NotOnWindows")] public class UnixSignalTest { // helper method to create a thread waiting on a UnixSignal diff --git a/mcs/class/Mono.Posix/Test/Mono.Unix/UnixUserTest.cs b/mcs/class/Mono.Posix/Test/Mono.Unix/UnixUserTest.cs index 30f0450637c..68a36c935c6 100644 --- a/mcs/class/Mono.Posix/Test/Mono.Unix/UnixUserTest.cs +++ b/mcs/class/Mono.Posix/Test/Mono.Unix/UnixUserTest.cs @@ -21,7 +21,7 @@ using Syscall = Mono.Unix.Native.Syscall; namespace MonoTests.Mono.Unix { - [TestFixture, Category ("NotDotNet")] + [TestFixture, Category ("NotDotNet"), Category ("NotOnWindows")] public class UnixUserTest { [Test] diff --git a/mcs/class/Mono.Reactive.Testing/Makefile b/mcs/class/Mono.Reactive.Testing/Makefile index ae7afa670cb..aa931ee9db7 100644 --- a/mcs/class/Mono.Reactive.Testing/Makefile +++ b/mcs/class/Mono.Reactive.Testing/Makefile @@ -3,7 +3,7 @@ SUBDIRS = include ../../build/rules.make LIBRARY = Mono.Reactive.Testing.dll -LIB_REFS = System System.Core System.Reactive.Interfaces System.Reactive.Core System.Reactive.Linq System.Reactive.PlatformServices System.Reactive.Providers System.Reactive.Runtime.Remoting System.Reactive.Experimental System.Reactive.Windows.Forms System.Reactive.Windows.Threading System.Reactive.Observable.Aliases System.Windows.Forms WindowsBase nunit.framework +LIB_REFS = System System.Core System.Reactive.Interfaces System.Reactive.Core System.Reactive.Linq System.Reactive.PlatformServices System.Reactive.Providers System.Reactive.Runtime.Remoting System.Reactive.Experimental System.Reactive.Windows.Forms System.Reactive.Windows.Threading System.Reactive.Observable.Aliases System.Windows.Forms WindowsBase nunitlite LIB_MCS_FLAGS = \ @more_build_args \ -d:NUNIT -d:MONO -d:DESKTOPCLR diff --git a/mcs/class/Mono.Security/Test/tools/sockethell/Makefile b/mcs/class/Mono.Security/Test/tools/sockethell/Makefile index 0ad21f2c436..6557bccc3e5 100644 --- a/mcs/class/Mono.Security/Test/tools/sockethell/Makefile +++ b/mcs/class/Mono.Security/Test/tools/sockethell/Makefile @@ -2,7 +2,7 @@ thisdir = class/Mono.Security/Test/tools/sockethell SUBDIRS = include ../../../../../build/rules.make -LOCAL_MCS_FLAGS = -r:System.dll -r:Mono.Security.dll -r:../../../../lib/net_4_x/nunit.framework.dll +LOCAL_MCS_FLAGS = -r:System.dll -r:Mono.Security.dll -r:../../../../lib/net_4_x/nunitlite.dll all-local install-local uninstall-local: diff --git a/mcs/class/Mono.XBuild.Tasks/.gitignore b/mcs/class/Mono.XBuild.Tasks/.gitignore new file mode 100644 index 00000000000..c8cb7179505 --- /dev/null +++ b/mcs/class/Mono.XBuild.Tasks/.gitignore @@ -0,0 +1 @@ +Test/test-config-file-* diff --git a/mcs/class/Mono.XBuild.Tasks/Makefile b/mcs/class/Mono.XBuild.Tasks/Makefile index 8d50c7ad629..11f7b791c43 100644 --- a/mcs/class/Mono.XBuild.Tasks/Makefile +++ b/mcs/class/Mono.XBuild.Tasks/Makefile @@ -10,6 +10,8 @@ LIBRARY = Mono.XBuild.Tasks.dll LIB_REFS = $(PARENT_PROFILE)System $(PARENT_PROFILE)System.Xml LIB_MCS_FLAGS = +TEST_NUNITLITE_APP_CONFIG_RUNTIME=Test/test-config-file-$(PROFILE) + include $(XBUILD_DIR)/xbuild_test.make include ../../build/library.make diff --git a/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks_test.dll.sources b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks_test.dll.sources index 0dbb1260ba9..902f1ac1629 100644 --- a/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks_test.dll.sources +++ b/mcs/class/Mono.XBuild.Tasks/Mono.XBuild.Tasks_test.dll.sources @@ -1 +1,2 @@ +../../test-helpers/NunitHelpers.cs Mono.XBuild.Tasks/PcFileCacheTest.cs diff --git a/mcs/class/System.Configuration/Makefile b/mcs/class/System.Configuration/Makefile index 7cdf1b26842..e6f48050a99 100644 --- a/mcs/class/System.Configuration/Makefile +++ b/mcs/class/System.Configuration/Makefile @@ -10,6 +10,7 @@ LIB_REFS = secxml/System bare/System.Xml System.Security LIB_MCS_FLAGS = -nowarn:618 TEST_MCS_FLAGS = TEST_LIB_REFS = System.Xml System +TEST_NUNITLITE_APP_CONFIG_GLOBAL=Test/test-config-file include ../../build/library.make @@ -20,6 +21,9 @@ configuration_library_deps = \ $(build_lib): $(configuration_library_deps) +test-local: + cp Test/appSettings.config $(dir $(NUNITLITE_CONFIG_FILE))/Test-appSettings.config + .NOTPARALLEL: $(configuration_library_deps) $(secxml_libdir)/System.dll: diff --git a/mcs/class/System.Configuration/Test/App.config b/mcs/class/System.Configuration/Test/App.config deleted file mode 100644 index d07b4f882f8..00000000000 --- a/mcs/class/System.Configuration/Test/App.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - diff --git a/mcs/class/System.Configuration/Test/System.Configuration/AppSettingsSectionTest.cs b/mcs/class/System.Configuration/Test/System.Configuration/AppSettingsSectionTest.cs index 83e87e21b6a..f0445810330 100644 --- a/mcs/class/System.Configuration/Test/System.Configuration/AppSettingsSectionTest.cs +++ b/mcs/class/System.Configuration/Test/System.Configuration/AppSettingsSectionTest.cs @@ -65,9 +65,9 @@ namespace MonoTests.System.Configuration { Directory.SetCurrentDirectory (tempFolder); - var currentAssembly = Assembly.GetExecutingAssembly ().Location; + var currentAssembly = TestUtil.ThisApplicationPath; var config = ConfigurationManager.OpenExeConfiguration (currentAssembly); - Assert.AreEqual ("Test/appSettings.config", config.AppSettings.File, "#A01"); + Assert.AreEqual ("Test-appSettings.config", config.AppSettings.File, "#A01"); Assert.AreEqual ("foo", ConfigurationSettings.AppSettings["TestKey1"], "#A02"); Assert.AreEqual ("bar", ConfigurationSettings.AppSettings["TestKey2"], "#A03"); } diff --git a/mcs/class/System.Configuration/Test/System.Configuration/ConfigurationManagerTest.cs b/mcs/class/System.Configuration/Test/System.Configuration/ConfigurationManagerTest.cs index 7efff1dddff..0b5b3cde0dc 100644 --- a/mcs/class/System.Configuration/Test/System.Configuration/ConfigurationManagerTest.cs +++ b/mcs/class/System.Configuration/Test/System.Configuration/ConfigurationManagerTest.cs @@ -257,10 +257,9 @@ namespace MonoTests.System.Configuration { [Test] public void exePath_UserLevelNone () { - string basedir = AppDomain.CurrentDomain.BaseDirectory; - string name = TestUtil.ThisDllName; + string name = TestUtil.ThisApplicationPath; SysConfig config = ConfigurationManager.OpenExeConfiguration (name); - Assert.AreEqual (Path.Combine (basedir, name + ".config"), config.FilePath); + Assert.AreEqual (TestUtil.ThisApplicationPath + ".config", config.FilePath); } [Test] @@ -615,11 +614,6 @@ namespace MonoTests.System.Configuration { [Test] public void TestConnectionStringRetrieval () { - var currentAssembly = Assembly.GetExecutingAssembly().Location; - Assert.IsTrue (File.Exists (currentAssembly + ".config"), - String.Format ("This test cannot succeed without the .config file being in the same place as the assembly ({0})", - currentAssembly)); - var connStringObj = ConfigurationManager.ConnectionStrings ["test-connstring"]; Assert.IsNotNull (connStringObj); var connString = connStringObj.ConnectionString; diff --git a/mcs/class/System.Configuration/Test/System.Configuration/ConfigurationSaveTest.cs b/mcs/class/System.Configuration/Test/System.Configuration/ConfigurationSaveTest.cs index 4d0e369b414..2bb7723f7a0 100644 --- a/mcs/class/System.Configuration/Test/System.Configuration/ConfigurationSaveTest.cs +++ b/mcs/class/System.Configuration/Test/System.Configuration/ConfigurationSaveTest.cs @@ -37,7 +37,6 @@ using SysConfig = System.Configuration.Configuration; using NUnit.Framework; using NUnit.Framework.Constraints; -using NUnit.Framework.SyntaxHelpers; namespace MonoTests.System.Configuration { using Util; diff --git a/mcs/class/System.Configuration/Test/Util/TestUtil.cs b/mcs/class/System.Configuration/Test/Util/TestUtil.cs index 6faeba67a14..497a8a8081d 100644 --- a/mcs/class/System.Configuration/Test/Util/TestUtil.cs +++ b/mcs/class/System.Configuration/Test/Util/TestUtil.cs @@ -64,17 +64,16 @@ namespace MonoTests.System.Configuration.Util { } } - public static string ThisDllName { + public static string ThisApplicationPath { get { - var asm = Assembly.GetCallingAssembly (); - return Path.GetFileName (asm.Location); + var asm = Assembly.GetEntryAssembly (); + return asm.Location; } } public static string ThisConfigFileName { get { - var asm = Assembly.GetCallingAssembly (); - var exe = Path.GetFileName (asm.Location); + var exe = Path.GetFileName (ThisApplicationPath); return exe + ".config"; } } diff --git a/mcs/class/System.Configuration/Test/test-config-file b/mcs/class/System.Configuration/Test/test-config-file new file mode 100644 index 00000000000..5920c6c2ab0 --- /dev/null +++ b/mcs/class/System.Configuration/Test/test-config-file @@ -0,0 +1,5 @@ + + + + diff --git a/mcs/class/System.Configuration/net_4_x_System.Configuration_test.dll.config b/mcs/class/System.Configuration/net_4_x_System.Configuration_test.dll.config deleted file mode 100644 index d07b4f882f8..00000000000 --- a/mcs/class/System.Configuration/net_4_x_System.Configuration_test.dll.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - diff --git a/mcs/class/System.Core/Microsoft.Win32.SafeHandles/SafeMemoryMappedViewHandle.cs b/mcs/class/System.Core/Microsoft.Win32.SafeHandles/SafeMemoryMappedViewHandle.cs index f165f3f6279..e48161a358a 100644 --- a/mcs/class/System.Core/Microsoft.Win32.SafeHandles/SafeMemoryMappedViewHandle.cs +++ b/mcs/class/System.Core/Microsoft.Win32.SafeHandles/SafeMemoryMappedViewHandle.cs @@ -44,6 +44,10 @@ namespace Microsoft.Win32.SafeHandles Initialize ((ulong)size); } + internal void Flush () { + MemoryMapImpl.Flush (this.mmap_handle); + } + protected override bool ReleaseHandle () { if (this.handle != (IntPtr) (-1)) return MemoryMapImpl.Unmap (this.mmap_handle); diff --git a/mcs/class/System.Core/System.IO.MemoryMappedFiles/MemoryMappedFile.cs b/mcs/class/System.Core/System.IO.MemoryMappedFiles/MemoryMappedFile.cs index fbc55fd73b5..7a3cce164f6 100644 --- a/mcs/class/System.Core/System.IO.MemoryMappedFiles/MemoryMappedFile.cs +++ b/mcs/class/System.Core/System.IO.MemoryMappedFiles/MemoryMappedFile.cs @@ -70,7 +70,7 @@ namespace System.IO.MemoryMappedFiles case 1: return new ArgumentException ("A positive capacity must be specified for a Memory Mapped File backed by an empty file."); case 2: - return new ArgumentOutOfRangeException ("The capacity may not be smaller than the file size."); + return new ArgumentOutOfRangeException ("capacity", "The capacity may not be smaller than the file size."); case 3: return new FileNotFoundException (path); case 4: @@ -85,6 +85,10 @@ namespace System.IO.MemoryMappedFiles return new ArgumentException ("Invalid FileMode value."); case 9: return new IOException ("Could not map file"); + case 10: + return new UnauthorizedAccessException ("Access to the path is denied."); + case 11: + return new ArgumentOutOfRangeException ("capacity", "The capacity cannot be greater than the size of the system's logical address space."); default: return new IOException ("Failed with unknown error code " + error); } @@ -140,7 +144,7 @@ namespace System.IO.MemoryMappedFiles if (mode == FileMode.Append) throw new ArgumentException ("mode"); - IntPtr handle = MemoryMapImpl.OpenFile (path, mode, null, out capacity, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.DelayAllocatePages); + IntPtr handle = MemoryMapImpl.OpenFile (path, mode, null, out capacity, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None); return new MemoryMappedFile () { handle = handle, @@ -172,7 +176,7 @@ namespace System.IO.MemoryMappedFiles if (capacity < 0) throw new ArgumentOutOfRangeException ("capacity"); - IntPtr handle = MemoryMapImpl.OpenFile (path, mode, mapName, out capacity, access, MemoryMappedFileOptions.DelayAllocatePages); + IntPtr handle = MemoryMapImpl.OpenFile (path, mode, mapName, out capacity, access, MemoryMappedFileOptions.None); return new MemoryMappedFile () { handle = handle, @@ -193,7 +197,7 @@ namespace System.IO.MemoryMappedFiles if ((!MonoUtil.IsUnix && capacity == 0 && fileStream.Length == 0) || (capacity > fileStream.Length)) throw new ArgumentException ("capacity"); - IntPtr handle = MemoryMapImpl.OpenHandle (fileStream.SafeFileHandle.DangerousGetHandle (), mapName, out capacity, access, MemoryMappedFileOptions.DelayAllocatePages); + IntPtr handle = MemoryMapImpl.OpenHandle (fileStream.SafeFileHandle.DangerousGetHandle (), mapName, out capacity, access, MemoryMappedFileOptions.None); MemoryMapImpl.ConfigureHandleInheritability (handle, inheritability); @@ -220,7 +224,7 @@ namespace System.IO.MemoryMappedFiles if ((!MonoUtil.IsUnix && capacity == 0 && fileStream.Length == 0) || (capacity > fileStream.Length)) throw new ArgumentException ("capacity"); - IntPtr handle = MemoryMapImpl.OpenHandle (fileStream.SafeFileHandle.DangerousGetHandle (), mapName, out capacity, access, MemoryMappedFileOptions.DelayAllocatePages); + IntPtr handle = MemoryMapImpl.OpenHandle (fileStream.SafeFileHandle.DangerousGetHandle (), mapName, out capacity, access, MemoryMappedFileOptions.None); MemoryMapImpl.ConfigureHandleInheritability (handle, inheritability); @@ -258,13 +262,13 @@ namespace System.IO.MemoryMappedFiles [MonoLimitation ("Named mappings scope is process local")] public static MemoryMappedFile CreateNew (string mapName, long capacity) { - return CreateNew (mapName, capacity, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.DelayAllocatePages, null, HandleInheritability.None); + return CreateNew (mapName, capacity, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None, null, HandleInheritability.None); } [MonoLimitation ("Named mappings scope is process local")] public static MemoryMappedFile CreateNew (string mapName, long capacity, MemoryMappedFileAccess access) { - return CreateNew (mapName, capacity, access, MemoryMappedFileOptions.DelayAllocatePages, null, HandleInheritability.None); + return CreateNew (mapName, capacity, access, MemoryMappedFileOptions.None, null, HandleInheritability.None); } [MonoLimitation ("Named mappings scope is process local; options is ignored")] @@ -290,7 +294,7 @@ namespace System.IO.MemoryMappedFiles [MonoLimitation ("Named mappings scope is process local")] public static MemoryMappedFile CreateOrOpen (string mapName, long capacity, MemoryMappedFileAccess access) { - return CreateOrOpen (mapName, capacity, access, MemoryMappedFileOptions.DelayAllocatePages, null, HandleInheritability.None); + return CreateOrOpen (mapName, capacity, access, MemoryMappedFileOptions.None, null, HandleInheritability.None); } [MonoLimitation ("Named mappings scope is process local")] diff --git a/mcs/class/System.Core/System.IO.MemoryMappedFiles/MemoryMappedView.cs b/mcs/class/System.Core/System.IO.MemoryMappedFiles/MemoryMappedView.cs index 9362f00b162..b0be2e4f188 100644 --- a/mcs/class/System.Core/System.IO.MemoryMappedFiles/MemoryMappedView.cs +++ b/mcs/class/System.Core/System.IO.MemoryMappedFiles/MemoryMappedView.cs @@ -92,7 +92,7 @@ namespace System.IO.MemoryMappedFiles public void Flush (IntPtr capacity) { - MemoryMapImpl.Flush (m_viewHandle.DangerousGetHandle ()); + m_viewHandle.Flush (); } protected virtual void Dispose (bool disposing) diff --git a/mcs/class/System.Core/Test/System.IO.MemoryMappedFiles/MemoryMappedFileTest.cs b/mcs/class/System.Core/Test/System.IO.MemoryMappedFiles/MemoryMappedFileTest.cs index 27191c37ed2..9c273b84a59 100644 --- a/mcs/class/System.Core/Test/System.IO.MemoryMappedFiles/MemoryMappedFileTest.cs +++ b/mcs/class/System.Core/Test/System.IO.MemoryMappedFiles/MemoryMappedFileTest.cs @@ -56,16 +56,28 @@ namespace MonoTests.System.IO.MemoryMappedFiles { return "test-" + named_index++; } - + static string baseTempDir = Path.Combine (Path.GetTempPath (), typeof (MemoryMappedFileTest).FullName); static string tempDir = Path.Combine (Path.GetTempPath (), typeof (MemoryMappedFileTest).FullName); string fname; - [SetUp] - protected void SetUp () { - if (Directory.Exists (tempDir)) - Directory.Delete (tempDir, true); + [TestFixtureSetUp] + public void FixtureSetUp () + { + try { + // Try to cleanup from any previous NUnit run. + Directory.Delete (baseTempDir, true); + } catch (Exception) { + } + } + [SetUp] + public void SetUp () + { + int i = 0; + do { + tempDir = Path.Combine (baseTempDir, (++i).ToString()); + } while (Directory.Exists (tempDir)); Directory.CreateDirectory (tempDir); fname = Path.Combine (tempDir, "basic.txt"); @@ -77,9 +89,14 @@ namespace MonoTests.System.IO.MemoryMappedFiles { } [TearDown] - protected void TearDown () { - if (Directory.Exists (tempDir)) + public void TearDown () + { + try { + // This throws an exception under MS.NET and Mono on Windows, + // since the directory contains open files. Directory.Delete (tempDir, true); + } catch (Exception) { + } } [Test] @@ -102,26 +119,16 @@ namespace MonoTests.System.IO.MemoryMappedFiles { public void CreateNew () { // This must succeed - MemoryMappedFile.CreateNew (Path.Combine (tempDir, "createNew.test"), 8192); - } - - [Test] - [ExpectedException (typeof (IOException))] - public void CreateNew_OnExistingFile () - { - // This must succeed - MemoryMappedFile.CreateNew (Path.Combine (tempDir, "createNew.test"), 8192); - - // This should fail, the file exists - MemoryMappedFile.CreateNew (Path.Combine (tempDir, "createNew.test"), 8192); + MemoryMappedFile.CreateNew (MkNamedMapping (), 8192); } // Call this twice, it should always work [Test] public void CreateOrOpen_Multiple () { - MemoryMappedFile.CreateOrOpen (Path.Combine (tempDir, "createOrOpen.test"), 8192); - MemoryMappedFile.CreateOrOpen (Path.Combine (tempDir, "createOrOpen.test"), 8192); + var name = MkNamedMapping (); + MemoryMappedFile.CreateOrOpen (name, 8192); + MemoryMappedFile.CreateOrOpen (name, 8192); } [Test] @@ -134,7 +141,7 @@ namespace MonoTests.System.IO.MemoryMappedFiles { // We are requesting fewer bytes to map. MemoryMappedFile.CreateFromFile (f, FileMode.Open, "myMap", 4192); } - + [Test] public void CreateFromFile_Null () { AssertThrows (delegate () { @@ -252,6 +259,9 @@ namespace MonoTests.System.IO.MemoryMappedFiles { [Test] public void NamedMappingToInvalidFile () { + if (Environment.OSVersion.Platform != PlatformID.Unix) { + Assert.Ignore ("Backslashes in mapping names are disallowed on .NET and Mono on Windows"); + } var fileName = Path.Combine (tempDir, "temp_file_123"); if (File.Exists (fileName)) File.Delete (fileName); @@ -352,7 +362,7 @@ namespace MonoTests.System.IO.MemoryMappedFiles { } [Test] - [ExpectedException(typeof(IOException))] + [ExpectedException(typeof(UnauthorizedAccessException))] public void CreateViewStreamWithOffsetPastFileEnd () { string f = Path.Combine (tempDir, "8192-file"); @@ -365,7 +375,7 @@ namespace MonoTests.System.IO.MemoryMappedFiles { } [Test] - [ExpectedException(typeof(IOException))] + [ExpectedException(typeof(UnauthorizedAccessException))] public void CreateViewStreamWithOffsetPastFileEnd2 () { string f = Path.Combine (tempDir, "8192-file"); @@ -394,7 +404,7 @@ namespace MonoTests.System.IO.MemoryMappedFiles { MemoryMappedViewStream stream = mappedFile.CreateViewStream (pageSize * 2, 0, MemoryMappedFileAccess.ReadWrite); #if !MONOTOUCH - Assert.AreEqual (stream.Capacity, Environment.SystemPageSize); + Assert.AreEqual (Environment.SystemPageSize, stream.Capacity); #endif stream.Write (new byte [pageSize], 0, pageSize); } @@ -407,9 +417,39 @@ namespace MonoTests.System.IO.MemoryMappedFiles { File.WriteAllBytes (f, new byte [size]); FileStream file = File.OpenRead (f); - MemoryMappedFile.CreateFromFile (file, null, size, MemoryMappedFileAccess.ReadExecute, null, 0, false); + MemoryMappedFile.CreateFromFile (file, null, size, MemoryMappedFileAccess.Read, null, 0, false); } - } -} + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void CreateNewLargerThanLogicalAddressSpace () + { + if (IntPtr.Size != 4) { + Assert.Ignore ("Only applies to 32-bit systems"); + } + MemoryMappedFile.CreateNew (MkNamedMapping (), (long) uint.MaxValue + 1); + } + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void CreateOrOpenLargerThanLogicalAddressSpace () + { + if (IntPtr.Size != 4) { + Assert.Ignore ("Only applies to 32-bit systems"); + } + MemoryMappedFile.CreateOrOpen (MkNamedMapping (), (long) uint.MaxValue + 1); + } + + [Test] + public void NamedMappingWithDelayAllocatePages () + { + var name = MkNamedMapping (); + using (var m0 = MemoryMappedFile.CreateNew(name, 4096, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.DelayAllocatePages, HandleInheritability.None)) { + using (MemoryMappedViewAccessor v0 = m0.CreateViewAccessor ()) { + Assert.AreEqual (0, v0.ReadInt32 (0)); + } + } + } + + } +} diff --git a/mcs/class/System.Core/Test/System.Linq/EnumerableFixture.cs b/mcs/class/System.Core/Test/System.Linq/EnumerableFixture.cs index a9389f9b497..ceef4c02157 100644 --- a/mcs/class/System.Core/Test/System.Linq/EnumerableFixture.cs +++ b/mcs/class/System.Core/Test/System.Linq/EnumerableFixture.cs @@ -34,12 +34,9 @@ using System.Text; using System.Threading; using NUnit.Framework; using System.Linq; -using NUnit.Framework.SyntaxHelpers; using NUnit.Framework.Constraints; using System.Diagnostics; -namespace NUnit.Framework.SyntaxHelpers { class Dummy {} } - namespace MonoTests.System.Linq { [TestFixture] diff --git a/mcs/class/System.Data.Linq/build/.gitignore b/mcs/class/System.Data.Linq/build/.gitignore new file mode 100644 index 00000000000..f2cf7dc6652 --- /dev/null +++ b/mcs/class/System.Data.Linq/build/.gitignore @@ -0,0 +1,2 @@ +Northwind.db3 + diff --git a/mcs/class/System.Data.Linq/build/DbLinq.Sqlite_test_mono_strict.dll.sources b/mcs/class/System.Data.Linq/build/DbLinq.Sqlite_test_mono_strict.dll.sources index 1079699a00f..22f797c60f4 100644 --- a/mcs/class/System.Data.Linq/build/DbLinq.Sqlite_test_mono_strict.dll.sources +++ b/mcs/class/System.Data.Linq/build/DbLinq.Sqlite_test_mono_strict.dll.sources @@ -1,3 +1,4 @@ +../../test-helpers/NunitHelpers.cs ../examples/DbLinq.SQLite.Example/nwind/Northwind.cs ../src/DbLinq.Sqlite/Test/DirectDataContext.cs ../src/DbLinq.Sqlite/Test/TestBase_mono.cs diff --git a/mcs/class/System.Data.Linq/build/Makefile b/mcs/class/System.Data.Linq/build/Makefile index bf28637588c..71e2154664a 100644 --- a/mcs/class/System.Data.Linq/build/Makefile +++ b/mcs/class/System.Data.Linq/build/Makefile @@ -25,15 +25,14 @@ sqlite_tests_dep = \ $(sqlite_tests): $(sqlite_tests_dep) $(TEST_COMPILE) -target:library -out:$@ \ - -r:System.Data.dll -r:$(the_assembly) -r:Mono.Data.Sqlite $(test_nunit_ref) \ + -r:$(topdir)/class/lib/$(PROFILE)/System.Data.dll -r:$(the_assembly) -r:$(topdir)/class/lib/$(PROFILE)/Mono.Data.Sqlite.dll -r:$(topdir)/class/lib/$(PROFILE)/System.Core.dll -r:$(topdir)/class/lib/$(PROFILE)/System.dll -r:$(topdir)/class/lib/$(PROFILE)/System.Xml.dll $(test_nunit_ref) \ $(TEST_MCS_FLAGS) -d:MONO_STRICT -d:SQLITE \ @$< $(TEST_SOURCES_WITH_SPACES) test-sqlite: $(sqlite_tests) RUN_TEST_COMMAND = \ - MONO_REGISTRY_PATH="$(HOME)/.mono/registry" $(TEST_RUNTIME) $(RUNTIME_FLAGS) $(TEST_HARNESS) $(1) -noshadow $(TEST_HARNESS_FLAGS) $(LOCAL_TEST_HARNESS_FLAGS) $(TEST_HARNESS_EXCLUDES) $(TEST_HARNESS_OUTPUT) -xml=TestResult-$(1:.dll=)-$(PROFILE).xml -out:TestResult-$(1:.dll=)-$(PROFILE).out $(FIXTURE_ARG) $(TESTNAME_ARG) ; \ - xsltproc $(topdir)/build/nunit-summary.xsl TestResult-$(1)-$(PROFILE).xml > TestResult-$(1:.dll=)-$(PROFILE).log + MONO_REGISTRY_PATH="$(HOME)/.mono/registry" $(TEST_RUNTIME) $(RUNTIME_FLAGS) $(TEST_HARNESS) $(1) $(TEST_HARNESS_FLAGS) $(LOCAL_TEST_HARNESS_FLAGS) $(TEST_HARNESS_EXCLUDES) $(TEST_HARNESS_OUTPUT) -labels -format:nunit2 -result=TestResult-$(1:.dll=)-$(PROFILE).xml $(FIXTURE_ARG) $(TESTNAME_ARG) ; run-test-sqlite: $(call RUN_TEST_COMMAND,$(sqlite_tests)) diff --git a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/DataContext.cs b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/DataContext.cs index c9bea8ea40c..f2b6d3ede66 100644 --- a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/DataContext.cs +++ b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/DataContext.cs @@ -71,7 +71,7 @@ using MsNorthwind; Assert.IsNotNull(dbCommand.CommandText); - Assert.Greater(dbCommand.Parameters.Count, 0); + AssertHelper.Greater(dbCommand.Parameters.Count, 0); } } } diff --git a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/DynamicLinqTest.cs b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/DynamicLinqTest.cs index 5ea0dbc7d76..9bd6aac50f9 100644 --- a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/DynamicLinqTest.cs +++ b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/DynamicLinqTest.cs @@ -186,7 +186,7 @@ using nwind; Northwind db = CreateDB(); Expression> predicate = c => c.City == "Paris"; int count = db.Customers.Count(predicate); - Assert.Greater(count, 0); // Some databases have more than 1 customer in Paris + AssertHelper.Greater(count, 0); // Some databases have more than 1 customer in Paris } /// diff --git a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ExecuteCommand_Test.cs b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ExecuteCommand_Test.cs index 87bf3d8cdee..b8a1c728d8e 100644 --- a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ExecuteCommand_Test.cs +++ b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ExecuteCommand_Test.cs @@ -68,7 +68,7 @@ using nwind; { Northwind db = CreateDB(); int result = db.ExecuteCommand("SELECT count(*) FROM \"Products\""); - Assert.Greater(result, 0, "Expecting some rows in Products table, got:" + result); + AssertHelper.Greater(result, 0, "Expecting some rows in Products table, got:" + result); } /// @@ -85,7 +85,7 @@ using nwind; Northwind db = CreateDB(); int result = db.ExecuteCommand("SELECT count(*) FROM [Products] WHERE [ProductID]>{0}", 3); //long iResult = base.ExecuteScalar(sql); - Assert.Greater(result, 0, "Expecting some rows in Products table, got:" + result); + AssertHelper.Greater(result, 0, "Expecting some rows in Products table, got:" + result); } } diff --git a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ExecuteQuery_Test.cs b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ExecuteQuery_Test.cs index ea375055d7e..fac3d615da5 100644 --- a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ExecuteQuery_Test.cs +++ b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ExecuteQuery_Test.cs @@ -67,7 +67,7 @@ using nwind; string beforecountry = character.Country; character.Country = "Burmuda"; - Assert.Greater(db.GetChangeSet().Updates.Count, 0); + AssertHelper.Greater(db.GetChangeSet().Updates.Count, 0); db.SubmitChanges(); var character2 = db.Customers.First(c=>c.CustomerID==character.CustomerID); diff --git a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/Linq_101_Samples/Advanced.cs b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/Linq_101_Samples/Advanced.cs index e420e84f6bb..dd976666e05 100644 --- a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/Linq_101_Samples/Advanced.cs +++ b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/Linq_101_Samples/Advanced.cs @@ -159,7 +159,7 @@ using nwind; var q3 = q1.Union(q2); - Assert.Greater(q1.Count(), 0); + AssertHelper.Greater(q1.Count(), 0); Assert.IsTrue(q1.Count() + q2.Count() >= q3.Count()); } diff --git a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTest.cs b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTest.cs index 1f443c32ac6..efde50c3dcc 100644 --- a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTest.cs +++ b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTest.cs @@ -234,7 +234,7 @@ namespace nwind var q = from p in db.Products select p; List products = q.ToList(); int productCount = products.Count; - Assert.Greater(productCount, 0, "Expected some products, got none"); + AssertHelper.Greater(productCount, 0, "Expected some products, got none"); } #if !DEBUG && SQLITE @@ -443,7 +443,7 @@ namespace nwind select p; int count = q.Count(); - Assert.Less(count, db.Customers.Count()); + AssertHelper.Less(count, db.Customers.Count()); } [Test] @@ -455,7 +455,7 @@ namespace nwind select p; int count = q.Count(); - Assert.Less(count, db.Customers.Count()); + AssertHelper.Less(count, db.Customers.Count()); } [Test] @@ -496,7 +496,7 @@ namespace nwind } [Test] - [ExpectedException(ExceptionType=typeof(InvalidOperationException), ExpectedMessage="Data context options cannot be modified after results have been returned from a query.")] + [ExpectedException(typeof(InvalidOperationException), ExpectedMessage="Data context options cannot be modified after results have been returned from a query.")] public void C13_Changing_ObjectTrackingEnabled2False() { Northwind db = CreateDB(); @@ -507,7 +507,7 @@ namespace nwind } [Test] - [ExpectedException(ExceptionType = typeof(InvalidOperationException), ExpectedMessage = "Data context options cannot be modified after results have been returned from a query.")] + [ExpectedException(typeof(InvalidOperationException), ExpectedMessage = "Data context options cannot be modified after results have been returned from a query.")] public void C14_Changing_DeferredLoadingEnabled2False() { Northwind db = CreateDB(); @@ -518,7 +518,7 @@ namespace nwind } [Test] - [ExpectedException(ExceptionType = typeof(InvalidOperationException), ExpectedMessage = "Object tracking is not enabled for the current data context instance.")] + [ExpectedException(typeof(InvalidOperationException), ExpectedMessage = "Object tracking is not enabled for the current data context instance.")] public void C15_SubmitChanges_DeferredLoadingEnabled_False() { Northwind db = CreateDB(); @@ -572,7 +572,7 @@ namespace nwind .Join(db.GetTable(), t => t.TerritoryID, l => l.TerritoryID, (t, l) => l) .Join(db.GetTable().Where(e => e.EmployeeID > 0), l => l.EmployeeID, e => e.EmployeeID, (l, e) => e); var employeeCount = q.Count(); - Assert.Greater(employeeCount, 0, "Expected any employees, got count=" + employeeCount); + AssertHelper.Greater(employeeCount, 0, "Expected any employees, got count=" + employeeCount); } /// @@ -839,7 +839,7 @@ namespace nwind var q = from p in db.Products where p.ProductName == "Chai" select p.ProductID; var productID = q.First(); - Assert.Greater(productID, 0, "Expected penID>0, got " + productID); + AssertHelper.Greater(productID, 0, "Expected penID>0, got " + productID); } @@ -880,7 +880,7 @@ namespace nwind var q = from p in db.Products where p.ProductName == "Chai" select p.ProductID; var productID = q.Last(); - Assert.Greater(productID, 0, "Expected penID>0, got " + productID); + AssertHelper.Greater(productID, 0, "Expected penID>0, got " + productID); } #if !DEBUG && (POSTGRES || (MSSQL && !L2SQL)) @@ -902,11 +902,11 @@ namespace nwind { //int compareNames = prevProductName.CompareTo(p.ProductName); int compareNames = string.Compare(prevProductName, p.ProductName, stringComparisonType); - Assert.Less(compareNames, 0, "When ordering by names, expected " + prevProductName + " to come after " + p.ProductName); + AssertHelper.Less(compareNames, 0, "When ordering by names, expected " + prevProductName + " to come after " + p.ProductName); } prevProductName = p.ProductName; } - //Assert.Greater(productID,0,"Expected penID>0, got "+productID); + //AssertHelper.Greater(productID,0,"Expected penID>0, got "+productID); } [Test] @@ -915,7 +915,7 @@ namespace nwind Northwind db = CreateDB(); //var q = from p in db.Products where "Chai"==p.ProductName select p.Order; //List penOrders = q.ToList(); - //Assert.Greater(penOrders.Count,0,"Expected some orders for product 'Chai'"); + //AssertHelper.Greater(penOrders.Count,0,"Expected some orders for product 'Chai'"); var q = from o in db.Orders @@ -929,7 +929,7 @@ namespace nwind Assert.IsNotNull(co.c.City, "Expected non-null customer city"); Assert.IsNotNull(co.o, "Expected non-null order"); } - Assert.Greater(list1.Count, 0, "Expected some orders for London customers"); + AssertHelper.Greater(list1.Count, 0, "Expected some orders for London customers"); } [Test] @@ -947,7 +947,7 @@ namespace nwind Assert.IsNotNull(co.c, "Expected non-null customer"); Assert.IsNotNull(co.o, "Expected non-null order"); } - Assert.Greater(list1.Count, 0, "Expected some orders for London customers"); + AssertHelper.Greater(list1.Count, 0, "Expected some orders for London customers"); } [Test] @@ -962,7 +962,7 @@ namespace nwind where c.City == "London" select new { c, o }; - Assert.Greater(q.ToList().Count, 0, "Expected some orders for London customers"); + AssertHelper.Greater(q.ToList().Count, 0, "Expected some orders for London customers"); } [Test] @@ -987,7 +987,7 @@ namespace nwind #else int expectedCount = 2; //Oracle, Mysql: 'Toilet Paper' and 'iPod' #endif - Assert.Greater(prods.Count, expectedCount, "Expected couple of products with letter 'p'"); + AssertHelper.Greater(prods.Count, expectedCount, "Expected couple of products with letter 'p'"); } [Test] @@ -1002,11 +1002,11 @@ namespace nwind ).Take(5); //var q = db.Products.Where( p=>p.ProductName.Contains("p")).Take(5); List prods = q.ToList(); - Assert.Greater(prods.Count, 2, "Expected couple of products with letter 'p'"); + AssertHelper.Greater(prods.Count, 2, "Expected couple of products with letter 'p'"); var prodID0 = prods[0].ProductID; var prodID1 = prods[1].ProductID; - Assert.Greater(prodID0, prodID1, "Sorting is broken"); + AssertHelper.Greater(prodID0, prodID1, "Sorting is broken"); } [Test] diff --git a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTest_Complex.cs b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTest_Complex.cs index 8d8c325cbec..fe7a6753181 100644 --- a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTest_Complex.cs +++ b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTest_Complex.cs @@ -136,7 +136,7 @@ using Id = System.Int32; { var q = from p in db.Products select p; int productCount = q.Count(); - Assert.Greater(productCount, 0, "Expected non-zero product count"); + AssertHelper.Greater(productCount, 0, "Expected non-zero product count"); } [Test] @@ -144,7 +144,7 @@ using Id = System.Int32; { var q = from p in db.Products select p.ProductID; int productCount = q.Count(); - Assert.Greater(productCount, 0, "Expected non-zero product count"); + AssertHelper.Greater(productCount, 0, "Expected non-zero product count"); Console.WriteLine(); } [Test] @@ -152,7 +152,7 @@ using Id = System.Int32; { var q = from p in db.Products select p.ProductID; int productCount = q.Count(i => i < 3); - Assert.Greater(productCount, 0, "Expected non-zero product count"); + AssertHelper.Greater(productCount, 0, "Expected non-zero product count"); Assert.IsTrue(productCount < 4, "Expected product count < 3"); } @@ -161,7 +161,7 @@ using Id = System.Int32; { var q = from p in db.Products select p.ProductID; var maxID = q.Max(); - Assert.Greater(maxID, 0, "Expected non-zero product count"); + AssertHelper.Greater(maxID, 0, "Expected non-zero product count"); } [Test] @@ -169,7 +169,7 @@ using Id = System.Int32; { var q = from p in db.Products select p.ProductID; var minID = q.Min(); - Assert.Greater(minID, 0, "Expected non-zero product count"); + AssertHelper.Greater(minID, 0, "Expected non-zero product count"); } #if !ORACLE // picrap: this test causes an internal buffer overflow when marshaling with oracle win32 driver @@ -179,7 +179,7 @@ using Id = System.Int32; { var q = from p in db.Products select p.ProductID; double avg = q.Average(); - Assert.Greater(avg, 0, "Expected non-zero productID average"); + AssertHelper.Greater(avg, 0, "Expected non-zero productID average"); } #endif @@ -268,7 +268,7 @@ using Id = System.Int32; var q4 = from p in db.Products select p.ProductName + p.ProductID; //var q4 = from p in db.Products select p.ProductID; var q5 = q4.ToList(); - Assert.Greater(q5.Count, 2, "Expected to see some concat strings"); + AssertHelper.Greater(q5.Count, 2, "Expected to see some concat strings"); foreach (string s0 in q5) { bool startWithLetter = Char.IsLetter(s0[0]); @@ -288,7 +288,7 @@ using Id = System.Int32; select p.ProductName+p.ProductID; //var q4 = from p in db.Products select p.ProductID; //var q5 = q4.ToList(); - Assert.Greater( q4.Count(), 2, "Expected to see some concat strings"); + AssertHelper.Greater( q4.Count(), 2, "Expected to see some concat strings"); foreach(string s0 in q4) { bool startWithLetter = Char.IsLetter(s0[0]); @@ -312,8 +312,8 @@ using Id = System.Int32; CustomerID = c.CustomerID }); var list = q.ToList(); - Assert.Greater(list.Count(), 0, "Expected list"); - //Assert.Greater(list.Count(), 0, "Expected list"); + AssertHelper.Greater(list.Count(), 0, "Expected list"); + //AssertHelper.Greater(list.Count(), 0, "Expected list"); Assert.Ignore("test passed but: theoretically constructions of entity types are not allowed"); } @@ -331,8 +331,8 @@ using Id = System.Int32; //this OrderBy clause messes up the SQL statement var q2 = q.OrderBy(c => c.CustomerID); var list = q2.ToList(); - Assert.Greater(list.Count(), 0, "Expected list"); - //Assert.Greater(list.Count(), 0, "Expected list"); + AssertHelper.Greater(list.Count(), 0, "Expected list"); + //AssertHelper.Greater(list.Count(), 0, "Expected list"); } @@ -344,7 +344,7 @@ using Id = System.Int32; orderby c.ContactName ?? "" select c; var list = q.ToList(); - Assert.Greater(list.Count(), 0, "Expected list"); + AssertHelper.Greater(list.Count(), 0, "Expected list"); } [Test(Description = "Non-dynamic version of DL5_NestedObjectSelect")] diff --git a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTest_GroupBy.cs b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTest_GroupBy.cs index 4d87952ed79..9ff4496ee8b 100644 --- a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTest_GroupBy.cs +++ b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTest_GroupBy.cs @@ -231,10 +231,10 @@ using nwind; select new { g.Key, OrderCount = g.Count() }; var lst = q2.ToList(); - Assert.Greater(lst.Count, 0, "Expected some grouped order results"); + AssertHelper.Greater(lst.Count, 0, "Expected some grouped order results"); var result0 = lst[0]; Assert.IsTrue(result0.Key != null, "Key must be non-null"); - Assert.Greater(result0.OrderCount, 0, "Count must be > 0"); + AssertHelper.Greater(result0.OrderCount, 0, "Count must be > 0"); //select new { g.Key , SumPerCustomer = g.Sum(o2=>o2.OrderID) }; } @@ -252,10 +252,10 @@ using nwind; select new { g.Key, OrderCount = g.Count() }; var lst = q2.ToList(); - Assert.Greater(lst.Count, 0, "Expected some grouped order results"); + AssertHelper.Greater(lst.Count, 0, "Expected some grouped order results"); var result0 = lst[0]; Assert.IsTrue(result0.Key != null, "Key must be non-null"); - Assert.Greater(result0.OrderCount, 0, "Count must be > 0"); + AssertHelper.Greater(result0.OrderCount, 0, "Count must be > 0"); //select new { g.Key , SumPerCustomer = g.Sum(o2=>o2.OrderID) }; } @@ -272,12 +272,12 @@ using nwind; //where g.Count()>1 select new { g.Key, OrderSum = g.Sum(o => o.OrderID) }; var lst = q2.ToList(); - Assert.Greater(lst.Count, 0, "Expected some grouped order results"); + AssertHelper.Greater(lst.Count, 0, "Expected some grouped order results"); foreach (var result in lst) { Console.WriteLine(" Result: custID=" + result.Key + " sum=" + result.OrderSum); Assert.IsTrue(result.Key != null, "Key must be non-null"); - Assert.Greater(result.OrderSum, 0, "OrderSum must be > 0"); + AssertHelper.Greater(result.OrderSum, 0, "OrderSum must be > 0"); } //select new { g.Key , SumPerCustomer = g.Sum(o2=>o2.OrderID) }; } diff --git a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTests_AnyCountFirst.cs b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTests_AnyCountFirst.cs index 0c58ea44d4c..48e0020e30f 100644 --- a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTests_AnyCountFirst.cs +++ b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTests_AnyCountFirst.cs @@ -331,7 +331,7 @@ using nwind; decimal[] d = new decimal[] { 1, 4, 5, 6, 10248, 10255 }; var q = db.OrderDetails.Where(o => d.Contains(o.OrderID)); - Assert.Greater(q.Count(), 0); + AssertHelper.Greater(q.Count(), 0); } diff --git a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTests_DateTimeFunctions.cs b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTests_DateTimeFunctions.cs index 3d1981a405d..dabe2f12a78 100644 --- a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTests_DateTimeFunctions.cs +++ b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTests_DateTimeFunctions.cs @@ -265,7 +265,7 @@ using DbLinq.Data.Linq; var list = query.ToList(); - Assert.Greater(list.Count, 0); + AssertHelper.Greater(list.Count, 0); } #if !DEBUG && SQLITE @@ -299,7 +299,7 @@ using DbLinq.Data.Linq; var list = query.ToList(); - Assert.Greater(list.Count, 0); + AssertHelper.Greater(list.Count, 0); } @@ -334,7 +334,7 @@ using DbLinq.Data.Linq; var list = query.ToList(); - Assert.Greater(list.Count, 0); + AssertHelper.Greater(list.Count, 0); } #if !DEBUG && (SQLITE || MSSQL) @@ -354,7 +354,7 @@ using DbLinq.Data.Linq; var list = query.ToList(); - Assert.Greater(list.Count, 0); + AssertHelper.Greater(list.Count, 0); } #if !DEBUG && SQLITE @@ -388,7 +388,7 @@ using DbLinq.Data.Linq; var list = query.ToList(); - Assert.Greater(list.Count, 0); + AssertHelper.Greater(list.Count, 0); } #if !DEBUG && SQLITE @@ -410,7 +410,7 @@ using DbLinq.Data.Linq; var list = query.ToList(); - Assert.Greater(list.Count, 0); + AssertHelper.Greater(list.Count, 0); } #if !DEBUG && POSTGRES @@ -443,7 +443,7 @@ using DbLinq.Data.Linq; var list = query.ToList(); - Assert.Greater(list.Count, 0); + AssertHelper.Greater(list.Count, 0); } finally { @@ -481,7 +481,7 @@ using DbLinq.Data.Linq; var list = query.ToList(); - Assert.Greater(list.Count, 0); + AssertHelper.Greater(list.Count, 0); } finally { diff --git a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTests_EntitySet.cs b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTests_EntitySet.cs index 40503fed4f5..16a0b0a7ba0 100644 --- a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTests_EntitySet.cs +++ b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/ReadTests_EntitySet.cs @@ -53,7 +53,7 @@ using nwind; { var db = CreateDB(); var customer = db.Customers.First(); - Assert.Greater(customer.Orders.Count, 0); + AssertHelper.Greater(customer.Orders.Count, 0); } #if !DEBUG && (SQLITE || (MSSQL && !L2SQL)) @@ -65,7 +65,7 @@ using nwind; var db = CreateDB(); var results = (from c in db.Customers select c.Orders).ToList(); - Assert.Greater(results.Count, 0); + AssertHelper.Greater(results.Count, 0); } [Test] @@ -98,7 +98,7 @@ using nwind; var db = CreateDB(); var customer = db.Customers.First(); - Assert.Greater(customer.Orders.Count, 0, "#1"); + AssertHelper.Greater(customer.Orders.Count, 0, "#1"); Assert.IsTrue(customer.Orders.HasLoadedOrAssignedValues, "#2"); customer.Orders.SetSource(System.Linq.Enumerable.Empty()); } @@ -136,7 +136,7 @@ using nwind; int ordersCount = (from cust in db.Customers select cust.Orders.Count).First(); - Assert.Greater(ordersCount, 0); + AssertHelper.Greater(ordersCount, 0); var customer2 = db.Customers.First(); customer2.Orders.SetSource(System.Linq.Enumerable.Empty()); @@ -154,11 +154,11 @@ using nwind; var c = db.Customers.First(); int beforeCount = c.Orders.Count; - Assert.Greater(beforeCount, 0); + AssertHelper.Greater(beforeCount, 0); c.Orders.Clear(); Assert.AreEqual(c.Orders.Count, 0); c.Orders.AddRange(db.Orders); - Assert.Greater(c.Orders.Count, beforeCount); + AssertHelper.Greater(c.Orders.Count, beforeCount); db.Refresh(RefreshMode.OverwriteCurrentValues, c.Orders); Assert.AreEqual(c.Orders.Count, beforeCount); @@ -174,13 +174,13 @@ using nwind; var c = db.Customers.First(); int beforeCount = c.Orders.Count; - Assert.Greater(beforeCount, 0); + AssertHelper.Greater(beforeCount, 0); c.Orders.Clear(); Assert.AreEqual(c.Orders.Count, 0); c.Orders.AddRange(db.Orders); int middleCount = c.Orders.Count; - Assert.Greater(c.Orders.Count, beforeCount); + AssertHelper.Greater(c.Orders.Count, beforeCount); db.Refresh(RefreshMode.KeepCurrentValues, c.Orders); Assert.AreEqual(c.Orders.Count, middleCount); @@ -233,7 +233,7 @@ using nwind; { var db = CreateDB(); var customer = db.Customers.Where(c => c.Orders.Count > 0).First(); - Assert.Greater(customer.Orders.Count, 0); + AssertHelper.Greater(customer.Orders.Count, 0); bool ok; System.ComponentModel.ListChangedEventArgs args = null; customer.Orders.ListChanged += delegate(object sender, System.ComponentModel.ListChangedEventArgs a) diff --git a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/StoredProcTest.cs b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/StoredProcTest.cs index f792f8e585f..e32291198ab 100644 --- a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/StoredProcTest.cs +++ b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/StoredProcTest.cs @@ -86,10 +86,10 @@ using nwind; foreach (var c in q) { Assert.IsNotNull(c.CustomerID); - Assert.Greater(c.OrderCount, -1); + AssertHelper.Greater(c.OrderCount, -1); count++; } - Assert.Greater(count, 0); + AssertHelper.Greater(count, 0); } [Test] @@ -103,10 +103,10 @@ using nwind; foreach (var v in q) { Assert.IsNotNull(v.c.CustomerID); - Assert.Greater(v.OrderCount, -1); + AssertHelper.Greater(v.OrderCount, -1); count++; } - Assert.Greater(count, 0); + AssertHelper.Greater(count, 0); } [Test] @@ -121,7 +121,7 @@ using nwind; Assert.IsTrue(c.CustomerID!=null, "Non-null customerID required"); count++; } - Assert.Greater(count, 0); + AssertHelper.Greater(count, 0); } #endif } diff --git a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/Table.cs b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/Table.cs index 3aa1c9e1b6f..08ed664f1b3 100644 --- a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/Table.cs +++ b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/Table.cs @@ -161,7 +161,7 @@ using nwind; var customer = new Customer(); db.Customers.Attach(customer, originalCustomer); - Assert.Greater(db.Customers.GetModifiedMembers(customer).Count(), 0); + AssertHelper.Greater(db.Customers.GetModifiedMembers(customer).Count(), 0); } #if !DEBUG && (SQLITE || POSTGRES || (MSSQL && !L2SQL)) diff --git a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/TestBase.cs b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/TestBase.cs index e593fc37c6e..ba0734df607 100644 --- a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/TestBase.cs +++ b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/TestBase.cs @@ -33,7 +33,7 @@ using NUnit.Framework; using nwind; -#if MONO_STRICT && !MONO +#if MONO_STRICT using System.Diagnostics; public static class Profiler { diff --git a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/WriteTest.cs b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/WriteTest.cs index a30b2cff6a4..11fe0098a2a 100644 --- a/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/WriteTest.cs +++ b/mcs/class/System.Data.Linq/src/DbLinq/Test/Providers/WriteTest.cs @@ -165,7 +165,7 @@ using Id = System.Int32; newProd.QuantityPerUnit = "33 1/2"; db.Products.InsertOnSubmit(newProd); db.SubmitChanges(); - Assert.Greater(newProd.ProductID, 0, "After insertion, ProductID should be non-zero"); + AssertHelper.Greater(newProd.ProductID, 0, "After insertion, ProductID should be non-zero"); //Assert.IsFalse(newProd.IsModified, "After insertion, Product.IsModified should be false"); return (int)newProd.ProductID; //this test cab be used from delete tests } @@ -180,7 +180,7 @@ using Id = System.Int32; public void G2_DeleteTest() { int insertedID = insertProduct_priv(); - Assert.Greater(insertedID, 0, "DeleteTest cannot operate if row was not inserted"); + AssertHelper.Greater(insertedID, 0, "DeleteTest cannot operate if row was not inserted"); Northwind db = CreateDB(); @@ -200,7 +200,7 @@ using Id = System.Int32; public void G3_DeleteTest() { int insertedID = insertProduct_priv(); - Assert.Greater(insertedID, 0, "DeleteTest cannot operate if row was not inserted"); + AssertHelper.Greater(insertedID, 0, "DeleteTest cannot operate if row was not inserted"); Northwind db = CreateDB(); diff --git a/mcs/class/System.Data.OracleClient/README.tests b/mcs/class/System.Data.OracleClient/README.tests index 431634ee37c..a3ef05590f2 100644 --- a/mcs/class/System.Data.OracleClient/README.tests +++ b/mcs/class/System.Data.OracleClient/README.tests @@ -1,10 +1,8 @@ Some tests located require a connection to Oracle database to execute. -To configure a connection, copy System.Data.OracleClient_test_default.dll.config.example -to System.Data.OracleClient_test_default.dll.config and fill in the ConnectionString with appropriate Data Source. +To configure a connection, set the MONO_TESTS_ORACLE_CONNECTION_STRING environment variable to a connection string like the following: -If no System.Data.OracleClient_test_default.dll.config is present, those tests will be ignored. +Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=)));uid=;pwd=; -To test .Net 2.0 profile, copy System.Data.OracleClient_test_default.dll.config -to System.Data.OracleClient_test_net_2_0.dll.config and launch tests with PROFILE=net_2_0 . +If the environment variable is not present, those tests will be ignored. Scripts for populating the database are located in Test/System.Data.OracleClient.jvm (for their usage, consult Test/System.Data.OracleClient.jvm/readme.txt). diff --git a/mcs/class/System.Data.OracleClient/System.Data.OracleClient_test_default.dll.config.example b/mcs/class/System.Data.OracleClient/System.Data.OracleClient_test_default.dll.config.example deleted file mode 100644 index 03703a71ff1..00000000000 --- a/mcs/class/System.Data.OracleClient/System.Data.OracleClient_test_default.dll.config.example +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient.Oci/OciDefineHandleTest.cs b/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient.Oci/OciDefineHandleTest.cs index 43e77ef1b22..02c12ee3c94 100644 --- a/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient.Oci/OciDefineHandleTest.cs +++ b/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient.Oci/OciDefineHandleTest.cs @@ -51,7 +51,7 @@ namespace MonoTests.System.Data.OracleClient { [TestFixtureSetUp] public void FixtureSetUp () { - connection_string = ConfigurationSettings.AppSettings.Get ("ConnectionString"); + connection_string = Environment.GetEnvironmentVariable ("MONO_TESTS_ORACLE_CONNECTION_STRING"); if(connection_string == null) Assert.Ignore ("Please consult README.tests."); } diff --git a/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient.jvm/GHTDB.ORACLE.sql b/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient.jvm/GHTDB.ORACLE.sql index a5feb72a00b..70421c51a8d 100755 --- a/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient.jvm/GHTDB.ORACLE.sql +++ b/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient.jvm/GHTDB.ORACLE.sql @@ -47,6 +47,7 @@ CREATE USER "GHTDB" TEMPORARY TABLESPACE "TEMP" ; GRANT CONNECT, RESOURCE, CREATE TABLE TO "GHTDB"; +ALTER USER GHTDB quota unlimited on USERS; CREATE OR REPLACE PACKAGE "GHTDB"."GHTPKG" AS TYPE RCT1 IS REF CURSOR; @@ -923,6 +924,7 @@ CREATE USER "GHTDB_EX" TEMPORARY TABLESPACE "TEMP" ; GRANT CONNECT, RESOURCE TO "GHTDB_EX"; +ALTER USER GHTDB_EX quota unlimited on USERS; CREATE OR REPLACE PACKAGE GHTDB_EX.GHTPKG AS diff --git a/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient.jvm/MonoTests.System.Data.Utils/ConnectedDataProvider.cs b/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient.jvm/MonoTests.System.Data.Utils/ConnectedDataProvider.cs index 3fd8b632a9f..ebe3de47ce5 100644 --- a/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient.jvm/MonoTests.System.Data.Utils/ConnectedDataProvider.cs +++ b/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient.jvm/MonoTests.System.Data.Utils/ConnectedDataProvider.cs @@ -72,7 +72,7 @@ namespace MonoTests.System.Data.Utils { public static string ConnectionString { get { - string connection_string = Sys.Configuration.ConfigurationSettings.AppSettings["ConnectionString"]; + string connection_string = Environment.GetEnvironmentVariable ("MONO_TESTS_ORACLE_CONNECTION_STRING"); if(connection_string == null) NUnit.Framework.Assert.Ignore ("Please consult README.tests."); return connection_string; diff --git a/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient.jvm/OracleConnection/IDBConnection_For_Oracle.cs b/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient.jvm/OracleConnection/IDBConnection_For_Oracle.cs index 9c638e8252d..f544c351006 100644 --- a/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient.jvm/OracleConnection/IDBConnection_For_Oracle.cs +++ b/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient.jvm/OracleConnection/IDBConnection_For_Oracle.cs @@ -39,14 +39,7 @@ namespace MonoTests.System.Data.OracleClient [SetUp] public void SetUp() { - try - { - _ConnectionString = MonoTests.System.Data.Utils.ConnectedDataProvider.ConnectionString; - } - catch(Exception ex) - { - EndCase(ex); - } + _ConnectionString = MonoTests.System.Data.Utils.ConnectedDataProvider.ConnectionString; } [TearDown] diff --git a/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient.jvm/readme.txt b/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient.jvm/readme.txt index a9164fb27a7..9c36355d57f 100755 --- a/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient.jvm/readme.txt +++ b/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient.jvm/readme.txt @@ -1,15 +1,6 @@ To run unit test the following should be prepared: -1. Test\System.Data.OracleClient.J2EE.config should contain an ConnectionString setting, i.e.: - - - - - - - - -2. A target db should be prepared with the relevant structure, following are the instruction for each supported database. +A target db should be prepared with the relevant structure, following are the instruction for each supported database. in order to create the testing database, on ORACLE, run: Run the scripts with a user wich have administrator permissions. (by default user:system, password:mainsoft). diff --git a/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient/OracleLobTest.cs b/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient/OracleLobTest.cs index 6b758dea47f..0dfd37e6402 100644 --- a/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient/OracleLobTest.cs +++ b/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient/OracleLobTest.cs @@ -48,7 +48,7 @@ namespace MonoTests.System.Data.OracleClient { [TestFixtureSetUp] public void FixtureSetUp () { - connection_string = ConfigurationSettings.AppSettings.Get ("ConnectionString"); + connection_string = Environment.GetEnvironmentVariable ("MONO_TESTS_ORACLE_CONNECTION_STRING"); if(connection_string == null) Assert.Ignore ("Please consult README.tests."); } diff --git a/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient/OracleParameterTest.cs b/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient/OracleParameterTest.cs index d625b6bf129..29c2e9022c7 100644 --- a/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient/OracleParameterTest.cs +++ b/mcs/class/System.Data.OracleClient/Test/System.Data.OracleClient/OracleParameterTest.cs @@ -52,7 +52,7 @@ namespace MonoTests.System.Data.OracleClient [TestFixtureSetUp] public void FixtureSetUp () { - connection_string = ConfigurationSettings.AppSettings.Get ("ConnectionString"); + connection_string = Environment.GetEnvironmentVariable ("MONO_TESTS_ORACLE_CONNECTION_STRING"); } [SetUp] diff --git a/mcs/class/System.Data/Makefile b/mcs/class/System.Data/Makefile index e8a641299b3..0806c36fb52 100644 --- a/mcs/class/System.Data/Makefile +++ b/mcs/class/System.Data/Makefile @@ -37,6 +37,8 @@ TXT_RESOURCE_STRINGS = ../referencesource/System.Data/system.data.txt TEST_LIB_REFS = System.Core Mono.Data.Sqlite TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) -nowarn:618,169,612,219,168 +TEST_NUNITLITE_APP_CONFIG_GLOBAL=Test/test-config-file + TEST_MONO_PATH = . EXTRA_DISTFILES = \ @@ -45,7 +47,7 @@ EXTRA_DISTFILES = \ $(wildcard Test/System.Xml/*.xml) \ $(wildcard Test/System.Xml/*.xsd) \ $(wildcard Test/System.Data/schemas/*.xsd) \ - app_test_net_4_x.config \ + Test/test-config-file \ Test/System.Data/binserialize/*.bin \ SqliteTest.db \ referencesource.sources @@ -91,8 +93,3 @@ gen_SqlParameterCollection.cs: ../referencesource/System.Data/System/Data/Provid sed -e s/PARAMETEROBJECTNAME/SqlParameter/g >$@ include ../../build/library.make - -$(test_lib): $(test_lib).config - -$(test_lib).config: app_test_$(PROFILE).config - cp $< $@ diff --git a/mcs/class/System.Data/System.Data.SqlClient/SqlConnection.cs b/mcs/class/System.Data/System.Data.SqlClient/SqlConnection.cs index f7248acb6bc..ff5dc821d85 100644 --- a/mcs/class/System.Data/System.Data.SqlClient/SqlConnection.cs +++ b/mcs/class/System.Data/System.Data.SqlClient/SqlConnection.cs @@ -931,13 +931,21 @@ namespace System.Data.SqlClient if (Client.Available <= 0) return -1; // Error - IPEndPoint endpoint = CreateLocalEndpoint (); - if (endpoint == null) - return -1; + IPEndPoint remoteEndpoint; + switch (Client.AddressFamily) { + case AddressFamily.InterNetwork: + remoteEndpoint = new IPEndPoint(IPAddress.Any, 0); + break; + case AddressFamily.InterNetworkV6: + remoteEndpoint = new IPEndPoint(IPAddress.IPv6Any, 0); + break; + default: + return -1; // Error + } Byte [] rawrs; - rawrs = Receive (ref endpoint); + rawrs = Receive (ref remoteEndpoint); string rs = Encoding.ASCII.GetString (rawrs); @@ -959,16 +967,6 @@ namespace System.Data.SqlClient return SqlServerTcpPort; } - - IPEndPoint CreateLocalEndpoint () - { - foreach (var addr in Dns.GetHostEntry ("localhost").AddressList) { - if (addr.AddressFamily == Client.AddressFamily) - return new IPEndPoint (addr, 0); - } - - return null; - } } struct ColumnInfo diff --git a/mcs/class/System.Data/Test/System.Data/ConstraintCollectionTest.cs b/mcs/class/System.Data/Test/System.Data/ConstraintCollectionTest.cs index 2fbdeb16c8a..1357f253347 100644 --- a/mcs/class/System.Data/Test/System.Data/ConstraintCollectionTest.cs +++ b/mcs/class/System.Data/Test/System.Data/ConstraintCollectionTest.cs @@ -34,9 +34,6 @@ using NUnit.Framework; using System; using System.Data; -#if !MOBILE -using NUnit.Framework.SyntaxHelpers; -#endif namespace MonoTests.System.Data { diff --git a/mcs/class/System.Data/Test/System.Data/ConstraintTest.cs b/mcs/class/System.Data/Test/System.Data/ConstraintTest.cs index 2875dc0a109..37a12abcffd 100644 --- a/mcs/class/System.Data/Test/System.Data/ConstraintTest.cs +++ b/mcs/class/System.Data/Test/System.Data/ConstraintTest.cs @@ -34,9 +34,6 @@ using NUnit.Framework; using System; using System.Data; -#if !MOBILE -using NUnit.Framework.SyntaxHelpers; -#endif namespace MonoTests.System.Data { diff --git a/mcs/class/System.Data/Test/System.Data/DataRelationCollectionTest.cs b/mcs/class/System.Data/Test/System.Data/DataRelationCollectionTest.cs index 7da3dca21f0..9ba7870e7e0 100644 --- a/mcs/class/System.Data/Test/System.Data/DataRelationCollectionTest.cs +++ b/mcs/class/System.Data/Test/System.Data/DataRelationCollectionTest.cs @@ -30,9 +30,6 @@ using NUnit.Framework; using System; using System.Data; -#if !MOBILE -using NUnit.Framework.SyntaxHelpers; -#endif namespace MonoTests.System.Data { diff --git a/mcs/class/System.Data/Test/System.Data/DataRelationTest.cs b/mcs/class/System.Data/Test/System.Data/DataRelationTest.cs index 63d75f2c410..f020a208e6f 100644 --- a/mcs/class/System.Data/Test/System.Data/DataRelationTest.cs +++ b/mcs/class/System.Data/Test/System.Data/DataRelationTest.cs @@ -34,9 +34,6 @@ using NUnit.Framework; using System; using System.Data; -#if !MOBILE -using NUnit.Framework.SyntaxHelpers; -#endif namespace MonoTests.System.Data { diff --git a/mcs/class/System.Data/Test/System.Data/TypedDataSetGeneratorTest.cs b/mcs/class/System.Data/Test/System.Data/TypedDataSetGeneratorTest.cs index 945b22a484c..2e2890b4ec5 100644 --- a/mcs/class/System.Data/Test/System.Data/TypedDataSetGeneratorTest.cs +++ b/mcs/class/System.Data/Test/System.Data/TypedDataSetGeneratorTest.cs @@ -40,7 +40,7 @@ using Microsoft.CSharp; namespace MonoTests.System.Data { [TestFixture] - public class TypedDataSetGeneratorTest : Assertion + public class TypedDataSetGeneratorTest { private ICodeGenerator gen; private ICodeCompiler compiler; @@ -70,20 +70,20 @@ namespace MonoTests.System.Data public void TestGenerateIdName () { - AssertEquals ("#1", "a", TypedDataSetGenerator.GenerateIdName ("a", gen)); - AssertEquals ("#2", "_int", TypedDataSetGenerator.GenerateIdName ("int", gen)); - AssertEquals ("#3", "_", TypedDataSetGenerator.GenerateIdName ("_", gen)); - AssertEquals ("#3-2", "_", TypedDataSetGenerator.GenerateIdName ("_", gen)); - AssertEquals ("#4", "_1", TypedDataSetGenerator.GenerateIdName ("1", gen)); - AssertEquals ("#4-2", "_1", TypedDataSetGenerator.GenerateIdName ("1", gen)); - AssertEquals ("#5", "_1a", TypedDataSetGenerator.GenerateIdName ("1a", gen)); - AssertEquals ("#6", "_1_2", TypedDataSetGenerator.GenerateIdName ("1*2", gen)); - AssertEquals ("#7", "__", TypedDataSetGenerator.GenerateIdName ("-", gen)); - AssertEquals ("#8", "__", TypedDataSetGenerator.GenerateIdName ("+", gen)); - AssertEquals ("#9", "_", TypedDataSetGenerator.GenerateIdName ("", gen)); - AssertEquals ("#10", "___", TypedDataSetGenerator.GenerateIdName ("--", gen)); - AssertEquals ("#11", "___", TypedDataSetGenerator.GenerateIdName ("++", gen)); - AssertEquals ("#12", "\u3042", TypedDataSetGenerator.GenerateIdName ("\u3042", gen)); + Assert.AreEqual ("a", TypedDataSetGenerator.GenerateIdName ("a", gen), "#1"); + Assert.AreEqual ("_int", TypedDataSetGenerator.GenerateIdName ("int", gen), "#2"); + Assert.AreEqual ("_", TypedDataSetGenerator.GenerateIdName ("_", gen), "#3"); + Assert.AreEqual ("_", TypedDataSetGenerator.GenerateIdName ("_", gen), "#3-2"); + Assert.AreEqual ("_1", TypedDataSetGenerator.GenerateIdName ("1", gen), "#4"); + Assert.AreEqual ("_1", TypedDataSetGenerator.GenerateIdName ("1", gen), "#4-2"); + Assert.AreEqual ("_1a", TypedDataSetGenerator.GenerateIdName ("1a", gen), "#5"); + Assert.AreEqual ("_1_2", TypedDataSetGenerator.GenerateIdName ("1*2", gen), "#6"); + Assert.AreEqual ("__", TypedDataSetGenerator.GenerateIdName ("-", gen), "#7"); + Assert.AreEqual ("__", TypedDataSetGenerator.GenerateIdName ("+", gen), "#8"); + Assert.AreEqual ("_", TypedDataSetGenerator.GenerateIdName ("", gen), "#9"); + Assert.AreEqual ("___", TypedDataSetGenerator.GenerateIdName ("--", gen), "#10"); + Assert.AreEqual ("___", TypedDataSetGenerator.GenerateIdName ("++", gen), "#11"); + Assert.AreEqual ("\u3042", TypedDataSetGenerator.GenerateIdName ("\u3042", gen), "#12"); } [Test] @@ -98,7 +98,7 @@ namespace MonoTests.System.Data ccu.Namespaces.Add (cns); CompilerResults r = compiler.CompileAssemblyFromDom ( new CompilerParameters (), ccu); - AssertEquals (0, r.Errors.Count); + Assert.AreEqual (0, r.Errors.Count); } } } diff --git a/mcs/class/System.Data/Test/System.Data/UniqueConstraintTest.cs b/mcs/class/System.Data/Test/System.Data/UniqueConstraintTest.cs index 2be7b264d09..b1f4d2d1b7c 100644 --- a/mcs/class/System.Data/Test/System.Data/UniqueConstraintTest.cs +++ b/mcs/class/System.Data/Test/System.Data/UniqueConstraintTest.cs @@ -33,9 +33,6 @@ using NUnit.Framework; using System; using System.Data; -#if !MOBILE -using NUnit.Framework.SyntaxHelpers; -#endif namespace MonoTests.System.Data { diff --git a/mcs/class/System.Data/Test/test-config-file b/mcs/class/System.Data/Test/test-config-file new file mode 100644 index 00000000000..8135637f71a --- /dev/null +++ b/mcs/class/System.Data/Test/test-config-file @@ -0,0 +1,45 @@ + +
+
+ + + + + + + + + + + + + + + + + + + diff --git a/mcs/class/System.Data/app_test_mobile_static.config b/mcs/class/System.Data/app_test_mobile_static.config deleted file mode 100644 index 4f315973f1e..00000000000 --- a/mcs/class/System.Data/app_test_mobile_static.config +++ /dev/null @@ -1,48 +0,0 @@ - - - -
-
- - - - - - - - - - - - - - - - - - - - diff --git a/mcs/class/System.Data/app_test_net_4_x.config b/mcs/class/System.Data/app_test_net_4_x.config deleted file mode 100644 index 4f315973f1e..00000000000 --- a/mcs/class/System.Data/app_test_net_4_x.config +++ /dev/null @@ -1,48 +0,0 @@ - - - -
-
- - - - - - - - - - - - - - - - - - - - diff --git a/mcs/class/System.Drawing/System.Drawing_test.dll.sources b/mcs/class/System.Drawing/System.Drawing_test.dll.sources index 83e8ca47378..4b7cf62280f 100644 --- a/mcs/class/System.Drawing/System.Drawing_test.dll.sources +++ b/mcs/class/System.Drawing/System.Drawing_test.dll.sources @@ -1,3 +1,4 @@ +../../test-helpers/NunitHelpers.cs ../../../build/common/Locale.cs ../System.Drawing/gdipEnums.cs ../System.Drawing/gdipFunctions.cs diff --git a/mcs/class/System.Drawing/Test/DrawingTest/Test/Graphics.cs b/mcs/class/System.Drawing/Test/DrawingTest/Test/Graphics.cs index 98485656057..061d5e3ed70 100644 --- a/mcs/class/System.Drawing/Test/DrawingTest/Test/Graphics.cs +++ b/mcs/class/System.Drawing/Test/DrawingTest/Test/Graphics.cs @@ -38,9 +38,6 @@ using System.Drawing.Text; using System.Drawing.Imaging; using DrawingTestHelper; using System.IO; -#if !MONOTOUCH -using NUnit.Framework.SyntaxHelpers; -#endif namespace Test.Sys.Drawing.GraphicsFixtures { #region GraphicsFixtureProps diff --git a/mcs/class/System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/IpcChannel.cs b/mcs/class/System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/IpcChannel.cs index 883ea72ebe2..599edd8a803 100644 --- a/mcs/class/System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/IpcChannel.cs +++ b/mcs/class/System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/IpcChannel.cs @@ -115,7 +115,8 @@ namespace System.Runtime.Remoting.Channels.Ipc.Win32 public void StartListening(object data) { - serverChannel.StartListening(data); + if (serverChannel != null) + serverChannel.StartListening(data); } public object ChannelData @@ -128,7 +129,8 @@ namespace System.Runtime.Remoting.Channels.Ipc.Win32 public void StopListening(object data) { - serverChannel.StopListening(data); + if (serverChannel != null) + serverChannel.StopListening(data); } public string[] GetUrlsForUri(string objectURI) diff --git a/mcs/class/System.Runtime.Remoting/System.Runtime.Remoting_test.dll.sources b/mcs/class/System.Runtime.Remoting/System.Runtime.Remoting_test.dll.sources index ff09e03824c..8aae7d9e602 100644 --- a/mcs/class/System.Runtime.Remoting/System.Runtime.Remoting_test.dll.sources +++ b/mcs/class/System.Runtime.Remoting/System.Runtime.Remoting_test.dll.sources @@ -1,3 +1,4 @@ +../../test-helpers/NunitHelpers.cs System.Runtime.Remoting.Channels.Tcp/TcpChannelTest.cs ServerObject.cs ContextsTest.cs diff --git a/mcs/class/System.Runtime.Remoting/Test/HttpBugTests.cs b/mcs/class/System.Runtime.Remoting/Test/HttpBugTests.cs index 68930b0d640..c809f96c940 100644 --- a/mcs/class/System.Runtime.Remoting/Test/HttpBugTests.cs +++ b/mcs/class/System.Runtime.Remoting/Test/HttpBugTests.cs @@ -169,16 +169,12 @@ namespace MonoTests.Remoting.Http public void Main () { channel = new HttpChannel (0); - try { ChannelServices.RegisterChannel (channel); MarshalByRefObject obj = (MarshalByRefObject) RemotingServices.Connect ( typeof (IFactorial), "http://localhost:60000/MyEndPoint"); IFactorial cal = (IFactorial) obj; - Assert.AreEqual (cal.CalculateFactorial (4), 24); - } finally { - ChannelServices.UnregisterChannel (channel); - } + Assert.AreEqual (cal.CalculateFactorial (4), 24); } [TestFixtureSetUp] diff --git a/mcs/class/System.Runtime.Remoting/Test/IpcChannelTest.cs b/mcs/class/System.Runtime.Remoting/Test/IpcChannelTest.cs index 831c69e72b5..45f76791b7c 100644 --- a/mcs/class/System.Runtime.Remoting/Test/IpcChannelTest.cs +++ b/mcs/class/System.Runtime.Remoting/Test/IpcChannelTest.cs @@ -78,7 +78,7 @@ namespace MonoTests.Remoting IpcServerChannel chan = new IpcServerChannel (channelName, portName); string[] uris = chan.GetUrlsForUri ("server.rem"); Assert.IsNotNull (uris); - Assert.Greater (uris.Length, 0); + AssertHelper.Greater (uris.Length, 0); bool found = false; foreach (string s in uris) { @@ -101,7 +101,7 @@ namespace MonoTests.Remoting IpcChannel chan = new IpcChannel (props, null, null); string[] uris = chan.GetUrlsForUri ("server.rem"); Assert.IsNotNull (uris); - Assert.Greater (uris.Length, 0); + AssertHelper.Greater (uris.Length, 0); bool found = false; foreach (string s in uris) { diff --git a/mcs/class/System.Runtime.Remoting/Test/RemotingServicesTest.cs b/mcs/class/System.Runtime.Remoting/Test/RemotingServicesTest.cs index f9ad75cd3ac..02c6a532c00 100644 --- a/mcs/class/System.Runtime.Remoting/Test/RemotingServicesTest.cs +++ b/mcs/class/System.Runtime.Remoting/Test/RemotingServicesTest.cs @@ -193,7 +193,7 @@ namespace MonoTests.Remoting // The main test class [TestFixture] - public class RemotingServicesTest : Assertion + public class RemotingServicesTest { private static int MarshalObjectId = 0; @@ -233,13 +233,13 @@ namespace MonoTests.Remoting MarshalObject objMarshal = NewMarshalObject (); ObjRef objRef = RemotingServices.Marshal (objMarshal); - Assert ("#A01", objRef.URI != null); + Assert.IsNotNull (objRef.URI, "#A01"); MarshalObject objRem = (MarshalObject) RemotingServices.Unmarshal (objRef); - AssertEquals ("#A02", objMarshal.Id, objRem.Id); + Assert.AreEqual (objMarshal.Id, objRem.Id, "#A02"); objRem.Id = 2; - AssertEquals ("#A03", objMarshal.Id, objRem.Id); + Assert.AreEqual (objMarshal.Id, objRem.Id, "#A03"); // TODO: uncomment when RemotingServices.Disconnect is implemented //RemotingServices.Disconnect(objMarshal); @@ -248,7 +248,7 @@ namespace MonoTests.Remoting objRef = RemotingServices.Marshal (objMarshal, objMarshal.Uri); - Assert ("#A04", objRef.URI.EndsWith (objMarshal.Uri)); + Assert.IsTrue (objRef.URI.EndsWith (objMarshal.Uri), "#A04"); // TODO: uncomment when RemotingServices.Disconnect is implemented //RemotingServices.Disconnect(objMarshal); } @@ -261,7 +261,7 @@ namespace MonoTests.Remoting ObjRef objRef = RemotingServices.Marshal (derivedObjMarshal, derivedObjMarshal.Uri, typeof (MarshalObject)); // Check that the type of the marshaled object is MarshalObject - Assert ("#A05", objRef.TypeInfo.TypeName.StartsWith ((typeof (MarshalObject)).ToString ())); + Assert.IsTrue (objRef.TypeInfo.TypeName.StartsWith ((typeof (MarshalObject)).ToString ()), "#A05"); // TODO: uncomment when RemotingServices.Disconnect is implemented //RemotingServices.Disconnect(derivedObjMarshal); @@ -273,11 +273,11 @@ namespace MonoTests.Remoting { MarshalObject objMarshal = NewMarshalObject (); - Assert ("#A06", RemotingServices.GetObjectUri (objMarshal) == null); + Assert.IsNull (RemotingServices.GetObjectUri (objMarshal), "#A06"); RemotingServices.Marshal (objMarshal); - Assert ("#A07", RemotingServices.GetObjectUri (objMarshal) != null); + Assert.IsNotNull (RemotingServices.GetObjectUri (objMarshal), "#A07"); // TODO: uncomment when RemotingServices.Disconnect is implemented //RemotingServices.Disconnect(objMarshal); } @@ -297,7 +297,7 @@ namespace MonoTests.Remoting try { RemotingServices.Marshal (objMarshal, objMarshal.Uri); MarshalObject objRem = (MarshalObject) RemotingServices.Connect (typeof (MarshalObject), "tcp://localhost:1236/" + objMarshal.Uri); - Assert ("#A08", RemotingServices.IsTransparentProxy (objRem)); + Assert.IsTrue (RemotingServices.IsTransparentProxy (objRem), "#A08"); } finally { ChannelServices.UnregisterChannel (chn); RemotingServices.Disconnect (objMarshal); @@ -324,7 +324,7 @@ namespace MonoTests.Remoting // a real object try { RemotingServices.Marshal (objRem, objMarshal.Uri); - Fail ("#1"); + Assert.Fail ("#1"); } catch (RemotingException e) { } } finally { @@ -355,15 +355,15 @@ namespace MonoTests.Remoting objRem.Method1 (); // Tests RemotingServices.GetMethodBaseFromMethodMessage() - AssertEquals ("#A09", "Method1", proxy.MthBase.Name); - Assert ("#A09.1", !proxy.IsMethodOverloaded); + Assert.AreEqual ("Method1", proxy.MthBase.Name, "#A09"); + Assert.IsFalse (proxy.IsMethodOverloaded, "#A09.1"); objRem.Method2 (); - Assert ("#A09.2", proxy.IsMethodOverloaded); + Assert.IsTrue (proxy.IsMethodOverloaded, "#A09.2"); // Tests RemotingServices.ExecuteMessage(); // If ExecuteMessage does it job well, Method1 should be called 2 times - AssertEquals ("#A10", 2, MarshalObject.Called); + Assert.AreEqual (2, MarshalObject.Called, "#A10"); } finally { ChannelServices.UnregisterChannel (chn); } @@ -380,14 +380,14 @@ namespace MonoTests.Remoting MarshalObject objRem = (MarshalObject) Activator.GetObject (typeof (MarshalObject), "tcp://localhost:1238/MarshalObject.rem"); - Assert ("#A10.1", RemotingServices.IsTransparentProxy (objRem)); + Assert.IsTrue (RemotingServices.IsTransparentProxy (objRem), "#A10.1"); objRem.Method1 (); Thread.Sleep (20); - Assert ("#A10.2", !MarshalObject.IsMethodOneWay); + Assert.IsFalse (MarshalObject.IsMethodOneWay, "#A10.2"); objRem.Method3 (); Thread.Sleep (20); - Assert ("#A10.3", MarshalObject.IsMethodOneWay); + Assert.IsTrue (MarshalObject.IsMethodOneWay, "#A10.3"); } finally { ChannelServices.UnregisterChannel (chn); } @@ -409,7 +409,7 @@ namespace MonoTests.Remoting ObjRef objRefRem = RemotingServices.GetObjRefForProxy ((MarshalByRefObject) objRem); - Assert ("#A11", objRefRem != null); + Assert.IsNotNull (objRefRem, "#A11"); } finally { ChannelServices.UnregisterChannel (chn); } @@ -429,8 +429,8 @@ namespace MonoTests.Remoting RealProxy rp = RemotingServices.GetRealProxy (objRem); - Assert ("#A12", rp != null); - AssertEquals ("#A13", "MonoTests.System.Runtime.Remoting.RemotingServicesInternal.MyProxy", rp.GetType ().ToString ()); + Assert.IsNotNull (rp, "#A12"); + Assert.AreEqual ("MonoTests.System.Runtime.Remoting.RemotingServicesInternal.MyProxy", rp.GetType ().ToString (), "#A13"); } finally { ChannelServices.UnregisterChannel (chn); } @@ -448,7 +448,7 @@ namespace MonoTests.Remoting RemotingServices.Marshal (objRem); objRem = (MarshalObject) Activator.GetObject (typeof (MarshalObject), "tcp://localhost:1242/" + objRem.Uri); - Assert ("#A14", objRem != null); + Assert.IsNotNull (objRem, "#A14"); } finally { ChannelServices.UnregisterChannel (chn); } @@ -468,7 +468,7 @@ namespace MonoTests.Remoting RemotingServices.Marshal (objRem); Type typeRem = RemotingServices.GetServerTypeForUri (RemotingServices.GetObjectUri (objRem)); - AssertEquals ("#A15", type, typeRem); + Assert.AreEqual (type, typeRem, "#A15"); } finally { ChannelServices.UnregisterChannel (chn); } @@ -487,12 +487,12 @@ namespace MonoTests.Remoting MarshalObject objRem = (MarshalObject) Activator.GetObject (typeof (MarshalObject), "tcp://localhost:1245/MarshalObject2.rem"); - Assert ("#A16", RemotingServices.IsObjectOutOfAppDomain (objRem)); - Assert ("#A17", RemotingServices.IsObjectOutOfContext (objRem)); + Assert.IsTrue (RemotingServices.IsObjectOutOfAppDomain (objRem), "#A16"); + Assert.IsTrue (RemotingServices.IsObjectOutOfContext (objRem), "#A17"); MarshalObject objMarshal = new MarshalObject (); - Assert ("#A18", !RemotingServices.IsObjectOutOfAppDomain (objMarshal)); - Assert ("#A19", !RemotingServices.IsObjectOutOfContext (objMarshal)); + Assert.IsFalse (RemotingServices.IsObjectOutOfAppDomain (objMarshal), "#A18"); + Assert.IsFalse (RemotingServices.IsObjectOutOfContext (objMarshal), "#A19"); } finally { ChannelServices.UnregisterChannel (chn); } @@ -510,16 +510,16 @@ namespace MonoTests.Remoting MarshalObject objRem = (MarshalObject) Activator.GetObject (typeof (MarshalObject), "tcp://localhost:1246/app/obj3.rem"); MarshalObject objRem2 = (MarshalObject) Activator.GetObject (typeof (MarshalObject), "tcp://localhost:1246/obj3.rem"); - Assert ("#AN1", RemotingServices.IsTransparentProxy (objRem)); - Assert ("#AN2", RemotingServices.IsTransparentProxy (objRem2)); + Assert.IsTrue (RemotingServices.IsTransparentProxy (objRem), "#AN1"); + Assert.IsTrue (RemotingServices.IsTransparentProxy (objRem2), "#AN2"); - AssertNotNull ("#AN3", RemotingServices.GetServerTypeForUri ("obj3.rem")); - AssertNotNull ("#AN4", RemotingServices.GetServerTypeForUri ("/app/obj3.rem")); - AssertNull ("#AN5", RemotingServices.GetServerTypeForUri ("//app/obj3.rem")); - AssertNull ("#AN6", RemotingServices.GetServerTypeForUri ("app/obj3.rem")); - AssertNull ("#AN7", RemotingServices.GetServerTypeForUri ("/whatever/obj3.rem")); - AssertNotNull ("#AN8", RemotingServices.GetServerTypeForUri ("/obj3.rem")); - AssertNull ("#AN9", RemotingServices.GetServerTypeForUri ("//obj3.rem")); + Assert.IsNotNull (RemotingServices.GetServerTypeForUri ("obj3.rem"), "#AN3"); + Assert.IsNotNull (RemotingServices.GetServerTypeForUri ("/app/obj3.rem"), "#AN4"); + Assert.IsNull (RemotingServices.GetServerTypeForUri ("//app/obj3.rem"), "#AN5"); + Assert.IsNull (RemotingServices.GetServerTypeForUri ("app/obj3.rem"), "#AN6"); + Assert.IsNull (RemotingServices.GetServerTypeForUri ("/whatever/obj3.rem"), "#AN7"); + Assert.IsNotNull (RemotingServices.GetServerTypeForUri ("/obj3.rem"), "#AN8"); + Assert.IsNull (RemotingServices.GetServerTypeForUri ("//obj3.rem"), "#AN9"); } finally { ChannelServices.UnregisterChannel (chn); } @@ -534,7 +534,7 @@ namespace MonoTests.Remoting RemotingConfiguration.RegisterWellKnownServiceType (typeof (MarshalObject), "getobjectwithchanneldata.rem", WellKnownObjectMode.Singleton); string channelData = "test"; - AssertNotNull ("#01", Activator.GetObject (typeof (MarshalObject), "tcp://localhost:1247/getobjectwithchanneldata.rem", channelData)); + Assert.IsNotNull (Activator.GetObject (typeof (MarshalObject), "tcp://localhost:1247/getobjectwithchanneldata.rem", channelData), "#01"); } finally { ChannelServices.UnregisterChannel (chn); } @@ -548,28 +548,28 @@ namespace MonoTests.Remoting RemotingConfiguration.Configure (null); o = RemotingServices.Connect (typeof (MarshalByRefObject), "tcp://localhost:3434/ff1.rem"); - Assert ("#m1", o is DD); - Assert ("#m2", o is A); - Assert ("#m3", o is B); - Assert ("#m4", !(o is CC)); + Assert.IsInstanceOfType (typeof (DD), o, "#m1"); + Assert.IsInstanceOfType (typeof (A), o, "#m2"); + Assert.IsInstanceOfType (typeof (B), o, "#m3"); + AssertHelper.IsNotInstanceOfType (typeof (CC), !(o is CC), "#m4"); o = RemotingServices.Connect (typeof (A), "tcp://localhost:3434/ff3.rem"); - Assert ("#a1", o is DD); - Assert ("#a2", o is A); - Assert ("#a3", o is B); - Assert ("#a4", !(o is CC)); + Assert.IsInstanceOfType (typeof (DD), o, "#a1"); + Assert.IsInstanceOfType (typeof (A), o, "#a2"); + Assert.IsInstanceOfType (typeof (B), o, "#a3"); + AssertHelper.IsNotInstanceOfType (typeof (CC), o, "#a4"); o = RemotingServices.Connect (typeof (DD), "tcp://localhost:3434/ff4.rem"); - Assert ("#d1", o is DD); - Assert ("#d2", o is A); - Assert ("#d3", o is B); - Assert ("#d4", !(o is CC)); + Assert.IsInstanceOfType (typeof (DD), o, "#d1"); + Assert.IsInstanceOfType (typeof (A), o, "#d2"); + Assert.IsInstanceOfType (typeof (B), o, "#d3"); + AssertHelper.IsNotInstanceOfType (typeof (CC), o, "#d4"); o = RemotingServices.Connect (typeof (CC), "tcp://localhost:3434/ff5.rem"); - Assert ("#c1", !(o is DD)); - Assert ("#c2", o is A); - Assert ("#c3", o is B); - Assert ("#c4", o is CC); + AssertHelper.IsNotInstanceOfType (typeof (DD), o, "#c1"); + Assert.IsInstanceOfType (typeof (A), o, "#c2"); + Assert.IsInstanceOfType (typeof (B), o, "#c3"); + Assert.IsInstanceOfType (typeof (CC), o, "#c4"); } // Don't add any tests that must create channels // after ConnectProxyCast (), because this test calls diff --git a/mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/CollectionSerialization.cs b/mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/CollectionSerialization.cs index 7a3834dd93c..cda78a94112 100644 --- a/mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/CollectionSerialization.cs +++ b/mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/CollectionSerialization.cs @@ -38,9 +38,6 @@ using System.Runtime.Serialization; using System.ServiceModel; using NUnit.Framework; using NUnit.Framework.Constraints; -#if !MOBILE -using NUnit.Framework.SyntaxHelpers; -#endif namespace MonoTests.System.Runtime.Serialization { diff --git a/mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/XsdDataContractExporterTest2.cs b/mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/XsdDataContractExporterTest2.cs index 6a9b66a6485..394d7d48ad0 100644 --- a/mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/XsdDataContractExporterTest2.cs +++ b/mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/XsdDataContractExporterTest2.cs @@ -44,7 +44,6 @@ using System.Xml.Serialization; using Microsoft.CSharp; using NUnit.Framework; using NUnit.Framework.Constraints; -using NUnit.Framework.SyntaxHelpers; using QName = System.Xml.XmlQualifiedName; @@ -67,7 +66,7 @@ namespace MonoTests.System.Runtime.Serialization var type = exporter.Schemas.GlobalTypes [typeName]; Assert.That (type, Is.Not.Null, "#2"); - Assert.That (type, Is.InstanceOfType (typeof (XmlSchemaComplexType)), "#3"); + Assert.IsInstanceOfType (typeof (XmlSchemaComplexType), type, "#3"); var complex = (XmlSchemaComplexType)type; Assert.That (complex.Annotation, Is.Null, "#4"); @@ -83,16 +82,16 @@ namespace MonoTests.System.Runtime.Serialization Assert.That (list, Is.Not.Null, "#6"); Assert.That (list.Annotation, Is.Null, "#6a"); Assert.That (list.Name, Is.EqualTo ("list"), "#6b"); - Assert.That (list.ElementSchemaType, Is.InstanceOfType (typeof (XmlSchemaComplexType)), "#6c"); + Assert.IsInstanceOfType (typeof (XmlSchemaComplexType), list.ElementSchemaType, "#6c"); var listElement = (XmlSchemaComplexType)list.ElementSchemaType; Assert.That (listElement.QualifiedName.Namespace, Is.EqualTo (MSArraysNamespace), "#6d"); Assert.That (listElement.QualifiedName.Name, Is.EqualTo ("ArrayOfint"), "#6e"); - Assert.That (listElement.Particle, Is.InstanceOfType (typeof(XmlSchemaSequence)), "#7"); + Assert.IsInstanceOfType (typeof(XmlSchemaSequence), listElement.Particle, "#7"); var listSeq = (XmlSchemaSequence)listElement.Particle; Assert.That (listSeq.Items.Count, Is.EqualTo (1), "#7b"); - Assert.That (listSeq.Items[0], Is.InstanceOfType (typeof(XmlSchemaElement)), "#7c"); + Assert.IsInstanceOfType (typeof(XmlSchemaElement), listSeq.Items[0], "#7c"); Assert.That (listSeq.Annotation, Is.Null, "#7d"); var listSeqElement = (XmlSchemaElement)listSeq.Items[0]; @@ -103,16 +102,16 @@ namespace MonoTests.System.Runtime.Serialization Assert.That (dict, Is.Not.Null, "#8"); Assert.That (dict.Annotation, Is.Null, "#8a"); Assert.That (dict.Name, Is.EqualTo ("dictionary"), "#8b"); - Assert.That (dict.ElementSchemaType, Is.InstanceOfType (typeof (XmlSchemaComplexType)), "#8c"); + Assert.IsInstanceOfType (typeof (XmlSchemaComplexType), dict.ElementSchemaType, "#8c"); var dictElement = (XmlSchemaComplexType)dict.ElementSchemaType; Assert.That (dictElement.QualifiedName.Namespace, Is.EqualTo (MSArraysNamespace), "#8d"); Assert.That (dictElement.QualifiedName.Name, Is.EqualTo ("ArrayOfKeyValueOfstringdouble"), "#8e"); - Assert.That (dictElement.Particle, Is.InstanceOfType (typeof(XmlSchemaSequence)), "#9"); + Assert.IsInstanceOfType (typeof(XmlSchemaSequence), dictElement.Particle, "#9"); var dictSeq = (XmlSchemaSequence)dictElement.Particle; Assert.That (dictSeq.Items.Count, Is.EqualTo (1), "#9b"); - Assert.That (dictSeq.Items[0], Is.InstanceOfType (typeof(XmlSchemaElement)), "#9c"); + Assert.IsInstanceOfType (typeof(XmlSchemaElement), dictSeq.Items[0], "#9c"); Assert.That (dictSeq.Annotation, Is.Null, "#9d"); var dictSeqElement = (XmlSchemaElement)dictSeq.Items[0]; @@ -124,7 +123,7 @@ namespace MonoTests.System.Runtime.Serialization Assert.That (custom, Is.Not.Null, "#10"); Assert.That (custom.Annotation, Is.Null, "#10a"); Assert.That (custom.Name, Is.EqualTo ("customCollection"), "#10b"); - Assert.That (custom.ElementSchemaType, Is.InstanceOfType (typeof (XmlSchemaComplexType)), "#10c"); + Assert.IsInstanceOfType (typeof (XmlSchemaComplexType), custom.ElementSchemaType, "#10c"); var customElement = (XmlSchemaComplexType)custom.ElementSchemaType; var customEQN = customElement.QualifiedName; @@ -132,10 +131,10 @@ namespace MonoTests.System.Runtime.Serialization Assert.That (customEQN.Name.StartsWith ("XsdDataContractExporterTest2.MyCollectionOfstring", StringComparison.InvariantCultureIgnoreCase), Is.True, "#10e"); - Assert.That (customElement.Particle, Is.InstanceOfType (typeof(XmlSchemaSequence)), "#11"); + Assert.IsInstanceOfType (typeof(XmlSchemaSequence), customElement.Particle, "#11"); var customSeq = (XmlSchemaSequence)customElement.Particle; Assert.That (customSeq.Items.Count, Is.EqualTo (1), "#11b"); - Assert.That (customSeq.Items[0], Is.InstanceOfType (typeof(XmlSchemaElement)), "#11c"); + Assert.IsInstanceOfType (typeof(XmlSchemaElement), customSeq.Items[0], "#11c"); Assert.That (customSeq.Annotation, Is.Null, "#11d"); var customSeqElement = (XmlSchemaElement)customSeq.Items[0]; diff --git a/mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/XsdDataContractImporterTest2.cs b/mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/XsdDataContractImporterTest2.cs index bee52d3e4f8..7e86906afe3 100644 --- a/mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/XsdDataContractImporterTest2.cs +++ b/mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/XsdDataContractImporterTest2.cs @@ -43,7 +43,6 @@ using System.Xml.Serialization; using Microsoft.CSharp; using NUnit.Framework; using NUnit.Framework.Constraints; -using NUnit.Framework.SyntaxHelpers; using QName = System.Xml.XmlQualifiedName; diff --git a/mcs/class/System.ServiceModel/System.ServiceModel.Channels/MessageFault.cs b/mcs/class/System.ServiceModel/System.ServiceModel.Channels/MessageFault.cs index e8e10533584..8527e5c3134 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel.Channels/MessageFault.cs +++ b/mcs/class/System.ServiceModel/System.ServiceModel.Channels/MessageFault.cs @@ -53,7 +53,7 @@ namespace System.ServiceModel.Channels { FaultCode fc = null; FaultReason fr = null; - object details = null; + string actor = null; XmlDictionaryReader r = message.GetReaderAtBodyContents (); r.ReadStartElement ("Fault", message.Version.Envelope.Namespace); r.MoveToContent (); @@ -66,11 +66,13 @@ namespace System.ServiceModel.Channels case "faultstring": fr = new FaultReason (r.ReadElementContentAsString()); break; - case "detail": - return new XmlReaderDetailMessageFault (message, r, fc, fr, null, null); case "faultactor": + actor = r.ReadElementContentAsString(); + break; + case "detail": + return new XmlReaderDetailMessageFault (message, r, fc, fr, actor, null); default: - throw new NotImplementedException (); + throw new XmlException (String.Format ("Unexpected node {0} name {1}", r.NodeType, r.Name)); } r.MoveToContent (); } @@ -79,9 +81,7 @@ namespace System.ServiceModel.Channels if (fr == null) throw new XmlException ("Reason is missing in the Fault message"); - if (details == null) - return CreateFault (fc, fr); - return CreateFault (fc, fr, details); + return new SimpleMessageFault (fc, fr, false, null, null, actor, null); } static MessageFault CreateFault12 (Message message, int maxBufferSize) diff --git a/mcs/class/System.ServiceModel/System.ServiceModel.Dispatcher/ChannelDispatcher.cs b/mcs/class/System.ServiceModel/System.ServiceModel.Dispatcher/ChannelDispatcher.cs index 65b5c8cf38a..f1a7ca308c0 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel.Dispatcher/ChannelDispatcher.cs +++ b/mcs/class/System.ServiceModel/System.ServiceModel.Dispatcher/ChannelDispatcher.cs @@ -364,8 +364,11 @@ namespace System.ServiceModel.Dispatcher public void Start () { - if (loop_thread == null) + if (loop_thread == null) { loop_thread = new Thread (new ThreadStart (Loop)); + loop_thread.IsBackground = true; + } + loop_thread.Start (); } @@ -425,8 +428,10 @@ namespace System.ServiceModel.Dispatcher Logger.Warning (String.Format ("Channel listener '{0}' is not closed. Aborting.", owner.Listener.GetType ())); owner.Listener.Abort (); } - if (loop_thread != null && loop_thread.IsAlive) - loop_thread.Abort (); + if (loop_thread != null && loop_thread.IsAlive) { + if (!loop_thread.Join (500)) + loop_thread.Abort (); + } loop_thread = null; } diff --git a/mcs/class/System.ServiceModel/System.ServiceModel_test.dll.sources b/mcs/class/System.ServiceModel/System.ServiceModel_test.dll.sources index d06cb33fe21..c788a402138 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel_test.dll.sources +++ b/mcs/class/System.ServiceModel/System.ServiceModel_test.dll.sources @@ -1,3 +1,4 @@ +../../test-helpers/NunitHelpers.cs NUnitMoonHelper.cs FeatureBased/Features.Client/AsyncCallTesterProxy.cs FeatureBased/Features.Client/AsyncPatternServer.cs diff --git a/mcs/class/System.ServiceModel/Test/MetadataTests/BindingTestAssertions.cs b/mcs/class/System.ServiceModel/Test/MetadataTests/BindingTestAssertions.cs index b85b9f02f4c..8942c7abf32 100644 --- a/mcs/class/System.ServiceModel/Test/MetadataTests/BindingTestAssertions.cs +++ b/mcs/class/System.ServiceModel/Test/MetadataTests/BindingTestAssertions.cs @@ -37,7 +37,6 @@ using System.ServiceModel.Channels; using System.ServiceModel.Description; using NUnit.Framework; using NUnit.Framework.Constraints; -using NUnit.Framework.SyntaxHelpers; using QName = System.Xml.XmlQualifiedName; using WS = System.Web.Services.Description; @@ -91,7 +90,7 @@ namespace MonoTests.System.ServiceModel.MetadataTests { static void CheckSoapBinding (object extension, string transport, TestLabel label) { label.EnterScope ("soap"); - Assert.That (extension, Is.InstanceOfType (typeof (WS.SoapBinding)), label.Get ()); + Assert.That (extension, Is.AssignableTo(), label.Get ()); var soap = (WS.SoapBinding)extension; Assert.That (soap.Style, Is.EqualTo (WS.SoapBindingStyle.Document), label.Get ()); Assert.That (soap.Transport, Is.EqualTo (transport), label.Get ()); @@ -107,9 +106,9 @@ namespace MonoTests.System.ServiceModel.MetadataTests { label.EnterScope ("http"); if (security == BasicHttpSecurityMode.Message) { - Assert.That (binding, Is.InstanceOfType (typeof(CustomBinding)), label.Get ()); + Assert.IsInstanceOfType (typeof(CustomBinding), binding, label.Get ()); } else { - Assert.That (binding, Is.InstanceOfType (typeof(BasicHttpBinding)), label.Get ()); + Assert.IsInstanceOfType (typeof(BasicHttpBinding), binding, label.Get ()); var basicHttp = (BasicHttpBinding)binding; Assert.That (basicHttp.EnvelopeVersion, Is.EqualTo (EnvelopeVersion.Soap11), label.Get ()); Assert.That (basicHttp.MessageVersion, Is.EqualTo (MessageVersion.Soap11), label.Get ()); @@ -157,7 +156,7 @@ namespace MonoTests.System.ServiceModel.MetadataTests { label.EnterScope ("text"); if (encoding == WSMessageEncoding.Text) { Assert.That (textElement, Is.Not.Null, label.Get ()); - Assert.That (textElement.WriteEncoding, Is.InstanceOfType (typeof(UTF8Encoding)), label.Get ()); + Assert.IsInstanceOfType (typeof(UTF8Encoding), textElement.WriteEncoding, label.Get ()); } else { Assert.That (textElement, Is.Null, label.Get ()); } @@ -409,9 +408,9 @@ namespace MonoTests.System.ServiceModel.MetadataTests { { label.EnterScope ("net-tcp"); if (security == SecurityMode.Message) { - Assert.That (binding, Is.InstanceOfType (typeof(CustomBinding)), label.Get ()); + Assert.IsInstanceOfType (typeof(CustomBinding), binding, label.Get ()); } else { - Assert.That (binding, Is.InstanceOfType (typeof(NetTcpBinding)), label.Get ()); + Assert.IsInstanceOfType (typeof(NetTcpBinding), binding, label.Get ()); var netTcp = (NetTcpBinding)binding; Assert.That (netTcp.EnvelopeVersion, Is.EqualTo (EnvelopeVersion.Soap12), label.Get ()); Assert.That (netTcp.MessageVersion, Is.EqualTo (MessageVersion.Soap12WSAddressing10), label.Get ()); @@ -751,7 +750,7 @@ namespace MonoTests.System.ServiceModel.MetadataTests { foreach (var node in all.ChildNodes) { if (node is XmlWhitespace) continue; - Assert.That (node, Is.InstanceOfType (typeof (XmlElement)), label.ToString ()); + Assert.IsInstanceOfType (typeof (XmlElement), node, label.ToString ()); collection.Add ((XmlElement)node); } label.LeaveScope (); @@ -789,7 +788,7 @@ namespace MonoTests.System.ServiceModel.MetadataTests { label.EnterScope ("extensions"); Assert.That (op.Extensions, Is.Not.Null, label.Get ()); Assert.That (op.Extensions.Count, Is.EqualTo (1), label.Get ()); - Assert.That (op.Extensions [0], Is.InstanceOfType (typeof (WS.SoapOperationBinding)), label.Get ()); + Assert.That (op.Extensions [0], Is.AssignableTo(), label.Get ()); var soap = (WS.SoapOperationBinding)op.Extensions [0]; TestSoap (soap, soap12, label); label.LeaveScope (); @@ -821,7 +820,7 @@ namespace MonoTests.System.ServiceModel.MetadataTests { Assert.That (binding.ExtensibleAttributes, Is.Null, label.Get ()); Assert.That (binding.Extensions, Is.Not.Null, label.Get ()); Assert.That (binding.Extensions.Count, Is.EqualTo (1), label.Get ()); - Assert.That (binding.Extensions [0], Is.InstanceOfType (typeof (WS.SoapBodyBinding)), label.Get ()); + Assert.That (binding.Extensions [0], Is.AssignableTo (), label.Get ()); var body = (WS.SoapBodyBinding)binding.Extensions [0]; TestSoapBody (body, soap12, label); label.LeaveScope (); diff --git a/mcs/class/System.ServiceModel/Test/MetadataTests/ExportTests.cs b/mcs/class/System.ServiceModel/Test/MetadataTests/ExportTests.cs index 3bd64b70ded..a4cbb9cd3ee 100644 --- a/mcs/class/System.ServiceModel/Test/MetadataTests/ExportTests.cs +++ b/mcs/class/System.ServiceModel/Test/MetadataTests/ExportTests.cs @@ -36,7 +36,6 @@ using WS = System.Web.Services.Description; using NUnit.Framework; using NUnit.Framework.Constraints; -using NUnit.Framework.SyntaxHelpers; namespace MonoTests.System.ServiceModel.MetadataTests { diff --git a/mcs/class/System.ServiceModel/Test/MetadataTests/ImportTests.cs b/mcs/class/System.ServiceModel/Test/MetadataTests/ImportTests.cs index f43655c5736..6262109c116 100644 --- a/mcs/class/System.ServiceModel/Test/MetadataTests/ImportTests.cs +++ b/mcs/class/System.ServiceModel/Test/MetadataTests/ImportTests.cs @@ -34,7 +34,6 @@ using System.ServiceModel.Channels; using System.ServiceModel.Description; using NUnit.Framework; using NUnit.Framework.Constraints; -using NUnit.Framework.SyntaxHelpers; using WS = System.Web.Services.Description; diff --git a/mcs/class/System.ServiceModel/Test/MetadataTests/ImportTests_LoadMetadata.cs b/mcs/class/System.ServiceModel/Test/MetadataTests/ImportTests_LoadMetadata.cs index 3a92db121d5..4da65c703a5 100644 --- a/mcs/class/System.ServiceModel/Test/MetadataTests/ImportTests_LoadMetadata.cs +++ b/mcs/class/System.ServiceModel/Test/MetadataTests/ImportTests_LoadMetadata.cs @@ -34,7 +34,6 @@ using System.ServiceModel.Channels; using System.ServiceModel.Description; using NUnit.Framework; using NUnit.Framework.Constraints; -using NUnit.Framework.SyntaxHelpers; namespace MonoTests.System.ServiceModel.MetadataTests { diff --git a/mcs/class/System.ServiceModel/Test/MetadataTests/MiscImportTests.cs b/mcs/class/System.ServiceModel/Test/MetadataTests/MiscImportTests.cs index f6656e5c7d9..1e5c270d988 100644 --- a/mcs/class/System.ServiceModel/Test/MetadataTests/MiscImportTests.cs +++ b/mcs/class/System.ServiceModel/Test/MetadataTests/MiscImportTests.cs @@ -34,7 +34,6 @@ using System.ServiceModel.Channels; using System.ServiceModel.Description; using NUnit.Framework; using NUnit.Framework.Constraints; -using NUnit.Framework.SyntaxHelpers; using WS = System.Web.Services.Description; diff --git a/mcs/class/System.ServiceModel/Test/System.ServiceModel.Channels/MessageEncoderTest.cs b/mcs/class/System.ServiceModel/Test/System.ServiceModel.Channels/MessageEncoderTest.cs index 19560b93150..2acf8f04b81 100644 --- a/mcs/class/System.ServiceModel/Test/System.ServiceModel.Channels/MessageEncoderTest.cs +++ b/mcs/class/System.ServiceModel/Test/System.ServiceModel.Channels/MessageEncoderTest.cs @@ -34,7 +34,6 @@ using System.ServiceModel.Description; using System.Text; using NUnit.Framework; using NUnit.Framework.Constraints; -using NUnit.Framework.SyntaxHelpers; using TextElement = System.ServiceModel.Channels.TextMessageEncodingBindingElement; using BinaryElement = System.ServiceModel.Channels.BinaryMessageEncodingBindingElement; diff --git a/mcs/class/System.ServiceModel/Test/System.ServiceModel.Channels/MessageFaultTest.cs b/mcs/class/System.ServiceModel/Test/System.ServiceModel.Channels/MessageFaultTest.cs index eae3d7ca74b..5c73c059324 100644 --- a/mcs/class/System.ServiceModel/Test/System.ServiceModel.Channels/MessageFaultTest.cs +++ b/mcs/class/System.ServiceModel/Test/System.ServiceModel.Channels/MessageFaultTest.cs @@ -71,6 +71,7 @@ namespace MonoTests.System.ServiceModel.Channels a:ActionNotSupported some error + Random "; diff --git a/mcs/class/System.ServiceProcess/System.ServiceProcess_test.dll.sources b/mcs/class/System.ServiceProcess/System.ServiceProcess_test.dll.sources index 6a85bfc9e8d..23c4a7ed6b8 100644 --- a/mcs/class/System.ServiceProcess/System.ServiceProcess_test.dll.sources +++ b/mcs/class/System.ServiceProcess/System.ServiceProcess_test.dll.sources @@ -1,3 +1,4 @@ +../../test-helpers/NunitHelpers.cs System.ServiceProcess/ServiceBaseTest.cs System.ServiceProcess/ServiceControllerTest.cs System.ServiceProcess/ServiceControllerPermissionAttributeTest.cs diff --git a/mcs/class/System.Threading.Tasks.Dataflow/System.Threading.Tasks.Dataflow_test.dll.sources b/mcs/class/System.Threading.Tasks.Dataflow/System.Threading.Tasks.Dataflow_test.dll.sources index f23cf2edc1f..548d7271a6c 100644 --- a/mcs/class/System.Threading.Tasks.Dataflow/System.Threading.Tasks.Dataflow_test.dll.sources +++ b/mcs/class/System.Threading.Tasks.Dataflow/System.Threading.Tasks.Dataflow_test.dll.sources @@ -1,3 +1,4 @@ +../../test-helpers/NunitHelpers.cs TestScheduler.cs AssertEx.cs Blocks.cs diff --git a/mcs/class/System.Threading.Tasks.Dataflow/Test/System.Threading.Tasks.Dataflow/BoundedCapacityTest.cs b/mcs/class/System.Threading.Tasks.Dataflow/Test/System.Threading.Tasks.Dataflow/BoundedCapacityTest.cs index bec9f30a188..46953497fd3 100644 --- a/mcs/class/System.Threading.Tasks.Dataflow/Test/System.Threading.Tasks.Dataflow/BoundedCapacityTest.cs +++ b/mcs/class/System.Threading.Tasks.Dataflow/Test/System.Threading.Tasks.Dataflow/BoundedCapacityTest.cs @@ -131,7 +131,7 @@ namespace MonoTests.System.Threading.Tasks.Dataflow { Assert.IsTrue (transform.Post (1)); Assert.IsTrue (transform.Post (2)); - Assert.GreaterOrEqual (scheduler.ExecuteAll (), 1); + AssertHelper.GreaterOrEqual (scheduler.ExecuteAll (), 1); Assert.AreEqual (2, Volatile.Read (ref n)); } @@ -154,7 +154,7 @@ namespace MonoTests.System.Threading.Tasks.Dataflow { Assert.IsTrue (transform.Post (1)); Assert.IsTrue (transform.Post (2)); - Assert.GreaterOrEqual (scheduler.ExecuteAll (), 1); + AssertHelper.GreaterOrEqual (scheduler.ExecuteAll (), 1); Assert.AreEqual (2, Volatile.Read (ref n)); } @@ -177,7 +177,7 @@ namespace MonoTests.System.Threading.Tasks.Dataflow { Assert.IsFalse (transform.Post (101)); - Assert.GreaterOrEqual (scheduler.ExecuteAll (), 1); + AssertHelper.GreaterOrEqual (scheduler.ExecuteAll (), 1); Assert.IsFalse (transform.Post (102)); diff --git a/mcs/class/System.Threading.Tasks.Dataflow/Test/System.Threading.Tasks.Dataflow/DataflowBlockTest.cs b/mcs/class/System.Threading.Tasks.Dataflow/Test/System.Threading.Tasks.Dataflow/DataflowBlockTest.cs index f897f06e23e..65ed145d72c 100644 --- a/mcs/class/System.Threading.Tasks.Dataflow/Test/System.Threading.Tasks.Dataflow/DataflowBlockTest.cs +++ b/mcs/class/System.Threading.Tasks.Dataflow/Test/System.Threading.Tasks.Dataflow/DataflowBlockTest.cs @@ -128,7 +128,7 @@ namespace MonoTests.System.Threading.Tasks.Dataflow { Assert.IsNotNull (ex); Assert.IsNotNull (ex.InnerException); - Assert.IsInstanceOfType (typeof(OperationCanceledException), + Assert.IsInstanceOfType (typeof(TaskCanceledException), ex.InnerException); Assert.IsTrue (task.IsCompleted); Assert.AreEqual (TaskStatus.Canceled, task.Status); diff --git a/mcs/class/System.Threading.Tasks.Dataflow/Test/System.Threading.Tasks.Dataflow/OptionsTest.cs b/mcs/class/System.Threading.Tasks.Dataflow/Test/System.Threading.Tasks.Dataflow/OptionsTest.cs index 6d879320584..087385c2ffc 100644 --- a/mcs/class/System.Threading.Tasks.Dataflow/Test/System.Threading.Tasks.Dataflow/OptionsTest.cs +++ b/mcs/class/System.Threading.Tasks.Dataflow/Test/System.Threading.Tasks.Dataflow/OptionsTest.cs @@ -90,7 +90,7 @@ namespace MonoTests.System.Threading.Tasks.Dataflow { var queue = new ConcurrentQueue> (); var block = factory (queue); - Assert.IsEmpty (queue); + CollectionAssert.IsEmpty (queue); for (int i = 0; i < 100; i++) block.Post (i); @@ -170,15 +170,15 @@ namespace MonoTests.System.Threading.Tasks.Dataflow { options = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 2 }; foreach (var taskIds in GetTaskIdsForExecutionsOptions (options)) - Assert.LessOrEqual (CalculateDegreeOfParallelism (taskIds), 2); + AssertHelper.LessOrEqual (CalculateDegreeOfParallelism (taskIds), 2); options = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 4 }; foreach (var taskIds in GetTaskIdsForExecutionsOptions (options)) - Assert.LessOrEqual (CalculateDegreeOfParallelism (taskIds), 4); + AssertHelper.LessOrEqual (CalculateDegreeOfParallelism (taskIds), 4); options = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = -1 }; foreach (var taskIds in GetTaskIdsForExecutionsOptions (options)) - Assert.LessOrEqual (CalculateDegreeOfParallelism (taskIds), taskIds.Length); + AssertHelper.LessOrEqual (CalculateDegreeOfParallelism (taskIds), taskIds.Length); } } @@ -187,7 +187,7 @@ namespace MonoTests.System.Threading.Tasks.Dataflow { { var options = new ExecutionDataflowBlockOptions (); foreach (var taskIds in GetTaskIdsForExecutionsOptions (options)) - Assert.GreaterOrEqual (taskIds.Distinct ().Count (), 1); + AssertHelper.GreaterOrEqual (taskIds.Distinct ().Count (), 1); options = new ExecutionDataflowBlockOptions { MaxMessagesPerTask = 1 }; foreach (var taskIds in GetTaskIdsForExecutionsOptions (options)) @@ -195,11 +195,11 @@ namespace MonoTests.System.Threading.Tasks.Dataflow { options = new ExecutionDataflowBlockOptions { MaxMessagesPerTask = 2 }; foreach (var taskIds in GetTaskIdsForExecutionsOptions (options)) - Assert.GreaterOrEqual (taskIds.Distinct ().Count (), taskIds.Length / 2); + AssertHelper.GreaterOrEqual (taskIds.Distinct ().Count (), taskIds.Length / 2); options = new ExecutionDataflowBlockOptions { MaxMessagesPerTask = 4 }; foreach (var taskIds in GetTaskIdsForExecutionsOptions (options)) - Assert.GreaterOrEqual (taskIds.Distinct ().Count (), taskIds.Length / 4); + AssertHelper.GreaterOrEqual (taskIds.Distinct ().Count (), taskIds.Length / 4); } [Test] diff --git a/mcs/class/System.Web.DynamicData/System.Web.DynamicData_test.dll.sources b/mcs/class/System.Web.DynamicData/System.Web.DynamicData_test.dll.sources index f619c25efb8..67e3e1a6408 100644 --- a/mcs/class/System.Web.DynamicData/System.Web.DynamicData_test.dll.sources +++ b/mcs/class/System.Web.DynamicData/System.Web.DynamicData_test.dll.sources @@ -1,3 +1,4 @@ +../../test-helpers/NunitHelpers.cs ../../System.Web/Test/mainsoft/MainsoftWebTest/HtmlAgilityPack/crc32.cs ../../System.Web/Test/mainsoft/MainsoftWebTest/HtmlAgilityPack/Header.cs ../../System.Web/Test/mainsoft/MainsoftWebTest/HtmlAgilityPack/HtmlAttribute.cs @@ -71,7 +72,6 @@ Common/FooWithToString.cs Common/ITestDataContext.cs Common/KnownResponseHeader.cs Common/MiscExtensions.cs -Common/Mocks.cs Common/MyDynamicDataRouteHandler.cs Common/MyHttpContextWrapper.cs Common/MyHttpRequestWrapper.cs diff --git a/mcs/class/System.Web.DynamicData/Test/Common/Mocks.cs b/mcs/class/System.Web.DynamicData/Test/Common/Mocks.cs deleted file mode 100644 index 5010769dff5..00000000000 --- a/mcs/class/System.Web.DynamicData/Test/Common/Mocks.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Web; - -using NUnit.Framework; -using NUnit.Mocks; - -namespace MonoTests.Common -{ - static class Mocks - { - - } -} diff --git a/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/DynamicControlTest.cs b/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/DynamicControlTest.cs index cbd6a10a533..7f2d214ea49 100644 --- a/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/DynamicControlTest.cs +++ b/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/DynamicControlTest.cs @@ -52,7 +52,6 @@ using System.Web.UI.WebControls; using System.IO; using NUnit.Framework; -using NUnit.Mocks; using MonoTests.stand_alone.WebHarness; using MonoTests.SystemWeb.Framework; using MonoTests.Common; diff --git a/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/DynamicDataRouteHandlerTest.cs b/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/DynamicDataRouteHandlerTest.cs index b144e17e4ed..b44c8bd9327 100644 --- a/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/DynamicDataRouteHandlerTest.cs +++ b/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/DynamicDataRouteHandlerTest.cs @@ -47,7 +47,6 @@ using System.Web.DynamicData.ModelProviders; using System.Web.Routing; using NUnit.Framework; -using NUnit.Mocks; using MonoTests.stand_alone.WebHarness; using MonoTests.SystemWeb.Framework; using MonoTests.Common; diff --git a/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/DynamicDataRouteTest.cs b/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/DynamicDataRouteTest.cs index 3954861970b..1151fb86612 100644 --- a/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/DynamicDataRouteTest.cs +++ b/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/DynamicDataRouteTest.cs @@ -49,7 +49,6 @@ using System.Web.DynamicData.ModelProviders; using System.Web.Routing; using NUnit.Framework; -using NUnit.Mocks; using MonoTests.stand_alone.WebHarness; using MonoTests.SystemWeb.Framework; using MonoTests.Common; diff --git a/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/DynamicValidatorTest.cs b/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/DynamicValidatorTest.cs index 6f5f4fdd3dc..0884c7a5cef 100644 --- a/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/DynamicValidatorTest.cs +++ b/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/DynamicValidatorTest.cs @@ -52,7 +52,6 @@ using System.Web.UI.WebControls; using System.IO; using NUnit.Framework; -using NUnit.Mocks; using MonoTests.stand_alone.WebHarness; using MonoTests.SystemWeb.Framework; using MonoTests.Common; diff --git a/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/FieldTemplateFactoryTest.cs b/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/FieldTemplateFactoryTest.cs index 4398b8bf4f5..8362f3b6a96 100644 --- a/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/FieldTemplateFactoryTest.cs +++ b/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/FieldTemplateFactoryTest.cs @@ -52,7 +52,6 @@ using System.Web.UI.WebControls; using System.IO; using NUnit.Framework; -using NUnit.Mocks; using MonoTests.stand_alone.WebHarness; using MonoTests.SystemWeb.Framework; using MonoTests.Common; @@ -647,7 +646,7 @@ namespace MonoTests.System.Web.DynamicData // Custom with UIHint attribute mc = t.GetColumn ("CustomColumn2"); Assert.IsNotNull (mc.UIHint, "#A2"); - Assert.Greater (mc.UIHint.Length, 0, "#A2-1"); + AssertHelper.Greater (mc.UIHint.Length, 0, "#A2-1"); // Proves that UIHint on the column is not used, just the uiHint argument AssertExtensions.Throws (() => { @@ -669,7 +668,7 @@ namespace MonoTests.System.Web.DynamicData // Custom with UIHint attribute mc = t.GetColumn ("CustomColumn4"); Assert.IsNotNull (mc.UIHint, "#A4"); - Assert.Greater (mc.UIHint.Length, 0, "#A4-1"); + AssertHelper.Greater (mc.UIHint.Length, 0, "#A4-1"); // Proves that UIHint on the column is not used, just the uiHint argument Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, null), "#A4-2"); @@ -686,7 +685,7 @@ namespace MonoTests.System.Web.DynamicData mc = t.GetColumn ("DateTimeColumn2"); Assert.IsNotNull (mc.UIHint, "#B2"); - Assert.Greater (mc.UIHint.Length, 0, "#B2-1"); + AssertHelper.Greater (mc.UIHint.Length, 0, "#B2-1"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "DateTime.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, null), "#B2-3"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "DateTime.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, String.Empty), "#B2-4"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "DateTime.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, "Boolean.ascx"), "#B2-5"); @@ -701,7 +700,7 @@ namespace MonoTests.System.Web.DynamicData mc = t.GetColumn ("DateColumn2"); Assert.IsNotNull (mc.UIHint, "#C2"); - Assert.Greater (mc.UIHint.Length, 0, "#C2-1"); + AssertHelper.Greater (mc.UIHint.Length, 0, "#C2-1"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, null), "#C2-3"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, String.Empty), "#C2-4"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, "Boolean.ascx"), "#C2-5"); @@ -715,7 +714,7 @@ namespace MonoTests.System.Web.DynamicData mc = t.GetColumn ("DateColumn4"); Assert.IsNotNull (mc.UIHint, "#C4"); - Assert.Greater (mc.UIHint.Length, 0, "#C4-1"); + AssertHelper.Greater (mc.UIHint.Length, 0, "#C4-1"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, null), "#C4-3"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, String.Empty), "#C4-4"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, "Boolean.ascx"), "#C4-5"); @@ -730,7 +729,7 @@ namespace MonoTests.System.Web.DynamicData mc = t.GetColumn ("TimeColumn2"); Assert.IsNotNull (mc.UIHint, "#D2"); - Assert.Greater (mc.UIHint.Length, 0, "#D2-1"); + AssertHelper.Greater (mc.UIHint.Length, 0, "#D2-1"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, null), "#D2-3"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, String.Empty), "#D2-4"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, "Boolean.ascx"), "#D2-5"); @@ -745,7 +744,7 @@ namespace MonoTests.System.Web.DynamicData mc = t.GetColumn ("DurationColumn2"); Assert.IsNotNull (mc.UIHint, "#E2"); - Assert.Greater (mc.UIHint.Length, 0, "#E2-1"); + AssertHelper.Greater (mc.UIHint.Length, 0, "#E2-1"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, null), "#E2-3"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, String.Empty), "#E2-4"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, "Boolean.ascx"), "#E2-5"); @@ -760,7 +759,7 @@ namespace MonoTests.System.Web.DynamicData mc = t.GetColumn ("PhoneNumberColumn2"); Assert.IsNotNull (mc.UIHint, "#F2"); - Assert.Greater (mc.UIHint.Length, 0, "#F2-1"); + AssertHelper.Greater (mc.UIHint.Length, 0, "#F2-1"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, null), "#F2-3"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, String.Empty), "#F2-4"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, "Boolean.ascx"), "#F2-5"); @@ -775,7 +774,7 @@ namespace MonoTests.System.Web.DynamicData mc = t.GetColumn ("CurrencyColumn2"); Assert.IsNotNull (mc.UIHint, "#G2"); - Assert.Greater (mc.UIHint.Length, 0, "#G2-1"); + AssertHelper.Greater (mc.UIHint.Length, 0, "#G2-1"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, null), "#G2-3"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, String.Empty), "#G2-4"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, "Boolean.ascx"), "#G2-5"); @@ -790,7 +789,7 @@ namespace MonoTests.System.Web.DynamicData mc = t.GetColumn ("TextColumn2"); Assert.IsNotNull (mc.UIHint, "#H2"); - Assert.Greater (mc.UIHint.Length, 0, "#H2-1"); + AssertHelper.Greater (mc.UIHint.Length, 0, "#H2-1"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, null), "#H2-3"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, String.Empty), "#H2-4"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, "Boolean.ascx"), "#H2-5"); @@ -805,7 +804,7 @@ namespace MonoTests.System.Web.DynamicData mc = t.GetColumn ("HtmlColumn2"); Assert.IsNotNull (mc.UIHint, "#I2"); - Assert.Greater (mc.UIHint.Length, 0, "#I2-1"); + AssertHelper.Greater (mc.UIHint.Length, 0, "#I2-1"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, null), "#I2-3"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, String.Empty), "#I2-4"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, "Boolean.ascx"), "#I2-5"); @@ -820,7 +819,7 @@ namespace MonoTests.System.Web.DynamicData mc = t.GetColumn ("MultilineTextColumn2"); Assert.IsNotNull (mc.UIHint, "#J2"); - Assert.Greater (mc.UIHint.Length, 0, "#J2-1"); + AssertHelper.Greater (mc.UIHint.Length, 0, "#J2-1"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, null), "#J2-3"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, String.Empty), "#J2-4"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, "Boolean.ascx"), "#J2-5"); @@ -835,7 +834,7 @@ namespace MonoTests.System.Web.DynamicData mc = t.GetColumn ("EmailAddressColumn2"); Assert.IsNotNull (mc.UIHint, "#K2"); - Assert.Greater (mc.UIHint.Length, 0, "#K2-1"); + AssertHelper.Greater (mc.UIHint.Length, 0, "#K2-1"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, null), "#K2-3"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, String.Empty), "#K2-4"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, "Boolean.ascx"), "#K2-5"); @@ -850,7 +849,7 @@ namespace MonoTests.System.Web.DynamicData mc = t.GetColumn ("PasswordColumn2"); Assert.IsNotNull (mc.UIHint, "#L2"); - Assert.Greater (mc.UIHint.Length, 0, "#L2-1"); + AssertHelper.Greater (mc.UIHint.Length, 0, "#L2-1"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, null), "#L2-3"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, String.Empty), "#L2-4"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, "Boolean.ascx"), "#L2-5"); @@ -865,7 +864,7 @@ namespace MonoTests.System.Web.DynamicData mc = t.GetColumn ("UrlColumn2"); Assert.IsNotNull (mc.UIHint, "#M2"); - Assert.Greater (mc.UIHint.Length, 0, "#M2-1"); + AssertHelper.Greater (mc.UIHint.Length, 0, "#M2-1"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, null), "#M2-3"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, String.Empty), "#M2-4"); Assert.AreEqual (ftf.TemplateFolderVirtualPath + "Text.ascx", ftf.GetFieldTemplateVirtualPath (mc, DataBoundControlMode.ReadOnly, "Boolean.ascx"), "#M2-5"); diff --git a/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/FieldTemplateUserControlTest.cs b/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/FieldTemplateUserControlTest.cs index 46de57ad76c..423237d1ec0 100644 --- a/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/FieldTemplateUserControlTest.cs +++ b/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/FieldTemplateUserControlTest.cs @@ -52,7 +52,6 @@ using System.Web.UI.WebControls; using System.IO; using NUnit.Framework; -using NUnit.Mocks; using MonoTests.stand_alone.WebHarness; using MonoTests.SystemWeb.Framework; using MonoTests.Common; diff --git a/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/MetaColumnTest.cs b/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/MetaColumnTest.cs index e2e1e24b154..17766eae14e 100644 --- a/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/MetaColumnTest.cs +++ b/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/MetaColumnTest.cs @@ -47,7 +47,6 @@ using System.Web.DynamicData.ModelProviders; using System.Web.Routing; using NUnit.Framework; -using NUnit.Mocks; using MonoTests.stand_alone.WebHarness; using MonoTests.SystemWeb.Framework; using MonoTests.Common; diff --git a/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/MetaModelTest.cs b/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/MetaModelTest.cs index fe43459bfc7..ed33152de0d 100644 --- a/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/MetaModelTest.cs +++ b/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/MetaModelTest.cs @@ -48,7 +48,6 @@ using System.Web.DynamicData.ModelProviders; using System.Web.Routing; using NUnit.Framework; -using NUnit.Mocks; using MonoTests.stand_alone.WebHarness; using MonoTests.SystemWeb.Framework; using MonoTests.Common; diff --git a/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/MetaTableTest.cs b/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/MetaTableTest.cs index 76d528e4e79..b51fb6d7314 100644 --- a/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/MetaTableTest.cs +++ b/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/MetaTableTest.cs @@ -49,7 +49,6 @@ using System.Web.Routing; using System.Web.UI.WebControls; using NUnit.Framework; -using NUnit.Mocks; using MonoTests.stand_alone.WebHarness; using MonoTests.SystemWeb.Framework; using MonoTests.Common; diff --git a/mcs/class/System.Web/System.Web_standalone_test.dll.sources b/mcs/class/System.Web/System.Web_standalone_test.dll.sources index 09bd670bd4d..47a1fa4a8de 100644 --- a/mcs/class/System.Web/System.Web_standalone_test.dll.sources +++ b/mcs/class/System.Web/System.Web_standalone_test.dll.sources @@ -1,3 +1,4 @@ +../../test-helpers/NunitHelpers.cs Test/standalone-tests/Consts.cs Test/standalone-tests/Locations.cs Test/standalone-tests/OutputCacheProvider.cs diff --git a/mcs/class/System.Web/System.Web_test.dll.sources b/mcs/class/System.Web/System.Web_test.dll.sources index 4416f5a698b..70593c25d06 100644 --- a/mcs/class/System.Web/System.Web_test.dll.sources +++ b/mcs/class/System.Web/System.Web_test.dll.sources @@ -1,3 +1,4 @@ +../../test-helpers/NunitHelpers.cs ../../System.Web.DynamicData/Test/Common/AssertExtensions.cs mainsoft/MainsoftWebTest/HtmlAgilityPack/AssemblyInfo.cs mainsoft/MainsoftWebTest/HtmlAgilityPack/crc32.cs diff --git a/mcs/class/System.Web/Test/System.Web.Hosting/HostingEnvironmentTest.cs b/mcs/class/System.Web/Test/System.Web.Hosting/HostingEnvironmentTest.cs index 22f3996e76b..e240e4355ff 100644 --- a/mcs/class/System.Web/Test/System.Web.Hosting/HostingEnvironmentTest.cs +++ b/mcs/class/System.Web/Test/System.Web.Hosting/HostingEnvironmentTest.cs @@ -77,13 +77,13 @@ namespace MonoTests.System.Web.Hosting { Assert.IsNull (HostingEnvironment.InitializationException, "During:InitializationException"); Assert.IsTrue (HostingEnvironment.IsHosted, "During:IsHosted"); Assert.IsNotNull (HostingEnvironment.ApplicationID, "During:ApplicationID:Null"); - Assert.IsNotEmpty (HostingEnvironment.ApplicationID, "During:ApplicationID:Empty"); + AssertHelper.IsNotEmpty (HostingEnvironment.ApplicationID, "During:ApplicationID:Empty"); Assert.IsNotNull (HostingEnvironment.ApplicationPhysicalPath, "During:ApplicationPhysicalPath:Null"); - Assert.IsNotEmpty (HostingEnvironment.ApplicationPhysicalPath, "During:ApplicationPhysicalPath:Empty"); + AssertHelper.IsNotEmpty (HostingEnvironment.ApplicationPhysicalPath, "During:ApplicationPhysicalPath:Empty"); Assert.IsNotNull (HostingEnvironment.ApplicationVirtualPath, "During:ApplicationVirtualPath:Null"); - Assert.IsNotEmpty (HostingEnvironment.ApplicationVirtualPath, "During:ApplicationVirtualPath:Empty"); + AssertHelper.IsNotEmpty (HostingEnvironment.ApplicationVirtualPath, "During:ApplicationVirtualPath:Empty"); Assert.IsNotNull (HostingEnvironment.SiteName, "During:SiteName:Null"); - Assert.IsNotEmpty (HostingEnvironment.SiteName, "During:SiteName:Empty"); + AssertHelper.IsNotEmpty (HostingEnvironment.SiteName, "During:SiteName:Empty"); Assert.IsNotNull (HostingEnvironment.Cache, "During:Cache"); Assert.AreEqual (ApplicationShutdownReason.None, HostingEnvironment.ShutdownReason, "During:ShutdownReason"); Assert.IsNotNull (HostingEnvironment.VirtualPathProvider, "During:VirtualPathProvider"); diff --git a/mcs/class/System.Web/Test/System.Web/HttpResponseTest.cs b/mcs/class/System.Web/Test/System.Web/HttpResponseTest.cs index 2ce8621aec4..0342a707978 100644 --- a/mcs/class/System.Web/Test/System.Web/HttpResponseTest.cs +++ b/mcs/class/System.Web/Test/System.Web/HttpResponseTest.cs @@ -547,7 +547,7 @@ namespace MonoTests.System.Web { KnownResponseHeader known; - Assert.LessOrEqual (1, f.KnownResponseHeaders.Count, "#B1"); + AssertHelper.LessOrEqual (1, f.KnownResponseHeaders.Count, "#B1"); known = (KnownResponseHeader)f.KnownResponseHeaders ["Content-Type"]; Assert.AreEqual (HttpWorkerRequest.HeaderContentType, known.Index, "#B2"); @@ -571,7 +571,7 @@ namespace MonoTests.System.Web { KnownResponseHeader known; - Assert.LessOrEqual (1, f.KnownResponseHeaders.Count, "#B1"); + AssertHelper.LessOrEqual (1, f.KnownResponseHeaders.Count, "#B1"); known = (KnownResponseHeader)f.KnownResponseHeaders ["Content-Type"]; Assert.AreEqual (HttpWorkerRequest.HeaderContentType, known.Index, "#B2"); diff --git a/mcs/class/System.Web/Test/System.Web/HttpRuntimeTest.cs b/mcs/class/System.Web/Test/System.Web/HttpRuntimeTest.cs index 52439e975ab..51742ec6bc9 100644 --- a/mcs/class/System.Web/Test/System.Web/HttpRuntimeTest.cs +++ b/mcs/class/System.Web/Test/System.Web/HttpRuntimeTest.cs @@ -55,7 +55,6 @@ namespace MonoTests.System.Web [Test] [Category ("NunitWeb")] [Ignore ("Pending fix for bug 351878")] - [Explicit] public void UnloadAppDomain100Times () { for (int i = 0; i < 100; i++) diff --git a/mcs/class/System.Web/Test/System.Web/XmlSiteMapProviderTest.cs b/mcs/class/System.Web/Test/System.Web/XmlSiteMapProviderTest.cs index 23487dacb07..73c5c75bb2c 100644 --- a/mcs/class/System.Web/Test/System.Web/XmlSiteMapProviderTest.cs +++ b/mcs/class/System.Web/Test/System.Web/XmlSiteMapProviderTest.cs @@ -148,7 +148,7 @@ namespace MonoTests.System.Web provider.DoAddNode (node, rootNode); Assert.IsNotNull (provider.CallTrace, "#A1"); - Assert.Greater (provider.CallTrace.Length, 1, "#A1-1"); + AssertHelper.Greater (provider.CallTrace.Length, 1, "#A1-1"); Assert.AreEqual (provider.CallTrace[0].Name, "BuildSiteMap", "#A1-2"); } @@ -247,7 +247,7 @@ namespace MonoTests.System.Web Assert.IsNotNull (provider.RootNode, "#A1"); Assert.AreEqual (provider.RootNode.Provider, provider, "#A2"); Assert.IsNotNull (provider.CallTrace, "#A3"); - Assert.Greater (provider.CallTrace.Length, 1, "#A3-1"); + AssertHelper.Greater (provider.CallTrace.Length, 1, "#A3-1"); Assert.AreEqual ("BuildSiteMap", provider.CallTrace[0].Name, "#A3-2"); Assert.AreEqual ("get_RootNode", provider.CallTrace[1].Name, "#A3-3"); } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms_test.dll.sources b/mcs/class/System.Windows.Forms/System.Windows.Forms_test.dll.sources index f336b1537be..884953ac3dd 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms_test.dll.sources +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms_test.dll.sources @@ -1,3 +1,4 @@ +../../test-helpers/NunitHelpers.cs ../../../build/common/Consts.cs System.Windows.Forms/ApplicationTest.cs System.Windows.Forms/AutoCompleteStringCollectionTest.cs diff --git a/mcs/class/System.Windows.Forms/Test/System.Resources/ResXDataNodeFileRefGetValueTests.cs b/mcs/class/System.Windows.Forms/Test/System.Resources/ResXDataNodeFileRefGetValueTests.cs index d0e3fc1bd3d..0414fa18e71 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Resources/ResXDataNodeFileRefGetValueTests.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Resources/ResXDataNodeFileRefGetValueTests.cs @@ -47,7 +47,7 @@ namespace MonoTests.System.Resources { Assert.IsNotNull (returnedNode, "#A1"); object val = returnedNode.GetValue (new ReturnSerializableSubClassITRS ()); - Assert.IsNotInstanceOfType (typeof (serializableSubClass), val, "#A2"); + AssertHelper.IsNotInstanceOfType (typeof (serializableSubClass), val, "#A2"); Assert.IsInstanceOfType (typeof (serializable), val, "#A3"); } @@ -84,7 +84,7 @@ namespace MonoTests.System.Resources { node = GetNodeFileRefToSerializable ("ser.bbb",true); object val = node.GetValue (new ReturnSerializableSubClassITRS ()); - Assert.IsNotInstanceOfType (typeof (serializableSubClass), val, "#A1"); + AssertHelper.IsNotInstanceOfType (typeof (serializableSubClass), val, "#A1"); Assert.IsInstanceOfType (typeof (serializable), val, "#A2"); } diff --git a/mcs/class/System.Windows.Forms/Test/System.Resources/ResXDataNodeSerialisedGetValueTypeNameTests.cs b/mcs/class/System.Windows.Forms/Test/System.Resources/ResXDataNodeSerialisedGetValueTypeNameTests.cs index 8ca5f4eb574..3c0fc3beaaf 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Resources/ResXDataNodeSerialisedGetValueTypeNameTests.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Resources/ResXDataNodeSerialisedGetValueTypeNameTests.cs @@ -90,7 +90,7 @@ namespace MonoTests.System.Resources { // get value passing no params object val = returnedNode.GetValue ((ITypeResolutionService) null); Assert.IsInstanceOfType (typeof (serializable), val, "#A2"); - Assert.IsNotInstanceOfType (typeof (serializableSubClass), val, "#A3"); + AssertHelper.IsNotInstanceOfType (typeof (serializableSubClass), val, "#A3"); //get value type passing different params string newType = returnedNode.GetValueTypeName (new ReturnSerializableSubClassITRS ()); diff --git a/mcs/class/System.Windows.Forms/Test/System.Resources/ResXDataNodeSerializedGetValueTests.cs b/mcs/class/System.Windows.Forms/Test/System.Resources/ResXDataNodeSerializedGetValueTests.cs index d27d4439bb6..ffd3711a8c2 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Resources/ResXDataNodeSerializedGetValueTests.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Resources/ResXDataNodeSerializedGetValueTests.cs @@ -50,10 +50,10 @@ namespace MonoTests.System.Resources { object defaultVal = returnedNode.GetValue ((ITypeResolutionService) null); Assert.IsInstanceOfType (typeof (serializable), defaultVal, "#A2"); - Assert.IsNotInstanceOfType (typeof (serializableSubClass), defaultVal, "#A3"); + AssertHelper.IsNotInstanceOfType (typeof (serializableSubClass), defaultVal, "#A3"); object newVal = returnedNode.GetValue (new ReturnSerializableSubClassITRS ()); - Assert.IsNotInstanceOfType (typeof (serializableSubClass), newVal, "#A4"); + AssertHelper.IsNotInstanceOfType (typeof (serializableSubClass), newVal, "#A4"); Assert.IsInstanceOfType (typeof (serializable), newVal, "#A5"); } @@ -88,7 +88,7 @@ namespace MonoTests.System.Resources { // get value passing null params object val = returnedNode.GetValue ((ITypeResolutionService) null); - // Assert.IsNotInstanceOfType (typeof (serializable), val, "#A5"); this would fail as subclasses are id-ed as instances of parents + // AssertHelper.IsNotInstanceOfType (typeof (serializable), val, "#A5"); this would fail as subclasses are id-ed as instances of parents Assert.IsInstanceOfType (typeof (serializableSubClass), val, "#A4"); } diff --git a/mcs/class/System.Windows.Forms/Test/System.Resources/ResXDataNodeTest.cs b/mcs/class/System.Windows.Forms/Test/System.Resources/ResXDataNodeTest.cs index 3a6cfbda95a..5c6d1a960cc 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Resources/ResXDataNodeTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Resources/ResXDataNodeTest.cs @@ -314,7 +314,7 @@ namespace MonoTests.System.Resources { object o = node.GetValue ((AssemblyName []) null); - Assert.IsNotInstanceOfType (typeof (serializableSubClass), o, "#A2"); + AssertHelper.IsNotInstanceOfType (typeof (serializableSubClass), o, "#A2"); Assert.IsInstanceOfType (typeof (serializable), o, "#A3"); rr.Close (); } diff --git a/mcs/class/System.Windows.Forms/Test/System.Resources/ResXDataNodeWriteBehavior.cs b/mcs/class/System.Windows.Forms/Test/System.Resources/ResXDataNodeWriteBehavior.cs index 6c69a328a08..9bfe7b1b416 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Resources/ResXDataNodeWriteBehavior.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Resources/ResXDataNodeWriteBehavior.cs @@ -252,7 +252,7 @@ namespace MonoTests.System.Resources { Assert.IsNotNull (finalNode, "#A3"); object finalVal = finalNode.GetValue ((ITypeResolutionService) null); - Assert.IsNotInstanceOfType (typeof (serializableSubClass), finalVal, "#A4"); + AssertHelper.IsNotInstanceOfType (typeof (serializableSubClass), finalVal, "#A4"); Assert.IsInstanceOfType (typeof (serializable), finalVal, "#A5"); } diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ApplicationTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ApplicationTest.cs index 02f4db20f28..6514bfe1c03 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ApplicationTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ApplicationTest.cs @@ -91,6 +91,7 @@ namespace MonoTests.System.Windows.Forms } [Test] + [Ignore ("causes an infinite restart loop since we're not in a separate AppDomain with nunit-lite")] [ExpectedException (typeof (NotSupportedException))] public void RestartNotSupportedExceptionTest () { diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TableLayoutTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TableLayoutTest.cs index acade5f6933..18271cfba2d 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TableLayoutTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TableLayoutTest.cs @@ -946,10 +946,10 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual (31, p.GetRowHeights ()[0], "D1"); Assert.AreEqual (31, p.GetRowHeights ()[1], "D2"); Assert.AreEqual (81, p.GetColumnWidths ()[0], "D3"); - Assert.LessOrEqual (75, p.GetColumnWidths ()[1], "D4"); - Assert.GreaterOrEqual (78, p.GetColumnWidths ()[1], "D5"); - Assert.LessOrEqual (78, p.GetColumnWidths ()[2], "D6"); - Assert.GreaterOrEqual (81, p.GetColumnWidths ()[2], "D7"); + AssertHelper.LessOrEqual (75, p.GetColumnWidths ()[1], "D4"); + AssertHelper.GreaterOrEqual (78, p.GetColumnWidths ()[1], "D5"); + AssertHelper.LessOrEqual (78, p.GetColumnWidths ()[2], "D6"); + AssertHelper.GreaterOrEqual (81, p.GetColumnWidths ()[2], "D7"); } [Test] @@ -1702,7 +1702,7 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual (4, tlp.RowCount, "X18638-1"); Assert.AreEqual (3, tlp.ColumnCount, "X18638-2"); Assert.AreEqual (60, widths[0], "X18638-3"); - Assert.Greater (label2.Width, widths[1], "X18638-5"); + AssertHelper.Greater (label2.Width, widths[1], "X18638-5"); Assert.AreEqual (45, widths[2], "X18638-4"); } diff --git a/mcs/class/System.XML/Test/System.Xml.Serialization/XmlCodeExporterTests.cs b/mcs/class/System.XML/Test/System.Xml.Serialization/XmlCodeExporterTests.cs index 661273a3bf7..e8bdfd8829c 100644 --- a/mcs/class/System.XML/Test/System.Xml.Serialization/XmlCodeExporterTests.cs +++ b/mcs/class/System.XML/Test/System.Xml.Serialization/XmlCodeExporterTests.cs @@ -46,7 +46,7 @@ namespace MonoTests.System.XmlSerialization Assert.AreEqual (string.Format(CultureInfo.InvariantCulture, "{0}{0}" + "/// {0}" + - "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Xml\", \"{1}\")]{0}" + + "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"nunit-lite-console\", \"0.0.0.0\")]{0}" + "[System.SerializableAttribute()]{0}" + "[System.Diagnostics.DebuggerStepThroughAttribute()]{0}" + "[System.ComponentModel.DesignerCategoryAttribute(\"code\")]{0}" + @@ -64,7 +64,7 @@ namespace MonoTests.System.XmlSerialization " this.namesField = value;{0}" + " }}{0}" + " }}{0}" + - "}}{0}", Environment.NewLine, XmlFileVersion), sw.ToString (), "#2"); + "}}{0}", Environment.NewLine), sw.ToString (), "#2"); codeNamespace = ExportCode (typeof (ArrayClass[])); @@ -76,7 +76,7 @@ namespace MonoTests.System.XmlSerialization Assert.AreEqual (string.Format (CultureInfo.InvariantCulture, "{0}{0}" + "/// {0}" + - "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Xml\", \"{1}\")]{0}" + + "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"nunit-lite-console\", \"0.0.0.0\")]{0}" + "[System.SerializableAttribute()]{0}" + "[System.Diagnostics.DebuggerStepThroughAttribute()]{0}" + "[System.ComponentModel.DesignerCategoryAttribute(\"code\")]{0}" + @@ -93,7 +93,7 @@ namespace MonoTests.System.XmlSerialization " this.namesField = value;{0}" + " }}{0}" + " }}{0}" + - "}}{0}", Environment.NewLine, XmlFileVersion), sw.ToString (), "#4"); + "}}{0}", Environment.NewLine), sw.ToString (), "#4"); } [Test] @@ -110,7 +110,7 @@ namespace MonoTests.System.XmlSerialization Assert.AreEqual (string.Format (CultureInfo.InvariantCulture, "{0}{0}" + "/// {0}" + - "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Xml\", \"{1}\")]{0}" + + "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"nunit-lite-console\", \"0.0.0.0\")]{0}" + "[System.SerializableAttribute()]{0}" + "[System.Diagnostics.DebuggerStepThroughAttribute()]{0}" + "[System.ComponentModel.DesignerCategoryAttribute(\"code\")]{0}" + @@ -128,7 +128,7 @@ namespace MonoTests.System.XmlSerialization " this.itemsField = value;{0}" + " }}{0}" + " }}{0}" + - "}}{0}", Environment.NewLine, XmlFileVersion), sw.ToString (), "#2"); + "}}{0}", Environment.NewLine), sw.ToString (), "#2"); } [Test] @@ -145,7 +145,7 @@ namespace MonoTests.System.XmlSerialization Assert.AreEqual (string.Format (CultureInfo.InvariantCulture, "{0}{0}" + "/// {0}" + - "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Xml\", \"{1}\")]{0}" + + "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"nunit-lite-console\", \"0.0.0.0\")]{0}" + "[System.SerializableAttribute()]{0}" + "[System.Diagnostics.DebuggerStepThroughAttribute()]{0}" + "[System.ComponentModel.DesignerCategoryAttribute(\"code\")]{0}" + @@ -163,7 +163,7 @@ namespace MonoTests.System.XmlSerialization " this.cdataField = value;{0}" + " }}{0}" + " }}{0}" + - "}}{0}", Environment.NewLine, XmlFileVersion), sw.ToString (), "#2"); + "}}{0}", Environment.NewLine), sw.ToString (), "#2"); } [Test] @@ -182,7 +182,7 @@ namespace MonoTests.System.XmlSerialization Assert.AreEqual (string.Format (CultureInfo.InvariantCulture, "{0}{0}" + "/// {0}" + - "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Xml\", \"{1}\")]{0}" + + "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"nunit-lite-console\", \"0.0.0.0\")]{0}" + "[System.SerializableAttribute()]{0}" + "[System.Diagnostics.DebuggerStepThroughAttribute()]{0}" + "[System.ComponentModel.DesignerCategoryAttribute(\"code\")]{0}" + @@ -204,7 +204,7 @@ namespace MonoTests.System.XmlSerialization " this.myChoiceField = value;{0}" + " }}{0}" + " }}{0}" + - "}}{0}", Environment.NewLine, XmlFileVersion), sw.ToString (), "#2"); + "}}{0}", Environment.NewLine), sw.ToString (), "#2"); } [Test] @@ -222,7 +222,7 @@ namespace MonoTests.System.XmlSerialization Assert.AreEqual (string.Format (CultureInfo.InvariantCulture, "{0}{0}" + "/// {0}" + - "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Xml\", \"{1}\")]{0}" + + "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"nunit-lite-console\", \"0.0.0.0\")]{0}" + "[System.SerializableAttribute()]{0}" + "[System.Diagnostics.DebuggerStepThroughAttribute()]{0}" + "[System.ComponentModel.DesignerCategoryAttribute(\"code\")]{0}" + @@ -403,7 +403,7 @@ namespace MonoTests.System.XmlSerialization "{0}" + "/// {0}" + "[System.FlagsAttribute()]{0}" + - "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Xml\", \"{1}\")]{0}" + + "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"nunit-lite-console\", \"0.0.0.0\")]{0}" + "[System.SerializableAttribute()]{0}" + "public enum MapModifiers {{{0}" + " {0}" + @@ -414,7 +414,7 @@ namespace MonoTests.System.XmlSerialization " /// {0}" + " [System.Xml.Serialization.XmlEnumAttribute(\"protected\")]{0}" + " Protected = 2,{0}" + - "}}{0}", Environment.NewLine, XmlFileVersion), sw.ToString (), "#2"); + "}}{0}", Environment.NewLine), sw.ToString (), "#2"); } [Test] @@ -431,7 +431,7 @@ namespace MonoTests.System.XmlSerialization Assert.AreEqual (string.Format (CultureInfo.InvariantCulture, "{0}{0}" + "/// {0}" + - "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Xml\", \"{1}\")]{0}" + + "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"nunit-lite-console\", \"0.0.0.0\")]{0}" + "[System.SerializableAttribute()]{0}" + "[System.Xml.Serialization.XmlTypeAttribute(IncludeInSchema=false)]{0}" + "[System.Xml.Serialization.XmlRootAttribute(Namespace=\"\", IsNullable=false)]{0}" + @@ -446,7 +446,7 @@ namespace MonoTests.System.XmlSerialization " {0}" + " /// {0}" + " ChoiceTwo,{0}" + - "}}{0}", Environment.NewLine, XmlFileVersion), sw.ToString (), "#2"); + "}}{0}", Environment.NewLine), sw.ToString (), "#2"); codeNamespace = ExportCode (typeof (ItemChoiceType[])); Assert.IsNotNull (codeNamespace, "#3"); @@ -457,7 +457,7 @@ namespace MonoTests.System.XmlSerialization Assert.AreEqual (string.Format (CultureInfo.InvariantCulture, "{0}{0}" + "/// {0}" + - "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Xml\", \"{1}\")]{0}" + + "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"nunit-lite-console\", \"0.0.0.0\")]{0}" + "[System.SerializableAttribute()]{0}" + "[System.Xml.Serialization.XmlTypeAttribute(IncludeInSchema=false)]{0}" + "public enum ItemChoiceType {{{0}" + @@ -471,7 +471,7 @@ namespace MonoTests.System.XmlSerialization " {0}" + " /// {0}" + " ChoiceTwo,{0}" + - "}}{0}", Environment.NewLine, XmlFileVersion), sw.ToString (), "#4"); + "}}{0}", Environment.NewLine), sw.ToString (), "#4"); } [Test] @@ -488,7 +488,7 @@ namespace MonoTests.System.XmlSerialization Assert.AreEqual (string.Format (CultureInfo.InvariantCulture, "{0}{0}" + "/// {0}" + - "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Xml\", \"{1}\")]{0}" + + "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"nunit-lite-console\", \"0.0.0.0\")]{0}" + "[System.SerializableAttribute()]{0}" + "[System.Diagnostics.DebuggerStepThroughAttribute()]{0}" + "[System.ComponentModel.DesignerCategoryAttribute(\"code\")]{0}" + @@ -509,7 +509,7 @@ namespace MonoTests.System.XmlSerialization "}}{0}" + "{0}" + "/// {0}" + - "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Xml\", \"{1}\")]{0}" + + "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"nunit-lite-console\", \"0.0.0.0\")]{0}" + "[System.SerializableAttribute()]{0}" + "[System.Diagnostics.DebuggerStepThroughAttribute()]{0}" + "[System.ComponentModel.DesignerCategoryAttribute(\"code\")]{0}" + @@ -526,7 +526,7 @@ namespace MonoTests.System.XmlSerialization " this.somethingField = value;{0}" + " }}{0}" + " }}{0}" + - "}}{0}", Environment.NewLine, XmlFileVersion), sw.ToString (), "#2"); + "}}{0}", Environment.NewLine), sw.ToString (), "#2"); } [Test] @@ -544,7 +544,7 @@ namespace MonoTests.System.XmlSerialization Assert.AreEqual (string.Format (CultureInfo.InvariantCulture, "{0}{0}" + "/// {0}" + - "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Xml\", \"{1}\")]{0}" + + "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"nunit-lite-console\", \"0.0.0.0\")]{0}" + "[System.SerializableAttribute()]{0}" + "[System.Diagnostics.DebuggerStepThroughAttribute()]{0}" + "[System.ComponentModel.DesignerCategoryAttribute(\"code\")]{0}" + @@ -578,7 +578,7 @@ namespace MonoTests.System.XmlSerialization "}}{0}" + "{0}" + "/// {0}" + - "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Xml\", \"{1}\")]{0}" + + "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"nunit-lite-console\", \"0.0.0.0\")]{0}" + "[System.SerializableAttribute()]{0}" + "[System.Diagnostics.DebuggerStepThroughAttribute()]{0}" + "[System.ComponentModel.DesignerCategoryAttribute(\"code\")]{0}" + @@ -667,7 +667,7 @@ namespace MonoTests.System.XmlSerialization "{0}" + "/// {0}" + "[System.FlagsAttribute()]{0}" + - "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Xml\", \"{1}\")]{0}" + + "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"nunit-lite-console\", \"0.0.0.0\")]{0}" + "[System.SerializableAttribute()]{0}" + "[System.Xml.Serialization.XmlTypeAttribute(Namespace=\"some:urn\")]{0}" + "public enum FlagEnum {{{0}" + @@ -786,7 +786,7 @@ namespace MonoTests.System.XmlSerialization "{0}" + "/// {0}" + "[System.FlagsAttribute()]{0}" + - "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Xml\", \"{1}\")]{0}" + + "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"nunit-lite-console\", \"0.0.0.0\")]{0}" + "[System.SerializableAttribute()]{0}" + "[System.Xml.Serialization.XmlTypeAttribute(Namespace=\"urn:myNS\")]{0}" + "public enum FlagEnum {{{0}" + @@ -806,7 +806,7 @@ namespace MonoTests.System.XmlSerialization "{0}" + "/// {0}" + "[System.FlagsAttribute()]{0}" + - "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Xml\", \"{1}\")]{0}" + + "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"nunit-lite-console\", \"0.0.0.0\")]{0}" + "[System.SerializableAttribute()]{0}" + "[System.Xml.Serialization.XmlTypeAttribute(Namespace=\"urn:myNS\")]{0}" + "public enum FlagEnum_Encoded {{{0}" + @@ -819,7 +819,7 @@ namespace MonoTests.System.XmlSerialization " {0}" + " /// {0}" + " e4 = 4,{0}" + - "}}{0}", Environment.NewLine, XmlFileVersion), sw.ToString (), "#2"); + "}}{0}", Environment.NewLine), sw.ToString (), "#2"); } [Test] @@ -836,7 +836,7 @@ namespace MonoTests.System.XmlSerialization Assert.AreEqual (string.Format (CultureInfo.InvariantCulture, "{0}{0}" + "/// {0}" + - "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Xml\", \"{1}\")]{0}" + + "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"nunit-lite-console\", \"0.0.0.0\")]{0}" + "[System.SerializableAttribute()]{0}" + "[System.Diagnostics.DebuggerStepThroughAttribute()]{0}" + "[System.ComponentModel.DesignerCategoryAttribute(\"code\")]{0}" + @@ -855,7 +855,7 @@ namespace MonoTests.System.XmlSerialization " this.somethingField = value;{0}" + " }}{0}" + " }}{0}" + - "}}{0}", Environment.NewLine, XmlFileVersion), sw.ToString (), "#2"); + "}}{0}", Environment.NewLine), sw.ToString (), "#2"); } [Test] @@ -909,7 +909,7 @@ namespace MonoTests.System.XmlSerialization "{0}{0}" + "/// {0}" + "[System.FlagsAttribute()]{0}" + - "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Xml\", \"{1}\")]{0}" + + "[System.CodeDom.Compiler.GeneratedCodeAttribute(\"nunit-lite-console\", \"0.0.0.0\")]{0}" + "[System.SerializableAttribute()]{0}" + "[System.Xml.Serialization.XmlRootAttribute(Namespace=\"\", IsNullable=false)]{0}" + "public enum ZeroFlagEnum {{{0}" + @@ -925,7 +925,7 @@ namespace MonoTests.System.XmlSerialization " /// {0}" + " [System.Xml.Serialization.XmlEnumAttribute(\"tns:to\")]{0}" + " e2 = 4,{0}" + - "}}{0}", Environment.NewLine, XmlFileVersion), sw.ToString (), "#2"); + "}}{0}", Environment.NewLine), sw.ToString (), "#2"); } [Test] @@ -1005,15 +1005,6 @@ namespace MonoTests.System.XmlSerialization return codeNamespace; } - string XmlFileVersion { - get { - Assembly xmlAsm = typeof (XmlDocument).Assembly; - AssemblyFileVersionAttribute afv = (AssemblyFileVersionAttribute) - Attribute.GetCustomAttribute (xmlAsm, typeof (AssemblyFileVersionAttribute)); - return afv.Version; - } - } - [XmlRootAttribute ("root", Namespace="urn:aNS", IsNullable=false)] public class Root { diff --git a/mcs/class/System.XML/Test/System.Xml/XmlSecureResolverTests.cs b/mcs/class/System.XML/Test/System.Xml/XmlSecureResolverTests.cs index 493bc6a8ad0..2624f2a5ba0 100644 --- a/mcs/class/System.XML/Test/System.Xml/XmlSecureResolverTests.cs +++ b/mcs/class/System.XML/Test/System.Xml/XmlSecureResolverTests.cs @@ -136,7 +136,7 @@ namespace MonoTests.System.Xml Assert.AreEqual ("file", resolved.Scheme); var task = sr.GetEntityAsync (resolved, null, typeof (Stream)); Assert.That (task.Wait (3000)); - Assert.IsInstanceOfType (typeof (Stream), task.Result); + Assert.IsInstanceOfType (typeof (FileStream), task.Result); } } diff --git a/mcs/class/System.Xml.Linq/System.Xml.Linq_test.dll.sources b/mcs/class/System.Xml.Linq/System.Xml.Linq_test.dll.sources index 693d4a2e296..67efb6025e6 100644 --- a/mcs/class/System.Xml.Linq/System.Xml.Linq_test.dll.sources +++ b/mcs/class/System.Xml.Linq/System.Xml.Linq_test.dll.sources @@ -1,3 +1,4 @@ +../../test-helpers/NunitHelpers.cs System.Xml.Linq/ExtensionsTest.cs System.Xml.Linq/XAttributeTest.cs System.Xml.Linq/XCommentTest.cs diff --git a/mcs/class/System.Xml.Linq/Test/System.Xml.Schema/ExtensionsTest.cs b/mcs/class/System.Xml.Linq/Test/System.Xml.Schema/ExtensionsTest.cs index da577e644ef..bbbf42e13f5 100644 --- a/mcs/class/System.Xml.Linq/Test/System.Xml.Schema/ExtensionsTest.cs +++ b/mcs/class/System.Xml.Linq/Test/System.Xml.Schema/ExtensionsTest.cs @@ -220,8 +220,8 @@ namespace MonoTests.System.Xml.Schema } } - Assert.GreaterOrEqual (afterNoOfAttributes, beforeNoOfAttributes, "newAttributes"); - Assert.GreaterOrEqual (afterNoOfElements, beforeNoOfElements, "newElements"); + AssertHelper.GreaterOrEqual (afterNoOfAttributes, beforeNoOfAttributes, "newAttributes"); + AssertHelper.GreaterOrEqual (afterNoOfElements, beforeNoOfElements, "newElements"); } /* diff --git a/mcs/class/System/Makefile b/mcs/class/System/Makefile index b4f825fb502..3c4d4dfc432 100644 --- a/mcs/class/System/Makefile +++ b/mcs/class/System/Makefile @@ -34,6 +34,8 @@ endif TEST_MCS_FLAGS = -nowarn:618,672,219,67,169,612 \ $(foreach f, $(TEST_RESOURCES), -resource:$(f),$(notdir $(f))) +TEST_NUNITLITE_APP_CONFIG_GLOBAL=Test/test-config-file + REFERENCE_SOURCES_FLAGS = -d:FEATURE_PAL,SYSTEM_NAMESPACE,MONO,PLATFORM_UNIX ifndef NO_PROCESS_START REFERENCE_SOURCES_FLAGS += -d:MONO_FEATURE_PROCESS_START @@ -101,7 +103,6 @@ endif EXTRA_DISTFILES = \ Test/test-config-file \ - Test/test-config-file-net-2.0 \ Test/System.Security.Cryptography.X509Certificates/pkits/Makefile \ Test/System.Security.Cryptography.X509Certificates/pkits/README \ Test/System.Security.Cryptography.X509Certificates/pkits/x509build.cs \ @@ -157,10 +158,7 @@ $(the_libdir_base)System.Configuration.dll: $(build_lib): $(CYCLIC_DEP_FILES) -$(test_lib): $(test_lib).config $(TEST_RESOURCES) - -$(test_lib).config: Test/test-config-file - cp $< $@ +$(test_lib): $(TEST_RESOURCES) CLEAN_FILES = $(test_lib).config $(bare_libdir)/System.dll $(secxml_libdir)/System.dll $(bare_libdir)/System.dll.mdb $(secxml_libdir)/System.dll.mdb diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509Lookup.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509Lookup.cs index b2e863b085a..8a6bf30903d 100644 --- a/mcs/class/System/Mono.Btls/MonoBtlsX509Lookup.cs +++ b/mcs/class/System/Mono.Btls/MonoBtlsX509Lookup.cs @@ -64,10 +64,6 @@ namespace Mono.Btls [DllImport (BTLS_DYLIB)] extern static int mono_btls_x509_lookup_add_mono (IntPtr handle, IntPtr monoLookup); - [DllImport (BTLS_DYLIB)] - extern static void mono_btls_x509_lookup_method_mono_init ( - IntPtr handle, IntPtr instance, IntPtr by_subject_func); - [DllImport (BTLS_DYLIB)] extern static int mono_btls_x509_lookup_init (IntPtr handle); diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509NameList.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509NameList.cs deleted file mode 100644 index 005ffd03eab..00000000000 --- a/mcs/class/System/Mono.Btls/MonoBtlsX509NameList.cs +++ /dev/null @@ -1,121 +0,0 @@ -// -// MonoBtlsX509NameList.cs -// -// Author: -// Martin Baulig -// -// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -#if SECURITY_DEP && MONO_FEATURE_BTLS -using System; -using System.IO; -using System.Text; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; - -namespace Mono.Btls -{ - class MonoBtlsX509NameList : MonoBtlsObject - { - internal class BoringX509NameListHandle : MonoBtlsHandle - { - bool dontFree; - - internal BoringX509NameListHandle (IntPtr handle, bool ownsHandle) - : base (handle, ownsHandle) - { - this.dontFree = !ownsHandle; - } - - protected override bool ReleaseHandle () - { - if (!dontFree) - mono_btls_x509_name_list_free (handle); - return true; - } - } - - [DllImport (BTLS_DYLIB)] - extern static IntPtr mono_btls_x509_name_list_new (); - - [DllImport (BTLS_DYLIB)] - extern static int mono_btls_x509_name_list_get_count (IntPtr handle); - - [DllImport (BTLS_DYLIB)] - extern static int mono_btls_x509_name_list_add (IntPtr handle, IntPtr name); - - [DllImport (BTLS_DYLIB)] - extern static IntPtr mono_btls_x509_name_list_get_item (IntPtr handle, int index); - - [DllImport (BTLS_DYLIB)] - extern static void mono_btls_x509_name_list_free (IntPtr handle); - - new internal BoringX509NameListHandle Handle { - get { return (BoringX509NameListHandle)base.Handle; } - } - - internal MonoBtlsX509NameList (BoringX509NameListHandle handle) - : base (handle) - { - } - - internal MonoBtlsX509NameList () - : this (Create_internal ()) - { - } - - static BoringX509NameListHandle Create_internal () - { - var handle = mono_btls_x509_name_list_new (); - if (handle == IntPtr.Zero) - throw new MonoBtlsException (); - return new BoringX509NameListHandle (handle, true); - } - - public int GetCount () - { - CheckThrow (); - return mono_btls_x509_name_list_get_count ( - Handle.DangerousGetHandle ()); - } - - public MonoBtlsX509Name GetItem (int index) - { - CheckThrow (); - if (index < 0 || index >= GetCount ()) - throw new ArgumentOutOfRangeException (); - var ptr = mono_btls_x509_name_list_get_item ( - Handle.DangerousGetHandle (), index); - if (ptr == IntPtr.Zero) - return null; - return new MonoBtlsX509Name ( - new MonoBtlsX509Name.BoringX509NameHandle (ptr, true)); - } - - public void Add (MonoBtlsX509Name name) - { - CheckThrow (); - mono_btls_x509_name_list_add ( - Handle.DangerousGetHandle (), - name.Handle.DangerousGetHandle ()); - } - } -} -#endif diff --git a/mcs/class/System/Mono.Net.Security/MonoTlsProviderFactory.Droid.cs b/mcs/class/System/Mono.Net.Security/MonoTlsProviderFactory.Droid.cs index db2e81529ba..f9bd47396e6 100644 --- a/mcs/class/System/Mono.Net.Security/MonoTlsProviderFactory.Droid.cs +++ b/mcs/class/System/Mono.Net.Security/MonoTlsProviderFactory.Droid.cs @@ -2,7 +2,9 @@ #if SECURITY_DEP using System; using MSI = Mono.Security.Interface; +#if MONO_FEATURE_BTLS using Mono.Btls; +#endif namespace Mono.Net.Security { @@ -17,10 +19,12 @@ namespace Mono.Net.Security case "default": case "legacy": return new LegacyTlsProvider (); +#if MONO_FEATURE_BTLS case "btls": if (!IsBtlsSupported ()) throw new NotSupportedException ("BTLS in not supported!"); return new MonoBtlsProvider (); +#endif default: throw new NotSupportedException (string.Format ("Invalid TLS Provider: `{0}'.", provider)); } diff --git a/mcs/class/System/ReferenceSources/HttpApi.cs b/mcs/class/System/ReferenceSources/HttpApi.cs index b7f3043a594..8d92f001d56 100644 --- a/mcs/class/System/ReferenceSources/HttpApi.cs +++ b/mcs/class/System/ReferenceSources/HttpApi.cs @@ -2,7 +2,7 @@ using System.Collections; namespace System.Net { - static class UnsafeNclNativeMethods + static partial class UnsafeNclNativeMethods { internal static unsafe class HttpApi { diff --git a/mcs/class/System/ReferenceSources/SecureStringHelper.cs b/mcs/class/System/ReferenceSources/SecureStringHelper.cs new file mode 100644 index 00000000000..31372e2cc6c --- /dev/null +++ b/mcs/class/System/ReferenceSources/SecureStringHelper.cs @@ -0,0 +1,47 @@ +using System.Security; +using System.Runtime.InteropServices; + +namespace System.Net +{ + static partial class UnsafeNclNativeMethods + { + internal unsafe static class SecureStringHelper + { + internal static string CreateString(SecureString secureString) + { + string plainString; + IntPtr bstr = IntPtr.Zero; + + if (secureString == null || secureString.Length == 0) + return String.Empty; + + try + { + bstr = Marshal.SecureStringToBSTR(secureString); + plainString = Marshal.PtrToStringBSTR(bstr); + } + finally + { + if (bstr != IntPtr.Zero) + Marshal.ZeroFreeBSTR(bstr); + } + return plainString; + } + + internal static SecureString CreateSecureString(string plainString) + { + SecureString secureString; + + if (plainString == null || plainString.Length == 0) + return new SecureString(); + + fixed (char* pch = plainString) + { + secureString = new SecureString(pch, plainString.Length); + } + + return secureString; + } + } + } +} \ No newline at end of file diff --git a/mcs/class/System/System-bare-net_4_x.csproj b/mcs/class/System/System-bare-net_4_x.csproj index 5979582c21d..6d6ee2b5d23 100644 --- a/mcs/class/System/System-bare-net_4_x.csproj +++ b/mcs/class/System/System-bare-net_4_x.csproj @@ -575,6 +575,7 @@ + @@ -776,7 +777,6 @@ - @@ -839,6 +839,7 @@ + @@ -1167,7 +1168,6 @@ - diff --git a/mcs/class/System/System-net_4_x.csproj b/mcs/class/System/System-net_4_x.csproj index fa55d4fa95c..8e045c3da84 100644 --- a/mcs/class/System/System-net_4_x.csproj +++ b/mcs/class/System/System-net_4_x.csproj @@ -575,6 +575,7 @@ + @@ -776,7 +777,6 @@ - @@ -839,6 +839,7 @@ + @@ -1167,7 +1168,6 @@ - diff --git a/mcs/class/System/System-secxml-net_4_x.csproj b/mcs/class/System/System-secxml-net_4_x.csproj index fbb01b231b4..1f644f32d70 100644 --- a/mcs/class/System/System-secxml-net_4_x.csproj +++ b/mcs/class/System/System-secxml-net_4_x.csproj @@ -575,6 +575,7 @@ + @@ -776,7 +777,6 @@ - @@ -839,6 +839,7 @@ + @@ -1167,7 +1168,6 @@ - diff --git a/mcs/class/System/System.Net.Sockets/Socket.cs b/mcs/class/System/System.Net.Sockets/Socket.cs index 08c2630eacc..752dcd08d8b 100644 --- a/mcs/class/System/System.Net.Sockets/Socket.cs +++ b/mcs/class/System/System.Net.Sockets/Socket.cs @@ -2453,9 +2453,6 @@ m_Handle, buffer, offset + sent, size - sent, socketFlags, out nativeError, is_b { ThrowIfDisposedAndClosed (); - if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.ReuseAddress && optionValue != 0 && !SupportsPortReuse (protocolType)) - throw new SocketException ((int) SocketError.OperationNotSupported, "Operating system sockets do not support ReuseAddress.\nIf your socket is not intended to bind to the same address and port multiple times remove this option, otherwise you should ignore this exception inside a try catch and check that ReuseAddress is true before binding to the same address and port multiple times."); - int error; SetSocketOption_internal (m_Handle, optionLevel, optionName, null, null, optionValue, out error); diff --git a/mcs/class/System/System.Net/NetworkCredential.cs b/mcs/class/System/System.Net/NetworkCredential.cs deleted file mode 100644 index faba55dd4fe..00000000000 --- a/mcs/class/System/System.Net/NetworkCredential.cs +++ /dev/null @@ -1,112 +0,0 @@ -// -// System.Net.NetworkCredential.cs -// -// Authors: Duncan Mak (duncan@ximian.com) -// Rolf Bjarne KVinge (rolf@xamarin.com) -// Marek Safar (marek.safar@gmail.com) -// -// (C) Ximian, Inc. -// Copyright (C) 2010 Novell, Inc (http://www.novell.com) -// Copyright (C) 2011, 2014 Xamarin Inc (http://www.xamarin.com) -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System.Security; - -namespace System.Net -{ - public class NetworkCredential : ICredentials - , ICredentialsByHost - { - // Fields - string userName; - string password; - string domain; - - SecureString securePassword; - - // Constructors - public NetworkCredential () - { - } - - public NetworkCredential (string userName, string password) - { - this.userName = userName; - this.password = password; - } - - public NetworkCredential (string userName, string password, string domain) - : this (userName, password) - { - this.domain = domain; - } - - public NetworkCredential (string userName, SecureString password) - { - this.userName = userName; - SecurePassword = password; - } - - public NetworkCredential (string userName, SecureString password, string domain) - : this (userName, password) - { - this.domain = domain; - } - // Properties - - public string Domain { - get { return domain ?? String.Empty; } - set { domain = value; } - } - - public string UserName { - get { return userName ?? String.Empty; } - set { userName = value; } - } - - public string Password { - get { return password ?? String.Empty; } - set { password = value; } - } - - public SecureString SecurePassword { - get { return securePassword; } - set { - if (value == null) { - securePassword = new SecureString (); - } else { - securePassword = value; - } - } - } - - public NetworkCredential GetCredential (Uri uri, string authType) - { - return this; - } - - public NetworkCredential GetCredential (string host, int port, string authenticationType) - { - return this; - } - } -} diff --git a/mcs/class/System/System.dll.sources b/mcs/class/System/System.dll.sources index e1cabcf69ae..d404a646402 100644 --- a/mcs/class/System/System.dll.sources +++ b/mcs/class/System/System.dll.sources @@ -337,7 +337,6 @@ System.Net.Mail/SmtpStatusCode.cs System.Net/MacProxy.cs System.Net/MonoHttpDate.cs System.Net/NetConfig.cs -System.Net/NetworkCredential.cs System.Net.NetworkInformation/IcmpV4Statistics.cs System.Net.NetworkInformation/IcmpV6Statistics.cs System.Net.NetworkInformation/IPAddressCollection.cs @@ -541,7 +540,6 @@ Mono.Btls/MonoBtlsX509LookupMonoCollection.cs Mono.Btls/MonoBtlsX509LookupMono.cs Mono.Btls/MonoBtlsX509LookupType.cs Mono.Btls/MonoBtlsX509Name.cs -Mono.Btls/MonoBtlsX509NameList.cs Mono.Btls/MonoBtlsX509NameEntryType.cs Mono.Btls/MonoBtlsX509Purpose.cs Mono.Btls/MonoBtlsX509Revoked.cs @@ -585,6 +583,7 @@ ReferenceSources/Logging.cs ReferenceSources/NativeMethods.cs ReferenceSources/RequestCacheProtocol.cs ReferenceSources/SettingsSectionInternal.cs +ReferenceSources/SecureStringHelper.cs ReferenceSources/Socket.cs ReferenceSources/SR.cs ReferenceSources/SR2.cs @@ -1024,6 +1023,7 @@ ReferenceSources/Win32Exception.cs ../referencesource/System/net/System/Net/IWebProxyFinder.cs ../referencesource/System/net/System/Net/IWebRequestCreate.cs ../referencesource/System/net/System/Net/NetworkAccess.cs +../referencesource/System/net/System/Net/NetworkCredential.cs ../referencesource/System/net/System/Net/ProtocolViolationException.cs ../referencesource/System/net/System/Net/TransportContext.cs ../referencesource/System/net/System/Net/TransportType.cs diff --git a/mcs/class/System/System/AndroidPlatform.cs b/mcs/class/System/System/AndroidPlatform.cs index 5d59fa64718..dc4f4aaa54e 100644 --- a/mcs/class/System/System/AndroidPlatform.cs +++ b/mcs/class/System/System/AndroidPlatform.cs @@ -33,8 +33,10 @@ using System.Net.Security; using System.Security.Cryptography.X509Certificates; #if SECURITY_DEP using MSX = Mono.Security.X509; +#if MONO_FEATURE_BTLS using Mono.Btls; #endif +#endif namespace System { @@ -60,12 +62,14 @@ namespace System { "TrustEvaluateSsl", ignoreCase:false, throwOnBindFailure:true); +#if MONO_FEATURE_BTLS certStoreLookup = (Func) Delegate.CreateDelegate (typeof (Func), t, "CertStoreLookup", ignoreCase:false, throwOnBindFailure:true); +#endif // MONO_FEATURE_BTLS #endif // SECURITY_DEP getDefaultProxy = (Func)Delegate.CreateDelegate ( typeof (Func), t, "GetDefaultProxy", @@ -92,6 +96,7 @@ namespace System { return trustEvaluateSsl (certsRawData); } +#if MONO_FEATURE_BTLS internal static MonoBtlsX509 CertStoreLookup (MonoBtlsX509Name name) { var hash = name.GetHash (); @@ -109,6 +114,7 @@ namespace System { return MonoBtlsX509.LoadFromData (result, MonoBtlsX509Format.DER); } +#endif // MONO_FEATURE_BTLS #endif // SECURITY_DEP internal static IWebProxy GetDefaultProxy () diff --git a/mcs/class/System/System_test.dll.sources b/mcs/class/System/System_test.dll.sources index 6ec32758faf..24351699070 100644 --- a/mcs/class/System/System_test.dll.sources +++ b/mcs/class/System/System_test.dll.sources @@ -1,3 +1,4 @@ +../../test-helpers/NunitHelpers.cs Microsoft.CSharp/CodeGeneratorFromCompileUnitTest.cs Microsoft.CSharp/CodeGeneratorFromExpressionTest.cs Microsoft.CSharp/CodeGeneratorFromNamespaceTest.cs diff --git a/mcs/class/System/Test/System.CodeDom.Compiler/CodeGeneratorGenerateFromCompileUnitTest.cs b/mcs/class/System/Test/System.CodeDom.Compiler/CodeGeneratorGenerateFromCompileUnitTest.cs index c6ccdf0a26a..823204cf486 100644 --- a/mcs/class/System/Test/System.CodeDom.Compiler/CodeGeneratorGenerateFromCompileUnitTest.cs +++ b/mcs/class/System/Test/System.CodeDom.Compiler/CodeGeneratorGenerateFromCompileUnitTest.cs @@ -53,7 +53,7 @@ namespace MonoTests.System.CodeDom.Compiler int importPosition = result.IndexOf (IMPORT); int attributePosition = result.IndexOf (ATTRIBUTE); - Assert.Greater (attributePosition, importPosition, "Actual order: " + result); + AssertHelper.Greater (attributePosition, importPosition, "Actual order: " + result); } [Test] diff --git a/mcs/class/System/Test/System.Collections.Generic/SortedListTest.cs b/mcs/class/System/Test/System.Collections.Generic/SortedListTest.cs index b6baac08e85..6586c4c092f 100644 --- a/mcs/class/System/Test/System.Collections.Generic/SortedListTest.cs +++ b/mcs/class/System/Test/System.Collections.Generic/SortedListTest.cs @@ -38,9 +38,6 @@ using System.Text; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using NUnit.Framework; -#if !MOBILE -using NUnit.Framework.SyntaxHelpers; -#endif namespace MonoTests.System.Collections.Generic { diff --git a/mcs/class/System/Test/System.Diagnostics/SourceSwitchTest.cs b/mcs/class/System/Test/System.Diagnostics/SourceSwitchTest.cs index 820e84d2a89..07195bb9246 100644 --- a/mcs/class/System/Test/System.Diagnostics/SourceSwitchTest.cs +++ b/mcs/class/System/Test/System.Diagnostics/SourceSwitchTest.cs @@ -53,7 +53,7 @@ namespace MonoTests.System.Diagnostics public void ConstructorNullName () { SourceSwitch s = new SourceSwitch (null); - Assert.IsEmpty (s.DisplayName); + AssertHelper.IsEmpty (s.DisplayName); } [Test] diff --git a/mcs/class/System/Test/System.Diagnostics/SwitchesTest.cs b/mcs/class/System/Test/System.Diagnostics/SwitchesTest.cs index 9d97fc8b53c..d8821a00c2d 100644 --- a/mcs/class/System/Test/System.Diagnostics/SwitchesTest.cs +++ b/mcs/class/System/Test/System.Diagnostics/SwitchesTest.cs @@ -190,8 +190,8 @@ namespace MonoTests.System.Diagnostics { public void NullSwitchHasEmptyDisplayNameAndDescription () { var s = new TestNullSwitch (); - Assert.IsEmpty (s.DisplayName); - Assert.IsEmpty (s.Description); + AssertHelper.IsEmpty (s.DisplayName); + AssertHelper.IsEmpty (s.Description); } } } diff --git a/mcs/class/System/Test/System.IO.Compression/DeflateStreamTest.cs b/mcs/class/System/Test/System.IO.Compression/DeflateStreamTest.cs index 0fe01aaf102..1aa78a9d993 100644 --- a/mcs/class/System/Test/System.IO.Compression/DeflateStreamTest.cs +++ b/mcs/class/System/Test/System.IO.Compression/DeflateStreamTest.cs @@ -410,6 +410,46 @@ namespace MonoTests.System.IO.Compression using (var unZippedStream = new StreamReader (gZipStream, Encoding.UTF8)) { unZipped = unZippedStream.ReadToEnd (); } + + Assert.AreEqual(1877, unZipped.Length); + } + + [Test] + public void Bug44994_Inflate() + { + var base64String = @"7cWxCQAgDACwpeBjgqsgXiHU0fd9QzBLErX1EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADepcxcuU/atm3btm3btm3btm3btm3btm3btm3btm3btm3btm3btm3btm3btm3btm3btm3btm3btm3btm3btm3btm3btm3btm3btm3btm3btm3btm3btm3btm3btm3btm37zy8="; + + byte[] byteArray = Convert.FromBase64String(base64String); + string unZipped = null; + + using (var zippedMemoryStream = new MemoryStream(byteArray)) + using (var gZipStream = new DeflateStream(zippedMemoryStream, CompressionMode.Decompress)) + using (var unzippedMemStream = new MemoryStream()) + using (var unZippedStream = new StreamReader(gZipStream, Encoding.UTF8)) + { + unZipped = unZippedStream.ReadToEnd(); + } + + Assert.AreEqual(81942, unZipped.Length); + } + + [Test] + [Category ("MobileNotWorking")] + public void Bug44994_InflateByteByByte() + { + int byteCount = 0; + using (var fileStream = File.OpenRead(Path.Combine("Test", "compressed.bin"))) + { + using (var deflateStream = new DeflateStream(fileStream, CompressionMode.Decompress, false)) + { + while (deflateStream.ReadByte() != -1) + { + byteCount++; + } + } + } + + Assert.AreEqual(125387, byteCount); } } } diff --git a/mcs/class/System/Test/System.Net/NetworkCredentialTest.cs b/mcs/class/System/Test/System.Net/NetworkCredentialTest.cs index dbe3255cd68..e5c46f8f901 100644 --- a/mcs/class/System/Test/System.Net/NetworkCredentialTest.cs +++ b/mcs/class/System/Test/System.Net/NetworkCredentialTest.cs @@ -28,6 +28,7 @@ using System; using System.Net; +using System.Security; using NUnit.Framework; @@ -99,6 +100,21 @@ namespace MonoTests.System.Net { nc = new NetworkCredential ("user", "********", "dom"); CheckCustom (nc); } + + [Test] + public void DecipherSecureString () + { + // many code snippets suggest using the following to get the decrypted string from a SecureString + var ss = new SecureString (); + ss.AppendChar('h'); + ss.AppendChar('e'); + ss.AppendChar('l'); + ss.AppendChar('l'); + ss.AppendChar('o'); + + string plain = new NetworkCredential (string.Empty, ss).Password; + Assert.AreEqual ("hello", plain); + } } } diff --git a/mcs/class/System/Test/System.Security.Cryptography.X509Certificates/PkitsTest.cs b/mcs/class/System/Test/System.Security.Cryptography.X509Certificates/PkitsTest.cs index 5da8a5d59c7..5f6daa28b60 100644 --- a/mcs/class/System/Test/System.Security.Cryptography.X509Certificates/PkitsTest.cs +++ b/mcs/class/System/Test/System.Security.Cryptography.X509Certificates/PkitsTest.cs @@ -37,6 +37,7 @@ using System.IO; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; +using System.Reflection; namespace MonoTests.System.Security.Cryptography.X509Certificates { @@ -64,7 +65,7 @@ namespace MonoTests.System.Security.Cryptography.X509Certificates { public void FixtureSetUp () { base_dir = String.Format ("{0}{1}Test{1}System.Security.Cryptography.X509Certificates{1}pkits{1}certs", - Directory.GetCurrentDirectory (), Path.DirectorySeparatorChar); + Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location), Path.DirectorySeparatorChar); if (!Directory.Exists (base_dir)) Assert.Ignore ("PKITS tests data not found under '{0}'.", new object[] { base_dir }); @@ -75,7 +76,8 @@ namespace MonoTests.System.Security.Cryptography.X509Certificates { [TestFixtureTearDown] public void FixtureTearDown () { - cache.Clear (); + if (cache != null) + cache.Clear (); // clean-up, as best as possible, the stores } diff --git a/mcs/class/System/Test/compressed.bin b/mcs/class/System/Test/compressed.bin new file mode 100644 index 00000000000..3098195f875 Binary files /dev/null and b/mcs/class/System/Test/compressed.bin differ diff --git a/mcs/class/System/Test/test-config-file b/mcs/class/System/Test/test-config-file index d2eea338663..69d28f6df91 100644 --- a/mcs/class/System/Test/test-config-file +++ b/mcs/class/System/Test/test-config-file @@ -1,5 +1,3 @@ - - @@ -22,5 +20,4 @@ - diff --git a/mcs/class/System/Test/test-config-file-net-2.0 b/mcs/class/System/Test/test-config-file-net-2.0 deleted file mode 100644 index 03940481236..00000000000 --- a/mcs/class/System/Test/test-config-file-net-2.0 +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mcs/class/System/mobile_System.dll.sources b/mcs/class/System/mobile_System.dll.sources index 830e8c0db7e..1351778bb86 100644 --- a/mcs/class/System/mobile_System.dll.sources +++ b/mcs/class/System/mobile_System.dll.sources @@ -166,7 +166,6 @@ System.Net/ListenerPrefix.cs System.Net/MacProxy.cs System.Net/MonoHttpDate.cs System.Net/NetConfig.cs -System.Net/NetworkCredential.cs System.Net/NtlmClient.cs System.Net/RequestStream.cs System.Net/ResponseStream.cs @@ -305,7 +304,6 @@ Mono.Btls/MonoBtlsX509LookupMonoCollection.cs Mono.Btls/MonoBtlsX509LookupMono.cs Mono.Btls/MonoBtlsX509LookupType.cs Mono.Btls/MonoBtlsX509Name.cs -Mono.Btls/MonoBtlsX509NameList.cs Mono.Btls/MonoBtlsX509NameEntryType.cs Mono.Btls/MonoBtlsX509Purpose.cs Mono.Btls/MonoBtlsX509Revoked.cs @@ -330,6 +328,7 @@ ReferenceSources/Logging.cs ReferenceSources/NativeMethods.cs ReferenceSources/RequestCacheProtocol.cs ReferenceSources/SettingsSectionInternal.cs +ReferenceSources/SecureStringHelper.cs ReferenceSources/Socket.cs ReferenceSources/SR.cs ReferenceSources/SRCategoryAttribute.cs @@ -757,6 +756,7 @@ ReferenceSources/Win32Exception.cs ../referencesource/System/net/System/Net/IWebProxyFinder.cs ../referencesource/System/net/System/Net/IWebRequestCreate.cs ../referencesource/System/net/System/Net/NetworkAccess.cs +../referencesource/System/net/System/Net/NetworkCredential.cs ../referencesource/System/net/System/Net/ProtocolViolationException.cs ../referencesource/System/net/System/Net/TransportContext.cs ../referencesource/System/net/System/Net/TransportType.cs diff --git a/mcs/class/WebMatrix.Data/WebMatrix.Data_test.dll.sources b/mcs/class/WebMatrix.Data/WebMatrix.Data_test.dll.sources index 927528aa296..0d885863e40 100644 --- a/mcs/class/WebMatrix.Data/WebMatrix.Data_test.dll.sources +++ b/mcs/class/WebMatrix.Data/WebMatrix.Data_test.dll.sources @@ -1,3 +1,4 @@ +../../test-helpers/NunitHelpers.cs WebMatrix.Data/ConnectionEventArgsTests.cs WebMatrix.Data/DynamicRecordTests.cs ../WebMatrix.Data/DynamicRecord.cs diff --git a/mcs/class/WindowsBase/WindowsBase_test.dll.sources b/mcs/class/WindowsBase/WindowsBase_test.dll.sources index 64a199a988f..620b1628eb8 100644 --- a/mcs/class/WindowsBase/WindowsBase_test.dll.sources +++ b/mcs/class/WindowsBase/WindowsBase_test.dll.sources @@ -1,3 +1,4 @@ +../../test-helpers/NunitHelpers.cs System.Collections.ObjectModel/ObservableCollectionTest.cs System.Collections.ObjectModel/ReadOnlyObservableCollectionTest.cs System.Collections.Specialized/NotifyCollectionChangedEventArgsTest.cs diff --git a/mcs/class/corlib/ReferenceSources/SharedStatics.cs b/mcs/class/corlib/ReferenceSources/SharedStatics.cs deleted file mode 100644 index 01252ccc2f1..00000000000 --- a/mcs/class/corlib/ReferenceSources/SharedStatics.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Threading; -using StringMaker = System.Security.Util.Tokenizer.StringMaker; - -namespace System -{ - static class SharedStatics - { - static StringMaker shared; - static public StringMaker GetSharedStringMaker () - { - if (shared == null) - Interlocked.CompareExchange (ref shared, new StringMaker (), null); - - return shared; - } - - static public void ReleaseSharedStringMaker (ref StringMaker maker) - { - - } - } -} \ No newline at end of file diff --git a/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs b/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs index 30ff8b74bce..1516216ddc2 100644 --- a/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs +++ b/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs @@ -75,6 +75,13 @@ namespace System.Runtime.InteropServices return false; } + [MonoTODO] + public static void CleanupUnusedObjectsInCurrentContext () + { + if (Environment.IsRunningOnWindows) + throw new PlatformNotSupportedException (); + } + [MethodImplAttribute(MethodImplOptions.InternalCall)] public extern static IntPtr AllocCoTaskMem (int cb); @@ -789,15 +796,8 @@ namespace System.Runtime.InteropServices [MethodImplAttribute(MethodImplOptions.InternalCall)] public extern static string PtrToStringUni (IntPtr ptr, int len); -#if !MOBILE [MethodImplAttribute(MethodImplOptions.InternalCall)] public extern static string PtrToStringBSTR (IntPtr ptr); -#else - public static string PtrToStringBSTR (IntPtr ptr) - { - throw new NotImplementedException (); - } -#endif [MethodImplAttribute(MethodImplOptions.InternalCall)] [ComVisible (true)] diff --git a/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs b/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs index e74123e7611..4f20771c40a 100644 --- a/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs +++ b/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs @@ -416,6 +416,15 @@ public partial class CryptoConfig { unresolved_algorithms.Add (nameECDsa_2, defaultECDsa); unresolved_algorithms.Add (nameECDsa_3, defaultECDsa); +#if MONODROID + algorithms.Add (nameSHA1Cng, defaultSHA1); + algorithms.Add (nameSHA256Cng, defaultSHA256); + algorithms.Add (nameSHA256Provider, defaultSHA256); + algorithms.Add (nameSHA384Cng, defaultSHA384); + algorithms.Add (nameSHA384Provider, defaultSHA384); + algorithms.Add (nameSHA512Cng, defaultSHA512); + algorithms.Add (nameSHA512Provider, defaultSHA512); +#else unresolved_algorithms.Add (nameSHA1Cng, defaultSHA1Cng); unresolved_algorithms.Add (nameSHA256Cng, defaultSHA256Cng); unresolved_algorithms.Add (nameSHA256Provider, defaultSHA256Provider); @@ -423,6 +432,7 @@ public partial class CryptoConfig { unresolved_algorithms.Add (nameSHA384Provider, defaultSHA384Provider); unresolved_algorithms.Add (nameSHA512Cng, defaultSHA512Cng); unresolved_algorithms.Add (nameSHA512Provider, defaultSHA512Provider); +#endif Dictionary oid = new Dictionary (StringComparer.OrdinalIgnoreCase); // comments here are to match with MS implementation (but not with doc) diff --git a/mcs/class/corlib/System.Threading/Thread.cs b/mcs/class/corlib/System.Threading/Thread.cs index 2e19104a39d..24ada26034c 100644 --- a/mcs/class/corlib/System.Threading/Thread.cs +++ b/mcs/class/corlib/System.Threading/Thread.cs @@ -49,7 +49,8 @@ namespace System.Threading { #region Sync with metadata/object-internals.h int lock_thread_id; // stores a thread handle - internal IntPtr system_thread_handle; + IntPtr handle; + IntPtr native_handle; // used only on Win32 /* Note this is an opaque object (an array), not a CultureInfo */ private object cached_culture_info; @@ -92,6 +93,7 @@ namespace System.Threading { private IntPtr abort_protected_block_count; private int priority = (int) ThreadPriority.Normal; private IntPtr owned_mutex; + private IntPtr suspended_event; /* * These fields are used to avoid having to increment corlib versions * when a new field is added to the unmanaged MonoThread structure. @@ -109,11 +111,11 @@ namespace System.Threading { // Closes the system thread handle [MethodImplAttribute(MethodImplOptions.InternalCall)] - private extern void Thread_free_internal(IntPtr handle); + private extern void Thread_free_internal(); [ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)] ~InternalThread() { - Thread_free_internal(system_thread_handle); + Thread_free_internal(); } } diff --git a/mcs/class/corlib/System/Environment.cs b/mcs/class/corlib/System/Environment.cs index 13e99d04b9a..91e76352ddc 100644 --- a/mcs/class/corlib/System/Environment.cs +++ b/mcs/class/corlib/System/Environment.cs @@ -57,7 +57,7 @@ namespace System { * of icalls, do not require an increment. */ #pragma warning disable 169 - private const int mono_corlib_version = 160; + private const int mono_corlib_version = 162; #pragma warning restore 169 [ComVisible (true)] diff --git a/mcs/class/corlib/Test/Mono/DataConvertTest.cs b/mcs/class/corlib/Test/Mono/DataConvertTest.cs index f02a6a7db40..4ac94d59e1f 100644 --- a/mcs/class/corlib/Test/Mono/DataConvertTest.cs +++ b/mcs/class/corlib/Test/Mono/DataConvertTest.cs @@ -4,10 +4,6 @@ using System.Text; using NUnit.Framework; using Mono; -#if !MOBILE -using NUnit.Framework.SyntaxHelpers; -#endif - namespace MonoTests.Mono { [TestFixture] diff --git a/mcs/class/corlib/Test/System.Collections.Concurrent/ConcurrentDictionaryTests.cs b/mcs/class/corlib/Test/System.Collections.Concurrent/ConcurrentDictionaryTests.cs index 70c250d015d..75b2de89aac 100644 --- a/mcs/class/corlib/Test/System.Collections.Concurrent/ConcurrentDictionaryTests.cs +++ b/mcs/class/corlib/Test/System.Collections.Concurrent/ConcurrentDictionaryTests.cs @@ -32,9 +32,6 @@ using System.Collections.Concurrent; using NUnit; using NUnit.Framework; -#if !MOBILE -using NUnit.Framework.SyntaxHelpers; -#endif namespace MonoTests.System.Collections.Concurrent { diff --git a/mcs/class/corlib/Test/System.Collections.Concurrent/PartitionerTests.cs b/mcs/class/corlib/Test/System.Collections.Concurrent/PartitionerTests.cs index 9cd2d1e1113..4bf774937d5 100644 --- a/mcs/class/corlib/Test/System.Collections.Concurrent/PartitionerTests.cs +++ b/mcs/class/corlib/Test/System.Collections.Concurrent/PartitionerTests.cs @@ -30,9 +30,6 @@ using System.Collections.Generic; using System.Collections.Concurrent; using NUnit.Framework; -#if !MOBILE -using NUnit.Framework.SyntaxHelpers; -#endif namespace MonoTests.System.Collections.Concurrent { diff --git a/mcs/class/corlib/Test/System.IO.IsolatedStorage/IsolatedStorageFileStreamTest.cs b/mcs/class/corlib/Test/System.IO.IsolatedStorage/IsolatedStorageFileStreamTest.cs index 3ec70c82c26..a343cbe58b5 100644 --- a/mcs/class/corlib/Test/System.IO.IsolatedStorage/IsolatedStorageFileStreamTest.cs +++ b/mcs/class/corlib/Test/System.IO.IsolatedStorage/IsolatedStorageFileStreamTest.cs @@ -68,8 +68,9 @@ namespace MonoTests.System.IO.IsolatedStorageTest { public void Constructor_StringMode () { string test = "string-filemode"; - IsolatedStorageFileStream isfs = new IsolatedStorageFileStream (test, FileMode.Create); - CheckCommonDetails (test, isfs, true, true); + using (var isfs = new IsolatedStorageFileStream (test, FileMode.Create)) { + CheckCommonDetails (test, isfs, true, true); + } } [Test] @@ -83,8 +84,9 @@ namespace MonoTests.System.IO.IsolatedStorageTest { public void Constructor_StringModeAccess () { string test = "string-filemode-fileaccess"; - IsolatedStorageFileStream isfs = new IsolatedStorageFileStream (test, FileMode.Create, FileAccess.ReadWrite); - CheckCommonDetails (test, isfs, true, true); + using (var isfs = new IsolatedStorageFileStream (test, FileMode.Create, FileAccess.ReadWrite)) { + CheckCommonDetails (test, isfs, true, true); + } } [Test] @@ -98,22 +100,24 @@ namespace MonoTests.System.IO.IsolatedStorageTest { public void Constructor_StringModeAccessShare () { string test = "string-filemode-fileaccess-fileshare"; - IsolatedStorageFileStream isfs = new IsolatedStorageFileStream (test, FileMode.Create, FileAccess.Write, FileShare.Read); - CheckCommonDetails (test, isfs, false, true); + using (var isfs = new IsolatedStorageFileStream (test, FileMode.Create, FileAccess.Write, FileShare.Read)) { + CheckCommonDetails (test, isfs, false, true); + } } [Test] [ExpectedException (typeof (IsolatedStorageException))] public void Handle () { - IsolatedStorageFileStream isfs = new IsolatedStorageFileStream ("handle", FileMode.Create); - IntPtr p = isfs.Handle; + using (var isfs = new IsolatedStorageFileStream ("handle", FileMode.Create)) { + IntPtr p = isfs.Handle; + } } [Test] public void RootPath () { - new IsolatedStorageFileStream ("/rootpath", FileMode.Create); + new IsolatedStorageFileStream ("/rootpath", FileMode.Create).Close (); } [Test] diff --git a/mcs/class/corlib/Test/System.Runtime.CompilerServices/TaskAwaiterTest.cs b/mcs/class/corlib/Test/System.Runtime.CompilerServices/TaskAwaiterTest.cs index c9d7aca855b..6a6ecc0b36d 100644 --- a/mcs/class/corlib/Test/System.Runtime.CompilerServices/TaskAwaiterTest.cs +++ b/mcs/class/corlib/Test/System.Runtime.CompilerServices/TaskAwaiterTest.cs @@ -247,8 +247,8 @@ namespace MonoTests.System.Runtime.CompilerServices return res.Result; } -#if !MOBILE_STATIC [Test] + [Ignore ("Incompatible with nunitlite")] public void FinishedTaskOnCompleted () { var mres = new ManualResetEvent (false); @@ -268,12 +268,10 @@ namespace MonoTests.System.Runtime.CompilerServices mres.Set (); // this will only terminate correctly if the test was not executed from the main thread - // e.g. Touch.Unit defaults to run tests on the main thread and this will return false + // e.g. nunitlite/Touch.Unit defaults to run tests on the main thread and this will return false Assert.AreEqual (Thread.CurrentThread.IsBackground, mres2.WaitOne (2000), "#2");; } -#endif - [Test] public void CompletionOnSameCustomSynchronizationContext () { diff --git a/mcs/class/corlib/Test/System.Runtime.InteropServices/MarshalTest.cs b/mcs/class/corlib/Test/System.Runtime.InteropServices/MarshalTest.cs index 18f58415a1b..51f1797a2b8 100644 --- a/mcs/class/corlib/Test/System.Runtime.InteropServices/MarshalTest.cs +++ b/mcs/class/corlib/Test/System.Runtime.InteropServices/MarshalTest.cs @@ -416,7 +416,6 @@ namespace MonoTests.System.Runtime.InteropServices } [Test] - [Category ("MobileNotWorking")] public void BSTR_Roundtrip () { string s = "mono"; @@ -426,7 +425,6 @@ namespace MonoTests.System.Runtime.InteropServices } [Test] - [Category ("MobileNotWorking")] public void StringToBSTRWithNullValues () { int size = 128; @@ -871,6 +869,7 @@ namespace MonoTests.System.Runtime.InteropServices ); #endif +#if !MOBILE_STATIC [StructLayout( LayoutKind.Sequential, Pack = 1 )] public class FourByteStruct { @@ -1015,6 +1014,7 @@ namespace MonoTests.System.Runtime.InteropServices return objResult; } +#endif } #if !MOBILE [ComImport()] diff --git a/mcs/class/corlib/Test/System.Security.AccessControl/RawSecurityDescriptorTest.cs b/mcs/class/corlib/Test/System.Security.AccessControl/RawSecurityDescriptorTest.cs index bf93320e26b..7a0e837cacf 100644 --- a/mcs/class/corlib/Test/System.Security.AccessControl/RawSecurityDescriptorTest.cs +++ b/mcs/class/corlib/Test/System.Security.AccessControl/RawSecurityDescriptorTest.cs @@ -9,7 +9,6 @@ using System; using System.Security.AccessControl; using System.Security.Principal; using NUnit.Framework; -using NUnit.Framework.SyntaxHelpers; namespace MonoTests.System.Security.AccessControl { diff --git a/mcs/class/corlib/Test/System.Security.Cryptography/SignatureDescriptionTest.cs b/mcs/class/corlib/Test/System.Security.Cryptography/SignatureDescriptionTest.cs index 44830498971..46fbe94a6d7 100644 --- a/mcs/class/corlib/Test/System.Security.Cryptography/SignatureDescriptionTest.cs +++ b/mcs/class/corlib/Test/System.Security.Cryptography/SignatureDescriptionTest.cs @@ -310,7 +310,7 @@ public class SignatureDescriptionTest { public void RSASignatureDescription () { // TODO: this would be cleaner with NUnit TestCase'es but they're NUnit 2.5+ :( -#if FULL_AOT_RUNTIME || MONOTOUCH +#if FULL_AOT_RUNTIME || MONOTOUCH || MONODROID RSASignatureDescriptionCore ("http://www.w3.org/2000/09/xmldsig#rsa-sha1", "System.Security.Cryptography.SHA1Cng", "System.Security.Cryptography.SHA1CryptoServiceProvider"); RSASignatureDescriptionCore ("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", "System.Security.Cryptography.SHA256Cng", "System.Security.Cryptography.SHA256Managed"); RSASignatureDescriptionCore ("http://www.w3.org/2001/04/xmldsig-more#rsa-sha384", "System.Security.Cryptography.SHA384Cng", "System.Security.Cryptography.SHA384Managed"); @@ -345,4 +345,4 @@ public class SignatureDescriptionTest { } } -} \ No newline at end of file +} diff --git a/mcs/class/corlib/Test/System.Text/ASCIIEncodingTest.cs b/mcs/class/corlib/Test/System.Text/ASCIIEncodingTest.cs index f35a9d38830..ea6380d0977 100644 --- a/mcs/class/corlib/Test/System.Text/ASCIIEncodingTest.cs +++ b/mcs/class/corlib/Test/System.Text/ASCIIEncodingTest.cs @@ -10,10 +10,6 @@ using System.Text; using NUnit.Framework; using NUnit.Framework.Constraints; -#if !MOBILE -using NUnit.Framework.SyntaxHelpers; -#endif - namespace MonoTests.System.Text { [TestFixture] diff --git a/mcs/class/corlib/Test/System.Text/Latin1EncodingTest.cs b/mcs/class/corlib/Test/System.Text/Latin1EncodingTest.cs index 0195967cd36..c96da97d9c1 100644 --- a/mcs/class/corlib/Test/System.Text/Latin1EncodingTest.cs +++ b/mcs/class/corlib/Test/System.Text/Latin1EncodingTest.cs @@ -32,10 +32,6 @@ using System.Text; using NUnit.Framework; using NUnit.Framework.Constraints; -#if !MOBILE -using NUnit.Framework.SyntaxHelpers; -#endif - namespace MonoTests.System.Text { [TestFixture] diff --git a/mcs/class/corlib/Test/System.Text/UTF8EncodingTest.cs b/mcs/class/corlib/Test/System.Text/UTF8EncodingTest.cs index 474abcd2208..12de999dc5b 100644 --- a/mcs/class/corlib/Test/System.Text/UTF8EncodingTest.cs +++ b/mcs/class/corlib/Test/System.Text/UTF8EncodingTest.cs @@ -11,6 +11,7 @@ using NUnit.Framework; using System; +using System.Reflection; using System.IO; using System.Text; @@ -1042,7 +1043,7 @@ namespace MonoTests.System.Text [Category ("MobileNotWorking")] public void Bug415628 () { - using (var f = File.Open ("Test/resources/415628.bin", FileMode.Open)) { + using (var f = File.Open (Path.Combine (Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location), "Test/resources/415628.bin"), FileMode.Open)) { BinaryReader br = new BinaryReader (f); byte [] buf = br.ReadBytes (8000); Encoding.UTF8.GetString(buf); diff --git a/mcs/class/corlib/Test/System.Threading.Tasks/TaskCompletionSourceTests.cs b/mcs/class/corlib/Test/System.Threading.Tasks/TaskCompletionSourceTests.cs index 903a6946a08..94f191a121a 100644 --- a/mcs/class/corlib/Test/System.Threading.Tasks/TaskCompletionSourceTests.cs +++ b/mcs/class/corlib/Test/System.Threading.Tasks/TaskCompletionSourceTests.cs @@ -30,9 +30,6 @@ using System.Threading; using System.Threading.Tasks; using NUnit.Framework; -#if !MOBILE -using NUnit.Framework.SyntaxHelpers; -#endif namespace MonoTests.System.Threading.Tasks { diff --git a/mcs/class/corlib/Test/System.Threading.Tasks/TaskFactoryTest.cs b/mcs/class/corlib/Test/System.Threading.Tasks/TaskFactoryTest.cs index 94d36a131e5..1af618d3336 100644 --- a/mcs/class/corlib/Test/System.Threading.Tasks/TaskFactoryTest.cs +++ b/mcs/class/corlib/Test/System.Threading.Tasks/TaskFactoryTest.cs @@ -35,9 +35,6 @@ using System.Threading.Tasks; using System.Collections.Generic; using NUnit.Framework; -#if !MOBILE -using NUnit.Framework.SyntaxHelpers; -#endif namespace MonoTests.System.Threading.Tasks { diff --git a/mcs/class/corlib/Test/System.Threading.Tasks/TaskFactoryTest_T.cs b/mcs/class/corlib/Test/System.Threading.Tasks/TaskFactoryTest_T.cs index 0ca7f49f474..803b10c15eb 100644 --- a/mcs/class/corlib/Test/System.Threading.Tasks/TaskFactoryTest_T.cs +++ b/mcs/class/corlib/Test/System.Threading.Tasks/TaskFactoryTest_T.cs @@ -32,9 +32,6 @@ using System.Threading; using System.Threading.Tasks; using NUnit.Framework; -#if !MOBILE -using NUnit.Framework.SyntaxHelpers; -#endif namespace MonoTests.System.Threading.Tasks { diff --git a/mcs/class/corlib/Test/System.Threading.Tasks/TaskSchedulerTest.cs b/mcs/class/corlib/Test/System.Threading.Tasks/TaskSchedulerTest.cs index e8130bc06fd..001f4d454cd 100644 --- a/mcs/class/corlib/Test/System.Threading.Tasks/TaskSchedulerTest.cs +++ b/mcs/class/corlib/Test/System.Threading.Tasks/TaskSchedulerTest.cs @@ -29,9 +29,6 @@ using System.Threading.Tasks; using System.Collections.Generic; using NUnit.Framework; -#if !MOBILE -using NUnit.Framework.SyntaxHelpers; -#endif namespace MonoTests.System.Threading.Tasks { diff --git a/mcs/class/corlib/Test/System.Threading.Tasks/TaskTest.cs b/mcs/class/corlib/Test/System.Threading.Tasks/TaskTest.cs index f4e8a9705f7..07bd1fe0b56 100644 --- a/mcs/class/corlib/Test/System.Threading.Tasks/TaskTest.cs +++ b/mcs/class/corlib/Test/System.Threading.Tasks/TaskTest.cs @@ -34,10 +34,6 @@ using System.Threading.Tasks; using System.Collections.Generic; using NUnit.Framework; -#if !MOBILE -using NUnit.Framework.SyntaxHelpers; -#endif - namespace MonoTests.System.Threading.Tasks { [TestFixture] diff --git a/mcs/class/corlib/Test/System.Threading/ThreadLocalTests.cs b/mcs/class/corlib/Test/System.Threading/ThreadLocalTests.cs index 8c063dccdc8..b65d150bb58 100644 --- a/mcs/class/corlib/Test/System.Threading/ThreadLocalTests.cs +++ b/mcs/class/corlib/Test/System.Threading/ThreadLocalTests.cs @@ -29,9 +29,6 @@ using System.Threading; using NUnit; using NUnit.Framework; -#if !MOBILE -using NUnit.Framework.SyntaxHelpers; -#endif namespace MonoTests.System.Threading { diff --git a/mcs/class/corlib/Test/System/SingleTest.cs b/mcs/class/corlib/Test/System/SingleTest.cs index bf3beb47200..c4d0bd82fc9 100644 --- a/mcs/class/corlib/Test/System/SingleTest.cs +++ b/mcs/class/corlib/Test/System/SingleTest.cs @@ -15,10 +15,6 @@ using System.Threading; using NUnit.Framework; -#if !MOBILE -using NUnit.Framework.SyntaxHelpers; -#endif - namespace MonoTests.System { [TestFixture] diff --git a/mcs/class/corlib/Test/System/TypeTest.cs b/mcs/class/corlib/Test/System/TypeTest.cs index d70e5fdde70..4ea4f283bce 100644 --- a/mcs/class/corlib/Test/System/TypeTest.cs +++ b/mcs/class/corlib/Test/System/TypeTest.cs @@ -4197,6 +4197,17 @@ namespace MonoTests.System MustTLE (string.Format ("{0}ZZZZ,{1}", typeof (MyRealEnum).FullName, aqn)); } + [Test] + public void GetTypeExceptionMsg () { + string typeName = "system.int32, foo"; + try { + Type.GetType(typeName, true, false); + } catch (TypeLoadException ex) { + Assert.IsTrue (ex.Message.Contains ("system.int32")); + Assert.IsTrue (ex.Message.Contains ("foo")); + } + } + delegate void MyAction(T ag); [Test] //bug #668506 @@ -4324,6 +4335,24 @@ namespace MonoTests.System } #endif + + [Test] + public void GetTypeBadArity() + { + // Regression test for #46250 + try { + Type.GetType ("System.Collections.Generic.Dictionary`2[System.String]", true); + Assert.Fail ("Did not throw an exception (#1)"); + } catch (ArgumentException) { + } + + try { + Type.GetType ("System.Collections.Generic.Dictionary`2[System.String,System.Int32,System.Int64]", true); + Assert.Fail ("Did not throw an exception (#2)"); + } catch (ArgumentException) { + } + } + public abstract class Stream : IDisposable { public void Dispose () diff --git a/mcs/class/corlib/corlib-net_4_x.csproj b/mcs/class/corlib/corlib-net_4_x.csproj index 9ab59b31503..5b3d72dee38 100644 --- a/mcs/class/corlib/corlib-net_4_x.csproj +++ b/mcs/class/corlib/corlib-net_4_x.csproj @@ -690,6 +690,7 @@ + @@ -866,7 +867,6 @@ - diff --git a/mcs/class/corlib/corlib.dll.sources b/mcs/class/corlib/corlib.dll.sources index f8107e8c342..371d01ba4c1 100644 --- a/mcs/class/corlib/corlib.dll.sources +++ b/mcs/class/corlib/corlib.dll.sources @@ -896,7 +896,6 @@ ReferenceSources/CompareInfo.cs ReferenceSources/Buffer.cs ReferenceSources/TextInfo.cs ReferenceSources/win32native.cs -ReferenceSources/SharedStatics.cs ReferenceSources/SecurityContext.cs ReferenceSources/PathInternal.cs ReferenceSources/BinaryCompatibility.cs @@ -1024,6 +1023,7 @@ ReferenceSources/Type.cs ../referencesource/mscorlib/system/rttype.cs ../referencesource/mscorlib/system/sbyte.cs ../referencesource/mscorlib/system/serializableattribute.cs +../referencesource/mscorlib/system/sharedstatics.cs ../referencesource/mscorlib/system/stackoverflowexception.cs ../referencesource/mscorlib/system/single.cs ../referencesource/mscorlib/system/string.cs diff --git a/mcs/class/corlib/corlib_test.dll.sources b/mcs/class/corlib/corlib_test.dll.sources index bc43d92b920..4e444a37efa 100644 --- a/mcs/class/corlib/corlib_test.dll.sources +++ b/mcs/class/corlib/corlib_test.dll.sources @@ -1,3 +1,4 @@ +../../test-helpers/NunitHelpers.cs Microsoft.Win32/RegistryKeyTest.cs Mono/DataConvertTest.cs ../Mono/DataConverter.cs diff --git a/mcs/class/monodoc/Test/Monodoc.Generators/RawGeneratorTests.cs b/mcs/class/monodoc/Test/Monodoc.Generators/RawGeneratorTests.cs index 9af81920a16..fa3ffe15ac5 100644 --- a/mcs/class/monodoc/Test/Monodoc.Generators/RawGeneratorTests.cs +++ b/mcs/class/monodoc/Test/Monodoc.Generators/RawGeneratorTests.cs @@ -47,7 +47,7 @@ namespace MonoTests.Monodoc.Generators { var xml = rootTree.RenderUrl ("T:System.String", generator); Assert.IsNotNull (xml); - Assert.IsNotEmpty (xml); + AssertHelper.IsNotEmpty (xml); AssertValidXml (xml); AssertEcmaFullTypeName (xml, "System.String"); } @@ -57,7 +57,7 @@ namespace MonoTests.Monodoc.Generators { var xml = rootTree.RenderUrl ("T:System.Int32", generator); Assert.IsNotNull (xml); - Assert.IsNotEmpty (xml); + AssertHelper.IsNotEmpty (xml); AssertValidXml (xml); AssertEcmaFullTypeName (xml, "System.Int32"); } diff --git a/mcs/class/monodoc/Test/Monodoc/HelpSourceTests.cs b/mcs/class/monodoc/Test/Monodoc/HelpSourceTests.cs index 867c9b79389..29da7513704 100644 --- a/mcs/class/monodoc/Test/Monodoc/HelpSourceTests.cs +++ b/mcs/class/monodoc/Test/Monodoc/HelpSourceTests.cs @@ -85,7 +85,7 @@ namespace MonoTests.Monodoc // HACK: in reality we have currently 4 known issues which are due to duplicated namespaces across // doc sources, something that was never supported and that we need to improve/fix at some stage - Assert.LessOrEqual (4, errorCount, errorCount + " / " + testCount.ToString ()); + AssertHelper.LessOrEqual (4, errorCount, errorCount + " / " + testCount.ToString ()); } IEnumerable GetLeaves (Node node) diff --git a/mcs/class/monodoc/Test/Monodoc/SettingsTest.cs b/mcs/class/monodoc/Test/Monodoc/SettingsTest.cs index 29ac108da8d..fc6bf8da18a 100644 --- a/mcs/class/monodoc/Test/Monodoc/SettingsTest.cs +++ b/mcs/class/monodoc/Test/Monodoc/SettingsTest.cs @@ -17,7 +17,7 @@ namespace MonoTests.Monodoc { // the docPath variable is the only one we know for sure should exist Assert.IsNotNull (Config.Get ("docPath")); - Assert.IsNotEmpty (Config.Get ("docPath")); + AssertHelper.IsNotEmpty (Config.Get ("docPath")); } } } diff --git a/mcs/class/monodoc/monodoc_test.dll.sources b/mcs/class/monodoc/monodoc_test.dll.sources index b806b8fb6e9..a3f19b731a0 100644 --- a/mcs/class/monodoc/monodoc_test.dll.sources +++ b/mcs/class/monodoc/monodoc_test.dll.sources @@ -1,3 +1,4 @@ +../../test-helpers/NunitHelpers.cs Monodoc/HelpSourceTests.cs Monodoc/EcmaDocTests.cs Monodoc/TreeTest.cs diff --git a/mcs/class/referencesource/System/net/System/Net/NetworkCredential.cs b/mcs/class/referencesource/System/net/System/Net/NetworkCredential.cs index 06aa93aa15b..3f9b4d7c8c8 100644 --- a/mcs/class/referencesource/System/net/System/Net/NetworkCredential.cs +++ b/mcs/class/referencesource/System/net/System/Net/NetworkCredential.cs @@ -4,6 +4,10 @@ // //------------------------------------------------------------------------------ +#if MONO +#undef FEATURE_PAL +#endif + namespace System.Net { using System.IO; @@ -22,9 +26,11 @@ namespace System.Net { /// public class NetworkCredential : ICredentials,ICredentialsByHost { +#if FEATURE_MONO_CAS private static volatile EnvironmentPermission m_environmentUserNamePermission; private static volatile EnvironmentPermission m_environmentDomainNamePermission; private static readonly object lockingObject = new object(); +#endif private string m_domain; private string m_userName; #if !FEATURE_PAL @@ -85,6 +91,7 @@ namespace System.Net { } #endif //!FEATURE_PAL +#if FEATURE_MONO_CAS void InitializePart1() { if (m_environmentUserNamePermission == null) { lock(lockingObject) { @@ -95,7 +102,7 @@ namespace System.Net { } } } - +#endif /// /// @@ -104,8 +111,10 @@ namespace System.Net { /// public string UserName { get { +#if FEATURE_MONO_CAS InitializePart1(); m_environmentUserNamePermission.Demand(); +#endif return InternalGetUserName(); } set { @@ -124,7 +133,9 @@ namespace System.Net { /// public string Password { get { +#if FEATURE_MONO_CAS ExceptionHelper.UnmanagedPermission.Demand(); +#endif return InternalGetPassword(); } set { @@ -151,7 +162,9 @@ namespace System.Net { /// public SecureString SecurePassword { get { +#if FEATURE_MONO_CAS ExceptionHelper.UnmanagedPermission.Demand(); +#endif return InternalGetSecurePassword().Copy(); } set { @@ -171,8 +184,10 @@ namespace System.Net { /// public string Domain { get { +#if FEATURE_MONO_CAS InitializePart1(); m_environmentDomainNamePermission.Demand(); +#endif return InternalGetDomain(); } set { diff --git a/mcs/class/referencesource/mscorlib/system/sharedstatics.cs b/mcs/class/referencesource/mscorlib/system/sharedstatics.cs index 87f99a67da3..d455031e761 100644 --- a/mcs/class/referencesource/mscorlib/system/sharedstatics.cs +++ b/mcs/class/referencesource/mscorlib/system/sharedstatics.cs @@ -28,6 +28,15 @@ namespace System { internal sealed class SharedStatics { +#if MONO + // TODO: We are using only GetSharedStringMaker for now which is + // ok to be AppDomain static + static readonly SharedStatics _sharedStatics = new SharedStatics(); + + private SharedStatics() + { + } +#else // this is declared static but is actually forced to be the same object // for each AppDomain at AppDomain create time. private static SharedStatics _sharedStatics; @@ -38,6 +47,7 @@ namespace System { { BCLDebug.Assert(false, "SharedStatics..ctor() is never called."); } +#endif private volatile String _Remoting_Identity_IDGuid; public static String Remoting_Identity_IDGuid diff --git a/mcs/class/test-helpers/NunitHelpers.cs b/mcs/class/test-helpers/NunitHelpers.cs new file mode 100644 index 00000000000..f16683e7a50 --- /dev/null +++ b/mcs/class/test-helpers/NunitHelpers.cs @@ -0,0 +1,112 @@ +using System.IO; +using System.Collections; +using NUnit.Framework.Constraints; + +namespace NUnit.Framework +{ + static class CollectionAssert + { + public static void DoesNotContain (IEnumerable collection, object val) + { + Assert.That(collection, Has.No.Member(val)); + } + + public static void Contains (IEnumerable collection, object val) + { + Assert.That(collection, Has.Member(val)); + } + + public static void AreEqual (IEnumerable expected, IEnumerable actual, string message = null, params object[] args) + { + Assert.That(actual, Is.EqualTo(expected), message, args); + } + + public static void AreEquivalent (IEnumerable expected, IEnumerable actual, string message = null, params object[] args) + { + Assert.That(actual, Is.EquivalentTo(expected), message, args); + } + + public static void IsEmpty(IEnumerable collection, string message = null, params object[] args) + { + Assert.That(collection, new EmptyCollectionConstraint(), message, args); + } + } + + static class FileAssert + { + public static void AreEqual(Stream expected, Stream actual, string message, params object[] args) + { + Assert.That(actual, Is.EqualTo(expected), message, args); + } + + public static void AreEqual(string expected, string actual, string message, params object[] args) + { + using (FileStream exStream = File.OpenRead(expected)) + using (FileStream acStream = File.OpenRead(actual)) + { + AreEqual(exStream, acStream, message, args); + } + } + } + + static class StringAssert + { + public static void Contains(string expected, string actual, string message = null, params object[] args) + { + Assert.That(actual, Is.StringContaining (expected), message, args); + } + + public static void StartsWith(string expected, string actual, string message = null, params object[] args) + { + Assert.IsTrue (actual.StartsWith (expected), message, args); + } + } + + static class AssertHelper + { + public static void IsEmpty (string aString, string message = null, params object[] args ) + { + Assert.That(aString, Is.Empty, message, args); + } + + public static void IsNotEmpty (string aString, string message = null, params object[] args ) + { + Assert.That(aString, Is.Not.Empty, message, args); + } + + public static void Less(int arg1, int arg2, string message = null, params object[] args) + { + Assert.That(arg1, Is.LessThan(arg2), message, args); + } + + public static void Greater(int arg1, int arg2, string message = null, params object[] args) + { + Assert.That(arg1, Is.GreaterThan(arg2), message, args); + } + + public static void Greater(double arg1, double arg2, string message = null, params object[] args) + { + Assert.That(arg1, Is.GreaterThan(arg2), message, args); + } + + public static void GreaterOrEqual(int arg1, int arg2, string message = null, params object[] args) + { + Assert.That(arg1, Is.GreaterThanOrEqualTo(arg2), message, args); + } + + public static void GreaterOrEqual(long arg1, long arg2, string message = null, params object[] args) + { + Assert.That(arg1, Is.GreaterThanOrEqualTo(arg2), message, args); + } + + public static void LessOrEqual (int arg1, int arg2, string message = null, params object[] args) + { + Assert.That(arg1, Is.LessThanOrEqualTo(arg2), message, args); + } + + public static void IsNotInstanceOfType(System.Type expected, object actual, string message, params object[] args ) + { + Assert.IsFalse (actual.GetType ().IsInstanceOfType (expected), message, args); + } + } +} diff --git a/mcs/errors/cs1691-2.cs b/mcs/errors/cs1691-2.cs deleted file mode 100644 index 8c096991a71..00000000000 --- a/mcs/errors/cs1691-2.cs +++ /dev/null @@ -1,4 +0,0 @@ -// CS1691: `2' is not a valid warning number -// Line: 0 -// Compiler options: -warnaserror -warnaserror:1691,2 - diff --git a/mcs/errors/cs1691-3.cs b/mcs/errors/cs1691-3.cs deleted file mode 100644 index c423ebf4f37..00000000000 --- a/mcs/errors/cs1691-3.cs +++ /dev/null @@ -1,4 +0,0 @@ -// CS1691: `20' is not a valid warning number -// Line: 0 -// Compiler options: -warnaserror -warnaserror-:20 - diff --git a/mcs/errors/cs1691-4.cs b/mcs/errors/cs1691-4.cs deleted file mode 100644 index cd9ce646a4e..00000000000 --- a/mcs/errors/cs1691-4.cs +++ /dev/null @@ -1,4 +0,0 @@ -// CS1691: `20' is not a valid warning number -// Line: 0 -// Compiler options: -warnaserror -nowarn:20 - diff --git a/mcs/errors/cs1691.cs b/mcs/errors/cs1691.cs deleted file mode 100644 index bd3e169f4b9..00000000000 --- a/mcs/errors/cs1691.cs +++ /dev/null @@ -1,6 +0,0 @@ -// CS1691: `1' is not a valid warning number -// Line: 5 -// Compiler options: -warnaserror - -#pragma warning disable 1 - diff --git a/mcs/errors/cs1744-3.cs b/mcs/errors/cs1744-3.cs new file mode 100644 index 00000000000..b899816d213 --- /dev/null +++ b/mcs/errors/cs1744-3.cs @@ -0,0 +1,18 @@ +// CS1744: Named argument `p1' cannot be used for a parameter which has positional argument specified +// Line: 8 + +internal class Program +{ + public static void Main () + { + Method (1, 2, p1: 3); + } + + static void Method (int p1, int paramNamed, int p2) + { + } + + static void Method (int p1, int p2, object paramNamed) + { + } +} diff --git a/mcs/errors/cs1904.cs b/mcs/errors/cs1904.cs deleted file mode 100644 index 441753793d4..00000000000 --- a/mcs/errors/cs1904.cs +++ /dev/null @@ -1,8 +0,0 @@ -// CS1904: `4013' is not a valid warning number -// Line: 0 -// Compiler options: -nowarn:4014,4013 - -class ClassMain { - public static void Main () {} -} - diff --git a/mcs/mcs/ecore.cs b/mcs/mcs/ecore.cs index 6f1b80596d0..ad4faf3ce24 100644 --- a/mcs/mcs/ecore.cs +++ b/mcs/mcs/ecore.cs @@ -5050,7 +5050,7 @@ namespace Mono.CSharp { // The slot has been taken by positional argument if (temp != null && !(temp is NamedArgument)) - break; + return NamedArgumentsMismatch - i - 1; } if (!arg_moved) { diff --git a/mcs/mcs/iterators.cs b/mcs/mcs/iterators.cs index 47919ec8ce2..0b6fc1abf77 100644 --- a/mcs/mcs/iterators.cs +++ b/mcs/mcs/iterators.cs @@ -254,7 +254,7 @@ namespace Mono.CSharp // Special format which encodes original variable name and // it's scope to support lifted variables debugging. This // is same what csc does and allows to correctly set fields - // scope information (like ambiguity, our of scope, etc). + // scope information (like ambiguity, out of scope, etc). // var id = rc.CurrentBlock.Explicit.GetDebugSymbolScopeIndex (); return "<" + local_info.Name + ">__" + id; @@ -1067,6 +1067,7 @@ namespace Mono.CSharp method.Block = new ToplevelBlock (method.Compiler, method.ParameterInfo, loc, ToplevelBlock.Flags.CompilerGenerated | ToplevelBlock.Flags.NoFlowAnalysis); + method.Block.AddStatement (new TryFinallyBlockProxyStatement (this, block)); // Cannot it add to storey because it'd be emitted before nested diff --git a/mcs/mcs/report.cs b/mcs/mcs/report.cs index 74bbb46c640..afa4f75bd84 100644 --- a/mcs/mcs/report.cs +++ b/mcs/mcs/report.cs @@ -61,12 +61,10 @@ namespace Mono.CSharp { 8009, 8094 }; - static HashSet AllWarningsHashSet; - public Report (CompilerContext context, ReportPrinter printer) { if (context == null) - throw new ArgumentNullException ("settings"); + throw new ArgumentNullException ("context"); if (printer == null) throw new ArgumentNullException ("printer"); @@ -175,18 +173,6 @@ namespace Mono.CSharp { extra_information.Add (msg); } - public bool CheckWarningCode (int code, Location loc) - { - if (AllWarningsHashSet == null) - AllWarningsHashSet = new HashSet (AllWarnings); - - if (AllWarningsHashSet.Contains (code)) - return true; - - Warning (1691, 1, loc, "`{0}' is not a valid warning number", code); - return false; - } - public void ExtraInformation (Location loc, string msg) { extra_information.Add (String.Format ("{0} {1}", loc, msg)); @@ -1109,8 +1095,7 @@ namespace Mono.CSharp { public void WarningDisable (Location location, int code, Report Report) { - if (Report.CheckWarningCode (code, location)) - regions.Add (new Disable (location.Row, code)); + regions.Add (new Disable (location.Row, code)); } public void WarningEnable (int line) @@ -1120,9 +1105,6 @@ namespace Mono.CSharp { public void WarningEnable (Location location, int code, CompilerContext context) { - if (!context.Report.CheckWarningCode (code, location)) - return; - if (context.Settings.IsWarningDisabledGlobally (code)) context.Report.Warning (1635, 1, location, "Cannot restore warning `CS{0:0000}' because it was disabled globally", code); diff --git a/mcs/mcs/settings.cs b/mcs/mcs/settings.cs index 63c6c41d516..1393bcd58f3 100644 --- a/mcs/mcs/settings.cs +++ b/mcs/mcs/settings.cs @@ -583,7 +583,6 @@ namespace Mono.CSharp { public bool ProcessWarningsList (string text, Action action) { - bool valid = true; foreach (string wid in text.Split (numeric_value_separator, StringSplitOptions.RemoveEmptyEntries)) { var warning = wid; if (warning.Length == 6 && warning [0] == 'C' && warning [1] == 'S') @@ -594,15 +593,10 @@ namespace Mono.CSharp { continue; } - if (report.CheckWarningCode (id, Location.Null)) { - action (id); - } else { - report.Error (1904, "`{0}' is not a valid warning number", wid); - valid = false; - } + action (id); } - return valid; + return true; } void Error_RequiresArgument (string option) @@ -1242,6 +1236,8 @@ namespace Mono.CSharp { case "/appconfig": case "/baseaddress": case "/deterministic": + case "/deterministic+": + case "/deterministic-": case "/errorendlocation": case "/errorlog": case "/features": diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs index eab87d16a17..fbb060f5296 100644 --- a/mcs/mcs/statement.cs +++ b/mcs/mcs/statement.cs @@ -3245,9 +3245,10 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { - if (Parent != null) { - // TODO: It's needed only when scope has variable (normal or lifted) - ec.BeginScope (GetDebugSymbolScopeIndex ()); + // TODO: It's needed only when scope has variable (normal or lifted) + var scopeIndex = GetDebugSymbolScopeIndex (); + if (scopeIndex > 0) { + ec.BeginScope (scopeIndex); } EmitScopeInitialization (ec); @@ -3258,7 +3259,7 @@ namespace Mono.CSharp { DoEmit (ec); - if (Parent != null) + if (scopeIndex > 0) ec.EndScope (); if (ec.EmitAccurateDebugInfo && HasReachableClosingBrace && !(this is ParametersBlock) && @@ -3451,7 +3452,12 @@ namespace Mono.CSharp { storey.Parent.PartialContainer.AddCompilerGeneratedClass (storey); } - public int GetDebugSymbolScopeIndex () + public void DisableDebugScopeIndex () + { + debug_scope_index = -1; + } + + public virtual int GetDebugSymbolScopeIndex () { if (debug_scope_index == 0) debug_scope_index = ++ParametersBlock.debug_scope_index; @@ -3859,6 +3865,11 @@ namespace Mono.CSharp { return res; } + public override int GetDebugSymbolScopeIndex () + { + return 0; + } + public LabeledStatement GetLabel (string name, Block block) { // @@ -8338,15 +8349,14 @@ namespace Mono.CSharp { ec.LoopBegin = ec.DefineLabel (); ec.LoopEnd = ec.DefineLabel (); - if (!(Statement is Block)) - ec.BeginCompilerScope (variable.Block.Explicit.GetDebugSymbolScopeIndex ()); + ec.BeginCompilerScope (variable.Block.Explicit.GetDebugSymbolScopeIndex ()); + body.Explicit.DisableDebugScopeIndex (); variable.CreateBuilder (ec); Statement.Emit (ec); - if (!(Statement is Block)) - ec.EndScope (); + ec.EndScope (); ec.LoopBegin = old_begin; ec.LoopEnd = old_end; diff --git a/mcs/tests/test-debug-11-ref.xml b/mcs/tests/test-debug-11-ref.xml index db740c2456f..d14a377f00f 100644 --- a/mcs/tests/test-debug-11-ref.xml +++ b/mcs/tests/test-debug-11-ref.xml @@ -378,8 +378,7 @@ - - + @@ -401,8 +400,7 @@ - - + @@ -423,8 +421,7 @@ - - + @@ -446,8 +443,7 @@ - - + diff --git a/mcs/tests/test-debug-21-ref.xml b/mcs/tests/test-debug-21-ref.xml index 3958eb589f8..41445be8cee 100644 --- a/mcs/tests/test-debug-21-ref.xml +++ b/mcs/tests/test-debug-21-ref.xml @@ -83,7 +83,8 @@ - + + diff --git a/mcs/tests/test-debug-28-ref.xml b/mcs/tests/test-debug-28-ref.xml index 1038be00dde..c823a34e298 100644 --- a/mcs/tests/test-debug-28-ref.xml +++ b/mcs/tests/test-debug-28-ref.xml @@ -28,9 +28,7 @@ - - - + diff --git a/mcs/tests/test-debug-31-ref.xml b/mcs/tests/test-debug-31-ref.xml new file mode 100644 index 00000000000..1a77894386f --- /dev/null +++ b/mcs/tests/test-debug-31-ref.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mcs/tests/test-debug-31.cs b/mcs/tests/test-debug-31.cs new file mode 100644 index 00000000000..5a3d55de825 --- /dev/null +++ b/mcs/tests/test-debug-31.cs @@ -0,0 +1,25 @@ +using System; + +namespace cp534534 +{ + class MainClass + { + public static void Main () + { + var array = new string[] { "a", "b", "c" }; + + foreach (var item in array) + { + Console.WriteLine (item); + } + + foreach (var item1 in array) { + Console.WriteLine (item1); + } + + foreach (var item2 in array) { + Console.WriteLine (item2); + } + } + } +} \ No newline at end of file diff --git a/mcs/tests/test-debug-32-ref.xml b/mcs/tests/test-debug-32-ref.xml new file mode 100644 index 00000000000..acabcfb38af --- /dev/null +++ b/mcs/tests/test-debug-32-ref.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mcs/tests/test-debug-32.cs b/mcs/tests/test-debug-32.cs new file mode 100644 index 00000000000..ba52a104c11 --- /dev/null +++ b/mcs/tests/test-debug-32.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; + +class X +{ + internal static IEnumerable EnumerateKind () + { + yield return 1; + + int h = 3; + try { + yield return h; + } finally { + if (h != 1) { + } + } + } + + public static void Main () + { + } +} \ No newline at end of file diff --git a/mcs/tests/test-named-10.cs b/mcs/tests/test-named-10.cs new file mode 100644 index 00000000000..6434c836612 --- /dev/null +++ b/mcs/tests/test-named-10.cs @@ -0,0 +1,18 @@ +using System; + +internal class Program +{ + public static void Main () + { + Method (1, 2, paramNamed: 3); + } + + static void Method (int p1, int paramNamed, int p2) + { + throw new ApplicationException (); + } + + static void Method (int p1, int p2, object paramNamed) + { + } +} diff --git a/mcs/tests/ver-il-net_4_x.xml b/mcs/tests/ver-il-net_4_x.xml index 56e35f7709f..f9c8f8b2465 100644 --- a/mcs/tests/ver-il-net_4_x.xml +++ b/mcs/tests/ver-il-net_4_x.xml @@ -67870,6 +67870,58 @@ + + + + 158 + + + 7 + + + + + + + 23 + + + 2 + + + 7 + + + + + 152 + + + 14 + + + 19 + + + 57 + + + 6 + + + 14 + + + 26 + + + 17 + + + 7 + + + @@ -70016,6 +70068,22 @@ + + + + 15 + + + 7 + + + 2 + + + 7 + + + diff --git a/mcs/tools/corcompare/mono-api-info.csproj b/mcs/tools/corcompare/mono-api-info.csproj index bb93b0e0619..eacdad812b8 100644 --- a/mcs/tools/corcompare/mono-api-info.csproj +++ b/mcs/tools/corcompare/mono-api-info.csproj @@ -33,9 +33,6 @@ - - ..\..\class\lib\net_4_x\Mono.Cecil.dll - @@ -45,6 +42,96 @@ Options.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - diff --git a/mcs/tools/nunit-lite/nunit-lite-console/nunit-lite-console.exe.config.tmpl b/mcs/tools/nunit-lite/nunit-lite-console/nunit-lite-console.exe.config.tmpl new file mode 100644 index 00000000000..bc218db9f19 --- /dev/null +++ b/mcs/tools/nunit-lite/nunit-lite-console/nunit-lite-console.exe.config.tmpl @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/mcs/tools/xbuild/Makefile b/mcs/tools/xbuild/Makefile index 9d6e914532d..ca06717b19b 100644 --- a/mcs/tools/xbuild/Makefile +++ b/mcs/tools/xbuild/Makefile @@ -131,6 +131,7 @@ install-pcl5-framework: EXTRA_DISTFILES = \ data/xbuild.rsp \ data/xbuild.exe.config.in \ + data/xbuild.exe.config_test.in \ data/Microsoft.Build.xsd \ data/2.0/Microsoft.Common.tasks \ data/3.5/Microsoft.Common.tasks \ diff --git a/mcs/tools/xbuild/data/xbuild.exe.config_test.in b/mcs/tools/xbuild/data/xbuild.exe.config_test.in new file mode 100644 index 00000000000..a90dbf2ae48 --- /dev/null +++ b/mcs/tools/xbuild/data/xbuild.exe.config_test.in @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/mcs/tools/xbuild/xbuild_test.make b/mcs/tools/xbuild/xbuild_test.make index 9dcf0987ec8..4c503c060ac 100644 --- a/mcs/tools/xbuild/xbuild_test.make +++ b/mcs/tools/xbuild/xbuild_test.make @@ -9,7 +9,7 @@ export XBUILD_FRAMEWORK_FOLDERS_PATH= $(topdir)/class/Microsoft.Build/xbuild-tes ifeq (4.0, $(FRAMEWORK_VERSION)) NO_TEST=true else -test-local: copy-targets $(test_lib).config +test-local: copy-targets Test/test-config-file-$(PROFILE) clean-local: clean-targets clean-test-config endif @@ -17,11 +17,11 @@ xbuild-net4-fail: @echo "The net_4_0 profile contains reference assemblies only and cannot be installed/tested as an xbuild toolset" @exit 1 -$(test_lib).config: $(XBUILD_DATA_DIR)/xbuild.exe.config.in - sed -e 's/@ASM_VERSION@/$(XBUILD_ASSEMBLY_VERSION)/g' $(XBUILD_DATA_DIR)/xbuild.exe.config.in > $(test_lib).config +Test/test-config-file-$(PROFILE): $(XBUILD_DATA_DIR)/xbuild.exe.config_test.in + sed -e 's/@ASM_VERSION@/$(XBUILD_ASSEMBLY_VERSION)/g' $(XBUILD_DATA_DIR)/xbuild.exe.config_test.in > Test/test-config-file-$(PROFILE) clean-test-config: - rm -f $(test_lib).config + rm -f Test/test-config-file-$(PROFILE) copy-targets: copy-targets-$(XBUILD_VERSION) diff --git a/mono/btls/CMakeLists.txt b/mono/btls/CMakeLists.txt index ddd976ccd20..7c3fb3d2c72 100644 --- a/mono/btls/CMakeLists.txt +++ b/mono/btls/CMakeLists.txt @@ -51,6 +51,7 @@ set ( btls-ssl-ctx.h btls-ssl.c btls-ssl.h + btls-time64.c btls-util.c btls-util.h btls-x509-chain.c @@ -74,8 +75,6 @@ set ( btls-x509.c btls-x509.h - btls-android-utils.c - ${BORINGSSL_OBJECTS} ) diff --git a/mono/btls/Makefile.am b/mono/btls/Makefile.am index 4f640bead0b..38f879c629f 100644 --- a/mono/btls/Makefile.am +++ b/mono/btls/Makefile.am @@ -1,4 +1,4 @@ -EXTRA_DIST = btls-android-utils.c \ +EXTRA_DIST = \ btls-bio.c \ btls-bio.h \ btls-error.c \ @@ -11,6 +11,7 @@ EXTRA_DIST = btls-android-utils.c \ btls-ssl-ctx.c \ btls-ssl-ctx.h \ btls-ssl.h \ + btls-time64.c \ btls-util.c \ btls-util.h \ btls-x509.c \ @@ -61,4 +62,5 @@ clean-local: -rm -rf build-shared install-exec-local: - $(install_sh) build-shared/libmono-btls-shared.* "$(DESTDIR)/$(libdir)" + $(mkinstalldirs) "$(DESTDIR)$(libdir)" + $(install_sh) build-shared/libmono-btls-shared.* "$(DESTDIR)$(libdir)" diff --git a/mono/btls/btls-android-utils.c b/mono/btls/btls-android-utils.c deleted file mode 100644 index df30f855d7e..00000000000 --- a/mono/btls/btls-android-utils.c +++ /dev/null @@ -1,33 +0,0 @@ -// Copied from Chromium: https://src.chromium.org/svn/trunk/src/base/os_compat_android.cc - -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#if defined(__ANDROID__) - -#include -#include -#include -#include -#include - -#if !defined(__LP64__) -#include -#endif - -#if !defined(__LP64__) -// 32-bit Android has only timegm64() and not timegm(). -// We replicate the behaviour of timegm() when the result overflows time_t. -time_t timegm(struct tm* const t) { - // time_t is signed on Android. - static const time_t kTimeMax = ~(1L << (sizeof(time_t) * CHAR_BIT - 1)); - static const time_t kTimeMin = (1L << (sizeof(time_t) * CHAR_BIT - 1)); - time64_t result = timegm64(t); - if (result < kTimeMin || result > kTimeMax) - return -1; - return result; -} -#endif - -#endif diff --git a/mono/btls/btls-bio.c b/mono/btls/btls-bio.c index ea8fda67dc3..a35582a3b57 100644 --- a/mono/btls/btls-bio.c +++ b/mono/btls/btls-bio.c @@ -64,8 +64,8 @@ mono_write (BIO *bio, const char *in, int inl) return mono->write_func (mono->instance, in, inl); } -static long -mono_ctrl (BIO *bio, int cmd, long num, void *ptr) +static int64_t +mono_ctrl (BIO *bio, int cmd, int64_t num, void *ptr) { MonoBtlsBio *mono = (MonoBtlsBio *)bio->ptr; diff --git a/mono/btls/btls-bio.h b/mono/btls/btls-bio.h index d4429f6d628..0795ef0f2ba 100644 --- a/mono/btls/btls-bio.h +++ b/mono/btls/btls-bio.h @@ -18,7 +18,7 @@ typedef enum { typedef int (* MonoBtlsReadFunc) (const void *instance, const void *buf, int size, int *wantMore); typedef int (* MonoBtlsWriteFunc) (const void *instance, const void *buf, int size); -typedef long (* MonoBtlsControlFunc) (const void *instance, MonoBtlsControlCommand command, long arg); +typedef int64_t (* MonoBtlsControlFunc) (const void *instance, MonoBtlsControlCommand command, int64_t arg); BIO * mono_btls_bio_mono_new (void); diff --git a/mono/btls/btls-time64.c b/mono/btls/btls-time64.c new file mode 100644 index 00000000000..f01e8c0a2b3 --- /dev/null +++ b/mono/btls/btls-time64.c @@ -0,0 +1,157 @@ +/* + +Copyright (c) 2007-2008 Michael G Schwern + +This software originally derived from Paul Sheer's pivotal_gmtime_r.c. + +The MIT License: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +/* See http://code.google.com/p/y2038 for this code's origin */ + +#include +#include +#include +#include +#include +#include + +/* Spec says except for stftime() and the _r() functions, these + all return static memory. Stabbings! */ +static struct tm Static_Return_Date; +static char Static_Return_String[35]; + +static const int days_in_month[2][12] = { + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, +}; + +static const int julian_days_by_month[2][12] = { + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, + {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}, +}; + +static char const wday_name[7][3] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; + +static char const mon_name[12][3] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +static const int length_of_year[2] = { 365, 366 }; + +/* Some numbers relating to the gregorian cycle */ +static const int64_t years_in_gregorian_cycle = 400; +#define days_in_gregorian_cycle ((365 * 400) + 100 - 4 + 1) +static const int64_t seconds_in_gregorian_cycle = days_in_gregorian_cycle * 60LL * 60LL * 24LL; + +/* Year range we can trust the time funcitons with */ +#define MAX_SAFE_YEAR 2037 +#define MIN_SAFE_YEAR 1971 + +/* 28 year Julian calendar cycle */ +#define SOLAR_CYCLE_LENGTH 28 + +/* Year cycle from MAX_SAFE_YEAR down. */ +static const int safe_years_high[SOLAR_CYCLE_LENGTH] = { + 2016, 2017, 2018, 2019, + 2020, 2021, 2022, 2023, + 2024, 2025, 2026, 2027, + 2028, 2029, 2030, 2031, + 2032, 2033, 2034, 2035, + 2036, 2037, 2010, 2011, + 2012, 2013, 2014, 2015 +}; + +/* Year cycle from MIN_SAFE_YEAR up */ +static const int safe_years_low[SOLAR_CYCLE_LENGTH] = { + 1996, 1997, 1998, 1971, + 1972, 1973, 1974, 1975, + 1976, 1977, 1978, 1979, + 1980, 1981, 1982, 1983, + 1984, 1985, 1986, 1987, + 1988, 1989, 1990, 1991, + 1992, 1993, 1994, 1995, +}; + +/* Let's assume people are going to be looking for dates in the future. + Let's provide some cheats so you can skip ahead. + This has a 4x speed boost when near 2008. +*/ +/* Number of days since epoch on Jan 1st, 2008 GMT */ +#define CHEAT_DAYS (1199145600 / 24 / 60 / 60) +#define CHEAT_YEARS 108 + +#define IS_LEAP(n) ((!(((n) + 1900) % 400) || (!(((n) + 1900) % 4) && (((n) + 1900) % 100))) != 0) +#define WRAP(a,b,m) ((a) = ((a) < 0 ) ? ((b)--, (a) + (m)) : (a)) + +/* timegm() is not in the C or POSIX spec, but it is such a useful + extension I would be remiss in leaving it out. Also I need it + for localtime64() +*/ +int64_t btls_timegm64(const struct tm *date) { + int64_t days = 0; + int64_t seconds = 0; + int64_t year; + int64_t orig_year = (int64_t)date->tm_year; + int cycles = 0; + + if( orig_year > 100 ) { + cycles = (orig_year - 100) / 400; + orig_year -= cycles * 400; + days += (int64_t)cycles * days_in_gregorian_cycle; + } + else if( orig_year < -300 ) { + cycles = (orig_year - 100) / 400; + orig_year -= cycles * 400; + days += (int64_t)cycles * days_in_gregorian_cycle; + } + + if( orig_year > 70 ) { + year = 70; + while( year < orig_year ) { + days += length_of_year[IS_LEAP(year)]; + year++; + } + } + else if ( orig_year < 70 ) { + year = 69; + do { + days -= length_of_year[IS_LEAP(year)]; + year--; + } while( year >= orig_year ); + } + + + days += julian_days_by_month[IS_LEAP(orig_year)][date->tm_mon]; + days += date->tm_mday - 1; + + seconds = days * 60 * 60 * 24; + + seconds += date->tm_hour * 60 * 60; + seconds += date->tm_min * 60; + seconds += date->tm_sec; + + return(seconds); +} diff --git a/mono/btls/btls-util.c b/mono/btls/btls-util.c index 824b101f34c..7c7f4ca5b41 100644 --- a/mono/btls/btls-util.c +++ b/mono/btls/btls-util.c @@ -8,32 +8,33 @@ #include #include -#include - -#if defined(__ANDROID__) && !defined(__LP64__) -#include -extern time_t timegm (struct tm* const t); -#endif +// #include extern int asn1_generalizedtime_to_tm (struct tm *tm, const ASN1_GENERALIZEDTIME *d); +extern int64_t btls_timegm64 (const struct tm *date); + + MONO_API void mono_btls_free (void *data) { OPENSSL_free (data); } -long +int64_t mono_btls_util_asn1_time_to_ticks (ASN1_TIME *time) { ASN1_GENERALIZEDTIME *gtime; struct tm tm; - time_t epoch; + int64_t epoch; + int ret; + + memset (&tm, 0, sizeof (tm)); gtime = ASN1_TIME_to_generalizedtime (time, NULL); - asn1_generalizedtime_to_tm (&tm, gtime); + ret = asn1_generalizedtime_to_tm (&tm, gtime); ASN1_GENERALIZEDTIME_free (gtime); - epoch = timegm(&tm); + epoch = btls_timegm64 (&tm); return epoch; } diff --git a/mono/btls/btls-util.h b/mono/btls/btls-util.h index 525e6199750..a1b165235bd 100644 --- a/mono/btls/btls-util.h +++ b/mono/btls/btls-util.h @@ -33,7 +33,7 @@ void mono_btls_free (void *data); -long +int64_t mono_btls_util_asn1_time_to_ticks (ASN1_TIME *time); int diff --git a/mono/btls/btls-x509-crl.c b/mono/btls/btls-x509-crl.c index b4e861234ca..d496c072f12 100644 --- a/mono/btls/btls-x509-crl.c +++ b/mono/btls/btls-x509-crl.c @@ -124,19 +124,19 @@ mono_btls_x509_crl_get_revoked (MonoBtlsX509Crl *crl, int index) return mono_btls_x509_revoked_new (crl, revoked); } -MONO_API long +MONO_API int64_t mono_btls_x509_crl_get_last_update (MonoBtlsX509Crl *crl) { return mono_btls_util_asn1_time_to_ticks (X509_CRL_get_lastUpdate (crl->crl)); } -MONO_API long +MONO_API int64_t mono_btls_x509_crl_get_next_update (MonoBtlsX509Crl *crl) { return mono_btls_util_asn1_time_to_ticks (X509_CRL_get_nextUpdate (crl->crl)); } -MONO_API long +MONO_API int64_t mono_btls_x509_crl_get_version (MonoBtlsX509Crl *crl) { return X509_CRL_get_version (crl->crl); diff --git a/mono/btls/btls-x509-crl.h b/mono/btls/btls-x509-crl.h index 0813fe5436a..625037d99a2 100644 --- a/mono/btls/btls-x509-crl.h +++ b/mono/btls/btls-x509-crl.h @@ -34,13 +34,13 @@ mono_btls_x509_crl_get_revoked_count (MonoBtlsX509Crl *crl); MonoBtlsX509Revoked * mono_btls_x509_crl_get_revoked (MonoBtlsX509Crl *crl, int index); -long +int64_t mono_btls_x509_crl_get_last_update (MonoBtlsX509Crl *crl); -long +int64_t mono_btls_x509_crl_get_next_update (MonoBtlsX509Crl *crl); -long +int64_t mono_btls_x509_crl_get_version (MonoBtlsX509Crl *crl); MonoBtlsX509Name * diff --git a/mono/btls/btls-x509-lookup-mono.c b/mono/btls/btls-x509-lookup-mono.c index 1d8f7d3ee51..6d9d69a16f0 100644 --- a/mono/btls/btls-x509-lookup-mono.c +++ b/mono/btls/btls-x509-lookup-mono.c @@ -103,7 +103,7 @@ mono_btls_x509_lookup_mono_free (MonoBtlsX509LookupMono *mono) } static int -mono_lookup_ctrl (X509_LOOKUP *ctx, int cmd, const char *argp, long argl, char **ret) +mono_lookup_ctrl (X509_LOOKUP *ctx, int cmd, const char *argp, int64_t argl, char **ret) { MonoLookup *lookup = (MonoLookup*)ctx->method_data; MonoBtlsX509LookupMono *mono = (MonoBtlsX509LookupMono*)argp; diff --git a/mono/btls/btls-x509-name.c b/mono/btls/btls-x509-name.c index 782743f8752..7f987588002 100644 --- a/mono/btls/btls-x509-name.c +++ b/mono/btls/btls-x509-name.c @@ -153,13 +153,13 @@ mono_btls_x509_name_print_string (MonoBtlsX509Name *name, char *buffer, int size return X509_NAME_oneline (name->name, buffer, size) != NULL; } -MONO_API long +MONO_API int64_t mono_btls_x509_name_hash (MonoBtlsX509Name *name) { return X509_NAME_hash (name->name); } -MONO_API long +MONO_API int64_t mono_btls_x509_name_hash_old (MonoBtlsX509Name *name) { return X509_NAME_hash_old (name->name); diff --git a/mono/btls/btls-x509-name.h b/mono/btls/btls-x509-name.h index 604de2bb5e6..9d43bc64991 100644 --- a/mono/btls/btls-x509-name.h +++ b/mono/btls/btls-x509-name.h @@ -56,10 +56,10 @@ mono_btls_x509_name_print_string (MonoBtlsX509Name *name, char *buffer, int size int mono_btls_x509_name_get_raw_data (MonoBtlsX509Name *name, void **buffer, int use_canon_enc); -long +int64_t mono_btls_x509_name_hash (MonoBtlsX509Name *name); -long +int64_t mono_btls_x509_name_hash_old (MonoBtlsX509Name *name); int diff --git a/mono/btls/btls-x509-revoked.c b/mono/btls/btls-x509-revoked.c index d0540e6ca10..bf9af79de46 100644 --- a/mono/btls/btls-x509-revoked.c +++ b/mono/btls/btls-x509-revoked.c @@ -46,7 +46,7 @@ mono_btls_x509_revoked_get_serial_number (MonoBtlsX509Revoked *revoked, char *bu return serial->length; } -MONO_API long +MONO_API int64_t mono_btls_x509_revoked_get_revocation_date (MonoBtlsX509Revoked *revoked) { ASN1_TIME *date; diff --git a/mono/btls/btls-x509-revoked.h b/mono/btls/btls-x509-revoked.h index e1229c6a47f..592fc9316a1 100644 --- a/mono/btls/btls-x509-revoked.h +++ b/mono/btls/btls-x509-revoked.h @@ -22,7 +22,7 @@ mono_btls_x509_revoked_free (MonoBtlsX509Revoked *revoked); int mono_btls_x509_revoked_get_serial_number (MonoBtlsX509Revoked *revoked, char *buffer, int size); -long +int64_t mono_btls_x509_revoked_get_revocation_date (MonoBtlsX509Revoked *revoked); int diff --git a/mono/btls/btls-x509-verify-param.c b/mono/btls/btls-x509-verify-param.c index 5ac8bdbb099..24be3da8ca1 100644 --- a/mono/btls/btls-x509-verify-param.c +++ b/mono/btls/btls-x509-verify-param.c @@ -126,14 +126,14 @@ mono_btls_x509_verify_param_add_host (MonoBtlsX509VerifyParam *param, const char return X509_VERIFY_PARAM_set1_host (param->param, host, namelen); } -MONO_API unsigned long +MONO_API uint64_t mono_btls_x509_verify_param_get_flags (MonoBtlsX509VerifyParam *param) { return X509_VERIFY_PARAM_get_flags (param->param); } MONO_API int -mono_btls_x509_verify_param_set_flags (MonoBtlsX509VerifyParam *param, unsigned long flags) +mono_btls_x509_verify_param_set_flags (MonoBtlsX509VerifyParam *param, uint64_t flags) { if (!param->owns) return -1; @@ -144,7 +144,7 @@ MONO_API MonoBtlsX509VerifyFlags mono_btls_x509_verify_param_get_mono_flags (MonoBtlsX509VerifyParam *param) { MonoBtlsX509VerifyFlags current; - unsigned long flags; + uint64_t flags; if (!param->owns) return -1; @@ -165,7 +165,7 @@ mono_btls_x509_verify_param_get_mono_flags (MonoBtlsX509VerifyParam *param) MONO_API int mono_btls_x509_verify_param_set_mono_flags (MonoBtlsX509VerifyParam *param, MonoBtlsX509VerifyFlags flags) { - unsigned long current; + uint64_t current; if (!param->owns) return -1; @@ -205,7 +205,7 @@ mono_btls_x509_verify_param_set_depth (MonoBtlsX509VerifyParam *param, int depth } MONO_API int -mono_btls_x509_verify_param_set_time (MonoBtlsX509VerifyParam *param, long time) +mono_btls_x509_verify_param_set_time (MonoBtlsX509VerifyParam *param, int64_t time) { if (!param->owns) return -1; diff --git a/mono/btls/btls-x509-verify-param.h b/mono/btls/btls-x509-verify-param.h index 6f4f1b51a8e..e85d547fb3e 100644 --- a/mono/btls/btls-x509-verify-param.h +++ b/mono/btls/btls-x509-verify-param.h @@ -50,11 +50,11 @@ mono_btls_x509_verify_param_set_host (MonoBtlsX509VerifyParam *param, const char int mono_btls_x509_verify_param_add_host (MonoBtlsX509VerifyParam *param, const char *host, int namelen); -unsigned long +uint64_t mono_btls_x509_verify_param_get_flags (MonoBtlsX509VerifyParam *param); int -mono_btls_x509_verify_param_set_flags (MonoBtlsX509VerifyParam *param, unsigned long flags); +mono_btls_x509_verify_param_set_flags (MonoBtlsX509VerifyParam *param, uint64_t flags); MonoBtlsX509VerifyFlags mono_btls_x509_verify_param_get_mono_flags (MonoBtlsX509VerifyParam *param); @@ -72,7 +72,7 @@ int mono_btls_x509_verify_param_set_depth (MonoBtlsX509VerifyParam *param, int depth); int -mono_btls_x509_verify_param_set_time (MonoBtlsX509VerifyParam *param, long time); +mono_btls_x509_verify_param_set_time (MonoBtlsX509VerifyParam *param, int64_t time); char * mono_btls_x509_verify_param_get_peername (MonoBtlsX509VerifyParam *param); diff --git a/mono/btls/btls-x509.c b/mono/btls/btls-x509.c index ae75f3ce912..473d94fbaf3 100644 --- a/mono/btls/btls-x509.c +++ b/mono/btls/btls-x509.c @@ -101,13 +101,13 @@ mono_btls_x509_get_hash (X509 *x509, const void **data) return SHA_DIGEST_LENGTH; } -MONO_API long +MONO_API int64_t mono_btls_x509_get_not_before (X509 *x509) { return mono_btls_util_asn1_time_to_ticks (X509_get_notBefore (x509)); } -MONO_API long +MONO_API int64_t mono_btls_x509_get_not_after (X509 *x509) { return mono_btls_util_asn1_time_to_ticks (X509_get_notAfter (x509)); diff --git a/mono/btls/btls-x509.h b/mono/btls/btls-x509.h index a9a9200127d..d9137431333 100644 --- a/mono/btls/btls-x509.h +++ b/mono/btls/btls-x509.h @@ -79,10 +79,10 @@ mono_btls_x509_cmp (const X509 *a, const X509 *b); int mono_btls_x509_get_hash (X509 *x509, const void **data); -long +int64_t mono_btls_x509_get_not_before (X509 *x509); -long +int64_t mono_btls_x509_get_not_after (X509 *x509); int diff --git a/mono/dis/get.c b/mono/dis/get.c index f3724e4384d..ca9c92e0ae6 100755 --- a/mono/dis/get.c +++ b/mono/dis/get.c @@ -1103,8 +1103,8 @@ dis_stringify_object_with_class (MonoImage *m, MonoClass *c, gboolean prefix, gb esname = get_escaped_class_name (c); - if (c->generic_class) { - MonoGenericClass *gclass = c->generic_class; + if (mono_class_is_ginst (c)) { + MonoGenericClass *gclass = mono_class_get_generic_class (c); MonoGenericInst *inst = gclass->context.class_inst; GString *str = g_string_new (""); int i; @@ -1847,7 +1847,7 @@ get_memberref_container (MonoImage *m, guint32 mrp_token, MonoGenericContainer * case 4: /* TypeSpec */ klass = mono_class_get_full (m, MONO_TOKEN_TYPE_SPEC | idx, (MonoGenericContext *) container); g_assert (klass); - return klass->generic_class ? klass->generic_class->container_class->generic_container : NULL; + return mono_class_is_ginst (klass) ? mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class) : NULL; } g_assert_not_reached (); return NULL; @@ -3108,7 +3108,7 @@ get_method_override (MonoImage *m, guint32 token, MonoGenericContainer *containe MonoMethod *mh = NULL; mh = mono_get_method_checked (m, decl, NULL, (MonoGenericContext *) container, &error); - if (mh && (mh->klass && (mh->klass->generic_class || mh->klass->generic_container))) { + if (mh && (mh->klass && (mono_class_is_ginst (mh->klass) || mono_class_is_gtd (mh->klass)))) { char *meth_str; char *ret; diff --git a/mono/io-layer/Makefile.am b/mono/io-layer/Makefile.am index dfb60a16c82..dae93fe23a4 100644 --- a/mono/io-layer/Makefile.am +++ b/mono/io-layer/Makefile.am @@ -11,7 +11,6 @@ AM_CPPFLAGS = \ libwapiincludedir = $(includedir)/mono-$(API_VER)/mono/io-layer OTHER_H = \ - access.h \ context.h \ error.h \ io.h \ @@ -20,7 +19,6 @@ OTHER_H = \ io-portability.h \ macros.h \ messages.h \ - processes.h \ security.h \ sockets.h \ status.h \ @@ -33,7 +31,6 @@ OTHER_H = \ wapi-remap.h OTHER_SRC = \ - access.h \ context.c \ context.h \ error.c \ @@ -49,9 +46,6 @@ OTHER_SRC = \ messages.c \ messages.h \ posix.c \ - processes.c \ - processes.h \ - process-private.h \ security.c \ security.h \ sockets.c \ @@ -61,7 +55,6 @@ OTHER_SRC = \ status.h \ timefuncs.c \ timefuncs.h \ - timefuncs-private.h \ types.h \ uglify.h \ versioninfo.c \ diff --git a/mono/io-layer/access.h b/mono/io-layer/access.h deleted file mode 100644 index 2cb48b308ac..00000000000 --- a/mono/io-layer/access.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * access.h: Access control definitions - * - * Author: - * Dick Porter (dick@ximian.com) - * - * (C) 2002 Ximian, Inc. - */ - -#ifndef _WAPI_ACCESS_H_ -#define _WAPI_ACCESS_H_ - -#include - -#include - -#define SYNCHRONIZE 0x00100000 -#define STANDARD_RIGHTS_REQUIRED 0x000f0000 - -#endif /* _WAPI_ACCESS_H_ */ diff --git a/mono/io-layer/error.c b/mono/io-layer/error.c index db128be5c72..bc884c3d8d9 100644 --- a/mono/io-layer/error.c +++ b/mono/io-layer/error.c @@ -15,10 +15,10 @@ #include "mono/io-layer/wapi.h" #include "mono/io-layer/wapi-private.h" -#include "mono/utils/mono-once.h" +#include "mono/utils/mono-lazy-init.h" static pthread_key_t error_key; -static mono_once_t error_key_once=MONO_ONCE_INIT; +static mono_lazy_init_t error_key_once = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED; static void error_init(void) { @@ -28,7 +28,7 @@ static void error_init(void) g_assert (ret == 0); } -void _wapi_error_cleanup (void) +static void error_cleanup (void) { int ret; @@ -36,6 +36,11 @@ void _wapi_error_cleanup (void) g_assert (ret == 0); } +void _wapi_error_cleanup (void) +{ + mono_lazy_cleanup (&error_key_once, error_cleanup); +} + /** * GetLastError: * @@ -51,7 +56,7 @@ guint32 GetLastError(void) if (_wapi_has_shut_down) return 0; - mono_once(&error_key_once, error_init); + mono_lazy_initialize(&error_key_once, error_init); errptr=pthread_getspecific(error_key); err=GPOINTER_TO_UINT(errptr); @@ -71,7 +76,7 @@ void SetLastError(guint32 code) if (_wapi_has_shut_down) return; /* Set the thread-local error code */ - mono_once(&error_key_once, error_init); + mono_lazy_initialize(&error_key_once, error_init); ret = pthread_setspecific(error_key, GUINT_TO_POINTER(code)); g_assert (ret == 0); } diff --git a/mono/io-layer/io.c b/mono/io-layer/io.c index 661067dc7b2..3106fc13078 100644 --- a/mono/io-layer/io.c +++ b/mono/io-layer/io.c @@ -39,13 +39,13 @@ #include #include #include -#include +#include #include #include #include #include #include -#include +#include /* * If SHM is disabled, this will point to a hash of _WapiFileShare structures, otherwise diff --git a/mono/io-layer/locking.c b/mono/io-layer/locking.c index 001df9bef7e..86eb864365f 100644 --- a/mono/io-layer/locking.c +++ b/mono/io-layer/locking.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include gboolean _wapi_lock_file_region (int fd, off_t offset, off_t length) diff --git a/mono/io-layer/posix.c b/mono/io-layer/posix.c index fe350c8b866..995795bb326 100644 --- a/mono/io-layer/posix.c +++ b/mono/io-layer/posix.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include static guint32 convert_from_flags(int flags) diff --git a/mono/io-layer/process-private.h b/mono/io-layer/process-private.h deleted file mode 100644 index a17de8a3adb..00000000000 --- a/mono/io-layer/process-private.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * process-private.h: Private definitions for process handles - * - * Author: - * Dick Porter (dick@ximian.com) - * - * (C) 2002-2006 Novell, Inc. - */ - -#ifndef _WAPI_PROCESS_PRIVATE_H_ -#define _WAPI_PROCESS_PRIVATE_H_ - -#include -#include - -#include - -/* There doesn't seem to be a defined symbol for this */ -#define _WAPI_PROCESS_CURRENT (gpointer)0xFFFFFFFF - -/* - * Handles > _WAPI_PROCESS_UNHANDLED are pseudo handles which represent processes - * not started by the runtime. - */ -/* This marks a system process that we don't have a handle on */ -/* FIXME: Cope with PIDs > sizeof guint */ -#define _WAPI_PROCESS_UNHANDLED (1 << (8*sizeof(pid_t)-1)) -#define _WAPI_PROCESS_UNHANDLED_PID_MASK (-1 & ~_WAPI_PROCESS_UNHANDLED) -#define WAPI_IS_PSEUDO_PROCESS_HANDLE(handle) ((GPOINTER_TO_UINT(handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) -#define WAPI_PID_TO_HANDLE(pid) GINT_TO_POINTER (_WAPI_PROCESS_UNHANDLED + (pid)) -#define WAPI_HANDLE_TO_PID(handle) (GPOINTER_TO_UINT ((handle)) - _WAPI_PROCESS_UNHANDLED) - -void _wapi_processes_init (void); -extern gpointer _wapi_process_duplicate (void); -extern void wapi_processes_cleanup (void); - -/* - * MonoProcess describes processes we create. - * It contains a semaphore that can be waited on in order to wait - * for process termination. It's accessed in our SIGCHLD handler, - * when status is updated (and pid cleared, to not clash with - * subsequent processes that may get executed). - */ -struct MonoProcess { - pid_t pid; /* the pid of the process. This value is only valid until the process has exited. */ - MonoSemType exit_sem; /* this semaphore will be released when the process exits */ - int status; /* the exit status */ - gint32 handle_count; /* the number of handles to this mono_process instance */ - /* we keep a ref to the creating _WapiHandle_process handle until - * the process has exited, so that the information there isn't lost. - */ - gpointer handle; - gboolean freeable; - struct MonoProcess *next; -}; - -typedef struct MonoProcess MonoProcess; - -/* - * _WapiHandle_process is a structure containing all the required information - * for process handling. - */ -struct _WapiHandle_process -{ - pid_t id; - guint32 exitstatus; - gpointer main_thread; - WapiFileTime create_time; - WapiFileTime exit_time; - char *proc_name; - size_t min_working_set; - size_t max_working_set; - gboolean exited; - struct MonoProcess *mono_process; -}; - -typedef struct _WapiHandle_process WapiHandle_process; - -#endif /* _WAPI_PROCESS_PRIVATE_H_ */ diff --git a/mono/io-layer/processes.c b/mono/io-layer/processes.c deleted file mode 100644 index fd55cd74314..00000000000 --- a/mono/io-layer/processes.c +++ /dev/null @@ -1,2880 +0,0 @@ -/* - * processes.c: Process handles - * - * Author: - * Dick Porter (dick@ximian.com) - * - * (C) 2002-2011 Novell, Inc. - * Copyright 2011 Xamarin Inc - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_SIGNAL_H -#include -#endif -#include -#include -#ifdef HAVE_SYS_PARAM_H -#include -#endif -#include - -#ifdef HAVE_SYS_WAIT_H -#include -#endif -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif - -#ifdef HAVE_SYS_MKDEV_H -#include -#endif - -#ifdef HAVE_UTIME_H -#include -#endif - -/* sys/resource.h (for rusage) is required when using osx 10.3 (but not 10.4) */ -#ifdef __APPLE__ -#include -#include -#ifdef HAVE_LIBPROC_H -/* proc_name */ -#include -#endif -#endif - -#if defined(PLATFORM_MACOSX) -#define USE_OSX_LOADER -#endif - -#if ( defined(__OpenBSD__) || defined(__FreeBSD__) ) && defined(HAVE_LINK_H) -#define USE_BSD_LOADER -#endif - -#if defined(__HAIKU__) -#define USE_HAIKU_LOADER -#endif - -#if defined(USE_OSX_LOADER) || defined(USE_BSD_LOADER) -#include -#include -# if !defined(__OpenBSD__) -# include -# endif -# if defined(__FreeBSD__) -# include /* struct kinfo_proc */ -# endif -#endif - -#ifdef PLATFORM_SOLARIS -/* procfs.h cannot be included if this define is set, but it seems to work fine if it is undefined */ -#if _FILE_OFFSET_BITS == 64 -#undef _FILE_OFFSET_BITS -#include -#define _FILE_OFFSET_BITS 64 -#else -#include -#endif -#endif - -#ifdef __HAIKU__ -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define STILL_ACTIVE STATUS_PENDING - -/* The process' environment strings */ -#if defined(__APPLE__) -#if defined (TARGET_OSX) -/* Apple defines this in crt_externs.h but doesn't provide that header for - * arm-apple-darwin9. We'll manually define the symbol on Apple as it does - * in fact exist on all implementations (so far) - */ -gchar ***_NSGetEnviron(void); -#define environ (*_NSGetEnviron()) -#else -static char *mono_environ[1] = { NULL }; -#define environ mono_environ -#endif /* defined (TARGET_OSX) */ -#else -extern char **environ; -#endif - -static guint32 process_wait (gpointer handle, guint32 timeout, gboolean *alerted); -static void process_close (gpointer handle, gpointer data); -static void process_details (gpointer data); -static const gchar* process_typename (void); -static gsize process_typesize (void); -static gboolean is_pid_valid (pid_t pid); - -#if !(defined(USE_OSX_LOADER) || defined(USE_BSD_LOADER) || defined(USE_HAIKU_LOADER)) -static FILE * -open_process_map (int pid, const char *mode); -#endif - -static MonoW32HandleOps _wapi_process_ops = { - process_close, /* close_shared */ - NULL, /* signal */ - NULL, /* own */ - NULL, /* is_owned */ - process_wait, /* special_wait */ - NULL, /* prewait */ - process_details, /* details */ - process_typename, /* typename */ - process_typesize, /* typesize */ -}; - -#if HAVE_SIGACTION -static struct sigaction previous_chld_sa; -#endif -static mono_once_t process_sig_chld_once = MONO_ONCE_INIT; -static void process_add_sigchld_handler (void); - -/* The signal-safe logic to use mono_processes goes like this: - * - The list must be safe to traverse for the signal handler at all times. - * It's safe to: prepend an entry (which is a single store to 'mono_processes'), - * unlink an entry (assuming the unlinked entry isn't freed and doesn't - * change its 'next' pointer so that it can still be traversed). - * When cleaning up we first unlink an entry, then we verify that - * the read lock isn't locked. Then we can free the entry, since - * we know that nobody is using the old version of the list (including - * the unlinked entry). - * We also need to lock when adding and cleaning up so that those two - * operations don't mess with eachother. (This lock is not used in the - * signal handler) - */ -static struct MonoProcess *mono_processes = NULL; -static volatile gint32 mono_processes_cleaning_up = 0; -static mono_mutex_t mono_processes_mutex; -static void mono_processes_cleanup (void); - -static gpointer current_process; -static char *cli_launcher; - -static WapiHandle_process * -lookup_process_handle (gpointer handle) -{ - WapiHandle_process *process_data; - gboolean ret; - - ret = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, - (gpointer *)&process_data); - if (!ret) - return NULL; - return process_data; -} - -/* Check if a pid is valid - i.e. if a process exists with this pid. */ -static gboolean -is_pid_valid (pid_t pid) -{ - gboolean result = FALSE; - -#if defined(HOST_WATCHOS) - result = TRUE; // TODO: Rewrite using sysctl -#elif defined(PLATFORM_MACOSX) || defined(__OpenBSD__) || defined(__FreeBSD__) - if (((kill(pid, 0) == 0) || (errno == EPERM)) && pid != 0) - result = TRUE; -#elif defined(__HAIKU__) - team_info teamInfo; - if (get_team_info ((team_id)pid, &teamInfo) == B_OK) - result = TRUE; -#else - char *dir = g_strdup_printf ("/proc/%d", pid); - if (!access (dir, F_OK)) - result = TRUE; - g_free (dir); -#endif - - return result; -} - -static void -process_set_defaults (WapiHandle_process *process_handle) -{ - /* These seem to be the defaults on w2k */ - process_handle->min_working_set = 204800; - process_handle->max_working_set = 1413120; - - _wapi_time_t_to_filetime (time (NULL), &process_handle->create_time); -} - -static int -len16 (const gunichar2 *str) -{ - int len = 0; - - while (*str++ != 0) - len++; - - return len; -} - -static gunichar2 * -utf16_concat (const gunichar2 *first, ...) -{ - va_list args; - int total = 0, i; - const gunichar2 *s; - gunichar2 *ret; - - va_start (args, first); - total += len16 (first); - for (s = va_arg (args, gunichar2 *); s != NULL; s = va_arg(args, gunichar2 *)){ - total += len16 (s); - } - va_end (args); - - ret = g_new (gunichar2, total + 1); - if (ret == NULL) - return NULL; - - ret [total] = 0; - i = 0; - for (s = first; *s != 0; s++) - ret [i++] = *s; - va_start (args, first); - for (s = va_arg (args, gunichar2 *); s != NULL; s = va_arg (args, gunichar2 *)){ - const gunichar2 *p; - - for (p = s; *p != 0; p++) - ret [i++] = *p; - } - va_end (args); - - return ret; -} - -static const gunichar2 utf16_space_bytes [2] = { 0x20, 0 }; -static const gunichar2 *utf16_space = utf16_space_bytes; -static const gunichar2 utf16_quote_bytes [2] = { 0x22, 0 }; -static const gunichar2 *utf16_quote = utf16_quote_bytes; - -#ifdef DEBUG_ENABLED -/* Useful in gdb */ -void -print_utf16 (gunichar2 *str) -{ - char *res; - - res = g_utf16_to_utf8 (str, -1, NULL, NULL, NULL); - g_print ("%s\n", res); - g_free (res); -} -#endif - -/* Implemented as just a wrapper around CreateProcess () */ -gboolean -ShellExecuteEx (WapiShellExecuteInfo *sei) -{ - gboolean ret; - WapiProcessInformation process_info; - gunichar2 *args; - - if (sei == NULL) { - /* w2k just segfaults here, but we can do better than - * that - */ - SetLastError (ERROR_INVALID_PARAMETER); - return FALSE; - } - - if (sei->lpFile == NULL) - /* w2k returns TRUE for this, for some reason. */ - return TRUE; - - /* Put both executable and parameters into the second argument - * to CreateProcess (), so it searches $PATH. The conversion - * into and back out of utf8 is because there is no - * g_strdup_printf () equivalent for gunichar2 :-( - */ - args = utf16_concat (utf16_quote, sei->lpFile, utf16_quote, sei->lpParameters == NULL ? NULL : utf16_space, sei->lpParameters, NULL); - if (args == NULL) { - SetLastError (ERROR_INVALID_DATA); - return FALSE; - } - ret = CreateProcess (NULL, args, NULL, NULL, TRUE, - CREATE_UNICODE_ENVIRONMENT, NULL, - sei->lpDirectory, NULL, &process_info); - g_free (args); - - if (!ret && GetLastError () == ERROR_OUTOFMEMORY) - return ret; - - if (!ret) { - static char *handler; - static gunichar2 *handler_utf16; - - if (handler_utf16 == (gunichar2 *)-1) - return FALSE; - -#ifdef PLATFORM_MACOSX - handler = g_strdup ("/usr/bin/open"); -#else - /* - * On Linux, try: xdg-open, the FreeDesktop standard way of doing it, - * if that fails, try to use gnome-open, then kfmclient - */ - handler = g_find_program_in_path ("xdg-open"); - if (handler == NULL){ - handler = g_find_program_in_path ("gnome-open"); - if (handler == NULL){ - handler = g_find_program_in_path ("kfmclient"); - if (handler == NULL){ - handler_utf16 = (gunichar2 *) -1; - return FALSE; - } else { - /* kfmclient needs exec argument */ - char *old = handler; - handler = g_strconcat (old, " exec", - NULL); - g_free (old); - } - } - } -#endif - handler_utf16 = g_utf8_to_utf16 (handler, -1, NULL, NULL, NULL); - g_free (handler); - - /* Put quotes around the filename, in case it's a url - * that contains #'s (CreateProcess() calls - * g_shell_parse_argv(), which deliberately throws - * away anything after an unquoted #). Fixes bug - * 371567. - */ - args = utf16_concat (handler_utf16, utf16_space, utf16_quote, - sei->lpFile, utf16_quote, - sei->lpParameters == NULL ? NULL : utf16_space, - sei->lpParameters, NULL); - if (args == NULL) { - SetLastError (ERROR_INVALID_DATA); - return FALSE; - } - ret = CreateProcess (NULL, args, NULL, NULL, TRUE, - CREATE_UNICODE_ENVIRONMENT, NULL, - sei->lpDirectory, NULL, &process_info); - g_free (args); - if (!ret) { - if (GetLastError () != ERROR_OUTOFMEMORY) - SetLastError (ERROR_INVALID_DATA); - return FALSE; - } - /* Shell exec should not return a process handle when it spawned a GUI thing, like a browser. */ - CloseHandle (process_info.hProcess); - process_info.hProcess = NULL; - } - - if (sei->fMask & SEE_MASK_NOCLOSEPROCESS) - sei->hProcess = process_info.hProcess; - else - CloseHandle (process_info.hProcess); - - return ret; -} - -static gboolean -is_managed_binary (const char *filename) -{ - int original_errno = errno; -#if defined(HAVE_LARGE_FILE_SUPPORT) && defined(O_LARGEFILE) - int file = open (filename, O_RDONLY | O_LARGEFILE); -#else - int file = open (filename, O_RDONLY); -#endif - off_t new_offset; - unsigned char buffer[8]; - off_t file_size, optional_header_offset; - off_t pe_header_offset, clr_header_offset; - gboolean managed = FALSE; - int num_read; - guint32 first_word, second_word, magic_number; - - /* If we are unable to open the file, then we definitely - * can't say that it is managed. The child mono process - * probably wouldn't be able to open it anyway. - */ - if (file < 0) { - errno = original_errno; - return FALSE; - } - - /* Retrieve the length of the file for future sanity checks. */ - file_size = lseek (file, 0, SEEK_END); - lseek (file, 0, SEEK_SET); - - /* We know we need to read a header field at offset 60. */ - if (file_size < 64) - goto leave; - - num_read = read (file, buffer, 2); - - if ((num_read != 2) || (buffer[0] != 'M') || (buffer[1] != 'Z')) - goto leave; - - new_offset = lseek (file, 60, SEEK_SET); - - if (new_offset != 60) - goto leave; - - num_read = read (file, buffer, 4); - - if (num_read != 4) - goto leave; - pe_header_offset = buffer[0] - | (buffer[1] << 8) - | (buffer[2] << 16) - | (buffer[3] << 24); - - if (pe_header_offset + 24 > file_size) - goto leave; - - new_offset = lseek (file, pe_header_offset, SEEK_SET); - - if (new_offset != pe_header_offset) - goto leave; - - num_read = read (file, buffer, 4); - - if ((num_read != 4) || (buffer[0] != 'P') || (buffer[1] != 'E') || (buffer[2] != 0) || (buffer[3] != 0)) - goto leave; - - /* - * Verify that the header we want in the optional header data - * is present in this binary. - */ - new_offset = lseek (file, pe_header_offset + 20, SEEK_SET); - - if (new_offset != pe_header_offset + 20) - goto leave; - - num_read = read (file, buffer, 2); - - if ((num_read != 2) || ((buffer[0] | (buffer[1] << 8)) < 216)) - goto leave; - - optional_header_offset = pe_header_offset + 24; - - /* Read the PE magic number */ - new_offset = lseek (file, optional_header_offset, SEEK_SET); - - if (new_offset != optional_header_offset) - goto leave; - - num_read = read (file, buffer, 2); - - if (num_read != 2) - goto leave; - - magic_number = (buffer[0] | (buffer[1] << 8)); - - if (magic_number == 0x10B) // PE32 - clr_header_offset = 208; - else if (magic_number == 0x20B) // PE32+ - clr_header_offset = 224; - else - goto leave; - - /* Read the CLR header address and size fields. These will be - * zero if the binary is not managed. - */ - new_offset = lseek (file, optional_header_offset + clr_header_offset, SEEK_SET); - - if (new_offset != optional_header_offset + clr_header_offset) - goto leave; - - num_read = read (file, buffer, 8); - - /* We are not concerned with endianness, only with - * whether it is zero or not. - */ - first_word = *(guint32 *)&buffer[0]; - second_word = *(guint32 *)&buffer[4]; - - if ((num_read != 8) || (first_word == 0) || (second_word == 0)) - goto leave; - - managed = TRUE; - -leave: - close (file); - errno = original_errno; - return managed; -} - -gboolean -CreateProcessWithLogonW (const gunichar2 *username, - const gunichar2 *domain, - const gunichar2 *password, - const guint32 logonFlags, - const gunichar2 *appname, - const gunichar2 *cmdline, - guint32 create_flags, - gpointer env, - const gunichar2 *cwd, - WapiStartupInfo *startup, - WapiProcessInformation *process_info) -{ - /* FIXME: use user information */ - return CreateProcess (appname, cmdline, NULL, NULL, FALSE, create_flags, env, cwd, startup, process_info); -} - -static gboolean -is_readable_or_executable (const char *prog) -{ - struct stat buf; - int a = access (prog, R_OK); - int b = access (prog, X_OK); - if (a != 0 && b != 0) - return FALSE; - if (stat (prog, &buf)) - return FALSE; - if (S_ISREG (buf.st_mode)) - return TRUE; - return FALSE; -} - -static gboolean -is_executable (const char *prog) -{ - struct stat buf; - if (access (prog, X_OK) != 0) - return FALSE; - if (stat (prog, &buf)) - return FALSE; - if (S_ISREG (buf.st_mode)) - return TRUE; - return FALSE; -} - -static void -switch_dir_separators (char *path) -{ - size_t i, pathLength = strlen(path); - - /* Turn all the slashes round the right way, except for \' */ - /* There are probably other characters that need to be excluded as well. */ - for (i = 0; i < pathLength; i++) { - if (path[i] == '\\' && i < pathLength - 1 && path[i+1] != '\'' ) - path[i] = '/'; - } -} - -gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, - WapiSecurityAttributes *process_attrs G_GNUC_UNUSED, - WapiSecurityAttributes *thread_attrs G_GNUC_UNUSED, - gboolean inherit_handles, guint32 create_flags, - gpointer new_environ, const gunichar2 *cwd, - WapiStartupInfo *startup, - WapiProcessInformation *process_info) -{ -#if defined (HAVE_FORK) && defined (HAVE_EXECVE) - char *cmd = NULL, *prog = NULL, *full_prog = NULL, *args = NULL, *args_after_prog = NULL; - char *dir = NULL, **env_strings = NULL, **argv = NULL; - guint32 i, env_count = 0; - gboolean ret = FALSE; - gpointer handle = NULL; - WapiHandle_process process_handle = {0}, *process_handle_data; - GError *gerr = NULL; - int in_fd, out_fd, err_fd; - pid_t pid = 0; - int startup_pipe [2] = {-1, -1}; - int dummy; - struct MonoProcess *mono_process; - gboolean fork_failed = FALSE; - - mono_once (&process_sig_chld_once, process_add_sigchld_handler); - - /* appname and cmdline specify the executable and its args: - * - * If appname is not NULL, it is the name of the executable. - * Otherwise the executable is the first token in cmdline. - * - * Executable searching: - * - * If appname is not NULL, it can specify the full path and - * file name, or else a partial name and the current directory - * will be used. There is no additional searching. - * - * If appname is NULL, the first whitespace-delimited token in - * cmdline is used. If the name does not contain a full - * directory path, the search sequence is: - * - * 1) The directory containing the current process - * 2) The current working directory - * 3) The windows system directory (Ignored) - * 4) The windows directory (Ignored) - * 5) $PATH - * - * Just to make things more interesting, tokens can contain - * white space if they are surrounded by quotation marks. I'm - * beginning to understand just why windows apps are generally - * so crap, with an API like this :-( - */ - if (appname != NULL) { - cmd = mono_unicode_to_external (appname); - if (cmd == NULL) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", - __func__); - - SetLastError (ERROR_PATH_NOT_FOUND); - goto free_strings; - } - - switch_dir_separators(cmd); - } - - if (cmdline != NULL) { - args = mono_unicode_to_external (cmdline); - if (args == NULL) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__); - - SetLastError (ERROR_PATH_NOT_FOUND); - goto free_strings; - } - } - - if (cwd != NULL) { - dir = mono_unicode_to_external (cwd); - if (dir == NULL) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__); - - SetLastError (ERROR_PATH_NOT_FOUND); - goto free_strings; - } - - /* Turn all the slashes round the right way */ - switch_dir_separators(dir); - } - - - /* We can't put off locating the executable any longer :-( */ - if (cmd != NULL) { - char *unquoted; - if (g_ascii_isalpha (cmd[0]) && (cmd[1] == ':')) { - /* Strip off the drive letter. I can't - * believe that CP/M holdover is still - * visible... - */ - g_memmove (cmd, cmd+2, strlen (cmd)-2); - cmd[strlen (cmd)-2] = '\0'; - } - - unquoted = g_shell_unquote (cmd, NULL); - if (unquoted[0] == '/') { - /* Assume full path given */ - prog = g_strdup (unquoted); - - /* Executable existing ? */ - if (!is_readable_or_executable (prog)) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Couldn't find executable %s", - __func__, prog); - g_free (unquoted); - SetLastError (ERROR_FILE_NOT_FOUND); - goto free_strings; - } - } else { - /* Search for file named by cmd in the current - * directory - */ - char *curdir = g_get_current_dir (); - - prog = g_strdup_printf ("%s/%s", curdir, unquoted); - g_free (curdir); - - /* And make sure it's readable */ - if (!is_readable_or_executable (prog)) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Couldn't find executable %s", - __func__, prog); - g_free (unquoted); - SetLastError (ERROR_FILE_NOT_FOUND); - goto free_strings; - } - } - g_free (unquoted); - - args_after_prog = args; - } else { - char *token = NULL; - char quote; - - /* Dig out the first token from args, taking quotation - * marks into account - */ - - /* First, strip off all leading whitespace */ - args = g_strchug (args); - - /* args_after_prog points to the contents of args - * after token has been set (otherwise argv[0] is - * duplicated) - */ - args_after_prog = args; - - /* Assume the opening quote will always be the first - * character - */ - if (args[0] == '\"' || args [0] == '\'') { - quote = args [0]; - for (i = 1; args[i] != '\0' && args[i] != quote; i++); - if (args [i + 1] == '\0' || g_ascii_isspace (args[i+1])) { - /* We found the first token */ - token = g_strndup (args+1, i-1); - args_after_prog = g_strchug (args + i + 1); - } else { - /* Quotation mark appeared in the - * middle of the token. Just give the - * whole first token, quotes and all, - * to exec. - */ - } - } - - if (token == NULL) { - /* No quote mark, or malformed */ - for (i = 0; args[i] != '\0'; i++) { - if (g_ascii_isspace (args[i])) { - token = g_strndup (args, i); - args_after_prog = args + i + 1; - break; - } - } - } - - if (token == NULL && args[0] != '\0') { - /* Must be just one token in the string */ - token = g_strdup (args); - args_after_prog = NULL; - } - - if (token == NULL) { - /* Give up */ - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Couldn't find what to exec", __func__); - - SetLastError (ERROR_PATH_NOT_FOUND); - goto free_strings; - } - - /* Turn all the slashes round the right way. Only for - * the prg. name - */ - switch_dir_separators(token); - - if (g_ascii_isalpha (token[0]) && (token[1] == ':')) { - /* Strip off the drive letter. I can't - * believe that CP/M holdover is still - * visible... - */ - g_memmove (token, token+2, strlen (token)-2); - token[strlen (token)-2] = '\0'; - } - - if (token[0] == '/') { - /* Assume full path given */ - prog = g_strdup (token); - - /* Executable existing ? */ - if (!is_readable_or_executable (prog)) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Couldn't find executable %s", - __func__, token); - g_free (token); - SetLastError (ERROR_FILE_NOT_FOUND); - goto free_strings; - } - } else { - char *curdir = g_get_current_dir (); - - /* FIXME: Need to record the directory - * containing the current process, and check - * that for the new executable as the first - * place to look - */ - - prog = g_strdup_printf ("%s/%s", curdir, token); - g_free (curdir); - - /* I assume X_OK is the criterion to use, - * rather than F_OK - * - * X_OK is too strict *if* the target is a CLR binary - */ - if (!is_readable_or_executable (prog)) { - g_free (prog); - prog = g_find_program_in_path (token); - if (prog == NULL) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Couldn't find executable %s", __func__, token); - - g_free (token); - SetLastError (ERROR_FILE_NOT_FOUND); - goto free_strings; - } - } - } - - g_free (token); - } - - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Exec prog [%s] args [%s]", __func__, prog, - args_after_prog); - - /* Check for CLR binaries; if found, we will try to invoke - * them using the same mono binary that started us. - */ - if (is_managed_binary (prog)) { - gunichar2 *newapp = NULL, *newcmd; - gsize bytes_ignored; - - if (cli_launcher) - newapp = mono_unicode_from_external (cli_launcher, &bytes_ignored); - else - newapp = mono_unicode_from_external ("mono", &bytes_ignored); - - if (newapp != NULL) { - if (appname != NULL) { - newcmd = utf16_concat (utf16_quote, newapp, utf16_quote, utf16_space, - appname, utf16_space, - cmdline, NULL); - } else { - newcmd = utf16_concat (utf16_quote, newapp, utf16_quote, utf16_space, - cmdline, NULL); - } - - g_free ((gunichar2 *)newapp); - - if (newcmd != NULL) { - ret = CreateProcess (NULL, newcmd, - process_attrs, - thread_attrs, - inherit_handles, - create_flags, new_environ, - cwd, startup, - process_info); - - g_free ((gunichar2 *)newcmd); - - goto free_strings; - } - } - } else { - if (!is_executable (prog)) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Executable permisson not set on %s", __func__, prog); - SetLastError (ERROR_ACCESS_DENIED); - goto free_strings; - } - } - - if (args_after_prog != NULL && *args_after_prog) { - char *qprog; - - qprog = g_shell_quote (prog); - full_prog = g_strconcat (qprog, " ", args_after_prog, NULL); - g_free (qprog); - } else { - full_prog = g_shell_quote (prog); - } - - ret = g_shell_parse_argv (full_prog, NULL, &argv, &gerr); - if (ret == FALSE) { - g_message ("CreateProcess: %s\n", gerr->message); - g_error_free (gerr); - gerr = NULL; - goto free_strings; - } - - if (startup != NULL && startup->dwFlags & STARTF_USESTDHANDLES) { - in_fd = GPOINTER_TO_UINT (startup->hStdInput); - out_fd = GPOINTER_TO_UINT (startup->hStdOutput); - err_fd = GPOINTER_TO_UINT (startup->hStdError); - } else { - in_fd = GPOINTER_TO_UINT (GetStdHandle (STD_INPUT_HANDLE)); - out_fd = GPOINTER_TO_UINT (GetStdHandle (STD_OUTPUT_HANDLE)); - err_fd = GPOINTER_TO_UINT (GetStdHandle (STD_ERROR_HANDLE)); - } - - process_handle.proc_name = g_strdup (prog); - - process_set_defaults (&process_handle); - - handle = mono_w32handle_new (MONO_W32HANDLE_PROCESS, &process_handle); - if (handle == INVALID_HANDLE_VALUE) { - g_warning ("%s: error creating process handle", __func__); - - ret = FALSE; - SetLastError (ERROR_OUTOFMEMORY); - goto free_strings; - } - - /* new_environ is a block of NULL-terminated strings, which - * is itself NULL-terminated. Of course, passing an array of - * string pointers would have made things too easy :-( - * - * If new_environ is not NULL it specifies the entire set of - * environment variables in the new process. Otherwise the - * new process inherits the same environment. - */ - if (new_environ) { - gunichar2 *new_environp; - - /* Count the number of strings */ - for (new_environp = (gunichar2 *)new_environ; *new_environp; - new_environp++) { - env_count++; - while (*new_environp) { - new_environp++; - } - } - - /* +2: one for the process handle value, and the last - * one is NULL - */ - env_strings = g_new0 (char *, env_count + 2); - - /* Copy each environ string into 'strings' turning it - * into utf8 (or the requested encoding) at the same - * time - */ - env_count = 0; - for (new_environp = (gunichar2 *)new_environ; *new_environp; - new_environp++) { - env_strings[env_count] = mono_unicode_to_external (new_environp); - env_count++; - while (*new_environp) { - new_environp++; - } - } - } else { - for (i = 0; environ[i] != NULL; i++) - env_count++; - - /* +2: one for the process handle value, and the last - * one is NULL - */ - env_strings = g_new0 (char *, env_count + 2); - - /* Copy each environ string into 'strings' turning it - * into utf8 (or the requested encoding) at the same - * time - */ - env_count = 0; - for (i = 0; environ[i] != NULL; i++) { - env_strings[env_count] = g_strdup (environ[i]); - env_count++; - } - } - - /* Create a pipe to make sure the child doesn't exit before - * we can add the process to the linked list of mono_processes */ - if (pipe (startup_pipe) == -1) { - /* Could not create the pipe to synchroniz process startup. We'll just not synchronize. - * This is just for a very hard to hit race condition in the first place */ - startup_pipe [0] = startup_pipe [1] = -1; - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: new process startup not synchronized. We may not notice if the newly created process exits immediately.", __func__); - } - - switch (pid = fork ()) { - case -1: /* Error */ { - SetLastError (ERROR_OUTOFMEMORY); - ret = FALSE; - fork_failed = TRUE; - break; - } - case 0: /* Child */ { - if (startup_pipe [0] != -1) { - /* Wait until the parent has updated it's internal data */ - ssize_t _i G_GNUC_UNUSED = read (startup_pipe [0], &dummy, 1); - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: child: parent has completed its setup", __func__); - close (startup_pipe [0]); - close (startup_pipe [1]); - } - - /* should we detach from the process group? */ - - /* Connect stdin, stdout and stderr */ - dup2 (in_fd, 0); - dup2 (out_fd, 1); - dup2 (err_fd, 2); - - if (inherit_handles != TRUE) { - /* FIXME: do something here */ - } - - /* Close all file descriptors */ - for (i = mono_w32handle_fd_reserve - 1; i > 2; i--) - close (i); - -#ifdef DEBUG_ENABLED - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: exec()ing [%s] in dir [%s]", __func__, cmd, - dir == NULL?".":dir); - for (i = 0; argv[i] != NULL; i++) - g_message ("arg %d: [%s]", i, argv[i]); - - for (i = 0; env_strings[i] != NULL; i++) - g_message ("env %d: [%s]", i, env_strings[i]); -#endif - - /* set cwd */ - if (dir != NULL && chdir (dir) == -1) { - /* set error */ - _exit (-1); - } - - /* exec */ - execve (argv[0], argv, env_strings); - - /* set error */ - _exit (-1); - - break; - } - default: /* Parent */ { - process_handle_data = lookup_process_handle (handle); - if (!process_handle_data) { - g_warning ("%s: error looking up process handle %p", __func__, handle); - mono_w32handle_unref (handle); - } else { - process_handle_data->id = pid; - - /* Add our mono_process into the linked list of mono_processes */ - mono_process = (struct MonoProcess *) g_malloc0 (sizeof (struct MonoProcess)); - mono_process->pid = pid; - mono_process->handle_count = 1; - mono_os_sem_init (&mono_process->exit_sem, 0); - - /* Keep the process handle artificially alive until the process - * exits so that the information in the handle isn't lost. */ - mono_w32handle_ref (handle); - mono_process->handle = handle; - - process_handle_data->mono_process = mono_process; - - mono_os_mutex_lock (&mono_processes_mutex); - mono_process->next = mono_processes; - mono_processes = mono_process; - mono_os_mutex_unlock (&mono_processes_mutex); - - if (process_info != NULL) { - process_info->hProcess = handle; - process_info->dwProcessId = pid; - - /* FIXME: we might need to handle the thread info some day */ - process_info->hThread = INVALID_HANDLE_VALUE; - process_info->dwThreadId = 0; - } - } - - break; - } - } - - if (fork_failed) - mono_w32handle_unref (handle); - - if (startup_pipe [1] != -1) { - /* Write 1 byte, doesn't matter what */ - ssize_t _i G_GNUC_UNUSED = write (startup_pipe [1], startup_pipe, 1); - close (startup_pipe [0]); - close (startup_pipe [1]); - } - -free_strings: - if (cmd) - g_free (cmd); - if (full_prog) - g_free (full_prog); - if (prog) - g_free (prog); - if (args) - g_free (args); - if (dir) - g_free (dir); - if (env_strings) - g_strfreev (env_strings); - if (argv) - g_strfreev (argv); - - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning handle %p for pid %d", __func__, handle, pid); - - /* Check if something needs to be cleaned up. */ - mono_processes_cleanup (); - - return ret; -#else - SetLastError (ERROR_NOT_SUPPORTED); - return FALSE; -#endif // defined (HAVE_FORK) && defined (HAVE_EXECVE) -} - -static void -process_set_name (WapiHandle_process *process_handle) -{ - char *progname, *utf8_progname, *slash; - - progname = g_get_prgname (); - utf8_progname = mono_utf8_from_external (progname); - - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: using [%s] as prog name", __func__, progname); - - if (utf8_progname) { - slash = strrchr (utf8_progname, '/'); - if (slash) - process_handle->proc_name = g_strdup (slash+1); - else - process_handle->proc_name = g_strdup (utf8_progname); - g_free (utf8_progname); - } -} - -void -_wapi_processes_init (void) -{ - pid_t pid = wapi_getpid (); - WapiHandle_process process_handle = {0}; - - mono_w32handle_register_ops (MONO_W32HANDLE_PROCESS, &_wapi_process_ops); - - mono_w32handle_register_capabilities (MONO_W32HANDLE_PROCESS, - (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SPECIAL_WAIT)); - - process_handle.id = pid; - - process_set_defaults (&process_handle); - process_set_name (&process_handle); - - current_process = mono_w32handle_new (MONO_W32HANDLE_PROCESS, - &process_handle); - g_assert (current_process); - - mono_os_mutex_init (&mono_processes_mutex); -} - -gpointer -_wapi_process_duplicate (void) -{ - mono_w32handle_ref (current_process); - - return current_process; -} - -/* Returns a pseudo handle that doesn't need to be closed afterwards */ -gpointer -GetCurrentProcess (void) -{ - return _WAPI_PROCESS_CURRENT; -} - -guint32 -GetProcessId (gpointer handle) -{ - WapiHandle_process *process_handle; - - if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)) - /* This is a pseudo handle */ - return WAPI_HANDLE_TO_PID (handle); - - process_handle = lookup_process_handle (handle); - if (!process_handle) { - SetLastError (ERROR_INVALID_HANDLE); - return 0; - } - - return process_handle->id; -} - -static gboolean -process_open_compare (gpointer handle, gpointer user_data) -{ - pid_t wanted_pid; - WapiHandle_process *process_handle; - pid_t checking_pid; - - g_assert (!WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)); - - process_handle = lookup_process_handle (handle); - g_assert (process_handle); - - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: looking at process %d", __func__, process_handle->id); - - checking_pid = process_handle->id; - - if (checking_pid == 0) - return FALSE; - - wanted_pid = GPOINTER_TO_UINT (user_data); - - /* It's possible to have more than one process handle with the - * same pid, but only the one running process can be - * unsignalled - */ - if (checking_pid == wanted_pid && - !mono_w32handle_issignalled (handle)) { - /* If the handle is blown away in the window between - * returning TRUE here and mono_w32handle_search pinging - * the timestamp, the search will continue - */ - return TRUE; - } else { - return FALSE; - } -} - -gboolean -CloseProcess (gpointer handle) -{ - if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)) - return TRUE; - return CloseHandle (handle); -} - -/* - * The caller owns the returned handle and must call CloseProcess () on it to clean it up. - */ -gpointer -OpenProcess (guint32 req_access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 pid) -{ - /* Find the process handle that corresponds to pid */ - gpointer handle = NULL; - - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: looking for process %d", __func__, pid); - - handle = mono_w32handle_search (MONO_W32HANDLE_PROCESS, - process_open_compare, - GUINT_TO_POINTER (pid), NULL, TRUE); - if (handle == 0) { - if (is_pid_valid (pid)) { - /* Return a pseudo handle for processes we - * don't have handles for - */ - return WAPI_PID_TO_HANDLE (pid); - } else { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find pid %d", __func__, pid); - - SetLastError (ERROR_PROC_NOT_FOUND); - - return NULL; - } - } - - /* mono_w32handle_search () already added a ref */ - return handle; -} - -gboolean -GetExitCodeProcess (gpointer process, guint32 *code) -{ - WapiHandle_process *process_handle; - guint32 pid = -1; - gboolean alerted; - - if (!code) - return FALSE; - - if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) { - pid = WAPI_HANDLE_TO_PID (process); - /* This is a pseudo handle, so we don't know what the - * exit code was, but we can check whether it's alive or not - */ - if (is_pid_valid (pid)) { - *code = STILL_ACTIVE; - return TRUE; - } else { - *code = -1; - return TRUE; - } - } - - process_handle = lookup_process_handle (process); - if (!process_handle) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, process); - - return FALSE; - } - - if (process_handle->id == wapi_getpid ()) { - *code = STILL_ACTIVE; - return TRUE; - } - - /* A process handle is only signalled if the process has exited - * and has been waited for */ - - /* Make sure any process exit has been noticed, before - * checking if the process is signalled. Fixes bug 325463. - */ - process_wait (process, 0, &alerted); - - if (mono_w32handle_issignalled (process)) - *code = process_handle->exitstatus; - else - *code = STILL_ACTIVE; - - return TRUE; -} - -gboolean -GetProcessTimes (gpointer process, WapiFileTime *create_time, - WapiFileTime *exit_time, WapiFileTime *kernel_time, - WapiFileTime *user_time) -{ - WapiHandle_process *process_handle; - gboolean ku_times_set = FALSE; - - if (create_time == NULL || exit_time == NULL || kernel_time == NULL || - user_time == NULL) - /* Not sure if w32 allows NULLs here or not */ - return FALSE; - - if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) { - gpointer pid = GINT_TO_POINTER (WAPI_HANDLE_TO_PID(process)); - gint64 start_ticks, user_ticks, kernel_ticks; - - mono_process_get_times (pid, &start_ticks, &user_ticks, &kernel_ticks); - - _wapi_guint64_to_filetime (start_ticks, create_time); - _wapi_guint64_to_filetime (user_ticks, kernel_time); - _wapi_guint64_to_filetime (kernel_ticks, user_time); - - return TRUE; - } - - process_handle = lookup_process_handle (process); - if (!process_handle) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, process); - - return FALSE; - } - - *create_time = process_handle->create_time; - - /* A process handle is only signalled if the process has - * exited. Otherwise exit_time isn't set - */ - if (mono_w32handle_issignalled (process)) - *exit_time = process_handle->exit_time; - -#ifdef HAVE_GETRUSAGE - if (process_handle->id == getpid ()) { - struct rusage time_data; - if (getrusage (RUSAGE_SELF, &time_data) == 0) { - guint64 tick_val; - ku_times_set = TRUE; - tick_val = (guint64)time_data.ru_utime.tv_sec * 10000000 + (guint64)time_data.ru_utime.tv_usec * 10; - _wapi_guint64_to_filetime (tick_val, user_time); - tick_val = (guint64)time_data.ru_stime.tv_sec * 10000000 + (guint64)time_data.ru_stime.tv_usec * 10; - _wapi_guint64_to_filetime (tick_val, kernel_time); - } - } -#endif - if (!ku_times_set) { - memset (kernel_time, 0, sizeof (WapiFileTime)); - memset (user_time, 0, sizeof (WapiFileTime)); - } - - return TRUE; -} - -typedef struct -{ - gpointer address_start; - gpointer address_end; - char *perms; - gpointer address_offset; - guint64 device; - guint64 inode; - char *filename; -} WapiProcModule; - -static void free_procmodule (WapiProcModule *mod) -{ - if (mod->perms != NULL) { - g_free (mod->perms); - } - if (mod->filename != NULL) { - g_free (mod->filename); - } - g_free (mod); -} - -static gint find_procmodule (gconstpointer a, gconstpointer b) -{ - WapiProcModule *want = (WapiProcModule *)a; - WapiProcModule *compare = (WapiProcModule *)b; - - if ((want->device == compare->device) && - (want->inode == compare->inode)) { - return(0); - } else { - return(1); - } -} - -#if defined(USE_OSX_LOADER) -#include -#include - -static GSList *load_modules (void) -{ - GSList *ret = NULL; - WapiProcModule *mod; - uint32_t count = _dyld_image_count (); - int i = 0; - - for (i = 0; i < count; i++) { -#if SIZEOF_VOID_P == 8 - const struct mach_header_64 *hdr; - const struct section_64 *sec; -#else - const struct mach_header *hdr; - const struct section *sec; -#endif - const char *name; - - name = _dyld_get_image_name (i); -#if SIZEOF_VOID_P == 8 - hdr = (const struct mach_header_64*)_dyld_get_image_header (i); - sec = getsectbynamefromheader_64 (hdr, SEG_DATA, SECT_DATA); -#else - hdr = _dyld_get_image_header (i); - sec = getsectbynamefromheader (hdr, SEG_DATA, SECT_DATA); -#endif - - /* Some dynlibs do not have data sections on osx (#533893) */ - if (sec == 0) { - continue; - } - - mod = g_new0 (WapiProcModule, 1); - mod->address_start = GINT_TO_POINTER (sec->addr); - mod->address_end = GINT_TO_POINTER (sec->addr+sec->size); - mod->perms = g_strdup ("r--p"); - mod->address_offset = 0; - mod->device = makedev (0, 0); - mod->inode = i; - mod->filename = g_strdup (name); - - if (g_slist_find_custom (ret, mod, find_procmodule) == NULL) { - ret = g_slist_prepend (ret, mod); - } else { - free_procmodule (mod); - } - } - - ret = g_slist_reverse (ret); - - return(ret); -} -#elif defined(USE_BSD_LOADER) -#include -static int load_modules_callback (struct dl_phdr_info *info, size_t size, void *ptr) -{ - if (size < offsetof (struct dl_phdr_info, dlpi_phnum) - + sizeof (info->dlpi_phnum)) - return (-1); - - struct dl_phdr_info *cpy = g_calloc (1, sizeof(struct dl_phdr_info)); - if (!cpy) - return (-1); - - memcpy(cpy, info, sizeof(*info)); - - g_ptr_array_add ((GPtrArray *)ptr, cpy); - - return (0); -} - -static GSList *load_modules (void) -{ - GSList *ret = NULL; - WapiProcModule *mod; - GPtrArray *dlarray = g_ptr_array_new(); - int i; - - if (dl_iterate_phdr(load_modules_callback, dlarray) < 0) - return (ret); - - for (i = 0; i < dlarray->len; i++) { - struct dl_phdr_info *info = g_ptr_array_index (dlarray, i); - - mod = g_new0 (WapiProcModule, 1); - mod->address_start = (gpointer)(info->dlpi_addr + info->dlpi_phdr[0].p_vaddr); - mod->address_end = (gpointer)(info->dlpi_addr + - info->dlpi_phdr[info->dlpi_phnum - 1].p_vaddr); - mod->perms = g_strdup ("r--p"); - mod->address_offset = 0; - mod->inode = i; - mod->filename = g_strdup (info->dlpi_name); - - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: inode=%d, filename=%s, address_start=%p, address_end=%p", __func__, - mod->inode, mod->filename, mod->address_start, mod->address_end); - - g_free (info); - - if (g_slist_find_custom (ret, mod, find_procmodule) == NULL) { - ret = g_slist_prepend (ret, mod); - } else { - free_procmodule (mod); - } - } - - g_ptr_array_free (dlarray, TRUE); - - ret = g_slist_reverse (ret); - - return(ret); -} -#elif defined(USE_HAIKU_LOADER) - -static GSList *load_modules (void) -{ - GSList *ret = NULL; - WapiProcModule *mod; - int32 cookie = 0; - image_info imageInfo; - - while (get_next_image_info (B_CURRENT_TEAM, &cookie, &imageInfo) == B_OK) { - mod = g_new0 (WapiProcModule, 1); - mod->device = imageInfo.device; - mod->inode = imageInfo.node; - mod->filename = g_strdup (imageInfo.name); - mod->address_start = MIN (imageInfo.text, imageInfo.data); - mod->address_end = MAX ((uint8_t*)imageInfo.text + imageInfo.text_size, - (uint8_t*)imageInfo.data + imageInfo.data_size); - mod->perms = g_strdup ("r--p"); - mod->address_offset = 0; - - if (g_slist_find_custom (ret, mod, find_procmodule) == NULL) { - ret = g_slist_prepend (ret, mod); - } else { - free_procmodule (mod); - } - } - - ret = g_slist_reverse (ret); - - return ret; -} -#else -static GSList *load_modules (FILE *fp) -{ - GSList *ret = NULL; - WapiProcModule *mod; - char buf[MAXPATHLEN + 1], *p, *endp; - char *start_start, *end_start, *prot_start, *offset_start; - char *maj_dev_start, *min_dev_start, *inode_start, prot_buf[5]; - gpointer address_start, address_end, address_offset; - guint32 maj_dev, min_dev; - guint64 inode; - guint64 device; - - while (fgets (buf, sizeof(buf), fp)) { - p = buf; - while (g_ascii_isspace (*p)) ++p; - start_start = p; - if (!g_ascii_isxdigit (*start_start)) { - continue; - } - address_start = (gpointer)strtoul (start_start, &endp, 16); - p = endp; - if (*p != '-') { - continue; - } - - ++p; - end_start = p; - if (!g_ascii_isxdigit (*end_start)) { - continue; - } - address_end = (gpointer)strtoul (end_start, &endp, 16); - p = endp; - if (!g_ascii_isspace (*p)) { - continue; - } - - while (g_ascii_isspace (*p)) ++p; - prot_start = p; - if (*prot_start != 'r' && *prot_start != '-') { - continue; - } - memcpy (prot_buf, prot_start, 4); - prot_buf[4] = '\0'; - while (!g_ascii_isspace (*p)) ++p; - - while (g_ascii_isspace (*p)) ++p; - offset_start = p; - if (!g_ascii_isxdigit (*offset_start)) { - continue; - } - address_offset = (gpointer)strtoul (offset_start, &endp, 16); - p = endp; - if (!g_ascii_isspace (*p)) { - continue; - } - - while(g_ascii_isspace (*p)) ++p; - maj_dev_start = p; - if (!g_ascii_isxdigit (*maj_dev_start)) { - continue; - } - maj_dev = strtoul (maj_dev_start, &endp, 16); - p = endp; - if (*p != ':') { - continue; - } - - ++p; - min_dev_start = p; - if (!g_ascii_isxdigit (*min_dev_start)) { - continue; - } - min_dev = strtoul (min_dev_start, &endp, 16); - p = endp; - if (!g_ascii_isspace (*p)) { - continue; - } - - while (g_ascii_isspace (*p)) ++p; - inode_start = p; - if (!g_ascii_isxdigit (*inode_start)) { - continue; - } - inode = (guint64)strtol (inode_start, &endp, 10); - p = endp; - if (!g_ascii_isspace (*p)) { - continue; - } - - device = makedev ((int)maj_dev, (int)min_dev); - if ((device == 0) && - (inode == 0)) { - continue; - } - - while(g_ascii_isspace (*p)) ++p; - /* p now points to the filename */ - - mod = g_new0 (WapiProcModule, 1); - mod->address_start = address_start; - mod->address_end = address_end; - mod->perms = g_strdup (prot_buf); - mod->address_offset = address_offset; - mod->device = device; - mod->inode = inode; - mod->filename = g_strdup (g_strstrip (p)); - - if (g_slist_find_custom (ret, mod, find_procmodule) == NULL) { - ret = g_slist_prepend (ret, mod); - } else { - free_procmodule (mod); - } - } - - ret = g_slist_reverse (ret); - - return(ret); -} -#endif - -static gboolean match_procname_to_modulename (char *procname, char *modulename) -{ - char* lastsep = NULL; - char* lastsep2 = NULL; - char* pname = NULL; - char* mname = NULL; - gboolean result = FALSE; - - if (procname == NULL || modulename == NULL) - return (FALSE); - - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: procname=\"%s\", modulename=\"%s\"", __func__, procname, modulename); - pname = mono_path_resolve_symlinks (procname); - mname = mono_path_resolve_symlinks (modulename); - - if (!strcmp (pname, mname)) - result = TRUE; - - if (!result) { - lastsep = strrchr (mname, '/'); - if (lastsep) - if (!strcmp (lastsep+1, pname)) - result = TRUE; - if (!result) { - lastsep2 = strrchr (pname, '/'); - if (lastsep2){ - if (lastsep) { - if (!strcmp (lastsep+1, lastsep2+1)) - result = TRUE; - } else { - if (!strcmp (mname, lastsep2+1)) - result = TRUE; - } - } - } - } - - g_free (pname); - g_free (mname); - - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: result is %d", __func__, result); - return result; -} - -#if !(defined(USE_OSX_LOADER) || defined(USE_BSD_LOADER) || defined(USE_HAIKU_LOADER)) -static FILE * -open_process_map (int pid, const char *mode) -{ - FILE *fp = NULL; - const char *proc_path[] = { - "/proc/%d/maps", /* GNU/Linux */ - "/proc/%d/map", /* FreeBSD */ - NULL - }; - int i; - char *filename; - - for (i = 0; fp == NULL && proc_path [i]; i++) { - filename = g_strdup_printf (proc_path[i], pid); - fp = fopen (filename, mode); - g_free (filename); - } - - return fp; -} -#endif - -static char *get_process_name_from_proc (pid_t pid); - -gboolean EnumProcessModules (gpointer process, gpointer *modules, - guint32 size, guint32 *needed) -{ - WapiHandle_process *process_handle; -#if !defined(USE_OSX_LOADER) && !defined(USE_BSD_LOADER) - FILE *fp; -#endif - GSList *mods = NULL; - WapiProcModule *module; - guint32 count, avail = size / sizeof(gpointer); - int i; - pid_t pid; - char *proc_name = NULL; - - /* Store modules in an array of pointers (main module as - * modules[0]), using the load address for each module as a - * token. (Use 'NULL' as an alternative for the main module - * so that the simple implementation can just return one item - * for now.) Get the info from /proc//maps on linux, - * /proc//map on FreeBSD, other systems will have to - * implement /dev/kmem reading or whatever other horrid - * technique is needed. - */ - if (size < sizeof(gpointer)) - return FALSE; - - if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) { - pid = WAPI_HANDLE_TO_PID (process); - proc_name = get_process_name_from_proc (pid); - } else { - process_handle = lookup_process_handle (process); - if (!process_handle) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, process); - - return FALSE; - } - pid = process_handle->id; - proc_name = g_strdup (process_handle->proc_name); - } - -#if defined(USE_OSX_LOADER) || defined(USE_BSD_LOADER) || defined(USE_HAIKU_LOADER) - mods = load_modules (); - if (!proc_name) { - modules[0] = NULL; - *needed = sizeof(gpointer); - return TRUE; - } -#else - fp = open_process_map (pid, "r"); - if (!fp) { - /* No /proc//maps so just return the main module - * shortcut for now - */ - modules[0] = NULL; - *needed = sizeof(gpointer); - g_free (proc_name); - return TRUE; - } - mods = load_modules (fp); - fclose (fp); -#endif - count = g_slist_length (mods); - - /* count + 1 to leave slot 0 for the main module */ - *needed = sizeof(gpointer) * (count + 1); - - /* - * Use the NULL shortcut, as the first line in - * /proc//maps isn't the executable, and we need - * that first in the returned list. Check the module name - * to see if it ends with the proc name and substitute - * the first entry with it. FIXME if this turns out to - * be a problem. - */ - modules[0] = NULL; - for (i = 0; i < (avail - 1) && i < count; i++) { - module = (WapiProcModule *)g_slist_nth_data (mods, i); - if (modules[0] != NULL) - modules[i] = module->address_start; - else if (match_procname_to_modulename (proc_name, module->filename)) - modules[0] = module->address_start; - else - modules[i + 1] = module->address_start; - } - - for (i = 0; i < count; i++) { - free_procmodule ((WapiProcModule *)g_slist_nth_data (mods, i)); - } - g_slist_free (mods); - g_free (proc_name); - - return TRUE; -} - -static char * -get_process_name_from_proc (pid_t pid) -{ -#if defined(USE_BSD_LOADER) - int mib [6]; - size_t size; - struct kinfo_proc *pi; -#elif defined(USE_OSX_LOADER) -#if !(!defined (__mono_ppc__) && defined (TARGET_OSX)) - size_t size; - struct kinfo_proc *pi; - int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid }; -#endif -#else - FILE *fp; - char *filename = NULL; -#endif - char buf[256]; - char *ret = NULL; - -#if defined(PLATFORM_SOLARIS) - filename = g_strdup_printf ("/proc/%d/psinfo", pid); - if ((fp = fopen (filename, "r")) != NULL) { - struct psinfo info; - int nread; - - nread = fread (&info, sizeof (info), 1, fp); - if (nread == 1) { - ret = g_strdup (info.pr_fname); - } - - fclose (fp); - } - g_free (filename); -#elif defined(USE_OSX_LOADER) -#if !defined (__mono_ppc__) && defined (TARGET_OSX) - /* No proc name on OSX < 10.5 nor ppc nor iOS */ - memset (buf, '\0', sizeof(buf)); - proc_name (pid, buf, sizeof(buf)); - - // Fixes proc_name triming values to 15 characters #32539 - if (strlen (buf) >= MAXCOMLEN - 1) { - char path_buf [PROC_PIDPATHINFO_MAXSIZE]; - char *name_buf; - int path_len; - - memset (path_buf, '\0', sizeof(path_buf)); - path_len = proc_pidpath (pid, path_buf, sizeof(path_buf)); - - if (path_len > 0 && path_len < sizeof(path_buf)) { - name_buf = path_buf + path_len; - for(;name_buf > path_buf; name_buf--) { - if (name_buf [0] == '/') { - name_buf++; - break; - } - } - - if (memcmp (buf, name_buf, MAXCOMLEN - 1) == 0) - ret = g_strdup (name_buf); - } - } - - if (ret == NULL && strlen (buf) > 0) - ret = g_strdup (buf); -#else - if (sysctl(mib, 4, NULL, &size, NULL, 0) < 0) - return(ret); - - if ((pi = g_malloc (size)) == NULL) - return(ret); - - if (sysctl (mib, 4, pi, &size, NULL, 0) < 0) { - if (errno == ENOMEM) { - g_free (pi); - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Didn't allocate enough memory for kproc info", __func__); - } - return(ret); - } - - if (strlen (pi->kp_proc.p_comm) > 0) - ret = g_strdup (pi->kp_proc.p_comm); - - g_free (pi); -#endif -#elif defined(USE_BSD_LOADER) -#if defined(__FreeBSD__) - mib [0] = CTL_KERN; - mib [1] = KERN_PROC; - mib [2] = KERN_PROC_PID; - mib [3] = pid; - if (sysctl(mib, 4, NULL, &size, NULL, 0) < 0) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sysctl() failed: %d", __func__, errno); - return(ret); - } - - if ((pi = g_malloc (size)) == NULL) - return(ret); - - if (sysctl (mib, 4, pi, &size, NULL, 0) < 0) { - if (errno == ENOMEM) { - g_free (pi); - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Didn't allocate enough memory for kproc info", __func__); - } - return(ret); - } - - if (strlen (pi->ki_comm) > 0) - ret = g_strdup (pi->ki_comm); - g_free (pi); -#elif defined(__OpenBSD__) - mib [0] = CTL_KERN; - mib [1] = KERN_PROC; - mib [2] = KERN_PROC_PID; - mib [3] = pid; - mib [4] = sizeof(struct kinfo_proc); - mib [5] = 0; - -retry: - if (sysctl(mib, 6, NULL, &size, NULL, 0) < 0) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sysctl() failed: %d", __func__, errno); - return(ret); - } - - if ((pi = g_malloc (size)) == NULL) - return(ret); - - mib[5] = (int)(size / sizeof(struct kinfo_proc)); - - if ((sysctl (mib, 6, pi, &size, NULL, 0) < 0) || - (size != sizeof (struct kinfo_proc))) { - if (errno == ENOMEM) { - g_free (pi); - goto retry; - } - return(ret); - } - - if (strlen (pi->p_comm) > 0) - ret = g_strdup (pi->p_comm); - - g_free (pi); -#endif -#elif defined(USE_HAIKU_LOADER) - image_info imageInfo; - int32 cookie = 0; - - if (get_next_image_info ((team_id)pid, &cookie, &imageInfo) == B_OK) { - ret = g_strdup (imageInfo.name); - } -#else - memset (buf, '\0', sizeof(buf)); - filename = g_strdup_printf ("/proc/%d/exe", pid); - if (readlink (filename, buf, 255) > 0) { - ret = g_strdup (buf); - } - g_free (filename); - - if (ret != NULL) { - return(ret); - } - - filename = g_strdup_printf ("/proc/%d/cmdline", pid); - if ((fp = fopen (filename, "r")) != NULL) { - if (fgets (buf, 256, fp) != NULL) { - ret = g_strdup (buf); - } - - fclose (fp); - } - g_free (filename); - - if (ret != NULL) { - return(ret); - } - - filename = g_strdup_printf ("/proc/%d/stat", pid); - if ((fp = fopen (filename, "r")) != NULL) { - if (fgets (buf, 256, fp) != NULL) { - char *start, *end; - - start = strchr (buf, '('); - if (start != NULL) { - end = strchr (start + 1, ')'); - - if (end != NULL) { - ret = g_strndup (start + 1, - end - start - 1); - } - } - } - - fclose (fp); - } - g_free (filename); -#endif - - return ret; -} - -/* - * wapi_process_get_path: - * - * Return the full path of the executable of the process PID, or NULL if it cannot be determined. - * Returns malloc-ed memory. - */ -char* -wapi_process_get_path (pid_t pid) -{ -#if defined(PLATFORM_MACOSX) && !defined(__mono_ppc__) && defined(TARGET_OSX) - char buf [PROC_PIDPATHINFO_MAXSIZE]; - int res; - - res = proc_pidpath (pid, buf, sizeof (buf)); - if (res <= 0) - return NULL; - if (buf [0] == '\0') - return NULL; - return g_strdup (buf); -#else - return get_process_name_from_proc (pid); -#endif -} - -/* - * wapi_process_set_cli_launcher: - * - * Set the full path of the runtime executable used to launch managed exe's. - */ -void -wapi_process_set_cli_launcher (char *path) -{ - g_free (cli_launcher); - cli_launcher = path ? g_strdup (path) : NULL; -} - -static guint32 -get_module_name (gpointer process, gpointer module, - gunichar2 *basename, guint32 size, - gboolean base) -{ - WapiHandle_process *process_handle; - pid_t pid; - gunichar2 *procname; - char *procname_ext = NULL; - glong len; - gsize bytes; -#if !defined(USE_OSX_LOADER) && !defined(USE_BSD_LOADER) - FILE *fp; -#endif - GSList *mods = NULL; - WapiProcModule *found_module; - guint32 count; - int i; - char *proc_name = NULL; - - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Getting module base name, process handle %p module %p", - __func__, process, module); - - size = size * sizeof (gunichar2); /* adjust for unicode characters */ - - if (basename == NULL || size == 0) - return 0; - - if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) { - /* This is a pseudo handle */ - pid = (pid_t)WAPI_HANDLE_TO_PID (process); - proc_name = get_process_name_from_proc (pid); - } else { - process_handle = lookup_process_handle (process); - if (!process_handle) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, - process); - - return 0; - } - pid = process_handle->id; - proc_name = g_strdup (process_handle->proc_name); - } - - /* Look up the address in /proc//maps */ -#if defined(USE_OSX_LOADER) || defined(USE_BSD_LOADER) || defined(USE_HAIKU_LOADER) - mods = load_modules (); -#else - fp = open_process_map (pid, "r"); - if (fp == NULL) { - if (errno == EACCES && module == NULL && base == TRUE) { - procname_ext = get_process_name_from_proc (pid); - } else { - /* No /proc//maps, so just return failure - * for now - */ - g_free (proc_name); - return 0; - } - } else { - mods = load_modules (fp); - fclose (fp); - } -#endif - count = g_slist_length (mods); - - /* If module != NULL compare the address. - * If module == NULL we are looking for the main module. - * The best we can do for now check it the module name end with the process name. - */ - for (i = 0; i < count; i++) { - found_module = (WapiProcModule *)g_slist_nth_data (mods, i); - if (procname_ext == NULL && - ((module == NULL && match_procname_to_modulename (proc_name, found_module->filename)) || - (module != NULL && found_module->address_start == module))) { - if (base) - procname_ext = g_path_get_basename (found_module->filename); - else - procname_ext = g_strdup (found_module->filename); - } - - free_procmodule (found_module); - } - - if (procname_ext == NULL) { - /* If it's *still* null, we might have hit the - * case where reading /proc/$pid/maps gives an - * empty file for this user. - */ - procname_ext = get_process_name_from_proc (pid); - } - - g_slist_free (mods); - g_free (proc_name); - - if (procname_ext) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Process name is [%s]", __func__, - procname_ext); - - procname = mono_unicode_from_external (procname_ext, &bytes); - if (procname == NULL) { - /* bugger */ - g_free (procname_ext); - return 0; - } - - len = (bytes / 2); - - /* Add the terminator */ - bytes += 2; - - if (size < bytes) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Size %d smaller than needed (%ld); truncating", __func__, size, bytes); - - memcpy (basename, procname, size); - } else { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Size %d larger than needed (%ld)", - __func__, size, bytes); - - memcpy (basename, procname, bytes); - } - - g_free (procname); - g_free (procname_ext); - - return len; - } - - return 0; -} - -static guint32 -get_module_filename (gpointer process, gpointer module, - gunichar2 *basename, guint32 size) -{ - int pid, len; - gsize bytes; - char *path; - gunichar2 *proc_path; - - size *= sizeof (gunichar2); /* adjust for unicode characters */ - - if (basename == NULL || size == 0) - return 0; - - pid = GetProcessId (process); - - path = wapi_process_get_path (pid); - if (path == NULL) - return 0; - - proc_path = mono_unicode_from_external (path, &bytes); - g_free (path); - - if (proc_path == NULL) - return 0; - - len = (bytes / 2); - - /* Add the terminator */ - bytes += 2; - - if (size < bytes) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Size %d smaller than needed (%ld); truncating", __func__, size, bytes); - - memcpy (basename, proc_path, size); - } else { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Size %d larger than needed (%ld)", - __func__, size, bytes); - - memcpy (basename, proc_path, bytes); - } - - g_free (proc_path); - - return len; -} - -guint32 -GetModuleBaseName (gpointer process, gpointer module, - gunichar2 *basename, guint32 size) -{ - return get_module_name (process, module, basename, size, TRUE); -} - -guint32 -GetModuleFileNameEx (gpointer process, gpointer module, - gunichar2 *filename, guint32 size) -{ - return get_module_filename (process, module, filename, size); -} - -gboolean -GetModuleInformation (gpointer process, gpointer module, - WapiModuleInfo *modinfo, guint32 size) -{ - WapiHandle_process *process_handle; - pid_t pid; -#if !defined(USE_OSX_LOADER) && !defined(USE_BSD_LOADER) - FILE *fp; -#endif - GSList *mods = NULL; - WapiProcModule *found_module; - guint32 count; - int i; - gboolean ret = FALSE; - char *proc_name = NULL; - - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Getting module info, process handle %p module %p", - __func__, process, module); - - if (modinfo == NULL || size < sizeof (WapiModuleInfo)) - return FALSE; - - if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) { - pid = (pid_t)WAPI_HANDLE_TO_PID (process); - proc_name = get_process_name_from_proc (pid); - } else { - process_handle = lookup_process_handle (process); - if (!process_handle) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, - process); - - return FALSE; - } - pid = process_handle->id; - proc_name = g_strdup (process_handle->proc_name); - } - -#if defined(USE_OSX_LOADER) || defined(USE_BSD_LOADER) || defined(USE_HAIKU_LOADER) - mods = load_modules (); -#else - /* Look up the address in /proc//maps */ - if ((fp = open_process_map (pid, "r")) == NULL) { - /* No /proc//maps, so just return failure - * for now - */ - g_free (proc_name); - return FALSE; - } - mods = load_modules (fp); - fclose (fp); -#endif - count = g_slist_length (mods); - - /* If module != NULL compare the address. - * If module == NULL we are looking for the main module. - * The best we can do for now check it the module name end with the process name. - */ - for (i = 0; i < count; i++) { - found_module = (WapiProcModule *)g_slist_nth_data (mods, i); - if (ret == FALSE && - ((module == NULL && match_procname_to_modulename (proc_name, found_module->filename)) || - (module != NULL && found_module->address_start == module))) { - modinfo->lpBaseOfDll = found_module->address_start; - modinfo->SizeOfImage = (gsize)(found_module->address_end) - (gsize)(found_module->address_start); - modinfo->EntryPoint = found_module->address_offset; - ret = TRUE; - } - - free_procmodule (found_module); - } - - g_slist_free (mods); - g_free (proc_name); - - return ret; -} - -gboolean -GetProcessWorkingSetSize (gpointer process, size_t *min, size_t *max) -{ - WapiHandle_process *process_handle; - - if (min == NULL || max == NULL) - /* Not sure if w32 allows NULLs here or not */ - return FALSE; - - if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) - /* This is a pseudo handle, so just fail for now */ - return FALSE; - - process_handle = lookup_process_handle (process); - if (!process_handle) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, process); - - return FALSE; - } - - *min = process_handle->min_working_set; - *max = process_handle->max_working_set; - - return TRUE; -} - -gboolean -SetProcessWorkingSetSize (gpointer process, size_t min, size_t max) -{ - WapiHandle_process *process_handle; - - if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) - /* This is a pseudo handle, so just fail for now - */ - return FALSE; - - process_handle = lookup_process_handle (process); - if (!process_handle) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, process); - - return FALSE; - } - - process_handle->min_working_set = min; - process_handle->max_working_set = max; - - return TRUE; -} - - -gboolean -TerminateProcess (gpointer process, gint32 exitCode) -{ -#if defined(HAVE_KILL) - WapiHandle_process *process_handle; - int signo; - int ret; - pid_t pid; - - if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) { - /* This is a pseudo handle */ - pid = (pid_t)WAPI_HANDLE_TO_PID (process); - } else { - process_handle = lookup_process_handle (process); - if (!process_handle) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, process); - SetLastError (ERROR_INVALID_HANDLE); - return FALSE; - } - pid = process_handle->id; - } - - signo = (exitCode == -1) ? SIGKILL : SIGTERM; - ret = kill (pid, signo); - if (ret == -1) { - switch (errno) { - case EINVAL: - SetLastError (ERROR_INVALID_PARAMETER); - break; - case EPERM: - SetLastError (ERROR_ACCESS_DENIED); - break; - case ESRCH: - SetLastError (ERROR_PROC_NOT_FOUND); - break; - default: - SetLastError (ERROR_GEN_FAILURE); - } - } - - return (ret == 0); -#else - g_error ("kill() is not supported by this platform"); - return FALSE; -#endif -} - -guint32 -GetPriorityClass (gpointer process) -{ -#ifdef HAVE_GETPRIORITY - WapiHandle_process *process_handle; - int ret; - pid_t pid; - - if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) { - /* This is a pseudo handle */ - pid = (pid_t)WAPI_HANDLE_TO_PID (process); - } else { - process_handle = lookup_process_handle (process); - if (!process_handle) { - SetLastError (ERROR_INVALID_HANDLE); - return FALSE; - } - pid = process_handle->id; - } - - errno = 0; - ret = getpriority (PRIO_PROCESS, pid); - if (ret == -1 && errno != 0) { - switch (errno) { - case EPERM: - case EACCES: - SetLastError (ERROR_ACCESS_DENIED); - break; - case ESRCH: - SetLastError (ERROR_PROC_NOT_FOUND); - break; - default: - SetLastError (ERROR_GEN_FAILURE); - } - return FALSE; - } - - if (ret == 0) - return NORMAL_PRIORITY_CLASS; - else if (ret < -15) - return REALTIME_PRIORITY_CLASS; - else if (ret < -10) - return HIGH_PRIORITY_CLASS; - else if (ret < 0) - return ABOVE_NORMAL_PRIORITY_CLASS; - else if (ret > 10) - return IDLE_PRIORITY_CLASS; - else if (ret > 0) - return BELOW_NORMAL_PRIORITY_CLASS; - - return NORMAL_PRIORITY_CLASS; -#else - SetLastError (ERROR_NOT_SUPPORTED); - return 0; -#endif -} - -gboolean -SetPriorityClass (gpointer process, guint32 priority_class) -{ -#ifdef HAVE_SETPRIORITY - WapiHandle_process *process_handle; - int ret; - int prio; - pid_t pid; - - if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) { - /* This is a pseudo handle */ - pid = (pid_t)WAPI_HANDLE_TO_PID (process); - } else { - process_handle = lookup_process_handle (process); - if (!process_handle) { - SetLastError (ERROR_INVALID_HANDLE); - return FALSE; - } - pid = process_handle->id; - } - - switch (priority_class) { - case IDLE_PRIORITY_CLASS: - prio = 19; - break; - case BELOW_NORMAL_PRIORITY_CLASS: - prio = 10; - break; - case NORMAL_PRIORITY_CLASS: - prio = 0; - break; - case ABOVE_NORMAL_PRIORITY_CLASS: - prio = -5; - break; - case HIGH_PRIORITY_CLASS: - prio = -11; - break; - case REALTIME_PRIORITY_CLASS: - prio = -20; - break; - default: - SetLastError (ERROR_INVALID_PARAMETER); - return FALSE; - } - - ret = setpriority (PRIO_PROCESS, pid, prio); - if (ret == -1) { - switch (errno) { - case EPERM: - case EACCES: - SetLastError (ERROR_ACCESS_DENIED); - break; - case ESRCH: - SetLastError (ERROR_PROC_NOT_FOUND); - break; - default: - SetLastError (ERROR_GEN_FAILURE); - } - } - - return ret == 0; -#else - SetLastError (ERROR_NOT_SUPPORTED); - return FALSE; -#endif -} - -static void -mono_processes_cleanup (void) -{ - struct MonoProcess *mp; - struct MonoProcess *prev = NULL; - GSList *finished = NULL; - GSList *l; - gpointer unref_handle; - - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s", __func__); - - /* Ensure we're not in here in multiple threads at once, nor recursive. */ - if (InterlockedCompareExchange (&mono_processes_cleaning_up, 1, 0) != 0) - return; - - for (mp = mono_processes; mp; mp = mp->next) { - if (mp->pid == 0 && mp->handle) { - /* This process has exited and we need to remove the artifical ref - * on the handle */ - mono_os_mutex_lock (&mono_processes_mutex); - unref_handle = mp->handle; - mp->handle = NULL; - mono_os_mutex_unlock (&mono_processes_mutex); - if (unref_handle) - mono_w32handle_unref (unref_handle); - } - } - - /* - * Remove processes which exited from the mono_processes list. - * We need to synchronize with the sigchld handler here, which runs - * asynchronously. The handler requires that the mono_processes list - * remain valid. - */ - mono_os_mutex_lock (&mono_processes_mutex); - - mp = mono_processes; - while (mp) { - if (mp->handle_count == 0 && mp->freeable) { - /* - * Unlink the entry. - * This code can run parallel with the sigchld handler, but the - * modifications it makes are safe. - */ - if (mp == mono_processes) - mono_processes = mp->next; - else - prev->next = mp->next; - finished = g_slist_prepend (finished, mp); - - mp = mp->next; - } else { - prev = mp; - mp = mp->next; - } - } - - mono_memory_barrier (); - - for (l = finished; l; l = l->next) { - /* - * All the entries in the finished list are unlinked from mono_processes, and - * they have the 'finished' flag set, which means the sigchld handler is done - * accessing them. - */ - mp = (MonoProcess *)l->data; - mono_os_sem_destroy (&mp->exit_sem); - g_free (mp); - } - g_slist_free (finished); - - mono_os_mutex_unlock (&mono_processes_mutex); - - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s done", __func__); - - InterlockedDecrement (&mono_processes_cleaning_up); -} - -static void -process_close (gpointer handle, gpointer data) -{ - WapiHandle_process *process_handle; - - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s", __func__); - - process_handle = (WapiHandle_process *) data; - g_free (process_handle->proc_name); - process_handle->proc_name = NULL; - if (process_handle->mono_process) - InterlockedDecrement (&process_handle->mono_process->handle_count); - mono_processes_cleanup (); -} - -static void process_details (gpointer data) -{ - WapiHandle_process *process_handle = (WapiHandle_process *) data; - g_print ("id: %d, exited: %s, exitstatus: %d", - process_handle->id, process_handle->exited ? "true" : "false", process_handle->exitstatus); -} - -static const gchar* process_typename (void) -{ - return "Process"; -} - -static gsize process_typesize (void) -{ - return sizeof (WapiHandle_process); -} - -#if HAVE_SIGACTION -MONO_SIGNAL_HANDLER_FUNC (static, mono_sigchld_signal_handler, (int _dummy, siginfo_t *info, void *context)) -{ - int status; - int pid; - struct MonoProcess *p; - - do { - do { - pid = waitpid (-1, &status, WNOHANG); - } while (pid == -1 && errno == EINTR); - - if (pid <= 0) - break; - - /* - * This can run concurrently with the code in the rest of this module. - */ - for (p = mono_processes; p; p = p->next) { - if (p->pid == pid) { - break; - } - } - if (p) { - p->pid = 0; /* this pid doesn't exist anymore, clear it */ - p->status = status; - mono_os_sem_post (&p->exit_sem); - mono_memory_barrier (); - /* Mark this as freeable, the pointer becomes invalid afterwards */ - p->freeable = TRUE; - } - } while (1); -} - -#endif - -static void -process_add_sigchld_handler (void) -{ -#if HAVE_SIGACTION - struct sigaction sa; - - sa.sa_sigaction = mono_sigchld_signal_handler; - sigemptyset (&sa.sa_mask); - sa.sa_flags = SA_NOCLDSTOP | SA_SIGINFO; - g_assert (sigaction (SIGCHLD, &sa, &previous_chld_sa) != -1); - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "Added SIGCHLD handler"); -#endif -} - -static guint32 -process_wait (gpointer handle, guint32 timeout, gboolean *alerted) -{ - WapiHandle_process *process_handle; - pid_t pid G_GNUC_UNUSED, ret; - int status; - gint64 start, now; - struct MonoProcess *mp; - - /* FIXME: We can now easily wait on processes that aren't our own children, - * but WaitFor*Object won't call us for pseudo handles. */ - g_assert ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) != _WAPI_PROCESS_UNHANDLED); - - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u)", __func__, handle, timeout); - - if (alerted) - *alerted = FALSE; - - process_handle = lookup_process_handle (handle); - if (!process_handle) { - g_warning ("%s: error looking up process handle %p", __func__, handle); - return WAIT_FAILED; - } - - if (process_handle->exited) { - /* We've already done this one */ - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): Process already exited", __func__, handle, timeout); - return WAIT_OBJECT_0; - } - - pid = process_handle->id; - - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): PID: %d", __func__, handle, timeout, pid); - - /* We don't need to lock mono_processes here, the entry - * has a handle_count > 0 which means it will not be freed. */ - mp = process_handle->mono_process; - if (!mp) { - pid_t res; - - if (pid == mono_process_current_pid ()) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): waiting on current process", __func__, handle, timeout); - return WAIT_TIMEOUT; - } - - /* This path is used when calling Process.HasExited, so - * it is only used to poll the state of the process, not - * to actually wait on it to exit */ - g_assert (timeout == 0); - - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): waiting on non-child process", __func__, handle, timeout); - - res = waitpid (pid, &status, WNOHANG); - if (res == 0) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): non-child process WAIT_TIMEOUT", __func__, handle, timeout); - return WAIT_TIMEOUT; - } - if (res > 0) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): non-child process waited successfully", __func__, handle, timeout); - return WAIT_OBJECT_0; - } - - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): non-child process WAIT_FAILED, error : %s (%d))", __func__, handle, timeout, g_strerror (errno), errno); - return WAIT_FAILED; - } - - start = mono_msec_ticks (); - now = start; - - while (1) { - if (timeout != INFINITE) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): waiting on semaphore for %li ms...", - __func__, handle, timeout, (long)(timeout - (now - start))); - ret = mono_os_sem_timedwait (&mp->exit_sem, (timeout - (now - start)), alerted ? MONO_SEM_FLAGS_ALERTABLE : MONO_SEM_FLAGS_NONE); - } else { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): waiting on semaphore forever...", - __func__, handle, timeout); - ret = mono_os_sem_wait (&mp->exit_sem, alerted ? MONO_SEM_FLAGS_ALERTABLE : MONO_SEM_FLAGS_NONE); - } - - if (ret == MONO_SEM_TIMEDWAIT_RET_SUCCESS) { - /* Success, process has exited */ - mono_os_sem_post (&mp->exit_sem); - break; - } - - if (ret == MONO_SEM_TIMEDWAIT_RET_TIMEDOUT) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): WAIT_TIMEOUT (timeout = 0)", __func__, handle, timeout); - return WAIT_TIMEOUT; - } - - now = mono_msec_ticks (); - if (now - start >= timeout) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): WAIT_TIMEOUT", __func__, handle, timeout); - return WAIT_TIMEOUT; - } - - if (alerted && ret == MONO_SEM_TIMEDWAIT_RET_ALERTED) { - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): WAIT_IO_COMPLETION", __func__, handle, timeout); - *alerted = TRUE; - return WAIT_IO_COMPLETION; - } - } - - /* Process must have exited */ - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): Waited successfully", __func__, handle, timeout); - - status = mp ? mp->status : 0; - if (WIFSIGNALED (status)) - process_handle->exitstatus = 128 + WTERMSIG (status); - else - process_handle->exitstatus = WEXITSTATUS (status); - _wapi_time_t_to_filetime (time (NULL), &process_handle->exit_time); - - process_handle->exited = TRUE; - - MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): Setting pid %d signalled, exit status %d", - __func__, handle, timeout, process_handle->id, process_handle->exitstatus); - - mono_w32handle_set_signal_state (handle, TRUE, TRUE); - - return WAIT_OBJECT_0; -} - -void -wapi_processes_cleanup (void) -{ - g_free (cli_launcher); -} diff --git a/mono/io-layer/processes.h b/mono/io-layer/processes.h deleted file mode 100644 index c4da3eceee1..00000000000 --- a/mono/io-layer/processes.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - * processes.h: Process handles - * - * Author: - * Dick Porter (dick@ximian.com) - * - * (C) 2002 Ximian, Inc. - */ - -#ifndef _WAPI_PROCESSES_H_ -#define _WAPI_PROCESSES_H_ - -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#include - -#include -#include - -G_BEGIN_DECLS - -typedef enum { - STARTF_USESHOWWINDOW=0x001, - STARTF_USESIZE=0x002, - STARTF_USEPOSITION=0x004, - STARTF_USECOUNTCHARS=0x008, - STARTF_USEFILLATTRIBUTE=0x010, - STARTF_RUNFULLSCREEN=0x020, - STARTF_FORCEONFEEDBACK=0x040, - STARTF_FORCEOFFFEEDBACK=0x080, - STARTF_USESTDHANDLES=0x100 -} WapiStartupFlags; - - -typedef struct _WapiStartupInfo WapiStartupInfo; - -struct _WapiStartupInfo -{ - guint32 cb; - guchar *lpReserved; - guchar *lpDesktop; - guchar *lpTitle; - guint32 dwX; - guint32 dwY; - guint32 dwXSize; - guint32 dwYSize; - guint32 dwXCountChars; - guint32 dwYCountChars; - guint32 dwFillAttribute; - WapiStartupFlags dwFlags; - guint16 wShowWindow; - guint16 cbReserved2; - guint8 *lpReserved2; - gpointer hStdInput; - gpointer hStdOutput; - gpointer hStdError; -}; - -typedef struct _WapiProcessInformation WapiProcessInformation; - -struct _WapiProcessInformation -{ - gpointer hProcess; - gpointer hThread; - guint32 dwProcessId; - guint32 dwThreadId; -}; - -typedef enum { - SEE_MASK_CLASSNAME = 0x01, - SEE_MASK_CLASSKEY = 0x03, - SEE_MASK_IDLIST = 0x04, - SEE_MASK_INVOKEIDLIST = 0x0c, - SEE_MASK_ICON = 0x10, - SEE_MASK_HOTKEY = 0x20, - SEE_MASK_NOCLOSEPROCESS = 0x40, - SEE_MASK_CONNECTNETDRV = 0x80, - SEE_MASK_FLAG_DDEWAIT = 0x100, - SEE_MASK_DOENVSUBST = 0x200, - SEE_MASK_FLAG_NO_UI = 0x400, - SEE_MASK_NO_CONSOLE = 0x8000, - SEE_MASK_UNICODE = 0x10000, - SEE_MASK_HMONITOR = 0x200000, - /*SEE_MASK_FLAG_LOG_USAGE,*/ - /*SEE_MASK_NOZONECHECKS,*/ -} WapiShellExecuteInfoFlags; - -typedef enum { - SW_HIDE = 0, - SW_SHOWNORMAL = 1, - SW_SHOWMINIMIZED = 2, - SW_MAXIMIZE = 3, - SW_SHOWMAXIMIZED = 3, - SW_SHOWNOACTIVATE = 4, - SW_SHOW = 5, - SW_MINIMIZE = 6, - SW_SHOWMINNOACTIVE = 7, - SW_SHOWNA = 8, - SW_RESTORE = 9, - SW_SHOWDEFAULT = 10, -} WapiShellExecuteShowFlags; - -typedef struct _WapiShellExecuteInfo WapiShellExecuteInfo; - -struct _WapiShellExecuteInfo -{ - guint32 cbSize; - gulong fMask; - gpointer hwnd; - const gunichar2 *lpVerb; - const gunichar2 *lpFile; - const gunichar2 *lpParameters; - const gunichar2 *lpDirectory; - gulong nShow; - gpointer hInstApp; - gpointer lpIDList; - const gunichar2 *lpClass; - gpointer hkeyClass; - guint32 dwHotKey; - union - { - gpointer hIcon; - gpointer hMonitor; - } u; - gpointer hProcess; -}; - - -#define DEBUG_PROCESS 0x00000001 -#define DEBUG_ONLY_THIS_PROCESS 0x00000002 -#define DETACHED_PROCESS 0x00000008 -#define CREATE_NEW_CONSOLE 0x00000010 -#define NORMAL_PRIORITY_CLASS 0x00000020 -#define IDLE_PRIORITY_CLASS 0x00000040 -#define HIGH_PRIORITY_CLASS 0x00000080 -#define REALTIME_PRIORITY_CLASS 0x00000100 -#define CREATE_NEW_PROCESS_GROUP 0x00000200 -#define CREATE_UNICODE_ENVIRONMENT 0x00000400 -#define CREATE_SEPARATE_WOW_VDM 0x00000800 -#define CREATE_SHARED_WOW_VDM 0x00001000 -#define CREATE_FORCEDOS 0x00002000 -#define BELOW_NORMAL_PRIORITY_CLASS 0x00004000 -#define ABOVE_NORMAL_PRIORITY_CLASS 0x00008000 -#define CREATE_BREAKAWAY_FROM_JOB 0x01000000 -#define CREATE_WITH_USERPROFILE 0x02000000 -#define CREATE_DEFAULT_ERROR_MODE 0x04000000 -#define CREATE_NO_WINDOW 0x08000000 - -#ifdef NEW_STUFF -#define CREATE_PRESERVE_CODE_AUTHZ_LEVEL find out the value for this one... -#endif - -#define PROCESS_TERMINATE 0x0001 -#define PROCESS_CREATE_THREAD 0x0002 -#define PROCESS_SET_SESSIONID 0x0004 -#define PROCESS_VM_OPERATION 0x0008 -#define PROCESS_VM_READ 0x0010 -#define PROCESS_VM_WRITE 0x0020 -#define PROCESS_DUP_HANDLE 0x0040 -#define PROCESS_CREATE_PROCESS 0x0080 -#define PROCESS_SET_QUOTA 0x0100 -#define PROCESS_SET_INFORMATION 0x0200 -#define PROCESS_QUERY_INFORMATION 0x0400 -#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff) - -extern gboolean ShellExecuteEx (WapiShellExecuteInfo *sei); -extern gboolean CreateProcess (const gunichar2 *appname, - const gunichar2 *cmdline, - WapiSecurityAttributes *process_attrs, - WapiSecurityAttributes *thread_attrs, - gboolean inherit_handles, guint32 create_flags, - gpointer environ, const gunichar2 *cwd, - WapiStartupInfo *startup, - WapiProcessInformation *process_info); -extern gboolean CreateProcessWithLogonW (const gunichar2 *username, - const gunichar2 *domain, - const gunichar2 *password, - const guint32 logonFlags, - const gunichar2 *appname, - const gunichar2 *cmdline, - guint32 create_flags, - gpointer environ, - const gunichar2 *cwd, - WapiStartupInfo *startup, - WapiProcessInformation *process_info); -#define LOGON_WITH_PROFILE 0x00000001 -#define LOGON_NETCREDENTIALS_ONLY 0x00000002 - -extern gpointer GetCurrentProcess (void); -extern guint32 GetProcessId (gpointer handle); -extern gboolean CloseProcess (gpointer handle); -extern gpointer OpenProcess (guint32 access, gboolean inherit, guint32 pid); -extern gboolean GetExitCodeProcess (gpointer process, guint32 *code); -extern gboolean GetProcessTimes (gpointer process, WapiFileTime *create_time, - WapiFileTime *exit_time, - WapiFileTime *kernel_time, - WapiFileTime *user_time); -extern gboolean EnumProcessModules (gpointer process, gpointer *modules, - guint32 size, guint32 *needed); -extern guint32 GetModuleBaseName (gpointer process, gpointer module, - gunichar2 *basename, guint32 size); -extern guint32 GetModuleFileNameEx (gpointer process, gpointer module, - gunichar2 *filename, guint32 size); -extern gboolean GetModuleInformation (gpointer process, gpointer module, - WapiModuleInfo *modinfo, guint32 size); -extern gboolean GetProcessWorkingSetSize (gpointer process, size_t *min, - size_t *max); -extern gboolean SetProcessWorkingSetSize (gpointer process, size_t min, - size_t max); - -extern gboolean TerminateProcess (gpointer process, gint32 exitCode); - -extern guint32 GetPriorityClass (gpointer process); -extern gboolean SetPriorityClass (gpointer process, guint32 priority_class); - -gchar* wapi_process_get_path (pid_t pid); - -void wapi_process_set_cli_launcher (char *path); - -G_END_DECLS - -#endif /* _WAPI_PROCESSES_H_ */ diff --git a/mono/io-layer/sockets.c b/mono/io-layer/sockets.c index 05012d26fbb..b374973ebc6 100644 --- a/mono/io-layer/sockets.c +++ b/mono/io-layer/sockets.c @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include #include diff --git a/mono/io-layer/timefuncs-private.h b/mono/io-layer/timefuncs-private.h deleted file mode 100644 index ff008793d5b..00000000000 --- a/mono/io-layer/timefuncs-private.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * timefuncs-private.h: performance timer and other time private functions - * - * Author: - * Dick Porter (dick@ximian.com) - * - * (C) 2002 Ximian, Inc. - */ - -#ifndef _WAPI_TIMEFUNCS_PRIVATE_H_ -#define _WAPI_TIMEFUNCS_PRIVATE_H_ - -#include -#include -#include - -extern void _wapi_time_t_to_filetime (time_t timeval, WapiFileTime *filetime); -extern void _wapi_guint64_to_filetime (guint64 ticks, WapiFileTime *filetime); - -#endif /* _WAPI_TIMEFUNCS_PRIVATE_H_ */ diff --git a/mono/io-layer/timefuncs.c b/mono/io-layer/timefuncs.c index 0528ae6946d..7ec8e4a8ee7 100644 --- a/mono/io-layer/timefuncs.c +++ b/mono/io-layer/timefuncs.c @@ -14,7 +14,7 @@ #include #include -#include +#include #include "mono/utils/mono-time.h" #undef DEBUG @@ -27,9 +27,3 @@ void _wapi_time_t_to_filetime (time_t timeval, WapiFileTime *filetime) filetime->dwLowDateTime = ticks & 0xFFFFFFFF; filetime->dwHighDateTime = ticks >> 32; } - -void _wapi_guint64_to_filetime (guint64 ticks, WapiFileTime *filetime) -{ - filetime->dwLowDateTime = ticks & 0xFFFFFFFF; - filetime->dwHighDateTime = ticks >> 32; -} diff --git a/mono/io-layer/timefuncs.h b/mono/io-layer/timefuncs.h index d24800229f2..2b43396931b 100644 --- a/mono/io-layer/timefuncs.h +++ b/mono/io-layer/timefuncs.h @@ -12,6 +12,8 @@ #include +#include + #include "mono/io-layer/wapi.h" G_BEGIN_DECLS @@ -30,5 +32,7 @@ typedef struct #endif } WapiFileTime; +extern void _wapi_time_t_to_filetime (time_t timeval, WapiFileTime *filetime); + G_END_DECLS #endif /* _WAPI_TIME_H_ */ diff --git a/mono/io-layer/uglify.h b/mono/io-layer/uglify.h index 5176da07ea7..09fea6b7139 100644 --- a/mono/io-layer/uglify.h +++ b/mono/io-layer/uglify.h @@ -70,9 +70,6 @@ typedef WapiFindData WIN32_FIND_DATA; typedef WapiFindData *LPWIN32_FIND_DATA; typedef WapiFileAttributesData WIN32_FILE_ATTRIBUTE_DATA; typedef WapiGetFileExInfoLevels GET_FILEEX_INFO_LEVELS; -typedef WapiStartupInfo STARTUPINFO; -typedef WapiStartupInfo *LPSTARTUPINFO; -typedef WapiProcessInformation PROCESS_INFORMATION; typedef WapiFixedFileInfo VS_FIXEDFILEINFO; typedef WapiModuleInfo MODULEINFO; typedef WapiModuleInfo *LPMODULEINFO; @@ -102,8 +99,6 @@ typedef WapiImageResourceDirectoryEntry IMAGE_RESOURCE_DIRECTORY_ENTRY; typedef WapiImageResourceDirectoryEntry *PIMAGE_RESOURCE_DIRECTORY_ENTRY; typedef WapiImageResourceDataEntry IMAGE_RESOURCE_DATA_ENTRY; typedef WapiImageResourceDataEntry *PIMAGE_RESOURCE_DATA_ENTRY; -typedef WapiShellExecuteInfo SHELLEXECUTEINFO; -typedef WapiShellExecuteInfo *LPSHELLEXECUTEINFO; typedef WapiTransmitFileBuffers TRANSMIT_FILE_BUFFERS; typedef WapiTransmitFileBuffers *PTRANSMIT_FILE_BUFFERS; typedef WapiTransmitFileBuffers *LPTRANSMIT_FILE_BUFFERS; diff --git a/mono/io-layer/wait.c b/mono/io-layer/wait.c index aa58ea1614f..b7ff4684263 100644 --- a/mono/io-layer/wait.c +++ b/mono/io-layer/wait.c @@ -14,7 +14,7 @@ #include #include -#include +#include /** * WaitForSingleObjectEx: diff --git a/mono/io-layer/wait.h b/mono/io-layer/wait.h index b1fef4b1479..cbbf5d68203 100644 --- a/mono/io-layer/wait.h +++ b/mono/io-layer/wait.h @@ -11,7 +11,7 @@ #define _WAPI_WAIT_H_ #include "mono/io-layer/status.h" -#include "mono/utils/w32handle.h" +#include "mono/metadata/w32handle.h" G_BEGIN_DECLS diff --git a/mono/io-layer/wapi-private.h b/mono/io-layer/wapi-private.h index 8b82b609d19..9be764c1521 100644 --- a/mono/io-layer/wapi-private.h +++ b/mono/io-layer/wapi-private.h @@ -26,8 +26,7 @@ extern gboolean _wapi_has_shut_down; #include #include -#include -#include +#include struct _WapiHandle_shared_ref { diff --git a/mono/io-layer/wapi-remap.h b/mono/io-layer/wapi-remap.h index 935d2577225..783a9f1c4d4 100644 --- a/mono/io-layer/wapi-remap.h +++ b/mono/io-layer/wapi-remap.h @@ -52,24 +52,6 @@ #define UnlockFile wapi_UnlockFile #define GetVolumeInformation wapi_GetVolumeInformation #define FormatMessage wapi_FormatMessage -#define ShellExecuteEx wapi_ShellExecuteEx -#define CreateProcess wapi_CreateProcess -#define CreateProcessWithLogonW wapi_CreateProcessWithLogonW -#define GetCurrentProcess wapi_GetCurrentProcess -#define GetProcessId wapi_GetProcessId -#define CloseProcess wapi_CloseProcess -#define OpenProcess wapi_OpenProcess -#define GetExitCodeProcess wapi_GetExitCodeProcess -#define GetProcessTimes wapi_GetProcessTimes -#define EnumProcessModules wapi_EnumProcessModules -#define GetModuleBaseName wapi_GetModuleBaseName -#define GetModuleFileNameEx wapi_GetModuleFileNameEx -#define GetModuleInformation wapi_GetModuleInformation -#define GetProcessWorkingSetSize wapi_GetProcessWorkingSetSize -#define SetProcessWorkingSetSize wapi_SetProcessWorkingSetSize -#define TerminateProcess wapi_TerminateProcess -#define GetPriorityClass wapi_GetPriorityClass -#define SetPriorityClass wapi_SetPriorityClass #define ImpersonateLoggedOnUser wapi_ImpersonateLoggedOnUser #define RevertToSelf wapi_RevertToSelf #define WSASetLastError wapi_WSASetLastError diff --git a/mono/io-layer/wapi.c b/mono/io-layer/wapi.c index f1674179d9a..f162b0bb45c 100644 --- a/mono/io-layer/wapi.c +++ b/mono/io-layer/wapi.c @@ -3,11 +3,10 @@ #include "io-trace.h" #include "io.h" -#include "process-private.h" #include "socket-private.h" #include "mono/utils/mono-lazy-init.h" -#include "mono/utils/w32handle.h" +#include "mono/metadata/w32handle.h" gboolean _wapi_has_shut_down = FALSE; @@ -15,7 +14,6 @@ void wapi_init (void) { _wapi_io_init (); - _wapi_processes_init (); _wapi_socket_init (); } @@ -26,7 +24,6 @@ wapi_cleanup (void) _wapi_has_shut_down = TRUE; _wapi_error_cleanup (); - wapi_processes_cleanup (); _wapi_io_cleanup (); } @@ -54,19 +51,8 @@ gboolean DuplicateHandle (gpointer srcprocess, gpointer src, gpointer targetprocess, gpointer *target, guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 options G_GNUC_UNUSED) { - if (srcprocess != _WAPI_PROCESS_CURRENT || targetprocess != _WAPI_PROCESS_CURRENT) { - /* Duplicating other process's handles is not supported */ - SetLastError (ERROR_INVALID_HANDLE); - return FALSE; - } - - if (src == _WAPI_PROCESS_CURRENT) { - *target = _wapi_process_duplicate (); - } else { - mono_w32handle_ref (src); - *target = src; - } - + mono_w32handle_ref (src); + *target = src; return TRUE; } diff --git a/mono/io-layer/wapi.h b/mono/io-layer/wapi.h index c56622ea91c..1af86f7712c 100644 --- a/mono/io-layer/wapi.h +++ b/mono/io-layer/wapi.h @@ -14,11 +14,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include diff --git a/mono/metadata/Makefile.am b/mono/metadata/Makefile.am index 7e07c2549f5..a48d586713f 100644 --- a/mono/metadata/Makefile.am +++ b/mono/metadata/Makefile.am @@ -10,11 +10,11 @@ win32_sources = \ marshal-windows-internals.h \ mono-security-windows.c \ mono-security-windows-internals.h \ - process-windows.c \ - process-windows-internals.h \ w32mutex-win32.c \ w32semaphore-win32.c \ w32event-win32.c \ + w32process-win32.c \ + w32process-win32-internals.h \ socket-io-windows.c platform_sources = $(win32_sources) @@ -41,7 +41,13 @@ unix_sources = \ console-unix.c \ w32mutex-unix.c \ w32semaphore-unix.c \ - w32event-unix.c + w32event-unix.c \ + w32process-unix.c \ + w32process-unix-internals.h \ + w32process-unix-osx.c \ + w32process-unix-bsd.c \ + w32process-unix-haiku.c \ + w32process-unix-default.c platform_sources = $(unix_sources) endif @@ -119,6 +125,8 @@ common_sources = \ cil-coff.h \ class.c \ class-internals.h \ + class-inlines.h \ + class-accessors.c \ cominterop.c \ cominterop.h \ console-io.h \ @@ -195,9 +203,9 @@ common_sources = \ opcodes.c \ socket-io.c \ socket-io.h \ - process.c \ - process.h \ - process-internals.h \ + w32process.c \ + w32process.h \ + w32process-internals.h \ profiler.c \ profiler-private.h \ rand.h \ @@ -246,7 +254,9 @@ common_sources = \ w32semaphore.h \ w32event.h \ w32handle-namespace.h \ - w32handle-namespace.c + w32handle-namespace.c \ + w32handle.h \ + w32handle.c # These source files have compile time dependencies on GC code gc_dependent_sources = \ diff --git a/mono/metadata/appdomain.c b/mono/metadata/appdomain.c index e134b8f6120..db45a76a95e 100644 --- a/mono/metadata/appdomain.c +++ b/mono/metadata/appdomain.c @@ -68,7 +68,7 @@ #include #include #include -#include +#include #ifdef HOST_WIN32 #include #endif @@ -84,7 +84,7 @@ * Changes which are already detected at runtime, like the addition * of icalls, do not require an increment. */ -#define MONO_CORLIB_VERSION 160 +#define MONO_CORLIB_VERSION 162 typedef struct { @@ -2480,13 +2480,13 @@ mono_domain_unload (MonoDomain *domain) mono_domain_try_unload (domain, &exc); } -static guint32 -guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable) +static MonoThreadInfoWaitRet +guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable) { - guint32 result; + MonoThreadInfoWaitRet result; MONO_ENTER_GC_SAFE; - result = WaitForSingleObjectEx (handle, timeout, alertable); + result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable); MONO_EXIT_GC_SAFE; return result; @@ -2515,7 +2515,7 @@ void mono_domain_try_unload (MonoDomain *domain, MonoObject **exc) { MonoError error; - HANDLE thread_handle; + MonoThreadHandle *thread_handle; MonoAppDomainState prev_state; MonoMethod *method; unload_data *thread_data; @@ -2582,7 +2582,7 @@ mono_domain_try_unload (MonoDomain *domain, MonoObject **exc) return; /* Wait for the thread */ - while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) { + while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) { if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) { /* The unload thread tries to abort us */ /* The icall wrapper will execute the abort */ diff --git a/mono/metadata/assembly.c b/mono/metadata/assembly.c index 209e4ab4f98..cae45aa64ab 100644 --- a/mono/metadata/assembly.c +++ b/mono/metadata/assembly.c @@ -22,6 +22,7 @@ #include "object-internals.h" #include #include +#include #include #include #include @@ -205,8 +206,6 @@ static GSList *loaded_assembly_bindings = NULL; /* Class lazy loading functions */ static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, System.Runtime.CompilerServices, InternalsVisibleToAttribute) -static GENERATE_TRY_GET_CLASS_WITH_CACHE (reference_assembly, System.Runtime.CompilerServices, ReferenceAssemblyAttribute) - static MonoAssembly* mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload); static MonoAssembly* @@ -1768,7 +1767,7 @@ mono_assembly_load_friends (MonoAssembly* ass) if (ass->friend_assembly_names_inited) return; - attrs = mono_custom_attrs_from_assembly_checked (ass, &error); + attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error); mono_error_assert_ok (&error); if (!attrs) { mono_assemblies_lock (); @@ -1828,6 +1827,24 @@ mono_assembly_load_friends (MonoAssembly* ass) mono_assemblies_unlock (); } +struct HasReferenceAssemblyAttributeIterData { + gboolean has_attr; +}; + +static gboolean +has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data) +{ + gboolean stop_scanning = FALSE; + struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data; + + if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) { + /* Note we don't check the assembly name, same as coreCLR. */ + iter_data->has_attr = TRUE; + stop_scanning = TRUE; + } + + return stop_scanning; +} /** * mono_assembly_has_reference_assembly_attribute: @@ -1842,24 +1859,16 @@ mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoErro { mono_error_init (error); -/* TODO: mono_custom_attrs_from_assembly_checked returns NULL if a - * single assembly is missing. The custom attr we want is from - * corlib, however, so we need a more robust version that doesn't care - * about missing attributes. - */ -#if 0 - MonoCustomAttrInfo *attrs = mono_custom_attrs_from_assembly_checked (assembly, error); - return_val_if_nok (error, FALSE); - if (!attrs) - return FALSE; - MonoClass *ref_asm_class = mono_class_try_get_reference_assembly_class (); - g_assert (ref_asm_class != NULL && ref_asm_class != mono_defaults.object_class && !strcmp(ref_asm_class->name, "ReferenceAssemblyAttribute") ); - gboolean result = mono_custom_attrs_has_attr (attrs, ref_asm_class); - mono_custom_attrs_free (attrs); - return result; -#else - return FALSE; -#endif + /* + * This might be called during assembly loading, so do everything using the low-level + * metadata APIs. + */ + + struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE }; + + mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data); + + return iter_data.has_attr; } /** @@ -1981,24 +1990,6 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname, } } - mono_assemblies_lock (); - - if (image->assembly) { - /* - * This means another thread has already loaded the assembly, but not yet - * called the load hooks so the search hook can't find the assembly. - */ - mono_assemblies_unlock (); - ass2 = image->assembly; - g_free (ass); - g_free (base_dir); - mono_image_close (image); - *status = MONO_IMAGE_OK; - return ass2; - } - - mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name); - /* We need to check for ReferenceAssmeblyAttribute before we * mark the assembly as loaded and before we fire the load * hook. Otherwise mono_domain_fire_assembly_load () in @@ -2006,17 +1997,9 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname, * this image and we won't be able to look for a different * candidate. */ - if (!refonly && strcmp (ass->aname.name, "mscorlib") != 0) { - /* Don't check for reference assmebly attribute for - * corlib here because if corlib isn't loaded yet, - * it's too early to set up the - * ReferenceAssemblyAttribute class. We check that - * we're not running with a reference corlib in - * mono_init_internal(). - */ + if (!refonly) { MonoError refasm_error; if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) { - mono_assemblies_unlock (); mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name); g_free (ass); g_free (base_dir); @@ -2027,6 +2010,24 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname, mono_error_cleanup (&refasm_error); } + mono_assemblies_lock (); + + if (image->assembly) { + /* + * This means another thread has already loaded the assembly, but not yet + * called the load hooks so the search hook can't find the assembly. + */ + mono_assemblies_unlock (); + ass2 = image->assembly; + g_free (ass); + g_free (base_dir); + mono_image_close (image); + *status = MONO_IMAGE_OK; + return ass2; + } + + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name); + image->assembly = ass; loaded_assemblies = g_list_prepend (loaded_assemblies, ass); diff --git a/mono/metadata/attach.c b/mono/metadata/attach.c index 01d208c2ea2..2c4372ba4b4 100644 --- a/mono/metadata/attach.c +++ b/mono/metadata/attach.c @@ -94,7 +94,7 @@ static char *ipc_filename; static char *server_uri; -static HANDLE receiver_thread_handle; +static MonoThreadHandle *receiver_thread_handle; static gboolean stop_receiver_thread; @@ -260,7 +260,7 @@ mono_attach_cleanup (void) /* Wait for the receiver thread to exit */ if (receiver_thread_handle) - WaitForSingleObjectEx (receiver_thread_handle, 0, FALSE); + mono_thread_info_wait_one_handle (receiver_thread_handle, 0, FALSE); } static int diff --git a/mono/metadata/boehm-gc.c b/mono/metadata/boehm-gc.c index 2c648c85da6..0d47d88beda 100644 --- a/mono/metadata/boehm-gc.c +++ b/mono/metadata/boehm-gc.c @@ -1115,7 +1115,7 @@ create_allocator (int atype, int tls_key, gboolean slowpath) static MonoMethod* alloc_method_cache [ATYPE_NUM]; static MonoMethod* slowpath_alloc_method_cache [ATYPE_NUM]; -static G_GNUC_UNUSED gboolean +gboolean mono_gc_is_critical_method (MonoMethod *method) { int i; @@ -1234,7 +1234,7 @@ mono_gc_get_write_barrier (void) #else -static G_GNUC_UNUSED gboolean +gboolean mono_gc_is_critical_method (MonoMethod *method) { return FALSE; diff --git a/mono/metadata/class-accessors.c b/mono/metadata/class-accessors.c new file mode 100644 index 00000000000..fe793ddce7f --- /dev/null +++ b/mono/metadata/class-accessors.c @@ -0,0 +1,140 @@ +/* + * Copyright 2016 Microsoft + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ +#include +#include + + +/* Accessors based on class kind*/ + +/* +* mono_class_get_generic_class: +* +* Return the MonoGenericClass of @klass, which MUST be a generic instance. +*/ +MonoGenericClass* +mono_class_get_generic_class (MonoClass *klass) +{ + g_assert (mono_class_is_ginst (klass)); + return ((MonoClassGenericInst*)klass)->generic_class; +} + +/* +* mono_class_try_get_generic_class: +* +* Return the MonoGenericClass if @klass is a ginst, NULL otherwise +*/ +MonoGenericClass* +mono_class_try_get_generic_class (MonoClass *klass) +{ + if (mono_class_is_ginst (klass)) + return ((MonoClassGenericInst*)klass)->generic_class; + return NULL; +} + +/** + * mono_class_get_flags: + * @klass: the MonoClass to act on + * + * Return the TypeAttributes flags of @klass. + * See the TYPE_ATTRIBUTE_* definitions on tabledefs.h for the different values. + * + * Returns: The type flags + */ +guint32 +mono_class_get_flags (MonoClass *klass) +{ + switch (klass->class_kind) { + case MONO_CLASS_DEF: + case MONO_CLASS_GTD: + return ((MonoClassDef*)klass)->flags; + case MONO_CLASS_GINST: + return mono_class_get_flags (((MonoClassGenericInst*)klass)->generic_class->container_class); + case MONO_CLASS_GPARAM: + return TYPE_ATTRIBUTE_PUBLIC; + case MONO_CLASS_ARRAY: + /* all arrays are marked serializable and sealed, bug #42779 */ + return TYPE_ATTRIBUTE_CLASS | TYPE_ATTRIBUTE_SERIALIZABLE | TYPE_ATTRIBUTE_SEALED | TYPE_ATTRIBUTE_PUBLIC; + case MONO_CLASS_POINTER: + return TYPE_ATTRIBUTE_CLASS | (mono_class_get_flags (klass->element_class) & TYPE_ATTRIBUTE_VISIBILITY_MASK); + } + g_assert_not_reached (); +} + +void +mono_class_set_flags (MonoClass *klass, guint32 flags) +{ + g_assert (klass->class_kind == MONO_CLASS_DEF || klass->class_kind == MONO_CLASS_GTD); + ((MonoClassDef*)klass)->flags = flags; +} + +/* + * mono_class_get_generic_container: + * + * Return the generic container of KLASS which should be a generic type definition. + */ +MonoGenericContainer* +mono_class_get_generic_container (MonoClass *klass) +{ + g_assert (mono_class_is_gtd (klass)); + + return ((MonoClassGtd*)klass)->generic_container; +} + +MonoGenericContainer* +mono_class_try_get_generic_container (MonoClass *klass) +{ + if (mono_class_is_gtd (klass)) + return ((MonoClassGtd*)klass)->generic_container; + return NULL; +} + + +void +mono_class_set_generic_container (MonoClass *klass, MonoGenericContainer *container) +{ + g_assert (mono_class_is_gtd (klass)); + + ((MonoClassGtd*)klass)->generic_container = container; +} + +/* + * mono_class_get_first_method_idx: + * + * Return the table index of the first method for metadata classes. + */ +guint32 +mono_class_get_first_method_idx (MonoClass *klass) +{ + g_assert (mono_class_has_static_metadata (klass)); + + return ((MonoClassDef*)klass)->first_method_idx; +} + +void +mono_class_set_first_method_idx (MonoClass *klass, guint32 idx) +{ + g_assert (mono_class_has_static_metadata (klass)); + + ((MonoClassDef*)klass)->first_method_idx = idx; +} + +guint32 +mono_class_get_first_field_idx (MonoClass *klass) +{ + if (mono_class_is_ginst (klass)) + return mono_class_get_first_field_idx (mono_class_get_generic_class (klass)->container_class); + + g_assert (mono_class_has_static_metadata (klass)); + + return ((MonoClassDef*)klass)->first_field_idx; +} + +void +mono_class_set_first_field_idx (MonoClass *klass, guint32 idx) +{ + g_assert (mono_class_has_static_metadata (klass)); + + ((MonoClassDef*)klass)->first_field_idx = idx; +} diff --git a/mono/metadata/class-inlines.h b/mono/metadata/class-inlines.h new file mode 100644 index 00000000000..2e884ba3d35 --- /dev/null +++ b/mono/metadata/class-inlines.h @@ -0,0 +1,95 @@ +/* + * Copyright 2016 Microsoft + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ +#ifndef __MONO_METADATA_CLASS_INLINES_H__ +#define __MONO_METADATA_CLASS_INLINES_H__ + +#include +#include + +static inline gboolean +mono_class_is_def (MonoClass *klass) +{ + return klass->class_kind == MONO_CLASS_DEF; +} + +static inline gboolean +mono_class_is_gtd (MonoClass *klass) +{ + return klass->class_kind == MONO_CLASS_GTD; +} + +static inline gboolean +mono_class_is_ginst (MonoClass *klass) +{ + return klass->class_kind == MONO_CLASS_GINST; +} + +static inline gboolean +mono_class_is_gparam (MonoClass *klass) +{ + return klass->class_kind == MONO_CLASS_GPARAM; +} + +static inline gboolean +mono_class_is_array (MonoClass *klass) +{ + return klass->class_kind == MONO_CLASS_ARRAY; +} + +static inline gboolean +mono_class_is_pointer (MonoClass *klass) +{ + return klass->class_kind == MONO_CLASS_POINTER; +} + +static inline gboolean +mono_class_is_abstract (MonoClass *klass) +{ + return mono_class_get_flags (klass) & TYPE_ATTRIBUTE_ABSTRACT; +} + +static inline gboolean +mono_class_is_interface (MonoClass *klass) +{ + return mono_class_get_flags (klass) & TYPE_ATTRIBUTE_INTERFACE; +} + +static inline gboolean +mono_class_is_sealed (MonoClass *klass) +{ + return mono_class_get_flags (klass) & TYPE_ATTRIBUTE_SEALED; +} + +static inline gboolean +mono_class_is_before_field_init (MonoClass *klass) +{ + return mono_class_get_flags (klass) & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT; +} + +static inline gboolean +mono_class_is_auto_layout (MonoClass *klass) +{ + return (mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT; +} + +static inline gboolean +mono_class_is_explicit_layout (MonoClass *klass) +{ + return (mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT; +} + +static inline gboolean +mono_class_is_public (MonoClass *klass) +{ + return mono_class_get_flags (klass) & TYPE_ATTRIBUTE_PUBLIC; +} + +static inline gboolean +mono_class_has_static_metadata (MonoClass *klass) +{ + return klass->type_token && !klass->image->dynamic && !mono_class_is_ginst (klass); +} + +#endif diff --git a/mono/metadata/class-internals.h b/mono/metadata/class-internals.h index b2af4f79556..0c14ec3b042 100644 --- a/mono/metadata/class-internals.h +++ b/mono/metadata/class-internals.h @@ -16,7 +16,7 @@ #define MONO_CLASS_IS_ARRAY(c) ((c)->rank) -#define MONO_CLASS_HAS_STATIC_METADATA(klass) ((klass)->type_token && !(klass)->image->dynamic && !(klass)->generic_class) +#define MONO_CLASS_HAS_STATIC_METADATA(klass) ((klass)->type_token && !(klass)->image->dynamic && !mono_class_is_ginst (klass)) #define MONO_DEFAULT_SUPERTABLE_SIZE 6 @@ -256,6 +256,15 @@ typedef struct { GList *nested_classes; } MonoClassExt; +typedef enum { + MONO_CLASS_DEF = 1, /* non-generic type */ + MONO_CLASS_GTD, /* generic type definition */ + MONO_CLASS_GINST, /* generic instantiation */ + MONO_CLASS_GPARAM, /* generic parameter */ + MONO_CLASS_ARRAY, /* vector or array, bounded or not */ + MONO_CLASS_POINTER, /* pointer of function pointer*/ +} MonoTypeKind; + struct _MonoClass { /* element class for arrays and enum basetype for enums */ MonoClass *element_class; @@ -272,8 +281,6 @@ struct _MonoClass { int instance_size; /* object instance size */ guint inited : 1; - /* We use init_pending to detect cyclic calls to mono_class_init */ - guint init_pending : 1; /* A class contains static and non static data. Static data can be * of the same type as the class itselfs, but it does not influence @@ -317,10 +324,9 @@ struct _MonoClass { guint nested_classes_inited : 1; /* Whenever nested_class is initialized */ /* next byte*/ + guint class_kind : 3; /* One of the values from MonoTypeKind */ guint interfaces_inited : 1; /* interfaces is initialized */ guint simd_type : 1; /* class is a simd intrinsic type */ - guint is_generic : 1; /* class is a generic type definition */ - guint is_inflated : 1; /* class is a generic instance */ guint has_finalize_inited : 1; /* has_finalize is initialized */ guint fields_inited : 1; /* setup_fields () has finished */ guint has_failure : 1; /* See MONO_CLASS_PROP_EXCEPTION_DATA for a MonoErrorBoxed with the details */ @@ -336,8 +342,8 @@ struct _MonoClass { int vtable_size; /* number of slots */ guint16 interface_count; - guint16 interface_id; /* unique inderface id (for interfaces) */ - guint16 max_interface_id; + guint32 interface_id; /* unique inderface id (for interfaces) */ + guint32 max_interface_id; guint16 interface_offsets_count; MonoClass **interfaces_packed; @@ -359,14 +365,20 @@ struct _MonoClass { /* * From the TypeDef table */ - guint32 flags; struct { #if MONO_SMALL_CONFIG - guint16 first, count; + guint16 count; #else - guint32 first, count; + guint32 count; +#endif + } field; + struct { +#if MONO_SMALL_CONFIG + guint16 count; +#else + guint32 count; #endif - } field, method; + } method; /* A GC handle pointing to the corresponding type builder/generic param builder */ guint32 ref_info_handle; @@ -385,16 +397,10 @@ struct _MonoClass { MonoType this_arg; MonoType byval_arg; - MonoGenericClass *generic_class; - MonoGenericContainer *generic_container; - MonoGCDescriptor gc_descr; MonoClassRuntimeInfo *runtime_info; - /* next element in the class_cache hash list (in MonoImage) */ - MonoClass *next_class_cache; - /* Generic vtable. Initialized by a call to mono_class_setup_vtable () */ MonoMethod **vtable; @@ -402,6 +408,40 @@ struct _MonoClass { MonoClassExt *ext; }; +typedef struct { + MonoClass class; + guint32 flags; + /* + * From the TypeDef table + */ + guint32 first_method_idx; + guint32 first_field_idx; + /* next element in the class_cache hash list (in MonoImage) */ + MonoClass *next_class_cache; +} MonoClassDef; + +typedef struct { + MonoClassDef class; + MonoGenericContainer *generic_container; +} MonoClassGtd; + +typedef struct { + MonoClass class; + MonoGenericClass *generic_class; +} MonoClassGenericInst; + +typedef struct { + MonoClass class; +} MonoClassGenericParam; + +typedef struct { + MonoClass class; +} MonoClassArray; + +typedef struct { + MonoClass class; +} MonoClassPointer; + #ifdef COMPRESSED_INTERFACE_BITMAP int mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size); int mono_class_interface_match (const uint8_t *bitmap, int id); @@ -450,7 +490,7 @@ struct MonoVTable { MonoDomain *domain; /* each object/vtable belongs to exactly one domain */ gpointer type; /* System.Type type for klass */ guint8 *interface_bitmap; - guint16 max_interface_id; + guint32 max_interface_id; guint8 rank; guint remote : 1; /* class is remotely activated */ guint initialized : 1; /* cctor has been run */ @@ -1338,9 +1378,6 @@ mono_class_setup_interface_id (MonoClass *klass); MonoGenericContainer* mono_class_get_generic_container (MonoClass *klass); -MonoGenericClass* -mono_class_get_generic_class (MonoClass *klass); - gpointer mono_class_alloc (MonoClass *klass, int size); @@ -1433,4 +1470,35 @@ mono_error_set_for_class_failure (MonoError *orerror, const MonoClass *klass); gboolean mono_class_has_failure (const MonoClass *klass); +/* Kind specific accessors */ +MonoGenericClass* +mono_class_get_generic_class (MonoClass *klass); + +MonoGenericClass* +mono_class_try_get_generic_class (MonoClass *klass); + +void +mono_class_set_flags (MonoClass *klass, guint32 flags); + +MonoGenericContainer* +mono_class_try_get_generic_container (MonoClass *klass); + +void +mono_class_set_generic_container (MonoClass *klass, MonoGenericContainer *container); + +guint32 +mono_class_get_first_method_idx (MonoClass *klass); + +void +mono_class_set_first_method_idx (MonoClass *klass, guint32 idx); + +guint32 +mono_class_get_first_field_idx (MonoClass *klass); + +void +mono_class_set_first_field_idx (MonoClass *klass, guint32 idx); + +/*Now that everything has been defined, let's include the inline functions */ +#include + #endif /* __MONO_METADATA_CLASS_INTERNALS_H__ */ diff --git a/mono/metadata/class.c b/mono/metadata/class.c index fa67e15b0f1..042c869adcc 100644 --- a/mono/metadata/class.c +++ b/mono/metadata/class.c @@ -54,8 +54,9 @@ gboolean mono_print_vtable = FALSE; gboolean mono_align_small_structs = FALSE; /* Statistics */ -guint32 inflated_classes, inflated_classes_size, inflated_methods_size; -guint32 classes_size, class_ext_size; +guint32 inflated_classes_size, inflated_methods_size; +guint32 classes_size, class_ext_size, class_ext_count; +guint32 class_def_count, class_gtd_count, class_ginst_count, class_gparam_count, class_array_count, class_pointer_count; /* Low level lock which protects data structures in this module */ static mono_mutex_t classes_mutex; @@ -111,6 +112,8 @@ typedef gboolean (*gclass_record_func) (MonoClass*, void*); /* This TLS variable points to a GSList of classes which have setup_fields () executing */ static MonoNativeTlsKey setup_fields_tls_id; +static MonoNativeTlsKey init_pending_tls_id; + static inline void classes_lock (void) { @@ -504,8 +507,8 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed, } if (is_recursed) break; - if (klass->generic_class) { - MonoGenericClass *gclass = klass->generic_class; + if (mono_class_is_ginst (klass)) { + MonoGenericClass *gclass = mono_class_get_generic_class (klass); MonoGenericInst *inst = gclass->context.class_inst; MonoTypeNameFormat nested_format; int i; @@ -534,7 +537,7 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed, g_string_append_c (str, '>'); else g_string_append_c (str, ']'); - } else if (klass->generic_container && + } else if (mono_class_is_gtd (klass) && (format != MONO_TYPE_NAME_FORMAT_FULL_NAME) && (format != MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)) { int i; @@ -543,10 +546,10 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed, g_string_append_c (str, '<'); else g_string_append_c (str, '['); - for (i = 0; i < klass->generic_container->type_argc; i++) { + for (i = 0; i < mono_class_get_generic_container (klass)->type_argc; i++) { if (i) g_string_append_c (str, ','); - g_string_append (str, mono_generic_container_get_param_info (klass->generic_container, i)->name); + g_string_append (str, mono_generic_container_get_param_info (mono_class_get_generic_container (klass), i)->name); } if (format == MONO_TYPE_NAME_FORMAT_IL) g_string_append_c (str, '>'); @@ -665,7 +668,7 @@ mono_class_is_open_constructed_type (MonoType *t) return t->data.generic_class->context.class_inst->is_open; case MONO_TYPE_CLASS: case MONO_TYPE_VALUETYPE: - return t->data.klass->generic_container != NULL; + return mono_class_is_gtd (t->data.klass); default: return FALSE; } @@ -788,7 +791,7 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont case MONO_TYPE_CLASS: case MONO_TYPE_VALUETYPE: { MonoClass *klass = type->data.klass; - MonoGenericContainer *container = klass->generic_container; + MonoGenericContainer *container = mono_class_try_get_generic_container (klass); MonoGenericInst *inst; MonoGenericClass *gclass = NULL; MonoType *nt; @@ -825,33 +828,8 @@ mono_generic_class_get_context (MonoGenericClass *gclass) MonoGenericContext * mono_class_get_context (MonoClass *klass) { - return klass->generic_class ? mono_generic_class_get_context (klass->generic_class) : NULL; -} - -/* - * mono_class_get_generic_container: - * - * Return the generic container of KLASS which should be a generic type definition. - */ -MonoGenericContainer* -mono_class_get_generic_container (MonoClass *klass) -{ - g_assert (klass->is_generic); - - return klass->generic_container; -} - -/* - * mono_class_get_generic_class: - * - * Return the MonoGenericClass of KLASS, which should be a generic instance. - */ -MonoGenericClass* -mono_class_get_generic_class (MonoClass *klass) -{ - g_assert (klass->is_inflated); - - return klass->generic_class; + MonoGenericClass *gklass = mono_class_try_get_generic_class (klass); + return gklass ? mono_generic_class_get_context (gklass) : NULL; } /* @@ -1082,7 +1060,7 @@ mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *k * */ if (!((method->is_generic && context->method_inst) || - (method->klass->generic_container && context->class_inst))) + (mono_class_is_gtd (method->klass) && context->class_inst))) return method; iresult = g_new0 (MonoMethodInflated, 1); @@ -1093,14 +1071,12 @@ mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *k iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst; if (!context->class_inst) { - g_assert (!iresult->declaring->klass->generic_class); - if (iresult->declaring->klass->generic_container) - iresult->context.class_inst = iresult->declaring->klass->generic_container->context.class_inst; - else if (iresult->declaring->klass->generic_class) - iresult->context.class_inst = iresult->declaring->klass->generic_class->context.class_inst; + g_assert (!mono_class_is_ginst (iresult->declaring->klass)); + if (mono_class_is_gtd (iresult->declaring->klass)) + iresult->context.class_inst = mono_class_get_generic_container (iresult->declaring->klass)->context.class_inst; } /* This can happen with some callers like mono_object_get_virtual_method () */ - if (!iresult->declaring->klass->generic_container && !iresult->declaring->klass->generic_class) + if (!mono_class_is_gtd (iresult->declaring->klass) && !mono_class_is_ginst (iresult->declaring->klass)) iresult->context.class_inst = NULL; MonoImageSet *set = mono_metadata_get_image_set_for_method (iresult); @@ -1158,12 +1134,13 @@ mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *k } } - if (!klass_hint || !klass_hint->generic_class || - klass_hint->generic_class->container_class != method->klass || - klass_hint->generic_class->context.class_inst != context->class_inst) - klass_hint = NULL; + if (klass_hint) { + MonoGenericClass *gklass_hint = mono_class_try_get_generic_class (klass_hint); + if (gklass_hint && (gklass_hint->container_class != method->klass || gklass_hint->context.class_inst != context->class_inst)) + klass_hint = NULL; + } - if (method->klass->generic_container) + if (mono_class_is_gtd (method->klass)) result->klass = klass_hint; if (!result->klass) { @@ -1238,8 +1215,8 @@ mono_method_get_context_general (MonoMethod *method, gboolean uninflated) return NULL; if (method->is_generic) return &(mono_method_get_generic_container (method)->context); - if (method->klass->generic_container) - return &method->klass->generic_container->context; + if (mono_class_is_gtd (method->klass)) + return &mono_class_get_generic_container (method->klass)->context; return NULL; } @@ -1304,31 +1281,31 @@ mono_class_find_enum_basetype (MonoClass *klass, MonoError *error) MonoGenericContainer *container = NULL; MonoImage *m = klass->image; const int top = klass->field.count; - int i; + int i, first_field_idx; g_assert (klass->enumtype); mono_error_init (error); - if (klass->generic_container) - container = klass->generic_container; - else if (klass->generic_class) { - MonoClass *gklass = klass->generic_class->container_class; + container = mono_class_try_get_generic_container (klass); + if (mono_class_is_ginst (klass)) { + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; - container = gklass->generic_container; + container = mono_class_get_generic_container (gklass); g_assert (container); } /* * Fetch all the field information. */ + first_field_idx = mono_class_get_first_field_idx (klass); for (i = 0; i < top; i++){ const char *sig; guint32 cols [MONO_FIELD_SIZE]; - int idx = klass->field.first + i; + int idx = first_field_idx + i; MonoType *ftype; - /* klass->field.first and idx points into the fieldptr table */ + /* first_field_idx and idx points into the fieldptr table */ mono_metadata_decode_table_row (m, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE); if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC) //no need to decode static fields @@ -1351,7 +1328,7 @@ mono_class_find_enum_basetype (MonoClass *klass, MonoError *error) if (!ftype) goto fail; - if (klass->generic_class) { + if (mono_class_is_ginst (klass)) { //FIXME do we leak here? ftype = mono_class_inflate_generic_type_checked (ftype, mono_class_get_context (klass), error); if (!mono_error_ok (error)) @@ -1405,8 +1382,9 @@ mono_error_set_for_class_failure (MonoError *oerror, const MonoClass *klass) gpointer mono_class_alloc (MonoClass *klass, int size) { - if (klass->generic_class) - return mono_image_set_alloc (klass->generic_class->owner, size); + MonoGenericClass *gklass = mono_class_try_get_generic_class (klass); + if (gklass) + return mono_image_set_alloc (gklass->owner, size); else return mono_image_alloc (klass->image, size); } @@ -1431,12 +1409,13 @@ mono_class_alloc0 (MonoClass *klass, int size) * Initializes the following fields in MonoClass: * * klass->fields (only field->parent and field->name) * * klass->field.count - * * klass->field.first + * * klass->first_field_idx * LOCKING: Acquires the loader lock */ static void mono_class_setup_basic_field_info (MonoClass *klass) { + MonoGenericClass *gklass; MonoClassField *field; MonoClassField *fields; MonoClass *gtd; @@ -1446,10 +1425,12 @@ mono_class_setup_basic_field_info (MonoClass *klass) if (klass->fields) return; - gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL; + gklass = mono_class_try_get_generic_class (klass); + gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL; image = klass->image; - if (klass->generic_class && image_is_dynamic (klass->generic_class->container_class->image) && !klass->generic_class->container_class->wastypebuilder) { + + if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) { /* * This happens when a generic instance of an unfinished generic typebuilder * is used as an element type for creating an array type. We can't initialize @@ -1463,7 +1444,6 @@ mono_class_setup_basic_field_info (MonoClass *klass) mono_class_setup_basic_field_info (gtd); mono_loader_lock (); - klass->field.first = gtd->field.first; klass->field.count = gtd->field.count; mono_loader_unlock (); } @@ -1475,15 +1455,16 @@ mono_class_setup_basic_field_info (MonoClass *klass) /* * Fetch all the field information. */ - for (i = 0; i < top; i++){ + int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0; + for (i = 0; i < top; i++) { field = &fields [i]; field->parent = klass; if (gtd) { field->name = mono_field_get_name (>d->fields [i]); } else { - int idx = klass->field.first + i; - /* klass->field.first and idx points into the fieldptr table */ + int idx = first_field_idx + i; + /* first_field_idx and idx points into the fieldptr table */ guint32 name_idx = mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_NAME); /* The name is needed for fieldrefs */ field->name = mono_metadata_string_heap (image, name_idx); @@ -1532,15 +1513,9 @@ mono_class_set_type_load_failure_causedby_class (MonoClass *klass, const MonoCla * Initializes klass->fields, computes class layout and sizes. * typebuilder_setup_fields () is the corresponding function for dynamic classes. * Sets the following fields in @klass: - * - packing_size - * - min_align - * - blittable - * - has_references (if the class contains instance references firled or structs that contain references) - * - has_static_refs (same, but for static fields) - * - instance_size (size of the object in memory) - * - class_size (size needed for the static fields) - * - size_inited (flag set when the instance_size is set) + * - all the fields initialized by mono_class_init_sizes () * - element_class/cast_class (for enums) + * - field->type/offset for all fields * - fields_inited * * LOCKING: Acquires the loader lock. @@ -1551,19 +1526,20 @@ mono_class_setup_fields (MonoClass *klass) MonoError error; MonoImage *m = klass->image; int top; - guint32 layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK; + guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK; int i; guint32 real_size = 0; guint32 packing_size = 0; int instance_size; gboolean explicit_size; MonoClassField *field; - MonoClass *gtd; + MonoGenericClass *gklass = mono_class_try_get_generic_class (klass); + MonoClass *gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL; if (klass->fields_inited) return; - if (klass->generic_class && image_is_dynamic (klass->generic_class->container_class->image) && !klass->generic_class->container_class->wastypebuilder) { + if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) { /* * This happens when a generic instance of an unfinished generic typebuilder * is used as an element type for creating an array type. We can't initialize @@ -1576,7 +1552,6 @@ mono_class_setup_fields (MonoClass *klass) mono_class_setup_basic_field_info (klass); top = klass->field.count; - gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL; if (gtd) { mono_class_setup_fields (gtd); if (mono_class_set_type_load_failure_causedby_class (klass, gtd, "Generic type definition failed")) @@ -1613,8 +1588,9 @@ mono_class_setup_fields (MonoClass *klass) /* * Fetch all the field information. */ + int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0; for (i = 0; i < top; i++) { - int idx = klass->field.first + i; + int idx = first_field_idx + i; field = &klass->fields [i]; if (!field->type) { @@ -1644,7 +1620,7 @@ mono_class_setup_fields (MonoClass *klass) mono_class_set_type_load_failure (klass, "Field '%s' has a negative offset %d", field->name, offset); break; } - if (klass->generic_container) { + if (mono_class_is_gtd (klass)) { mono_class_set_type_load_failure (klass, "Generic class cannot have explicit layout."); break; } @@ -1669,23 +1645,51 @@ mono_class_setup_fields (MonoClass *klass) mono_native_tls_set_value (setup_fields_tls_id, init_list); } +static void +init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info) +{ + if (cached_info) { + klass->instance_size = cached_info->instance_size; + klass->sizes.class_size = cached_info->class_size; + klass->packing_size = cached_info->packing_size; + klass->min_align = cached_info->min_align; + klass->blittable = cached_info->blittable; + klass->has_references = cached_info->has_references; + klass->has_static_refs = cached_info->has_static_refs; + klass->no_special_static_fields = cached_info->no_special_static_fields; + } + else { + if (!klass->size_inited) + mono_class_setup_fields (klass); + } +} /* - * mono_class_has_references: + + * mono_class_init_sizes: + * + * Initializes the size related fields of @klass without loading all field data if possible. + * Sets the following fields in @klass: + * - instance_size + * - sizes.class_size + * - packing_size + * - min_align + * - blittable + * - has_references + * - has_static_refs + * - size_inited + * Can fail the class. * - * Returns whenever @klass->has_references is set, initializing it if needed. - * Aquires the loader lock. + * LOCKING: Acquires the loader lock. */ -static gboolean -mono_class_has_references (MonoClass *klass) +static void +mono_class_init_sizes (MonoClass *klass) { - if (klass->init_pending) { - /* Be conservative */ - return TRUE; - } else { - mono_class_init (klass); + MonoCachedClassInfo cached_info; + gboolean has_cached_info; - return klass->has_references; - } + has_cached_info = mono_class_get_cached_class_info (klass, &cached_info); + + init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL); } /* @@ -1705,16 +1709,29 @@ mono_type_get_basic_type_from_generic (MonoType *type) return type; } +static gboolean +class_has_references (MonoClass *klass) +{ + mono_class_init_sizes (klass); + + /* + * has_references is not set if this is called recursively, but this is not a problem since this is only used + * during field layout, and instance fields are initialized before static fields, and instance fields can't + * embed themselves. + */ + return klass->has_references; +} + static gboolean type_has_references (MonoClass *klass, MonoType *ftype) { - if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (klass, ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) + if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (klass, ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && class_has_references (mono_class_from_mono_type (ftype))))) return TRUE; if (!ftype->byref && (ftype->type == MONO_TYPE_VAR || ftype->type == MONO_TYPE_MVAR)) { MonoGenericParam *gparam = ftype->data.generic_param; if (gparam->gshared_constraint) - return mono_class_has_references (mono_class_from_mono_type (gparam->gshared_constraint)); + return class_has_references (mono_class_from_mono_type (gparam->gshared_constraint)); } return FALSE; } @@ -1736,7 +1753,7 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ { int i; const int top = klass->field.count; - guint32 layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK; + guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK; guint32 pass, passes, real_size; gboolean gc_aware_layout = FALSE; gboolean has_static_fields = FALSE; @@ -1876,6 +1893,7 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ * Compute field layout and total size (not considering static fields) */ field_offsets = g_new0 (int, top); + int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0; switch (layout) { case TYPE_ATTRIBUTE_AUTO_LAYOUT: case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT: @@ -1984,7 +2002,7 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ /* Already set by typebuilder_setup_fields () */ field_offsets [i] = field->offset + sizeof (MonoObject); } else { - int idx = klass->field.first + i; + int idx = first_field_idx + i; guint32 offset; mono_metadata_field_info (klass->image, idx, &offset, NULL, NULL); field_offsets [i] = offset + sizeof (MonoObject); @@ -2205,9 +2223,9 @@ mono_class_setup_methods (MonoClass *klass) if (klass->methods) return; - if (klass->generic_class) { + if (mono_class_is_ginst (klass)) { MonoError error; - MonoClass *gklass = klass->generic_class->container_class; + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; mono_class_init (gklass); if (!mono_class_has_failure (gklass)) @@ -2321,19 +2339,23 @@ mono_class_setup_methods (MonoClass *klass) for (i = 0; i < klass->interface_count; i++) setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic); - } else { + } else if (mono_class_has_static_metadata (klass)) { MonoError error; + int first_idx = mono_class_get_first_method_idx (klass); count = klass->method.count; methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * count); for (i = 0; i < count; ++i) { - int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, klass->method.first + i + 1); + int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, first_idx + i + 1); methods [i] = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | idx, klass, NULL, &error); if (!methods [i]) { mono_class_set_type_load_failure (klass, "Could not load method %d due to %s", i, mono_error_get_message (&error)); mono_error_cleanup (&error); } } + } else { + methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * 1); + count = 0; } if (MONO_CLASS_IS_INTERFACE (klass)) { @@ -2370,13 +2392,14 @@ MonoMethod* mono_class_get_method_by_index (MonoClass *klass, int index) { MonoError error; + + MonoGenericClass *gklass = mono_class_try_get_generic_class (klass); /* Avoid calling setup_methods () if possible */ - if (klass->generic_class && !klass->methods) { - MonoClass *gklass = klass->generic_class->container_class; + if (gklass && !klass->methods) { MonoMethod *m; m = mono_class_inflate_generic_method_full_checked ( - gklass->methods [index], klass, mono_class_get_context (klass), &error); + gklass->container_class->methods [index], klass, mono_class_get_context (klass), &error); g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */ /* * If setup_methods () is called later for this class, no duplicates are created, @@ -2406,7 +2429,7 @@ mono_class_get_method_by_index (MonoClass *klass, int index) MonoMethod* mono_class_get_inflated_method (MonoClass *klass, MonoMethod *method) { - MonoClass *gklass = klass->generic_class->container_class; + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; int i; g_assert (method->klass == gklass); @@ -2451,9 +2474,9 @@ mono_class_get_vtable_entry (MonoClass *klass, int offset) return klass->parent->vtable [offset]; } - if (klass->generic_class) { + if (mono_class_is_ginst (klass)) { MonoError error; - MonoClass *gklass = klass->generic_class->container_class; + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; mono_class_setup_vtable (gklass); m = gklass->vtable [offset]; @@ -2502,8 +2525,8 @@ mono_class_setup_properties (MonoClass *klass) if (klass->ext && klass->ext->properties) return; - if (klass->generic_class) { - MonoClass *gklass = klass->generic_class->container_class; + if (mono_class_is_ginst (klass)) { + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; mono_class_init (gklass); mono_class_setup_properties (gklass); @@ -2549,6 +2572,7 @@ mono_class_setup_properties (MonoClass *klass) properties [i - first].name = mono_metadata_string_heap (klass->image, cols [MONO_PROPERTY_NAME]); startm = mono_metadata_methods_from_property (klass->image, i, &endm); + int first_idx = mono_class_get_first_method_idx (klass); for (j = startm; j < endm; ++j) { MonoMethod *method; @@ -2560,7 +2584,7 @@ mono_class_setup_properties (MonoClass *klass) method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, &error); mono_error_cleanup (&error); /* FIXME don't swallow this error */ } else { - method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - klass->method.first]; + method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx]; } switch (cols [MONO_METHOD_SEMA_SEMANTICS]) { @@ -2633,8 +2657,8 @@ mono_class_setup_events (MonoClass *klass) if (klass->ext && klass->ext->events) return; - if (klass->generic_class) { - MonoClass *gklass = klass->generic_class->container_class; + if (mono_class_is_ginst (klass)) { + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; MonoGenericContext *context = NULL; mono_class_setup_events (gklass); @@ -2691,6 +2715,7 @@ mono_class_setup_events (MonoClass *klass) event->name = mono_metadata_string_heap (klass->image, cols [MONO_EVENT_NAME]); startm = mono_metadata_methods_from_event (klass->image, i, &endm); + int first_idx = mono_class_get_first_method_idx (klass); for (j = startm; j < endm; ++j) { MonoMethod *method; @@ -2702,7 +2727,7 @@ mono_class_setup_events (MonoClass *klass) method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, &error); mono_error_cleanup (&error); /* FIXME don't swallow this error */ } else { - method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - klass->method.first]; + method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx]; } switch (cols [MONO_METHOD_SEMA_SEMANTICS]) { @@ -2801,7 +2826,7 @@ mono_unload_interface_id (MonoClass *klass) * LOCKING: Acquires the classes lock. * Returns: The new ID. */ -static guint +static guint32 mono_get_unique_iid (MonoClass *klass) { int iid; @@ -2824,7 +2849,7 @@ mono_get_unique_iid (MonoClass *klass) } mono_bitset_set (global_interface_bitset, iid); /* set the bit also in the per-image set */ - if (!klass->generic_class) { + if (!mono_class_is_ginst (klass)) { if (klass->image->interface_bitset) { if (iid >= mono_bitset_size (klass->image->interface_bitset)) { MonoBitSet *new_set = mono_bitset_clone (klass->image->interface_bitset, iid + 1); @@ -2843,8 +2868,9 @@ mono_get_unique_iid (MonoClass *klass) if (mono_print_vtable) { int generic_id; char *type_name = mono_type_full_name (&klass->byval_arg); - if (klass->generic_class && !klass->generic_class->context.class_inst->is_open) { - generic_id = klass->generic_class->context.class_inst->id; + MonoGenericClass *gklass = mono_class_try_get_generic_class (klass); + if (gklass && !gklass->context.class_inst->is_open) { + generic_id = gklass->context.class_inst->id; g_assert (generic_id != 0); } else { generic_id = 0; @@ -2854,7 +2880,9 @@ mono_get_unique_iid (MonoClass *klass) } #endif - g_assert (iid <= 65535); + /* I've confirmed iids safe past 16 bits, however bitset code uses a signed int while testing. + * Once this changes, it should be safe for us to allow 2^32-1 interfaces, until then 2^31-2 is the max. */ + g_assert (iid < INT_MAX); return iid; } @@ -3057,6 +3085,12 @@ fill_valuetype_array_derived_types (MonoClass **valuetype_types, MonoClass *ecla valuetype_types [1] = mono_class_from_mono_type (mono_class_enum_basetype (eclass)); } +static GENERATE_GET_CLASS_WITH_CACHE (generic_icollection, System.Collections.Generic, ICollection`1) +static GENERATE_GET_CLASS_WITH_CACHE (generic_ienumerable, System.Collections.Generic, IEnumerable`1) +static GENERATE_GET_CLASS_WITH_CACHE (generic_ienumerator, System.Collections.Generic, IEnumerator`1) +static GENERATE_GET_CLASS_WITH_CACHE (generic_ireadonlylist, System.Collections.Generic, IReadOnlyList`1) +static GENERATE_GET_CLASS_WITH_CACHE (generic_ireadonlycollection, System.Collections.Generic, IReadOnlyCollection`1) + /* this won't be needed once bug #325495 is completely fixed * though we'll need something similar to know which interfaces to allow * in arrays when they'll be lazyly created @@ -3074,11 +3108,11 @@ static MonoClass** get_implicit_generic_array_interfaces (MonoClass *klass, int *num, int *is_enumerator) { MonoClass *eclass = klass->element_class; - static MonoClass* generic_icollection_class = NULL; - static MonoClass* generic_ienumerable_class = NULL; - static MonoClass* generic_ienumerator_class = NULL; - static MonoClass* generic_ireadonlylist_class = NULL; - static MonoClass* generic_ireadonlycollection_class = NULL; + MonoClass* generic_icollection_class; + MonoClass* generic_ienumerable_class; + MonoClass* generic_ienumerator_class; + MonoClass* generic_ireadonlylist_class; + MonoClass* generic_ireadonlycollection_class; MonoClass *valuetype_types[2] = { NULL, NULL }; MonoClass **interfaces = NULL; int i, nifaces, interface_count, real_count, original_rank; @@ -3094,11 +3128,12 @@ get_implicit_generic_array_interfaces (MonoClass *klass, int *num, int *is_enume eclass_is_valuetype = FALSE; original_rank = eclass->rank; if (klass->byval_arg.type != MONO_TYPE_SZARRAY) { - if (klass->generic_class && klass->nested_in == mono_defaults.array_class && strcmp (klass->name, "InternalEnumerator`1") == 0) { + MonoGenericClass *gklass = mono_class_try_get_generic_class (klass); + if (gklass && klass->nested_in == mono_defaults.array_class && strcmp (klass->name, "InternalEnumerator`1") == 0) { /* * For a Enumerator we need to get the list of interfaces for T. */ - eclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]); + eclass = mono_class_from_mono_type (gklass->context.class_inst->type_argv [0]); original_rank = eclass->rank; if (!eclass->rank) eclass = eclass->element_class; @@ -3116,18 +3151,11 @@ get_implicit_generic_array_interfaces (MonoClass *klass, int *num, int *is_enume */ all_interfaces = eclass->rank && eclass->element_class->rank? FALSE: TRUE; - if (!generic_icollection_class) { - generic_icollection_class = mono_class_load_from_name (mono_defaults.corlib, - "System.Collections.Generic", "ICollection`1"); - generic_ienumerable_class = mono_class_load_from_name (mono_defaults.corlib, - "System.Collections.Generic", "IEnumerable`1"); - generic_ienumerator_class = mono_class_load_from_name (mono_defaults.corlib, - "System.Collections.Generic", "IEnumerator`1"); - generic_ireadonlylist_class = mono_class_load_from_name (mono_defaults.corlib, - "System.Collections.Generic", "IReadOnlyList`1"); - generic_ireadonlycollection_class = mono_class_load_from_name (mono_defaults.corlib, - "System.Collections.Generic", "IReadOnlyCollection`1"); - } + generic_icollection_class = mono_class_get_generic_icollection_class (); + generic_ienumerable_class = mono_class_get_generic_ienumerable_class (); + generic_ienumerator_class = mono_class_get_generic_ienumerator_class (); + generic_ireadonlylist_class = mono_class_get_generic_ireadonlylist_class (); + generic_ireadonlycollection_class = mono_class_get_generic_ireadonlycollection_class (); mono_class_init (eclass); @@ -3318,8 +3346,9 @@ count_virtual_methods (MonoClass *klass) ++count; } } else { + int first_idx = mono_class_get_first_method_idx (klass); for (i = 0; i < klass->method.count; ++i) { - flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, klass->method.first + i, MONO_METHOD_FLAGS); + flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS); if (flags & METHOD_ATTRIBUTE_VIRTUAL) ++count; @@ -3493,15 +3522,16 @@ mono_class_interface_match (const uint8_t *bitmap, int id) #endif /* - * LOCKING: this is supposed to be called with the loader lock held. * Return -1 on failure and set klass->has_failure and store a MonoErrorBoxed with the details. + * LOCKING: Acquires the loader lock. */ static int setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite) { MonoError error; MonoClass *k, *ic; - int i, j, max_iid, num_ifaces; + int i, j, num_ifaces; + guint32 max_iid; MonoClass **interfaces_full = NULL; int *interface_offsets_full = NULL; GPtrArray *ifaces; @@ -3529,8 +3559,7 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite) for (i = 0; i < k->interface_count; i++) { ic = k->interfaces [i]; - if (!ic->inited) - mono_class_init (ic); + mono_class_init (ic); if (max_iid < ic->interface_id) max_iid = ic->interface_id; @@ -3567,14 +3596,13 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite) if (max_iid < klass->interface_id) max_iid = klass->interface_id; } - klass->max_interface_id = max_iid; + /* compute vtable offset for interfaces */ interfaces_full = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * num_ifaces); interface_offsets_full = (int *)g_malloc (sizeof (int) * num_ifaces); - for (i = 0; i < num_ifaces; i++) { + for (i = 0; i < num_ifaces; i++) interface_offsets_full [i] = -1; - } /* skip the current class */ for (j = 0; j < klass->idepth - 1; j++) { @@ -3648,7 +3676,7 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite) for (i = 0; i < num_array_interfaces; ++i) { int offset; ic = array_interfaces [i]; - if (ic->generic_class->container_class == mono_defaults.generic_ilist_class) + if (mono_class_get_generic_class (ic)->container_class == mono_defaults.generic_ilist_class) offset = ilist_offset; else if (strcmp (ic->name, "ICollection`1") == 0) offset = icollection_offset; @@ -3667,11 +3695,14 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite) } for (interface_offsets_count = 0, i = 0; i < num_ifaces; i++) { - if (interface_offsets_full [i] != -1) { + if (interface_offsets_full [i] != -1) interface_offsets_count ++; - } } + /* Publish the data */ + mono_loader_lock (); + + klass->max_interface_id = max_iid; /* * We might get called multiple times: * - mono_class_init () @@ -3696,7 +3727,7 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite) bitmap = (uint8_t *)mono_class_alloc0 (klass, bsize); #endif for (i = 0; i < interface_offsets_count; i++) { - int id = interfaces_full [i]->interface_id; + guint32 id = interfaces_full [i]->interface_id; bitmap [id >> 3] |= (1 << (id & 7)); klass->interfaces_packed [i] = interfaces_full [i]; klass->interface_offsets_packed [i] = interface_offsets_full [i]; @@ -3712,6 +3743,7 @@ setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite) klass->interface_bitmap = bitmap; #endif } + mono_loader_unlock (); end: g_free (interfaces_full); @@ -3726,7 +3758,7 @@ end: //printf ("JUST DONE: "); //print_implemented_interfaces (klass); - + return cur_slot; } @@ -3744,11 +3776,7 @@ end: void mono_class_setup_interface_offsets (MonoClass *klass) { - mono_loader_lock (); - setup_interface_offsets (klass, 0, FALSE); - - mono_loader_unlock (); } /*Checks if @klass has @parent as one of it's parents type gtd @@ -3775,16 +3803,17 @@ mono_class_check_vtable_constraints (MonoClass *klass, GList *in_setup) { MonoGenericInst *ginst; int i; - if (!klass->generic_class) { + + if (!mono_class_is_ginst (klass)) { mono_class_setup_vtable_full (klass, in_setup); return !mono_class_has_failure (klass); } mono_class_setup_vtable_full (mono_class_get_generic_type_definition (klass), in_setup); - if (mono_class_set_type_load_failure_causedby_class (klass, klass->generic_class->container_class, "Failed to load generic definition vtable")) + if (mono_class_set_type_load_failure_causedby_class (klass, mono_class_get_generic_class (klass)->container_class, "Failed to load generic definition vtable")) return FALSE; - ginst = klass->generic_class->context.class_inst; + ginst = mono_class_get_generic_class (klass)->context.class_inst; for (i = 0; i < ginst->type_argc; ++i) { MonoClass *arg; if (ginst->type_argv [i]->type != MONO_TYPE_GENERICINST) @@ -3855,7 +3884,7 @@ mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup) mono_stats.generic_vtable_count ++; in_setup = g_list_prepend (in_setup, klass); - if (klass->generic_class) { + if (mono_class_is_ginst (klass)) { if (!mono_class_check_vtable_constraints (klass, in_setup)) { mono_loader_unlock (); g_list_remove (in_setup, klass); @@ -3863,9 +3892,9 @@ mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup) } context = mono_class_get_context (klass); - type_token = klass->generic_class->container_class->type_token; + type_token = mono_class_get_generic_class (klass)->container_class->type_token; } else { - context = (MonoGenericContext *) klass->generic_container; + context = (MonoGenericContext *) mono_class_try_get_generic_container (klass); //FIXME is this a case of a try? type_token = klass->type_token; } @@ -4328,7 +4357,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o MonoError error; MonoClass *k, *ic; MonoMethod **vtable; - int i, max_vtsize = 0, max_iid, cur_slot = 0; + int i, max_vtsize = 0, cur_slot = 0; + guint32 max_iid; GPtrArray *ifaces = NULL; GHashTable *override_map = NULL; MonoMethod *cm; @@ -4393,9 +4423,9 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot); /* Optimized version for generic instances */ - if (klass->generic_class) { + if (mono_class_is_ginst (klass)) { MonoError error; - MonoClass *gklass = klass->generic_class->container_class; + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; MonoMethod **tmp; mono_class_setup_vtable_full (gklass, in_setup); @@ -4612,7 +4642,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o // it can happen (for injected generic array interfaces) that the same slot is // processed multiple times (those interfaces have overlapping slots), and it // will not always be the first pass the one that fills the slot. - if (! (klass->flags & TYPE_ATTRIBUTE_ABSTRACT)) { + if (!mono_class_is_abstract (klass)) { for (i = 0; i < klass->interface_offsets_count; i++) { int ic_offset; int im_index; @@ -4756,7 +4786,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o virt_methods = NULL; /* Ensure that all vtable slots are filled with concrete instance methods */ - if (!(klass->flags & TYPE_ATTRIBUTE_ABSTRACT)) { + if (!mono_class_is_abstract (klass)) { for (i = 0; i < cur_slot; ++i) { if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) { char *type_name = mono_type_get_full_name (klass); @@ -4769,8 +4799,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o } } - if (klass->generic_class) { - MonoClass *gklass = klass->generic_class->container_class; + if (mono_class_is_ginst (klass)) { + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; mono_class_init (gklass); @@ -4873,14 +4903,14 @@ mono_method_get_vtable_slot (MonoMethod *method) MonoClass *gklass; int i; - if (!method->klass->generic_class) { + if (!mono_class_is_ginst (method->klass)) { g_assert (method->is_inflated); return mono_method_get_vtable_slot (((MonoMethodInflated*)method)->declaring); } /* This can happen for abstract methods of generic instances due to the shortcut code in mono_class_setup_vtable_general (). */ - g_assert (method->klass->generic_class); - gklass = method->klass->generic_class->container_class; + g_assert (mono_class_is_ginst (method->klass)); + gklass = mono_class_get_generic_class (method->klass)->container_class; mono_class_setup_methods (method->klass); g_assert (method->klass->methods); for (i = 0; i < method->klass->method.count; ++i) { @@ -5021,7 +5051,7 @@ setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **met int i; tmp_context.class_inst = NULL; - tmp_context.method_inst = iface->generic_class->context.class_inst; + tmp_context.method_inst = mono_class_get_generic_class (iface)->context.class_inst; //g_print ("setting up array interface: %s\n", mono_type_get_name_full (&iface->byval_arg, 0)); for (i = 0; i < generic_array_method_num; i++) { @@ -5051,21 +5081,30 @@ concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2) /** * mono_class_init: - * @class: the class to initialize + * @klass: the class to initialize * * Compute the instance_size, class_size and other infos that cannot be * computed at mono_class_get() time. Also compute vtable_size if possible. * Returns TRUE on success or FALSE if there was a problem in loading - * the type (incorrect assemblies, missing assemblies, methods, etc). + * the type (incorrect assemblies, missing assemblies, methods, etc). + * Initializes the following fields in @klass: + * - all the fields initialized by mono_class_init_sizes () + * - has_cctor + * - ghcimpl + * - inited * * LOCKING: Acquires the loader lock. */ gboolean mono_class_init (MonoClass *klass) { - int i; + int i, vtable_size = 0, array_method_count = 0; MonoCachedClassInfo cached_info; gboolean has_cached_info; + gboolean locked = FALSE; + gboolean ghcimpl = FALSE; + gboolean has_cctor = FALSE; + int first_iface_slot = 0; g_assert (klass); @@ -5075,28 +5114,27 @@ mono_class_init (MonoClass *klass) /*g_print ("Init class %s\n", mono_type_get_full_name (klass));*/ - /* We do everything inside the lock to prevent races */ - mono_loader_lock (); - - if (klass->inited || mono_class_has_failure (klass)) { - mono_loader_unlock (); - /* Somebody might have gotten in before us */ - return !mono_class_has_failure (klass); - } - - if (klass->init_pending) { + /* + * This function can recursively call itself. + */ + GSList *init_list = (GSList *)mono_native_tls_get_value (init_pending_tls_id); + if (g_slist_find (init_list, klass)) { mono_class_set_type_load_failure (klass, "Recursive type definition detected"); goto leave; } + init_list = g_slist_prepend (init_list, klass); + mono_native_tls_set_value (init_pending_tls_id, init_list); - klass->init_pending = 1; + /* + * We want to avoid doing complicated work inside locks, so we compute all the required + * information and write it to @klass inside a lock. + */ if (mono_verifier_is_enabled_for_class (klass) && !mono_verifier_verify_class (klass)) { mono_class_set_type_load_failure (klass, "%s", concat_two_strings_with_zero (klass->image, klass->name, klass->image->assembly_name)); goto leave; } - if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) { MonoClass *element_class = klass->element_class; if (!element_class->inited) @@ -5107,23 +5145,14 @@ mono_class_init (MonoClass *klass) mono_stats.initialized_class_count++; - if (klass->generic_class && !klass->generic_class->is_dynamic) { - MonoClass *gklass = klass->generic_class->container_class; - - mono_stats.generic_class_count++; - - klass->method = gklass->method; - klass->field = gklass->field; + if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) { + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; mono_class_init (gklass); - // FIXME: Why is this needed ? - if (!mono_class_has_failure (gklass)) - mono_class_setup_methods (gklass); if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic Type Definition failed to init")) goto leave; - if (MONO_CLASS_IS_INTERFACE (klass)) - klass->interface_id = mono_get_unique_iid (klass); + mono_class_setup_interface_id (klass); } if (klass->parent && !klass->parent->inited) @@ -5131,38 +5160,10 @@ mono_class_init (MonoClass *klass) has_cached_info = mono_class_get_cached_class_info (klass, &cached_info); - if (klass->generic_class || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes)) - klass->nested_classes_inited = TRUE; - - /* - * Computes the size used by the fields, and their locations - */ - if (has_cached_info) { - klass->instance_size = cached_info.instance_size; - klass->sizes.class_size = cached_info.class_size; - klass->packing_size = cached_info.packing_size; - klass->min_align = cached_info.min_align; - klass->blittable = cached_info.blittable; - klass->has_references = cached_info.has_references; - klass->has_static_refs = cached_info.has_static_refs; - klass->no_special_static_fields = cached_info.no_special_static_fields; - } - else - if (!klass->size_inited){ - mono_class_setup_fields (klass); - if (mono_class_has_failure (klass)) - goto leave; - } - - /* Initialize arrays */ - if (klass->rank) { - klass->method.count = 3 + (klass->rank > 1? 2: 1); - - if (klass->interface_count) { - int count_generic = generic_array_methods (klass); - klass->method.count += klass->interface_count * count_generic; - } - } + /* Compute instance size etc. */ + init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL); + if (mono_class_has_failure (klass)) + goto leave; mono_class_setup_supertypes (klass); @@ -5176,11 +5177,9 @@ mono_class_init (MonoClass *klass) */ if (has_cached_info) { /* AOT case */ - klass->vtable_size = cached_info.vtable_size; - klass->has_finalize = cached_info.has_finalize; - klass->has_finalize_inited = TRUE; - klass->ghcimpl = cached_info.ghcimpl; - klass->has_cctor = cached_info.has_cctor; + vtable_size = cached_info.vtable_size; + ghcimpl = cached_info.ghcimpl; + has_cctor = cached_info.has_cctor; } else if (klass->rank == 1 && klass->byval_arg.type == MONO_TYPE_SZARRAY) { /* SZARRAY can have 2 vtable layouts, with and without the stelemref method. * The first slot if for array with. @@ -5193,21 +5192,22 @@ mono_class_init (MonoClass *klass) if (!szarray_vtable_size [slot]) { mono_class_setup_vtable (klass); szarray_vtable_size [slot] = klass->vtable_size; + vtable_size = klass->vtable_size; } else { - klass->vtable_size = szarray_vtable_size[slot]; + vtable_size = szarray_vtable_size[slot]; } - } else if (klass->generic_class && !MONO_CLASS_IS_INTERFACE (klass)) { - MonoClass *gklass = klass->generic_class->container_class; + } else if (mono_class_is_ginst (klass) && !MONO_CLASS_IS_INTERFACE (klass)) { + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; /* Generic instance case */ - klass->ghcimpl = gklass->ghcimpl; - klass->has_cctor = gklass->has_cctor; + ghcimpl = gklass->ghcimpl; + has_cctor = gklass->has_cctor; mono_class_setup_vtable (gklass); if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to init")) goto leave; - klass->vtable_size = gklass->vtable_size; + vtable_size = gklass->vtable_size; } else { /* General case */ @@ -5227,11 +5227,17 @@ mono_class_init (MonoClass *klass) if (!MONO_CLASS_IS_INTERFACE (klass) || klass->image != mono_defaults.corlib) { MonoMethod *cmethod = NULL; - if (klass->type_token && !image_is_dynamic(klass->image)) { + if (mono_class_is_ginst (klass)) { + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; + + /* Generic instance case */ + ghcimpl = gklass->ghcimpl; + has_cctor = gklass->has_cctor; + } else if (klass->type_token && !image_is_dynamic(klass->image)) { cmethod = find_method_in_metadata (klass, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME); /* The find_method function ignores the 'flags' argument */ if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME)) - klass->has_cctor = 1; + has_cctor = 1; } else { mono_class_setup_methods (klass); if (mono_class_has_failure (klass)) @@ -5241,7 +5247,7 @@ mono_class_init (MonoClass *klass) MonoMethod *method = klass->methods [i]; if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && (strcmp (".cctor", method->name) == 0)) { - klass->has_cctor = 1; + has_cctor = 1; break; } } @@ -5249,45 +5255,85 @@ mono_class_init (MonoClass *klass) } } - if (klass->parent) { - MonoError parent_error; - mono_error_init (&parent_error); - int first_iface_slot; - /* This will compute klass->parent->vtable_size for some classes */ - mono_class_init (klass->parent); - if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class failed to initialize")) { - goto leave; + if (klass->rank) { + array_method_count = 3 + (klass->rank > 1? 2: 1); + + if (klass->interface_count) { + int count_generic = generic_array_methods (klass); + array_method_count += klass->interface_count * count_generic; } - if (!klass->parent->vtable_size) { - /* FIXME: Get rid of this somehow */ + } + + if (klass->parent) { + if (!klass->parent->vtable_size) mono_class_setup_vtable (klass->parent); - if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class vtable failed to initialize")) { - goto leave; - } - } + if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class vtable failed to initialize")) + goto leave; + g_assert (klass->parent->vtable_size); first_iface_slot = klass->parent->vtable_size; if (mono_class_need_stelemref_method (klass)) ++first_iface_slot; - setup_interface_offsets (klass, first_iface_slot, TRUE); - } else { - setup_interface_offsets (klass, 0, TRUE); } + /* + * Do the actual changes to @klass inside the loader lock + */ + mono_loader_lock (); + locked = TRUE; + + if (klass->inited || mono_class_has_failure (klass)) { + mono_loader_unlock (); + /* Somebody might have gotten in before us */ + return !mono_class_has_failure (klass); + } + + mono_stats.initialized_class_count++; + + if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) { + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; + + mono_stats.generic_class_count++; + + klass->method = gklass->method; + klass->field = gklass->field; + } + + if (mono_class_is_ginst (klass) || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes)) + klass->nested_classes_inited = TRUE; + klass->ghcimpl = ghcimpl; + klass->has_cctor = has_cctor; + if (vtable_size) + klass->vtable_size = vtable_size; + if (has_cached_info) { + klass->has_finalize = cached_info.has_finalize; + klass->has_finalize_inited = TRUE; + } + if (klass->rank) + klass->method.count = array_method_count; + + mono_loader_unlock (); + locked = FALSE; + + setup_interface_offsets (klass, first_iface_slot, TRUE); + if (mono_security_core_clr_enabled ()) mono_security_core_clr_check_inheritance (klass); - if (klass->generic_class && !mono_verifier_class_is_valid_generic_instantiation (klass)) + if (mono_class_is_ginst (klass) && !mono_verifier_class_is_valid_generic_instantiation (klass)) mono_class_set_type_load_failure (klass, "Invalid generic instantiation"); goto leave; leave: + init_list = g_slist_remove (init_list, klass); + mono_native_tls_set_value (init_pending_tls_id, init_list); + /* Because of the double-checking locking pattern */ mono_memory_barrier (); klass->inited = 1; - klass->init_pending = 0; - mono_loader_unlock (); + if (locked) + mono_loader_unlock (); return !mono_class_has_failure (klass); } @@ -5311,8 +5357,8 @@ mono_class_has_finalizer (MonoClass *klass) MonoMethod *cmethod = NULL; if (klass->rank == 1 && klass->byval_arg.type == MONO_TYPE_SZARRAY) { - } else if (klass->generic_class) { - MonoClass *gklass = klass->generic_class->container_class; + } else if (mono_class_is_ginst (klass)) { + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; has_finalize = mono_class_has_finalizer (gklass); } else if (klass->parent && klass->parent->has_finalize) { @@ -5489,7 +5535,6 @@ mono_class_setup_mono_type (MonoClass *klass) if (MONO_CLASS_IS_INTERFACE (klass)) klass->interface_id = mono_get_unique_iid (klass); - } #ifndef DISABLE_COM @@ -5559,7 +5604,7 @@ mono_class_setup_parent (MonoClass *klass, MonoClass *parent) klass->parent = parent; - if (parent->generic_class && !parent->name) { + if (mono_class_is_ginst (parent) && !parent->name) { /* * If the parent is a generic instance, we may get * called before it is fully initialized, especially @@ -5659,7 +5704,7 @@ fix_gclass_incomplete_instantiation (MonoClass *gclass, void *user_data) { MonoClass *gtd = (MonoClass*)user_data; /* Only try to fix generic instances of @gtd */ - if (gclass->generic_class->container_class != gtd) + if (mono_class_get_generic_class (gclass)->container_class != gtd) return FALSE; /* Check if the generic instance has no parent. */ @@ -5721,7 +5766,17 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]); nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]); - klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass)); + if (mono_metadata_has_generic_params (image, type_token)) { + klass = mono_image_alloc0 (image, sizeof (MonoClassGtd)); + klass->class_kind = MONO_CLASS_GTD; + classes_size += sizeof (MonoClassGtd); + ++class_gtd_count; + } else { + klass = mono_image_alloc0 (image, sizeof (MonoClassDef)); + klass->class_kind = MONO_CLASS_DEF; + classes_size += sizeof (MonoClassDef); + ++class_def_count; + } klass->name = name; klass->name_space = nspace; @@ -5730,25 +5785,21 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError klass->image = image; klass->type_token = type_token; - klass->flags = cols [MONO_TYPEDEF_FLAGS]; + mono_class_set_flags (klass, cols [MONO_TYPEDEF_FLAGS]); mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), klass); - classes_size += sizeof (MonoClass); - /* * Check whether we're a generic type definition. */ - klass->generic_container = mono_metadata_load_generic_params (image, klass->type_token, NULL); - if (klass->generic_container) { - klass->is_generic = 1; - klass->generic_container->owner.klass = klass; - klass->generic_container->is_anonymous = FALSE; // Owner class is now known, container is no longer anonymous - context = &klass->generic_container->context; - } - - if (klass->generic_container) + if (mono_class_is_gtd (klass)) { + MonoGenericContainer *generic_container = mono_metadata_load_generic_params (image, klass->type_token, NULL); + generic_container->owner.klass = klass; + generic_container->is_anonymous = FALSE; // Owner class is now known, container is no longer anonymous + context = &generic_container->context; + mono_class_set_generic_container (klass, generic_container); enable_gclass_recording (); + } if (cols [MONO_TYPEDEF_EXTENDS]) { MonoClass *tmp; @@ -5776,7 +5827,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError mono_class_set_failure_and_error (klass, error, "Cycle found while resolving parent"); goto parent_failure; } - if (klass->generic_container && tmp->generic_class && tmp->generic_class->container_class == klass) { + if (mono_class_is_gtd (klass) && mono_class_is_ginst (tmp) && mono_class_get_generic_class (tmp)->container_class == klass) { mono_class_set_failure_and_error (klass, error, "Parent extends generic instance of this type"); goto parent_failure; } @@ -5788,7 +5839,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError /* uses ->valuetype, which is initialized by mono_class_setup_parent above */ mono_class_setup_mono_type (klass); - if (klass->generic_container) + if (mono_class_is_gtd (klass)) disable_gclass_recording (fix_gclass_incomplete_instantiation, klass); /* @@ -5806,11 +5857,11 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError } } - if ((klass->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS) + if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS) klass->unicode = 1; #ifdef HOST_WIN32 - if ((klass->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS) + if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS) klass->unicode = 1; #endif @@ -5826,6 +5877,9 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError return NULL; } + /* This is required now that it is possible for more than 2^16 interfaces to exist. */ + g_assert(icount <= 65535); + klass->interfaces = interfaces; klass->interface_count = icount; klass->interfaces_inited = 1; @@ -5836,8 +5890,10 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError /* * Compute the field and method lists */ - klass->field.first = cols [MONO_TYPEDEF_FIELD_LIST] - 1; - klass->method.first = cols [MONO_TYPEDEF_METHOD_LIST] - 1; + int first_field_idx = cols [MONO_TYPEDEF_FIELD_LIST] - 1; + mono_class_set_first_field_idx (klass, first_field_idx); + int first_method_idx = cols [MONO_TYPEDEF_METHOD_LIST] - 1; + mono_class_set_first_method_idx (klass, first_method_idx); if (tt->rows > tidx){ mono_metadata_decode_row (tt, tidx, cols_next, MONO_TYPEDEF_SIZE); @@ -5850,12 +5906,12 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError if (cols [MONO_TYPEDEF_FIELD_LIST] && cols [MONO_TYPEDEF_FIELD_LIST] <= image->tables [MONO_TABLE_FIELD].rows) - klass->field.count = field_last - klass->field.first; + klass->field.count = field_last - first_field_idx; else klass->field.count = 0; if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows) - klass->method.count = method_last - klass->method.first; + klass->method.count = method_last - first_method_idx; else klass->method.count = 0; @@ -5883,7 +5939,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError * We must do this after the class has been constructed to make certain recursive scenarios * work. */ - if (klass->generic_container && !mono_metadata_load_generic_param_constraints_checked (image, type_token, klass->generic_container, error)) { + if (mono_class_is_gtd (klass) && !mono_metadata_load_generic_param_constraints_checked (image, type_token, mono_class_get_generic_container (klass), error)) { mono_class_set_type_load_failure (klass, "Could not load generic parameter constrains due to %s", mono_error_get_message (error)); mono_loader_unlock (); mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED); @@ -5912,8 +5968,8 @@ parent_failure: gboolean mono_class_is_nullable (MonoClass *klass) { - return klass->generic_class != NULL && - klass->generic_class->container_class == mono_defaults.generic_nullable_class; + MonoGenericClass *gklass = mono_class_try_get_generic_class (klass); + return gklass && gklass->container_class == mono_defaults.generic_nullable_class; } @@ -5922,7 +5978,7 @@ MonoClass* mono_class_get_nullable_param (MonoClass *klass) { g_assert (mono_class_is_nullable (klass)); - return mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]); + return mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]); } static void @@ -5930,7 +5986,7 @@ mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd) { if (gtd->parent) { MonoError error; - MonoGenericClass *gclass = klass->generic_class; + MonoGenericClass *gclass = mono_class_get_generic_class (klass); klass->parent = mono_class_inflate_generic_class_checked (gtd->parent, mono_generic_class_get_context (gclass), &error); if (!mono_error_ok (&error)) { @@ -5968,7 +6024,7 @@ mono_generic_class_get_class (MonoGenericClass *gclass) return gclass->cached_class; } - klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClass)); + klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClassGenericInst)); gklass = gclass->container_class; @@ -5986,12 +6042,12 @@ mono_generic_class_get_class (MonoGenericClass *gclass) mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD); klass->image = gklass->image; - klass->flags = gklass->flags; klass->type_token = gklass->type_token; klass->field.count = gklass->field.count; - klass->is_inflated = 1; - klass->generic_class = gclass; + klass->class_kind = MONO_CLASS_GINST; + //FIXME add setter + ((MonoClassGenericInst*)klass)->generic_class = gclass; klass->byval_arg.type = MONO_TYPE_GENERICINST; klass->this_arg.type = klass->byval_arg.type; @@ -6041,8 +6097,8 @@ mono_generic_class_get_class (MonoGenericClass *gclass) mono_profiler_class_loaded (klass, MONO_PROFILE_OK); - inflated_classes ++; - inflated_classes_size += sizeof (MonoClass); + ++class_ginst_count; + inflated_classes_size += sizeof (MonoClassGenericInst); mono_loader_unlock (); @@ -6103,8 +6159,10 @@ make_generic_param_class (MonoGenericParam *param, MonoGenericParamInfo *pinfo) gboolean is_mvar = container->is_method; gboolean is_anonymous = container->is_anonymous; - klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass)); - classes_size += sizeof (MonoClass); + klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassGenericParam)); + klass->class_kind = MONO_CLASS_GPARAM; + classes_size += sizeof (MonoClassGenericParam); + ++class_gparam_count; if (pinfo) { CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name , pinfo->name ); @@ -6154,7 +6212,6 @@ make_generic_param_class (MonoGenericParam *param, MonoGenericParamInfo *pinfo) klass->inited = TRUE; CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->cast_class , klass ); CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->element_class , klass ); - klass->flags = TYPE_ATTRIBUTE_PUBLIC; klass->byval_arg.type = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR; klass->this_arg.type = klass->byval_arg.type; @@ -6380,21 +6437,22 @@ mono_ptr_class_get (MonoType *type) } mono_image_unlock (image); - result = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass)); + result = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassPointer)); - classes_size += sizeof (MonoClass); + classes_size += sizeof (MonoClassPointer); + ++class_pointer_count; result->parent = NULL; /* no parent for PTR types */ result->name_space = el_class->name_space; name = g_strdup_printf ("%s*", el_class->name); result->name = mono_image_strdup (image, name); + result->class_kind = MONO_CLASS_POINTER; g_free (name); mono_profiler_class_event (result, MONO_PROFILE_START_LOAD); result->image = el_class->image; result->inited = TRUE; - result->flags = TYPE_ATTRIBUTE_CLASS | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK); result->instance_size = sizeof (MonoObject) + sizeof (gpointer); result->cast_class = result->element_class = el_class; result->blittable = TRUE; @@ -6444,15 +6502,18 @@ mono_fnptr_class_get (MonoMethodSignature *sig) } result = g_new0 (MonoClass, 1); + classes_size += sizeof (MonoClassPointer); + ++class_pointer_count; + result->parent = NULL; /* no parent for PTR types */ result->name_space = "System"; result->name = "MonoFNPtrFakeClass"; + result->class_kind = MONO_CLASS_POINTER; mono_profiler_class_event (result, MONO_PROFILE_START_LOAD); result->image = mono_defaults.corlib; /* need to fix... */ result->inited = TRUE; - result->flags = TYPE_ATTRIBUTE_CLASS; /* | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK); */ result->instance_size = sizeof (MonoObject) + sizeof (gpointer); result->cast_class = result->element_class = result; result->blittable = TRUE; @@ -6659,10 +6720,12 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) if (!parent->inited) mono_class_init (parent); - klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass)); + klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassArray)); klass->image = image; klass->name_space = eclass->name_space; + klass->class_kind = MONO_CLASS_ARRAY; + nsize = strlen (eclass->name); name = (char *)g_malloc (nsize + 2 + rank + 1); memcpy (name, eclass->name, nsize); @@ -6678,11 +6741,10 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD); - classes_size += sizeof (MonoClass); + classes_size += sizeof (MonoClassArray); + ++class_array_count; klass->type_token = 0; - /* all arrays are marked serializable and sealed, bug #42779 */ - klass->flags = TYPE_ATTRIBUTE_CLASS | TYPE_ATTRIBUTE_SERIALIZABLE | TYPE_ATTRIBUTE_SEALED | TYPE_ATTRIBUTE_PUBLIC; klass->parent = parent; klass->instance_size = mono_class_instance_size (klass->parent); @@ -6705,7 +6767,7 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) mono_class_setup_supertypes (klass); - if (eclass->generic_class) + if (mono_class_is_ginst (eclass)) mono_class_init (eclass); if (!eclass->size_inited) mono_class_setup_fields (eclass); @@ -6762,7 +6824,8 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) klass->this_arg = klass->byval_arg; klass->this_arg.byref = 1; - klass->generic_container = eclass->generic_container; + //WTF was this? it's wrong + // klass->generic_container = eclass->generic_container; if (rank == 1 && !bounded) { MonoClass *prev_class; @@ -6824,7 +6887,7 @@ mono_class_instance_size (MonoClass *klass) * * Use to get the computed minimum alignment requirements for the specified class. * - * Returns: minimm alignment requirements + * Returns: minimum alignment requirements */ gint32 mono_class_min_align (MonoClass *klass) @@ -6845,7 +6908,7 @@ mono_class_min_align (MonoClass *klass) * Returns: the size of a value of kind @klass */ gint32 -mono_class_value_size (MonoClass *klass, guint32 *align) +mono_class_value_size (MonoClass *klass, guint32 *align) { gint32 size; @@ -6898,9 +6961,10 @@ mono_class_get_field_idx (MonoClass *klass, int idx) return NULL; while (klass) { + int first_field_idx = mono_class_get_first_field_idx (klass); if (klass->image->uncompressed_metadata) { /* - * klass->field.first points to the FieldPtr table, while idx points into the + * first_field_idx points to the FieldPtr table, while idx points into the * Field table, so we have to do a search. */ /*FIXME this is broken for types with multiple fields with the same name.*/ @@ -6913,8 +6977,8 @@ mono_class_get_field_idx (MonoClass *klass, int idx) g_assert_not_reached (); } else { if (klass->field.count) { - if ((idx >= klass->field.first) && (idx < klass->field.first + klass->field.count)){ - return &klass->fields [idx - klass->field.first]; + if ((idx >= first_field_idx) && (idx < first_field_idx + klass->field.count)){ + return &klass->fields [idx - first_field_idx]; } } } @@ -7018,9 +7082,10 @@ mono_class_get_field_token (MonoClassField *field) while (klass) { if (!klass->fields) return 0; + int first_field_idx = mono_class_get_first_field_idx (klass); for (i = 0; i < klass->field.count; ++i) { if (&klass->fields [i] == field) { - int idx = klass->field.first + i + 1; + int idx = first_field_idx + i + 1; if (klass->image->uncompressed_metadata) idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_FIELD, idx); @@ -8064,10 +8129,10 @@ mono_class_has_variant_generic_params (MonoClass *klass) int i; MonoGenericContainer *container; - if (!klass->generic_class) + if (!mono_class_is_ginst (klass)) return FALSE; - container = klass->generic_class->container_class->generic_container; + container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class); for (i = 0; i < container->type_argc; ++i) if (mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)) @@ -8111,7 +8176,7 @@ mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean int j; MonoType **klass_argv, **oklass_argv; MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass); - MonoGenericContainer *container = klass_gtd->generic_container; + MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd); if (klass == oklass) return TRUE; @@ -8120,8 +8185,8 @@ mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd) return FALSE; - klass_argv = &klass->generic_class->context.class_inst->type_argv [0]; - oklass_argv = &oklass->generic_class->context.class_inst->type_argv [0]; + klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]; + oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0]; for (j = 0; j < container->type_argc; ++j) { MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]); @@ -8376,14 +8441,14 @@ mono_class_is_variant_compatible_slow (MonoClass *klass, MonoClass *oklass) int j; MonoType **klass_argv, **oklass_argv; MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass); - MonoGenericContainer *container = klass_gtd->generic_container; + MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd); /*Viable candidates are instances of the same generic interface*/ if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd) return FALSE; - klass_argv = &klass->generic_class->context.class_inst->type_argv [0]; - oklass_argv = &oklass->generic_class->context.class_inst->type_argv [0]; + klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]; + oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0]; for (j = 0; j < container->type_argc; ++j) { MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]); @@ -8560,8 +8625,8 @@ mono_class_get_cctor (MonoClass *klass) return result; } - if (klass->generic_class && !klass->methods) - return mono_class_get_inflated_method (klass, mono_class_get_cctor (klass->generic_class->container_class)); + if (mono_class_is_ginst (klass) && !klass->methods) + return mono_class_get_inflated_method (klass, mono_class_get_cctor (mono_class_get_generic_class (klass)->container_class)); return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME); } @@ -8942,22 +9007,6 @@ mono_class_get_rank (MonoClass *klass) return klass->rank; } -/** - * mono_class_get_flags: - * @klass: the MonoClass to act on - * - * The type flags from the TypeDef table from the metadata. - * see the TYPE_ATTRIBUTE_* definitions on tabledefs.h for the - * different values. - * - * Returns: The flags from the TypeDef table. - */ -guint32 -mono_class_get_flags (MonoClass *klass) -{ - return klass->flags; -} - /** * mono_class_get_name * @klass: the MonoClass to act on @@ -9209,11 +9258,12 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter) start_index = GPOINTER_TO_UINT (*iter); } + int first_idx = mono_class_get_first_method_idx (klass); for (i = start_index; i < klass->method.count; ++i) { guint32 flags; - /* klass->method.first points into the methodptr table */ - flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, klass->method.first + i, MONO_METHOD_FLAGS); + /* first_idx points into the methodptr table */ + flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS); if (flags & METHOD_ATTRIBUTE_VIRTUAL) break; @@ -9221,7 +9271,7 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter) if (i < klass->method.count) { MonoError error; - res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass, NULL, &error); + res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, &error); mono_error_cleanup (&error); /* FIXME don't swallow the error */ /* Add 1 here so the if (*iter) check fails */ @@ -9588,7 +9638,8 @@ mono_field_get_rva (MonoClassField *field) field_index = mono_field_get_index (field); if (!klass->ext->field_def_values [field_index].data && !image_is_dynamic (klass->image)) { - mono_metadata_field_info (field->parent->image, klass->field.first + field_index, NULL, &rva, NULL); + int first_field_idx = mono_class_get_first_field_idx (klass); + mono_metadata_field_info (field->parent->image, first_field_idx + field_index, NULL, &rva, NULL); if (!rva) g_warning ("field %s in %s should have RVA data, but hasn't", mono_field_get_name (field), field->parent->name); klass->ext->field_def_values [field_index].data = mono_image_rva_map (field->parent->image, rva); @@ -9778,17 +9829,18 @@ find_method_in_metadata (MonoClass *klass, const char *name, int param_count, in int i; /* Search directly in the metadata to avoid calling setup_methods () */ + int first_idx = mono_class_get_first_method_idx (klass); for (i = 0; i < klass->method.count; ++i) { MonoError error; guint32 cols [MONO_METHOD_SIZE]; MonoMethod *method; MonoMethodSignature *sig; - /* klass->method.first points into the methodptr table */ - mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, klass->method.first + i, cols, MONO_METHOD_SIZE); + /* first_idx points into the methodptr table */ + mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, first_idx + i, cols, MONO_METHOD_SIZE); if (!strcmp (mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]), name)) { - method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass, NULL, &error); + method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, &error); if (!method) { mono_error_cleanup (&error); /* FIXME don't swallow the error */ continue; @@ -9830,8 +9882,8 @@ mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int p mono_class_init (klass); - if (klass->generic_class && !klass->methods) { - res = mono_class_get_method_from_name_flags (klass->generic_class->container_class, name, param_count, flags); + if (mono_class_is_ginst (klass) && !klass->methods) { + res = mono_class_get_method_from_name_flags (mono_class_get_generic_class (klass)->container_class, name, param_count, flags); if (res) { MonoError error; res = mono_class_inflate_generic_method_full_checked (res, klass, mono_class_get_context (klass), &error); @@ -9961,17 +10013,31 @@ mono_classes_init (void) mono_os_mutex_init (&classes_mutex); mono_native_tls_alloc (&setup_fields_tls_id, NULL); - + mono_native_tls_alloc (&init_pending_tls_id, NULL); + + mono_counters_register ("MonoClassDef count", + MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_def_count); + mono_counters_register ("MonoClassGtd count", + MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gtd_count); + mono_counters_register ("MonoClassGenericInst count", + MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ginst_count); + mono_counters_register ("MonoClassGenericParam count", + MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gparam_count); + mono_counters_register ("MonoClassArray count", + MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_array_count); + mono_counters_register ("MonoClassPointer count", + MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_pointer_count); mono_counters_register ("Inflated methods size", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_methods_size); - mono_counters_register ("Inflated classes", - MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes); mono_counters_register ("Inflated classes size", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes_size); mono_counters_register ("MonoClass size", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &classes_size); mono_counters_register ("MonoClassExt size", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ext_size); + + mono_counters_register ("MonoClassExt count", + MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ext_count); } /** @@ -9983,6 +10049,7 @@ void mono_classes_cleanup (void) { mono_native_tls_free (setup_fields_tls_id); + mono_native_tls_free (init_pending_tls_id); if (global_interface_bitset) mono_bitset_free (global_interface_bitset); @@ -10025,7 +10092,8 @@ is_nesting_type (MonoClass *outer_klass, MonoClass *inner_klass) MonoClass * mono_class_get_generic_type_definition (MonoClass *klass) { - return klass->generic_class ? klass->generic_class->container_class : klass; + MonoGenericClass *gklass = mono_class_try_get_generic_class (klass); + return gklass ? gklass->container_class : klass; } /* @@ -10122,8 +10190,9 @@ static MonoClass* get_generic_definition_class (MonoClass *klass) { while (klass) { - if (klass->generic_class && klass->generic_class->container_class) - return klass->generic_class->container_class; + MonoGenericClass *gklass = mono_class_try_get_generic_class (klass); + if (gklass && gklass->container_class) + return gklass->container_class; klass = klass->parent; } return NULL; @@ -10177,12 +10246,12 @@ can_access_type (MonoClass *access_klass, MonoClass *member_klass) if (member_klass->element_class && !member_klass->enumtype) member_klass = member_klass->element_class; - access_level = member_klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK; + access_level = mono_class_get_flags (member_klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK; if (member_klass->byval_arg.type == MONO_TYPE_VAR || member_klass->byval_arg.type == MONO_TYPE_MVAR) return TRUE; - if (member_klass->generic_class && !can_access_instantiation (access_klass, member_klass->generic_class->context.class_inst)) + if (mono_class_is_ginst (member_klass) && !can_access_instantiation (access_klass, mono_class_get_generic_class (member_klass)->context.class_inst)) return FALSE; if (is_nesting_type (access_klass, member_klass) || (access_klass->nested_in && is_nesting_type (access_klass->nested_in, member_klass))) @@ -10233,15 +10302,16 @@ can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass* if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal) return TRUE; - if (((access_klass->generic_class && access_klass->generic_class->container_class) || - access_klass->generic_container) && + MonoGenericClass *access_gklass = mono_class_try_get_generic_class (access_klass); + if (((access_gklass && access_gklass->container_class) || + mono_class_is_gtd (access_klass)) && (member_generic_def = get_generic_definition_class (member_klass))) { MonoClass *access_container; - if (access_klass->generic_container) + if (mono_class_is_gtd (access_klass)) access_container = access_klass; else - access_container = access_klass->generic_class->container_class; + access_container = access_gklass->container_class; if (can_access_member (access_container, member_generic_def, context_klass, access_level)) return TRUE; @@ -10479,7 +10549,9 @@ gboolean mono_type_is_valid_enum_basetype (MonoType * type) { * FIXME: enum types are not allowed to have a cctor, but mono_reflection_create_runtime_class sets has_cctor to 1 for all types * FIXME: TypeBuilder enums can have any kind of static fields, but the spec is very explicit about that (P II 14.3) */ -gboolean mono_class_is_valid_enum (MonoClass *klass) { +gboolean +mono_class_is_valid_enum (MonoClass *klass) +{ MonoClassField * field; gpointer iter = NULL; gboolean found_base_field = FALSE; @@ -10490,7 +10562,7 @@ gboolean mono_class_is_valid_enum (MonoClass *klass) { return FALSE; } - if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT) + if (!mono_class_is_auto_layout (klass)) return FALSE; while ((field = mono_class_get_fields (klass, &iter))) { @@ -10515,7 +10587,7 @@ gboolean mono_class_is_valid_enum (MonoClass *klass) { gboolean mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass) { - return gklass->context.class_inst == gklass->container_class->generic_container->context.class_inst; + return gklass->context.class_inst == mono_class_get_generic_container (gklass->container_class)->context.class_inst; } /* @@ -10553,6 +10625,7 @@ mono_class_alloc_ext (MonoClass *klass) if (!klass->ext) klass->ext = ext; class_ext_size += sizeof (MonoClassExt); + ++class_ext_count; mono_image_unlock (klass->image); } @@ -10587,8 +10660,8 @@ mono_class_setup_interfaces (MonoClass *klass, MonoError *error) if (interface_count > 1) interfaces [1] = mono_class_bind_generic_parameters ( mono_defaults.generic_ireadonlylist_class, 1, args, FALSE); - } else if (klass->generic_class) { - MonoClass *gklass = klass->generic_class->container_class; + } else if (mono_class_is_ginst (klass)) { + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; mono_class_setup_interfaces (gklass, error); if (!mono_error_ok (error)) { @@ -10599,7 +10672,7 @@ mono_class_setup_interfaces (MonoClass *klass, MonoError *error) interface_count = gklass->interface_count; interfaces = mono_class_new0 (klass, MonoClass *, interface_count); for (i = 0; i < interface_count; i++) { - interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (klass->generic_class), error); + interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (mono_class_get_generic_class (klass)), error); if (!mono_error_ok (error)) { mono_class_set_type_load_failure (klass, "Could not setup the interfaces"); return; @@ -10629,7 +10702,7 @@ mono_field_resolve_type (MonoClassField *field, MonoError *error) { MonoClass *klass = field->parent; MonoImage *image = klass->image; - MonoClass *gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL; + MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL; int field_idx = field - klass->fields; mono_error_init (error); @@ -10638,35 +10711,41 @@ mono_field_resolve_type (MonoClassField *field, MonoError *error) MonoClassField *gfield = >d->fields [field_idx]; MonoType *gtype = mono_field_get_type_checked (gfield, error); if (!mono_error_ok (error)) { - mono_class_set_type_load_failure (klass, "Could not load field %d type due to: %s", field_idx, mono_error_get_message (error)); + char *full_name = mono_type_get_full_name (gtd); + mono_class_set_type_load_failure (klass, "Could not load generic type of field '%s:%s' (%d) due to: %s", full_name, gfield->name, field_idx, mono_error_get_message (error)); + g_free (full_name); } field->type = mono_class_inflate_generic_type_no_copy (image, gtype, mono_class_get_context (klass), error); if (!mono_error_ok (error)) { - mono_class_set_type_load_failure (klass, "Could not load field %d type due to: %s", field_idx, mono_error_get_message (error)); + char *full_name = mono_type_get_full_name (klass); + mono_class_set_type_load_failure (klass, "Could not load instantiated type of field '%s:%s' (%d) due to: %s", full_name, field->name, field_idx, mono_error_get_message (error)); + g_free (full_name); } } else { const char *sig; guint32 cols [MONO_FIELD_SIZE]; MonoGenericContainer *container = NULL; - int idx = klass->field.first + field_idx; + int idx = mono_class_get_first_field_idx (klass) + field_idx; /*FIXME, in theory we do not lazy load SRE fields*/ g_assert (!image_is_dynamic (image)); - if (klass->generic_container) { - container = klass->generic_container; + if (mono_class_is_gtd (klass)) { + container = mono_class_get_generic_container (klass); } else if (gtd) { - container = gtd->generic_container; + container = mono_class_get_generic_container (gtd); g_assert (container); } - /* klass->field.first and idx points into the fieldptr table */ + /* first_field_idx and idx points into the fieldptr table */ mono_metadata_decode_table_row (image, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE); if (!mono_verifier_verify_field_signature (image, cols [MONO_FIELD_SIGNATURE], NULL)) { - mono_error_set_type_load_class (error, klass, "Could not verify field %s signature", field->name);; + char *full_name = mono_type_get_full_name (klass); + mono_error_set_type_load_class (error, klass, "Could not verify field '%s:%s' signature", full_name, field->name);; mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error)); + g_free (full_name); return; } @@ -10678,7 +10757,9 @@ mono_field_resolve_type (MonoClassField *field, MonoError *error) field->type = mono_metadata_parse_type_checked (image, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error); if (!field->type) { - mono_class_set_type_load_failure (klass, "Could not load field %d type due to: %s", field_idx, mono_error_get_message (error)); + char *full_name = mono_type_get_full_name (klass); + mono_class_set_type_load_failure (klass, "Could not load type of field '%s:%s' (%d) due to: %s", full_name, field->name, field_idx, mono_error_get_message (error)); + g_free (full_name); } } } @@ -10688,7 +10769,7 @@ mono_field_resolve_flags (MonoClassField *field) { MonoClass *klass = field->parent; MonoImage *image = klass->image; - MonoClass *gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL; + MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL; int field_idx = field - klass->fields; @@ -10696,7 +10777,7 @@ mono_field_resolve_flags (MonoClassField *field) MonoClassField *gfield = >d->fields [field_idx]; return mono_field_get_flags (gfield); } else { - int idx = klass->field.first + field_idx; + int idx = mono_class_get_first_field_idx (klass) + field_idx; /*FIXME, in theory we do not lazy load SRE fields*/ g_assert (!image_is_dynamic (image)); diff --git a/mono/metadata/cominterop.c b/mono/metadata/cominterop.c index 5f7d15560aa..c918d3787df 100644 --- a/mono/metadata/cominterop.c +++ b/mono/metadata/cominterop.c @@ -1506,7 +1506,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk) static gboolean cominterop_can_support_dispatch (MonoClass* klass) { - if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) ) + if (!mono_class_is_public (klass)) return FALSE; if (!cominterop_com_visible (klass)) diff --git a/mono/metadata/custom-attrs-internals.h b/mono/metadata/custom-attrs-internals.h index 2f93fecc877..76bd1c21d8c 100644 --- a/mono/metadata/custom-attrs-internals.h +++ b/mono/metadata/custom-attrs-internals.h @@ -7,4 +7,9 @@ MonoCustomAttrInfo* mono_custom_attrs_from_builders (MonoImage *alloc_img, MonoImage *image, MonoArray *cattrs); +typedef gboolean (*MonoAssemblyMetadataCustomAttrIterFunc) (MonoImage *image, guint32 typeref_scope_token, const gchar* nspace, const gchar* name, guint32 method_token, gpointer user_data); + +void +mono_assembly_metadata_foreach_custom_attr (MonoAssembly *assembly, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data); + #endif /* __MONO_METADATA_REFLECTION_CUSTOM_ATTRS_INTERNALS_H__ */ diff --git a/mono/metadata/custom-attrs.c b/mono/metadata/custom-attrs.c index b30f3d8ef59..20fd8de7521 100644 --- a/mono/metadata/custom-attrs.c +++ b/mono/metadata/custom-attrs.c @@ -12,6 +12,7 @@ * Licensed under the MIT license. See LICENSE file in the project root for full license information. */ #include +#include "mono/metadata/assembly.h" #include "mono/metadata/gc-internals.h" #include "mono/metadata/mono-endian.h" #include "mono/metadata/object-internals.h" @@ -69,7 +70,7 @@ custom_attr_visible (MonoImage *image, MonoReflectionCustomAttr *cattr) /* FIXME: Need to do more checks */ if (cattr->ctor->method && (cattr->ctor->method->klass->image != image)) { - int visibility = cattr->ctor->method->klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK; + int visibility = mono_class_get_flags (cattr->ctor->method->klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK; if ((visibility != TYPE_ATTRIBUTE_PUBLIC) && (visibility != TYPE_ATTRIBUTE_NESTED_PUBLIC)) return FALSE; @@ -121,7 +122,7 @@ find_field_index (MonoClass *klass, MonoClassField *field) { for (i = 0; i < klass->field.count; ++i) { if (field == &klass->fields [i]) - return klass->field.first + 1 + i; + return mono_class_get_first_field_idx (klass) + 1 + i; } return 0; } @@ -1072,7 +1073,7 @@ MonoCustomAttrInfo* mono_custom_attrs_from_index (MonoImage *image, guint32 idx) { MonoError error; - MonoCustomAttrInfo *result = mono_custom_attrs_from_index_checked (image, idx, &error); + MonoCustomAttrInfo *result = mono_custom_attrs_from_index_checked (image, idx, FALSE, &error); mono_error_cleanup (&error); return result; } @@ -1082,7 +1083,7 @@ mono_custom_attrs_from_index (MonoImage *image, guint32 idx) * Returns: NULL if no attributes are found. On error returns NULL and sets @error. */ MonoCustomAttrInfo* -mono_custom_attrs_from_index_checked (MonoImage *image, guint32 idx, MonoError *error) +mono_custom_attrs_from_index_checked (MonoImage *image, guint32 idx, gboolean ignore_missing, MonoError *error) { guint32 mtoken, i, len; guint32 cols [MONO_CUSTOM_ATTR_SIZE]; @@ -1129,10 +1130,15 @@ mono_custom_attrs_from_index_checked (MonoImage *image, guint32 idx, MonoError * attr = &ainfo->attrs [i - 1]; attr->ctor = mono_get_method_checked (image, mtoken, NULL, NULL, error); if (!attr->ctor) { - g_warning ("Can't find custom attr constructor image: %s mtoken: 0x%08x due to %s", image->name, mtoken, mono_error_get_message (error)); - g_list_free (list); - g_free (ainfo); - return NULL; + g_warning ("Can't find custom attr constructor image: %s mtoken: 0x%08x due to: %s", image->name, mtoken, mono_error_get_message (error)); + if (ignore_missing) { + mono_error_cleanup (error); + mono_error_init (error); + } else { + g_list_free (list); + g_free (ainfo); + return NULL; + } } if (!mono_verifier_verify_cattr_blob (image, cols [MONO_CUSTOM_ATTR_VALUE], NULL)) { @@ -1186,7 +1192,7 @@ mono_custom_attrs_from_method_checked (MonoMethod *method, MonoError *error) idx = mono_method_get_index (method); idx <<= MONO_CUSTOM_ATTR_BITS; idx |= MONO_CUSTOM_ATTR_METHODDEF; - return mono_custom_attrs_from_index_checked (method->klass->image, idx, error); + return mono_custom_attrs_from_index_checked (method->klass->image, idx, FALSE, error); } MonoCustomAttrInfo* @@ -1205,8 +1211,8 @@ mono_custom_attrs_from_class_checked (MonoClass *klass, MonoError *error) mono_error_init (error); - if (klass->generic_class) - klass = klass->generic_class->container_class; + if (mono_class_is_ginst (klass)) + klass = mono_class_get_generic_class (klass)->container_class; if (image_is_dynamic (klass->image)) return lookup_custom_attr (klass->image, klass); @@ -1220,20 +1226,20 @@ mono_custom_attrs_from_class_checked (MonoClass *klass, MonoError *error) idx <<= MONO_CUSTOM_ATTR_BITS; idx |= MONO_CUSTOM_ATTR_TYPEDEF; } - return mono_custom_attrs_from_index_checked (klass->image, idx, error); + return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error); } MonoCustomAttrInfo* mono_custom_attrs_from_assembly (MonoAssembly *assembly) { MonoError error; - MonoCustomAttrInfo *result = mono_custom_attrs_from_assembly_checked (assembly, &error); + MonoCustomAttrInfo *result = mono_custom_attrs_from_assembly_checked (assembly, FALSE, &error); mono_error_cleanup (&error); return result; } MonoCustomAttrInfo* -mono_custom_attrs_from_assembly_checked (MonoAssembly *assembly, MonoError *error) +mono_custom_attrs_from_assembly_checked (MonoAssembly *assembly, gboolean ignore_missing, MonoError *error) { guint32 idx; @@ -1244,7 +1250,7 @@ mono_custom_attrs_from_assembly_checked (MonoAssembly *assembly, MonoError *erro idx = 1; /* there is only one assembly */ idx <<= MONO_CUSTOM_ATTR_BITS; idx |= MONO_CUSTOM_ATTR_ASSEMBLY; - return mono_custom_attrs_from_index_checked (assembly->image, idx, error); + return mono_custom_attrs_from_index_checked (assembly->image, idx, ignore_missing, error); } static MonoCustomAttrInfo* @@ -1257,7 +1263,7 @@ mono_custom_attrs_from_module (MonoImage *image, MonoError *error) idx = 1; /* there is only one module */ idx <<= MONO_CUSTOM_ATTR_BITS; idx |= MONO_CUSTOM_ATTR_MODULE; - return mono_custom_attrs_from_index_checked (image, idx, error); + return mono_custom_attrs_from_index_checked (image, idx, FALSE, error); } MonoCustomAttrInfo* @@ -1281,7 +1287,7 @@ mono_custom_attrs_from_property_checked (MonoClass *klass, MonoProperty *propert idx = find_property_index (klass, property); idx <<= MONO_CUSTOM_ATTR_BITS; idx |= MONO_CUSTOM_ATTR_PROPERTY; - return mono_custom_attrs_from_index_checked (klass->image, idx, error); + return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error); } MonoCustomAttrInfo* @@ -1305,7 +1311,7 @@ mono_custom_attrs_from_event_checked (MonoClass *klass, MonoEvent *event, MonoEr idx = find_event_index (klass, event); idx <<= MONO_CUSTOM_ATTR_BITS; idx |= MONO_CUSTOM_ATTR_EVENT; - return mono_custom_attrs_from_index_checked (klass->image, idx, error); + return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error); } MonoCustomAttrInfo* @@ -1330,7 +1336,7 @@ mono_custom_attrs_from_field_checked (MonoClass *klass, MonoClassField *field, M idx = find_field_index (klass, field); idx <<= MONO_CUSTOM_ATTR_BITS; idx |= MONO_CUSTOM_ATTR_FIELDDEF; - return mono_custom_attrs_from_index_checked (klass->image, idx, error); + return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error); } /** @@ -1426,7 +1432,7 @@ mono_custom_attrs_from_param_checked (MonoMethod *method, guint32 param, MonoErr idx = i; idx <<= MONO_CUSTOM_ATTR_BITS; idx |= MONO_CUSTOM_ATTR_PARAMDEF; - return mono_custom_attrs_from_index_checked (image, idx, error); + return mono_custom_attrs_from_index_checked (image, idx, FALSE, error); } gboolean @@ -1525,7 +1531,7 @@ mono_reflection_get_custom_attrs_info_checked (MonoObject *obj, MonoError *error return_val_if_nok (error, NULL); } else if (strcmp ("Assembly", klass->name) == 0 || strcmp ("MonoAssembly", klass->name) == 0) { MonoReflectionAssembly *rassembly = (MonoReflectionAssembly*)obj; - cinfo = mono_custom_attrs_from_assembly_checked (rassembly->assembly, error); + cinfo = mono_custom_attrs_from_assembly_checked (rassembly->assembly, FALSE, error); return_val_if_nok (error, NULL); } else if (strcmp ("Module", klass->name) == 0 || strcmp ("MonoModule", klass->name) == 0) { MonoReflectionModule *module = (MonoReflectionModule*)obj; @@ -1705,3 +1711,174 @@ mono_reflection_get_custom_attrs_data_checked (MonoObject *obj, MonoError *error return result; } + +static gboolean +custom_attr_class_name_from_methoddef (MonoImage *image, guint32 method_token, const gchar **nspace, const gchar **class_name) +{ + /* mono_get_method_from_token () */ + g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD); + guint32 type_token = mono_metadata_typedef_from_method (image, method_token); + if (!type_token) { + /* Bad method token (could not find corresponding typedef) */ + return FALSE; + } + type_token |= MONO_TOKEN_TYPE_DEF; + { + /* mono_class_create_from_typedef () */ + MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF]; + guint32 cols [MONO_TYPEDEF_SIZE]; + guint tidx = mono_metadata_token_index (type_token); + + if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) { + /* "Invalid typedef token %x", type_token */ + return FALSE; + } + + mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE); + + if (class_name) + *class_name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]); + if (nspace) + *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]); + return TRUE; + } +} + + +/** + * custom_attr_class_name_from_method_token: + * @image: The MonoImage + * @method_token: a token for a custom attr constructor in @image + * @assembly_token: out argment set to the assembly ref token of the custom attr + * @nspace: out argument set to namespace (a string in the string heap of @image) of the custom attr + * @class_name: out argument set to the class name of the custom attr. + * + * Given an @image and a @method_token (which is assumed to be a + * constructor), fills in the out arguments with the assembly ref (if + * a methodref) and the namespace and class name of the custom + * attribute. + * + * Returns: TRUE on success, FALSE otherwise. + * + * LOCKING: does not take locks + */ +static gboolean +custom_attr_class_name_from_method_token (MonoImage *image, guint32 method_token, guint32 *assembly_token, const gchar **nspace, const gchar **class_name) +{ + /* This only works with method tokens constructed from a + * custom attr token, which can only be methoddef or + * memberref */ + g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD + || mono_metadata_token_table (method_token) == MONO_TABLE_MEMBERREF); + + if (mono_metadata_token_table (method_token) == MONO_TABLE_MEMBERREF) { + /* method_from_memberref () */ + guint32 cols[6]; + guint32 nindex, class_index; + + int idx = mono_metadata_token_index (method_token); + + mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3); + nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS; + class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK; + if (class_index == MONO_MEMBERREF_PARENT_TYPEREF) { + guint32 type_token = MONO_TOKEN_TYPE_REF | nindex; + /* mono_class_from_typeref_checked () */ + { + guint32 cols [MONO_TYPEREF_SIZE]; + MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF]; + + mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE); + + if (class_name) + *class_name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]); + if (nspace) + *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]); + if (assembly_token) + *assembly_token = cols [MONO_TYPEREF_SCOPE]; + return TRUE; + } + } else if (class_index == MONO_MEMBERREF_PARENT_METHODDEF) { + guint32 methoddef_token = MONO_TOKEN_METHOD_DEF | nindex; + if (assembly_token) + *assembly_token = 0; + return custom_attr_class_name_from_methoddef (image, methoddef_token, nspace, class_name); + } else { + /* Attributes can't be generic, so it won't be + * a typespec, and they're always + * constructors, so it won't be a moduleref */ + g_assert_not_reached (); + } + } else { + /* must be MONO_TABLE_METHOD */ + if (assembly_token) + *assembly_token = 0; + return custom_attr_class_name_from_methoddef (image, method_token, nspace, class_name); + } +} + +/** + * mono_assembly_metadata_foreach_custom_attr: + * @assembly: the assembly to iterate over + * @func: the function to call for each custom attribute + * @user_data: passed to @func + * + * Calls @func for each custom attribute type on the given assembly until @func returns TRUE. + * Everything is done using low-level metadata APIs, so it is safe to use during assembly loading. + * + */ +void +mono_assembly_metadata_foreach_custom_attr (MonoAssembly *assembly, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data) +{ + MonoImage *image; + guint32 mtoken, i; + guint32 cols [MONO_CUSTOM_ATTR_SIZE]; + MonoTableInfo *ca; + guint32 idx; + + /* + * This might be called during assembly loading, so do everything using the low-level + * metadata APIs. + */ + + image = assembly->image; + g_assert (!image_is_dynamic (image)); + idx = 1; /* there is only one assembly */ + idx <<= MONO_CUSTOM_ATTR_BITS; + idx |= MONO_CUSTOM_ATTR_ASSEMBLY; + + /* Inlined from mono_custom_attrs_from_index_checked () */ + ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE]; + i = mono_metadata_custom_attrs_from_index (image, idx); + if (!i) + return; + i --; + gboolean stop_iterating = FALSE; + while (!stop_iterating && i < ca->rows) { + if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx) + break; + mono_metadata_decode_row (ca, i, cols, MONO_CUSTOM_ATTR_SIZE); + i ++; + mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS; + switch (cols [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) { + case MONO_CUSTOM_ATTR_TYPE_METHODDEF: + mtoken |= MONO_TOKEN_METHOD_DEF; + break; + case MONO_CUSTOM_ATTR_TYPE_MEMBERREF: + mtoken |= MONO_TOKEN_MEMBER_REF; + break; + default: + g_warning ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]); + continue; + } + + const char *nspace = NULL; + const char *name = NULL; + guint32 assembly_token = 0; + + if (!custom_attr_class_name_from_method_token (image, mtoken, &assembly_token, &nspace, &name)) + continue; + + stop_iterating = func (image, assembly_token, nspace, name, mtoken, user_data); + } +} diff --git a/mono/metadata/domain.c b/mono/metadata/domain.c index adb8909f460..020b0dd00c4 100644 --- a/mono/metadata/domain.c +++ b/mono/metadata/domain.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -510,7 +511,7 @@ mono_init_internal (const char *filename, const char *exe_filename, const char * static MonoDomain *domain = NULL; MonoAssembly *ass = NULL; MonoImageOpenStatus status = MONO_IMAGE_OK; - const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1]; + const MonoRuntimeInfo* runtimes [G_N_ELEMENTS (supported_runtimes) + 1] = { NULL }; int n, dummy; #ifdef DEBUG_DOMAIN_UNLOAD @@ -534,6 +535,7 @@ mono_init_internal (const char *filename, const char *exe_filename, const char * mono_w32mutex_init (); mono_w32semaphore_init (); mono_w32event_init (); + mono_w32process_init (); #ifndef DISABLE_PERFCOUNTERS mono_perfcounters_init (); @@ -814,16 +816,6 @@ mono_init_internal (const char *filename, const char *exe_filename, const char * mono_profiler_appdomain_name (domain, domain->friendly_name); - /* Have to do this quite late so that we at least have System.Object */ - MonoError custom_attr_error; - if (mono_assembly_has_reference_assembly_attribute (ass, &custom_attr_error)) { - char *corlib_file = g_build_filename (mono_assembly_getrootdir (), "mono", current_runtime->framework_version, "mscorlib.dll", NULL); - g_print ("Could not load file or assembly %s. Reference assemblies should not be loaded for execution. They can only be loaded in the Reflection-only loader context.", corlib_file); - g_free (corlib_file); - exit (1); - } - mono_error_assert_ok (&custom_attr_error); - return domain; } @@ -908,6 +900,8 @@ mono_cleanup (void) mono_native_tls_free (appdomain_thread_id); mono_coop_mutex_destroy (&appdomains_mutex); + mono_w32process_cleanup (); + #ifndef HOST_WIN32 wapi_cleanup (); #endif diff --git a/mono/metadata/file-io.c b/mono/metadata/file-io.c index dd722f289a9..7f55a5e9542 100644 --- a/mono/metadata/file-io.c +++ b/mono/metadata/file-io.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #undef DEBUG diff --git a/mono/metadata/file-mmap-posix.c b/mono/metadata/file-mmap-posix.c index 84e3b4aa68d..4b9ce74499e 100644 --- a/mono/metadata/file-mmap-posix.c +++ b/mono/metadata/file-mmap-posix.c @@ -63,7 +63,9 @@ enum { COULD_NOT_OPEN, CAPACITY_MUST_BE_POSITIVE, INVALID_FILE_MODE, - COULD_NOT_MAP_MEMORY + COULD_NOT_MAP_MEMORY, + ACCESS_DENIED, + CAPACITY_LARGER_THAN_LOGICAL_ADDRESS_SPACE }; enum { @@ -300,10 +302,16 @@ static void* open_memory_map (const char *c_mapName, int mode, gint64 *capacity, int access, int options, int *ioerror) { MmapHandle *handle; - if (*capacity <= 1) { + if (*capacity <= 0) { *ioerror = CAPACITY_MUST_BE_POSITIVE; return NULL; } +#if SIZEOF_VOID_P == 4 + if (*capacity > UINT32_MAX) { + *ioerror = CAPACITY_LARGER_THAN_LOGICAL_ADDRESS_SPACE; + return NULL; + } +#endif if (!(mode == FILE_MODE_CREATE_NEW || mode == FILE_MODE_OPEN_OR_CREATE || mode == FILE_MODE_OPEN)) { *ioerror = INVALID_FILE_MODE; @@ -499,8 +507,11 @@ mono_mmap_map (void *handle, gint64 offset, gint64 *size, int access, void **mma struct stat buf = { 0 }; fstat (fh->fd, &buf); //FIXME error handling + *mmap_handle = NULL; + *base_address = NULL; + if (offset > buf.st_size || ((eff_size + offset) > buf.st_size && !is_special_zero_size_file (&buf))) - goto error; + return ACCESS_DENIED; /** * We use the file size if one of the following conditions is true: * -input size is zero @@ -522,9 +533,6 @@ mono_mmap_map (void *handle, gint64 offset, gint64 *size, int access, void **mma return 0; } -error: - *mmap_handle = NULL; - *base_address = NULL; return COULD_NOT_MAP_MEMORY; } diff --git a/mono/metadata/file-mmap-windows.c b/mono/metadata/file-mmap-windows.c index dba37472c34..b0fd5d9b896 100644 --- a/mono/metadata/file-mmap-windows.c +++ b/mono/metadata/file-mmap-windows.c @@ -1,71 +1,413 @@ /* - * file-mmap-posix.c: File mmap internal calls + * file-mmap-windows.c: MemoryMappedFile internal calls for Windows * - * Author: - * Rodrigo Kumpera - * - * Copyright 2014 Xamarin Inc (http://www.xamarin.com) + * Copyright 2016 Microsoft * Licensed under the MIT license. See LICENSE file in the project root for full license information. */ +/* + * The code in this file has been inspired by the CoreFX MemoryMappedFile Windows implementation contained in the files + * + * https://github.com/dotnet/corefx/blob/master/src/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedFile.Windows.cs + * https://github.com/dotnet/corefx/blob/master/src/System.IO.MemoryMappedFiles/src/System/IO/MemoryMappedFiles/MemoryMappedView.Windows.cs + */ + #include #ifdef HOST_WIN32 #include -#include -#include - -#include #include -void * -mono_mmap_open_file (MonoString *path, int mode, MonoString *mapName, gint64 *capacity, int access, int options, int *error) +// These control the retry behaviour when lock violation errors occur during Flush: +#define MAX_FLUSH_WAITS 15 // must be <=30 +#define MAX_FLUSH_RETIRES_PER_WAIT 20 + +typedef struct { + void *address; + size_t length; +} MmapInstance; + +enum { + BAD_CAPACITY_FOR_FILE_BACKED = 1, + CAPACITY_SMALLER_THAN_FILE_SIZE, + FILE_NOT_FOUND, + FILE_ALREADY_EXISTS, + PATH_TOO_LONG, + COULD_NOT_OPEN, + CAPACITY_MUST_BE_POSITIVE, + INVALID_FILE_MODE, + COULD_NOT_MAP_MEMORY, + ACCESS_DENIED, + CAPACITY_LARGER_THAN_LOGICAL_ADDRESS_SPACE +}; + +enum { + FILE_MODE_CREATE_NEW = 1, + FILE_MODE_CREATE = 2, + FILE_MODE_OPEN = 3, + FILE_MODE_OPEN_OR_CREATE = 4, + FILE_MODE_TRUNCATE = 5, + FILE_MODE_APPEND = 6, +}; + +enum { + MMAP_FILE_ACCESS_READ_WRITE = 0, + MMAP_FILE_ACCESS_READ = 1, + MMAP_FILE_ACCESS_WRITE = 2, + MMAP_FILE_ACCESS_COPY_ON_WRITE = 3, + MMAP_FILE_ACCESS_READ_EXECUTE = 4, + MMAP_FILE_ACCESS_READ_WRITE_EXECUTE = 5, +}; + +static DWORD get_page_access (int access) { - g_error ("No windows backend"); - return NULL; + switch (access) { + case MMAP_FILE_ACCESS_READ: + return PAGE_READONLY; + case MMAP_FILE_ACCESS_READ_WRITE: + return PAGE_READWRITE; + case MMAP_FILE_ACCESS_COPY_ON_WRITE: + return PAGE_WRITECOPY; + case MMAP_FILE_ACCESS_READ_EXECUTE: + return PAGE_EXECUTE_READ; + case MMAP_FILE_ACCESS_READ_WRITE_EXECUTE: + return PAGE_EXECUTE_READWRITE; + default: + g_error ("unknown MemoryMappedFileAccess %d", access); + } } -void * -mono_mmap_open_handle (void *handle, MonoString *mapName, gint64 *capacity, int access, int options, int *error) +static DWORD get_file_access (int access) { - g_error ("No windows backend"); - return NULL; + switch (access) { + case MMAP_FILE_ACCESS_READ: + case MMAP_FILE_ACCESS_READ_EXECUTE: + return GENERIC_READ; + case MMAP_FILE_ACCESS_READ_WRITE: + case MMAP_FILE_ACCESS_COPY_ON_WRITE: + case MMAP_FILE_ACCESS_READ_WRITE_EXECUTE: + return GENERIC_READ | GENERIC_WRITE; + case MMAP_FILE_ACCESS_WRITE: + return GENERIC_WRITE; + default: + g_error ("unknown MemoryMappedFileAccess %d", access); + } } -void -mono_mmap_close (void *mmap_handle) +static int get_file_map_access (int access) { - g_error ("No windows backend"); + switch (access) { + case MMAP_FILE_ACCESS_READ: + return FILE_MAP_READ; + case MMAP_FILE_ACCESS_WRITE: + return FILE_MAP_WRITE; + case MMAP_FILE_ACCESS_READ_WRITE: + return FILE_MAP_READ | FILE_MAP_WRITE; + case MMAP_FILE_ACCESS_COPY_ON_WRITE: + return FILE_MAP_COPY; + case MMAP_FILE_ACCESS_READ_EXECUTE: + return FILE_MAP_EXECUTE | FILE_MAP_READ; + case MMAP_FILE_ACCESS_READ_WRITE_EXECUTE: + return FILE_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE; + default: + g_error ("unknown MemoryMappedFileAccess %d", access); + } } -void -mono_mmap_configure_inheritability (void *mmap_handle, gboolean inheritability) +static int convert_win32_error (int error, int def) { - g_error ("No windows backend"); + switch (error) { + case ERROR_FILE_NOT_FOUND: + return FILE_NOT_FOUND; + case ERROR_FILE_EXISTS: + case ERROR_ALREADY_EXISTS: + return FILE_ALREADY_EXISTS; + case ERROR_ACCESS_DENIED: + return ACCESS_DENIED; + } + return def; } -void -mono_mmap_flush (void *mmap_handle) +static void *open_handle (void *handle, MonoString *mapName, int mode, gint64 *capacity, int access, int options, int *error) { - g_error ("No windows backend"); + g_assert (handle != NULL); + + wchar_t *w_mapName = NULL; + HANDLE result = NULL; + + if (handle == INVALID_HANDLE_VALUE) { + if (*capacity <= 0) { + *error = CAPACITY_MUST_BE_POSITIVE; + return NULL; + } +#if SIZEOF_VOID_P == 4 + if (*capacity > UINT32_MAX) { + *error = CAPACITY_LARGER_THAN_LOGICAL_ADDRESS_SPACE; + return NULL; + } +#endif + if (!(mode == FILE_MODE_CREATE_NEW || mode == FILE_MODE_OPEN_OR_CREATE || mode == FILE_MODE_OPEN)) { + *error = INVALID_FILE_MODE; + return NULL; + } + } else { + FILE_STANDARD_INFO info; + if (!GetFileInformationByHandleEx ((HANDLE) handle, FileStandardInfo, &info, sizeof (FILE_STANDARD_INFO))) { + *error = convert_win32_error (GetLastError (), COULD_NOT_OPEN); + return NULL; + } + if (*capacity == 0) { + if (info.EndOfFile.QuadPart == 0) { + *error = CAPACITY_SMALLER_THAN_FILE_SIZE; + return NULL; + } + } else if (*capacity < info.EndOfFile.QuadPart) { + *error = CAPACITY_SMALLER_THAN_FILE_SIZE; + return NULL; + } + } + + w_mapName = mapName ? mono_string_to_utf16 (mapName) : NULL; + + if (mode == FILE_MODE_CREATE_NEW || handle != INVALID_HANDLE_VALUE) { + result = CreateFileMappingW ((HANDLE)handle, NULL, get_page_access (access) | options, (DWORD)(((guint64)*capacity) >> 32), (DWORD)*capacity, w_mapName); + if (result && GetLastError () == ERROR_ALREADY_EXISTS) { + CloseHandle (result); + result = NULL; + *error = FILE_ALREADY_EXISTS; + } else if (!result && GetLastError () != NO_ERROR) { + *error = convert_win32_error (GetLastError (), COULD_NOT_OPEN); + } + } else if (mode == FILE_MODE_OPEN || mode == FILE_MODE_OPEN_OR_CREATE && access == MMAP_FILE_ACCESS_WRITE) { + result = OpenFileMappingW (get_file_map_access (access), FALSE, w_mapName); + if (!result) { + if (mode == FILE_MODE_OPEN_OR_CREATE && GetLastError () == ERROR_FILE_NOT_FOUND) { + *error = INVALID_FILE_MODE; + } else { + *error = convert_win32_error (GetLastError (), COULD_NOT_OPEN); + } + } + } else if (mode == FILE_MODE_OPEN_OR_CREATE) { + + // This replicates how CoreFX does MemoryMappedFile.CreateOrOpen (). + + /// Try to open the file if it exists -- this requires a bit more work. Loop until we can + /// either create or open a memory mapped file up to a timeout. CreateFileMapping may fail + /// if the file exists and we have non-null security attributes, in which case we need to + /// use OpenFileMapping. But, there exists a race condition because the memory mapped file + /// may have closed between the two calls -- hence the loop. + /// + /// The retry/timeout logic increases the wait time each pass through the loop and times + /// out in approximately 1.4 minutes. If after retrying, a MMF handle still hasn't been opened, + /// throw an InvalidOperationException. + + guint32 waitRetries = 14; //((2^13)-1)*10ms == approximately 1.4mins + guint32 waitSleep = 0; + + while (waitRetries > 0) { + result = CreateFileMappingW ((HANDLE)handle, NULL, get_page_access (access) | options, (DWORD)(((guint64)*capacity) >> 32), (DWORD)*capacity, w_mapName); + if (result) + break; + if (GetLastError() != ERROR_ACCESS_DENIED) { + *error = convert_win32_error (GetLastError (), COULD_NOT_OPEN); + break; + } + result = OpenFileMappingW (get_file_map_access (access), FALSE, w_mapName); + if (result) + break; + if (GetLastError () != ERROR_FILE_NOT_FOUND) { + *error = convert_win32_error (GetLastError (), COULD_NOT_OPEN); + break; + } + // increase wait time + --waitRetries; + if (waitSleep == 0) { + waitSleep = 10; + } else { + mono_thread_info_sleep (waitSleep, NULL); + waitSleep *= 2; + } + } + + if (!result) { + *error = COULD_NOT_OPEN; + } + } + + if (w_mapName) + g_free (w_mapName); + return result; } +void *mono_mmap_open_file (MonoString *path, int mode, MonoString *mapName, gint64 *capacity, int access, int options, int *error) +{ + g_assert (path != NULL || mapName != NULL); + + wchar_t *w_path = NULL; + HANDLE hFile = INVALID_HANDLE_VALUE; + HANDLE result = NULL; + gboolean delete_on_error = FALSE; + if (path) { + w_path = mono_string_to_utf16 (path); + WIN32_FILE_ATTRIBUTE_DATA file_attrs; + gboolean existed = GetFileAttributesExW (w_path, GetFileExInfoStandard, &file_attrs); + if (!existed && mode == FILE_MODE_CREATE_NEW && *capacity == 0) { + *error = CAPACITY_SMALLER_THAN_FILE_SIZE; + goto done; + } + hFile = CreateFileW (w_path, get_file_access (access), FILE_SHARE_READ, NULL, mode, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + *error = convert_win32_error (GetLastError (), COULD_NOT_OPEN); + goto done; + } + delete_on_error = !existed; + } -int -mono_mmap_map (void *handle, gint64 offset, gint64 *size, int access, void **mmap_handle, void **base_address) + result = open_handle (hFile, mapName, mode, capacity, access, options, error); + +done: + if (!result && delete_on_error) + DeleteFileW (w_path); + if (w_path) + g_free (w_path); + + return result; +} + +void *mono_mmap_open_handle (void *handle, MonoString *mapName, gint64 *capacity, int access, int options, int *error) { - g_error ("No windows backend"); + g_assert (handle != NULL); + + return open_handle (handle, mapName, FILE_MODE_OPEN, capacity, access, options, error); +} + +void mono_mmap_close (void *mmap_handle) +{ + g_assert (mmap_handle); + CloseHandle ((HANDLE) mmap_handle); +} + +void mono_mmap_configure_inheritability (void *mmap_handle, gboolean inheritability) +{ + g_assert (mmap_handle); + if (!SetHandleInformation ((HANDLE) mmap_handle, HANDLE_FLAG_INHERIT, inheritability ? HANDLE_FLAG_INHERIT : 0)) { + g_error ("mono_mmap_configure_inheritability: SetHandleInformation failed with error %d!", GetLastError ()); + } +} + +void mono_mmap_flush (void *mmap_handle) +{ + g_assert (mmap_handle); + MmapInstance *h = (MmapInstance *)mmap_handle; + + if (FlushViewOfFile (h->address, h->length)) + return; + + // This replicates how CoreFX does MemoryMappedView.Flush (). + + // It is a known issue within the NTFS transaction log system that + // causes FlushViewOfFile to intermittently fail with ERROR_LOCK_VIOLATION + // As a workaround, we catch this particular error and retry the flush operation + // a few milliseconds later. If it does not work, we give it a few more tries with + // increasing intervals. Eventually, however, we need to give up. In ad-hoc tests + // this strategy successfully flushed the view after no more than 3 retries. + + if (GetLastError () != ERROR_LOCK_VIOLATION) + // TODO: Propagate error to caller + return; + + for (int w = 0; w < MAX_FLUSH_WAITS; w++) { + int pause = (1 << w); // MaxFlushRetries should never be over 30 + mono_thread_info_sleep (pause, NULL); + + for (int r = 0; r < MAX_FLUSH_RETIRES_PER_WAIT; r++) { + if (FlushViewOfFile (h->address, h->length)) + return; + + if (GetLastError () != ERROR_LOCK_VIOLATION) + // TODO: Propagate error to caller + return; + + mono_thread_info_yield (); + } + } + + // We got to here, so there was no success: + // TODO: Propagate error to caller +} + +int mono_mmap_map (void *handle, gint64 offset, gint64 *size, int access, void **mmap_handle, void **base_address) +{ + static DWORD allocationGranularity = 0; + if (allocationGranularity == 0) { + SYSTEM_INFO info; + GetSystemInfo (&info); + allocationGranularity = info.dwAllocationGranularity; + } + + gint64 extraMemNeeded = offset % allocationGranularity; + guint64 newOffset = offset - extraMemNeeded; + gint64 nativeSize = (*size != 0) ? *size + extraMemNeeded : 0; + +#if SIZEOF_VOID_P == 4 + if (nativeSize > UINT32_MAX) + return CAPACITY_LARGER_THAN_LOGICAL_ADDRESS_SPACE; +#endif + + void *address = MapViewOfFile ((HANDLE) handle, get_file_map_access (access), (DWORD) (newOffset >> 32), (DWORD) newOffset, (SIZE_T) nativeSize); + if (!address) + return convert_win32_error (GetLastError (), COULD_NOT_MAP_MEMORY); + + // Query the view for its size and allocation type + MEMORY_BASIC_INFORMATION viewInfo; + VirtualQuery (address, &viewInfo, sizeof (MEMORY_BASIC_INFORMATION)); + guint64 viewSize = (guint64) viewInfo.RegionSize; + + // Allocate the pages if we were using the MemoryMappedFileOptions.DelayAllocatePages option + // OR check if the allocated view size is smaller than the expected native size + // If multiple overlapping views are created over the file mapping object, the pages in a given region + // could have different attributes(MEM_RESERVE OR MEM_COMMIT) as MapViewOfFile preserves coherence between + // views created on a mapping object backed by same file. + // In which case, the viewSize will be smaller than nativeSize required and viewState could be MEM_COMMIT + // but more pages may need to be committed in the region. + // This is because, VirtualQuery function(that internally invokes VirtualQueryEx function) returns the attributes + // and size of the region of pages with matching attributes starting from base address. + // VirtualQueryEx: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366907(v=vs.85).aspx + if (((viewInfo.State & MEM_RESERVE) != 0) || viewSize < (guint64) nativeSize) { + void *tempAddress = VirtualAlloc (address, nativeSize != 0 ? nativeSize : viewSize, MEM_COMMIT, get_page_access (access)); + if (!tempAddress) { + return convert_win32_error (GetLastError (), COULD_NOT_MAP_MEMORY); + } + // again query the view for its new size + VirtualQuery (address, &viewInfo, sizeof (MEMORY_BASIC_INFORMATION)); + viewSize = (guint64) viewInfo.RegionSize; + } + + if (*size == 0) + *size = viewSize - extraMemNeeded; + + MmapInstance *h = g_malloc0 (sizeof (MmapInstance)); + h->address = address; + h->length = *size + extraMemNeeded; + *mmap_handle = h; + *base_address = (char*) address + (offset - newOffset); + return 0; } -gboolean -mono_mmap_unmap (void *mmap_handle) +gboolean mono_mmap_unmap (void *mmap_handle) { - g_error ("No windows backend"); - return TRUE; + g_assert (mmap_handle); + + MmapInstance *h = (MmapInstance *) mmap_handle; + + gboolean result = UnmapViewOfFile (h->address); + + g_free (h); + return result; } #endif diff --git a/mono/metadata/gc-internals.h b/mono/metadata/gc-internals.h index afb6522d1cb..2ef55c6e673 100644 --- a/mono/metadata/gc-internals.h +++ b/mono/metadata/gc-internals.h @@ -360,6 +360,8 @@ guint mono_gc_get_vtable_bits (MonoClass *klass); void mono_gc_register_altstack (gpointer stack, gint32 stack_size, gpointer altstack, gint32 altstack_size); +gboolean mono_gc_is_critical_method (MonoMethod *method); + /* If set, print debugging messages around finalizers. */ extern gboolean log_finalizers; diff --git a/mono/metadata/gc.c b/mono/metadata/gc.c index ae4329be666..e66b4da35a2 100644 --- a/mono/metadata/gc.c +++ b/mono/metadata/gc.c @@ -91,13 +91,13 @@ static void mono_reference_queue_cleanup (void); static void reference_queue_clear_for_domain (MonoDomain *domain); -static guint32 -guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable) +static MonoThreadInfoWaitRet +guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable) { - guint32 result; + MonoThreadInfoWaitRet result; MONO_ENTER_GC_SAFE; - result = WaitForSingleObjectEx (handle, timeout, alertable); + result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable); MONO_EXIT_GC_SAFE; return result; @@ -642,7 +642,9 @@ ves_icall_System_GC_WaitForPendingFinalizers (void) ResetEvent (pending_done_event); mono_gc_finalize_notify (); /* g_print ("Waiting for pending finalizers....\n"); */ - guarded_wait (pending_done_event, INFINITE, TRUE); + MONO_ENTER_GC_SAFE; + WaitForSingleObjectEx (pending_done_event, INFINITE, TRUE); + MONO_EXIT_GC_SAFE; /* g_print ("Done pending....\n"); */ #else gboolean alerted = FALSE; @@ -730,7 +732,7 @@ ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle) } else { /* the C# code will check and throw the exception */ /* FIXME: missing !klass->blittable test, see bug #61134 */ - if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) + if (mono_class_is_auto_layout (klass)) return (gpointer)-1; return (char*)obj + sizeof (MonoObject); } @@ -1014,6 +1016,7 @@ mono_gc_cleanup (void) if (!gc_disabled) { finished = TRUE; if (mono_thread_internal_current () != gc_thread) { + int ret; gint64 start_ticks = mono_msec_ticks (); gint64 end_ticks = start_ticks + 2000; @@ -1035,8 +1038,6 @@ mono_gc_cleanup (void) } if (!finalizer_thread_exited) { - int ret; - /* Set a flag which the finalizer thread can check */ suspend_finalizers = TRUE; mono_gc_suspend_finalizers (); @@ -1047,23 +1048,22 @@ mono_gc_cleanup (void) /* Wait for it to stop */ ret = guarded_wait (gc_thread->handle, 100, TRUE); - if (ret == WAIT_TIMEOUT) { + if (ret == MONO_THREAD_INFO_WAIT_RET_TIMEOUT) { /* * The finalizer thread refused to exit. Make it stop. */ mono_thread_internal_stop (gc_thread); ret = guarded_wait (gc_thread->handle, 100, TRUE); - g_assert (ret != WAIT_TIMEOUT); + g_assert (ret != MONO_THREAD_INFO_WAIT_RET_TIMEOUT); /* The thread can't set this flag */ finalizer_thread_exited = TRUE; } } - int ret; /* Wait for the thread to actually exit */ ret = guarded_wait (gc_thread->handle, INFINITE, TRUE); - g_assert (ret == WAIT_OBJECT_0); + g_assert (ret == MONO_THREAD_INFO_WAIT_RET_SUCCESS_0); mono_thread_join (GUINT_TO_POINTER (gc_thread->tid)); g_assert (finalizer_thread_exited); diff --git a/mono/metadata/handle.c b/mono/metadata/handle.c index 44327aed131..e201b38c687 100644 --- a/mono/metadata/handle.c +++ b/mono/metadata/handle.c @@ -163,8 +163,10 @@ mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data) while (cur) { int i; - for (i = 0; i < cur->size; ++i) - func ((gpointer*)&cur->objects [i], gc_data); + for (i = 0; i < cur->size; ++i) { + if (cur->objects [i] != NULL) + func ((gpointer*)&cur->objects [i], gc_data); + } if (cur == last) break; cur = cur->next; @@ -185,7 +187,7 @@ mono_stack_mark_record_size (MonoThreadInfo *info, HandleStackMark *stackmark, c } if (size > THIS_IS_AN_OK_NUMBER_OF_HANDLES) - printf ("%s USED %d handles\n", func_name, size); + g_warning ("%s USED %d handles\n", func_name, size); } /* diff --git a/mono/metadata/icall-def.h b/mono/metadata/icall-def.h index d74def55570..f264c4851ac 100644 --- a/mono/metadata/icall-def.h +++ b/mono/metadata/icall-def.h @@ -702,9 +702,7 @@ ICALL(MARSHAL_13, "Prelink", ves_icall_System_Runtime_InteropServices_Marshal_Pr ICALL(MARSHAL_14, "PrelinkAll", ves_icall_System_Runtime_InteropServices_Marshal_PrelinkAll) ICALL(MARSHAL_15, "PtrToStringAnsi(intptr)", ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi) ICALL(MARSHAL_16, "PtrToStringAnsi(intptr,int)", ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len) -#ifndef DISABLE_COM ICALL(MARSHAL_17, "PtrToStringBSTR", ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR) -#endif ICALL(MARSHAL_18, "PtrToStringUni(intptr)", ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni) ICALL(MARSHAL_19, "PtrToStringUni(intptr,int)", ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len) ICALL(MARSHAL_20, "PtrToStructure(intptr,System.Type)", ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type) diff --git a/mono/metadata/icall-internals.h b/mono/metadata/icall-internals.h index e2ec7762a3f..45a922c9c78 100644 --- a/mono/metadata/icall-internals.h +++ b/mono/metadata/icall-internals.h @@ -49,9 +49,6 @@ mono_icall_broadcast_setting_change (void); void mono_icall_write_windows_debug_string (MonoString *message); -MonoBoolean -mono_icall_close_process (gpointer handle); - gint32 mono_icall_wait_for_input_idle (gpointer handle, gint32 milliseconds); #endif /* HOST_WIN32 */ @@ -65,18 +62,6 @@ mono_icall_get_logical_drives (void); guint32 mono_icall_drive_info_get_drive_type (MonoString *root_path_name); - -MonoBoolean -mono_icall_get_process_working_set_size (gpointer handle, gsize *min, gsize *max); - -MonoBoolean -mono_icall_set_process_working_set_size (gpointer handle, gsize min, gsize max); - -gint32 -mono_icall_get_priority_class (gpointer handle); - -MonoBoolean -mono_icall_set_priority_class (gpointer handle, gint32 priorityClass); #endif /* !G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ #endif /* __MONO_METADATA_ICALL_INTERNALS_H__ */ diff --git a/mono/metadata/icall-windows-uwp.c b/mono/metadata/icall-windows-uwp.c index f27319863c3..0b5afa2624b 100644 --- a/mono/metadata/icall-windows-uwp.c +++ b/mono/metadata/icall-windows-uwp.c @@ -85,70 +85,6 @@ mono_icall_wait_for_input_idle (gpointer handle, gint32 milliseconds) return WAIT_TIMEOUT; } -MonoBoolean -mono_icall_get_process_working_set_size (gpointer handle, gsize *min, gsize *max) -{ - MonoError mono_error; - mono_error_init (&mono_error); - - g_unsupported_api ("GetProcessWorkingSetSize"); - - mono_error_set_not_supported(&mono_error, G_UNSUPPORTED_API, "GetProcessWorkingSetSize"); - mono_error_set_pending_exception (&mono_error); - - SetLastError (ERROR_NOT_SUPPORTED); - - return FALSE; -} - -MonoBoolean -mono_icall_set_process_working_set_size (gpointer handle, gsize min, gsize max) -{ - MonoError mono_error; - mono_error_init (&mono_error); - - g_unsupported_api ("SetProcessWorkingSetSize"); - - mono_error_set_not_supported (&mono_error, G_UNSUPPORTED_API, "SetProcessWorkingSetSize"); - mono_error_set_pending_exception (&mono_error); - - SetLastError (ERROR_NOT_SUPPORTED); - - return FALSE; -} - -gint32 -mono_icall_get_priority_class (gpointer handle) -{ - MonoError mono_error; - mono_error_init (&mono_error); - - g_unsupported_api ("GetPriorityClass"); - - mono_error_set_not_supported (&mono_error, G_UNSUPPORTED_API, "GetPriorityClass"); - mono_error_set_pending_exception (&mono_error); - - SetLastError (ERROR_NOT_SUPPORTED); - - return FALSE; -} - -MonoBoolean -mono_icall_set_priority_class (gpointer handle, gint32 priorityClass) -{ - MonoError mono_error; - mono_error_init (&mono_error); - - g_unsupported_api ("SetPriorityClass"); - - mono_error_set_not_supported(&mono_error, G_UNSUPPORTED_API, "SetPriorityClass"); - mono_error_set_pending_exception (&mono_error); - - SetLastError (ERROR_NOT_SUPPORTED); - - return FALSE; -} - #else /* G_HAVE_API_SUPPORT(HAVE_UWP_WINAPI_SUPPORT) */ #ifdef _MSC_VER diff --git a/mono/metadata/icall-windows.c b/mono/metadata/icall-windows.c index cd72e481eb4..9ebcf30f31b 100644 --- a/mono/metadata/icall-windows.c +++ b/mono/metadata/icall-windows.c @@ -213,9 +213,4 @@ mono_icall_write_windows_debug_string (MonoString *message) OutputDebugString (mono_string_chars (message)); } -MonoBoolean -mono_icall_close_process (gpointer handle) -{ - return (MonoBoolean)(CloseHandle (handle)); -} #endif /* HOST_WIN32 */ diff --git a/mono/metadata/icall.c b/mono/metadata/icall.c index ce2ea4883c6..0f54ea16dc0 100644 --- a/mono/metadata/icall.c +++ b/mono/metadata/icall.c @@ -63,7 +63,7 @@ #include #include #include -#include +#include #include #include #include @@ -944,7 +944,7 @@ ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_RunClassConstructor (Mo klass = mono_class_from_mono_type (handle); MONO_CHECK_ARG (handle, klass,); - if (klass->generic_container) + if (mono_class_is_gtd (klass)) return; vtable = mono_class_vtable_full (mono_domain_get (), klass, &error); @@ -1302,7 +1302,7 @@ get_caller_no_system_or_reflection (MonoMethod *m, gint32 no, gint32 ilo, gboole } static MonoReflectionType * -type_from_parsed_name (MonoTypeNameParse *info, MonoBoolean ignoreCase, MonoError *error) +type_from_parsed_name (MonoTypeNameParse *info, MonoBoolean ignoreCase, MonoAssembly **caller_assembly, MonoError *error) { MonoMethod *m, *dest; @@ -1353,6 +1353,7 @@ type_from_parsed_name (MonoTypeNameParse *info, MonoBoolean ignoreCase, MonoErro } else { g_warning (G_STRLOC); } + *caller_assembly = assembly; if (info->assembly.name) assembly = mono_assembly_load (&info->assembly, assembly ? assembly->basedir : NULL, NULL); @@ -1397,6 +1398,7 @@ ves_icall_System_Type_internal_from_name (MonoString *name, MonoTypeNameParse info; MonoReflectionType *type = NULL; gboolean parsedOk; + MonoAssembly *caller_assembly; char *str = mono_string_to_utf8_checked (name, &error); if (!is_ok (&error)) @@ -1412,18 +1414,27 @@ ves_icall_System_Type_internal_from_name (MonoString *name, goto leave; } - type = type_from_parsed_name (&info, ignoreCase, &error); + type = type_from_parsed_name (&info, ignoreCase, &caller_assembly, &error); - mono_reflection_free_type_info (&info); - - if (!is_ok (&error)) + if (!is_ok (&error)) { + mono_reflection_free_type_info (&info); goto leave; + } - if (type == NULL){ + if (type == NULL) { if (throwOnError) { - mono_error_set_type_load_name (&error, g_strdup (str), g_strdup (""), ""); - goto leave; + char *tname = info.name_space ? g_strdup_printf ("%s.%s", info.name_space, info.name) : g_strdup (info.name); + char *aname; + if (info.assembly.name) + aname = mono_stringify_assembly_name (&info.assembly); + else if (caller_assembly) + aname = mono_stringify_assembly_name (mono_assembly_get_name (caller_assembly)); + else + aname = g_strdup (""); + mono_error_set_type_load_name (&error, tname, aname, ""); } + mono_reflection_free_type_info (&info); + goto leave; } leave: @@ -1659,7 +1670,7 @@ ICALL_EXPORT guint32 ves_icall_RuntimeTypeHandle_GetAttributes (MonoReflectionType *type) { MonoClass *klass = mono_class_from_mono_type (type->type); - return klass->flags; + return mono_class_get_flags (klass); } ICALL_EXPORT MonoReflectionMarshalAsAttribute* @@ -1671,8 +1682,9 @@ ves_icall_System_Reflection_FieldInfo_get_marshal_info (MonoReflectionField *fie MonoType *ftype; int i; - if (klass->generic_container || - (klass->generic_class && klass->generic_class->context.class_inst->is_open)) + MonoGenericClass *gklass = mono_class_try_get_generic_class (klass); + if (mono_class_is_gtd (klass) || + (gklass && gklass->context.class_inst->is_open)) return NULL; ftype = mono_field_get_type (field->field); @@ -1882,8 +1894,6 @@ ICALL_EXPORT gint32 ves_icall_MonoField_GetFieldOffset (MonoReflectionField *field) { MonoClass *parent = field->field->parent; - if (!parent->size_inited) - mono_class_init (parent); mono_class_setup_fields (parent); return field->field->offset - sizeof (MonoObject); @@ -2360,7 +2370,7 @@ fill_iface_array (gpointer key, gpointer value, gpointer user_data) if (!mono_error_ok (data->error)) return; - if (data->context && ic->generic_class && ic->generic_class->context.class_inst->is_open) { + if (data->context && mono_class_is_ginst (ic) && mono_class_get_generic_class (ic)->context.class_inst->is_open) { inflated = ret = mono_class_inflate_generic_type_checked (ret, data->context, data->error); if (!mono_error_ok (data->error)) return; @@ -2395,9 +2405,9 @@ ves_icall_RuntimeType_GetInterfaces (MonoReflectionType* type) GHashTable *iface_hash = g_hash_table_new (get_interfaces_hash, NULL); - if (klass->generic_class && klass->generic_class->context.class_inst->is_open) { + if (mono_class_is_ginst (klass) && mono_class_get_generic_class (klass)->context.class_inst->is_open) { data.context = mono_class_get_context (klass); - klass = klass->generic_class->container_class; + klass = mono_class_get_generic_class (klass)->container_class; } for (parent = klass; parent; parent = parent->parent) { @@ -2720,8 +2730,8 @@ ves_icall_RuntimeType_GetGenericArguments (MonoReflectionType *type, MonoBoolean klass = mono_class_from_mono_type (type->type); - if (klass->generic_container) { - MonoGenericContainer *container = klass->generic_container; + if (mono_class_is_gtd (klass)) { + MonoGenericContainer *container = mono_class_get_generic_container (klass); res = create_type_array (domain, runtimeTypeArray, container->type_argc, &error); if (mono_error_set_pending_exception (&error)) return NULL; @@ -2734,8 +2744,8 @@ ves_icall_RuntimeType_GetGenericArguments (MonoReflectionType *type, MonoBoolean mono_array_setref (res, i, rt); } - } else if (klass->generic_class) { - MonoGenericInst *inst = klass->generic_class->context.class_inst; + } else if (mono_class_is_ginst (klass)) { + MonoGenericInst *inst = mono_class_get_generic_class (klass)->context.class_inst; res = create_type_array (domain, runtimeTypeArray, inst->type_argc, &error); if (mono_error_set_pending_exception (&error)) return NULL; @@ -2764,7 +2774,7 @@ ves_icall_RuntimeTypeHandle_IsGenericTypeDefinition (MonoReflectionType *type) return FALSE; klass = mono_class_from_mono_type (type->type); - return klass->generic_container != NULL; + return mono_class_is_gtd (klass); } ICALL_EXPORT MonoReflectionType* @@ -2779,11 +2789,11 @@ ves_icall_RuntimeTypeHandle_GetGenericTypeDefinition_impl (MonoReflectionType *t klass = mono_class_from_mono_type (type->type); - if (klass->generic_container) { + if (mono_class_is_gtd (klass)) { return type; /* check this one */ } - if (klass->generic_class) { - MonoClass *generic_class = klass->generic_class->container_class; + if (mono_class_is_ginst (klass)) { + MonoClass *generic_class = mono_class_get_generic_class (klass)->container_class; gpointer tb; tb = mono_class_get_ref_info (generic_class); @@ -2832,7 +2842,7 @@ ves_icall_RuntimeType_MakeGenericType (MonoReflectionType *type, MonoArray *type klass = mono_class_from_mono_type (geninst); /*we might inflate to the GTD*/ - if (klass->generic_class && !mono_verifier_class_is_valid_generic_instantiation (klass)) { + if (mono_class_is_ginst (klass) && !mono_verifier_class_is_valid_generic_instantiation (klass)) { mono_set_pending_exception (mono_get_exception_argument ("typeArguments", "Invalid generic arguments")); return NULL; } @@ -2855,7 +2865,7 @@ ves_icall_RuntimeTypeHandle_HasInstantiation (MonoReflectionType *type) return FALSE; klass = mono_class_from_mono_type (type->type); - return klass->generic_class != NULL || klass->generic_container != NULL; + return mono_class_is_ginst (klass) || mono_class_is_gtd (klass); } ICALL_EXPORT gint32 @@ -3176,7 +3186,7 @@ ves_icall_InternalInvoke (MonoReflectionMethod *method, MonoObject *this_arg, Mo return NULL; } - if ((m->klass->flags & TYPE_ATTRIBUTE_ABSTRACT) && !strcmp (m->name, ".ctor") && !this_arg) { + if (mono_class_is_abstract (m->klass) && !strcmp (m->name, ".ctor") && !this_arg) { mono_gc_wbarrier_generic_store (exc, (MonoObject*) mono_exception_from_name_msg (mono_defaults.corlib, "System.Reflection", "TargetException", "Cannot invoke constructor of an abstract class.")); return NULL; } @@ -4289,15 +4299,15 @@ ves_icall_RuntimeType_GetNestedTypes_native (MonoReflectionType *type, char *str * nested types that aren't generic. In any case, the container of that * nested type would be the generic type definition. */ - if (klass->generic_class) - klass = klass->generic_class->container_class; + if (mono_class_is_ginst (klass)) + klass = mono_class_get_generic_class (klass)->container_class; res_array = g_ptr_array_new (); iter = NULL; while ((nested = mono_class_get_nested_types (klass, &iter))) { match = 0; - if ((nested->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK) == TYPE_ATTRIBUTE_NESTED_PUBLIC) { + if ((mono_class_get_flags (nested) & TYPE_ATTRIBUTE_VISIBILITY_MASK) == TYPE_ATTRIBUTE_NESTED_PUBLIC) { if (bflags & BFLAGS_Public) match++; } else { @@ -5085,10 +5095,10 @@ mono_method_get_equivalent_method (MonoMethod *method, MonoClass *klass) MonoGenericContext ctx; ctx.method_inst = inflated->context.method_inst; ctx.class_inst = inflated->context.class_inst; - if (klass->generic_class) - ctx.class_inst = klass->generic_class->context.class_inst; - else if (klass->generic_container) - ctx.class_inst = klass->generic_container->context.class_inst; + if (mono_class_is_ginst (klass)) + ctx.class_inst = mono_class_get_generic_class (klass)->context.class_inst; + else if (mono_class_is_gtd (klass)) + ctx.class_inst = mono_class_get_generic_container (klass)->context.class_inst; result = mono_class_inflate_generic_method_full_checked (inflated->declaring, klass, &ctx, &error); g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */ return result; @@ -6975,7 +6985,7 @@ ves_icall_Remoting_RemotingServices_GetVirtualMethod ( mono_class_setup_vtable (klass); vtable = klass->vtable; - if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (method->klass)) { gboolean variance_used = FALSE; /*MS fails with variant interfaces but it's the right thing to do anyway.*/ int offs = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used); @@ -7038,7 +7048,7 @@ ves_icall_System_Runtime_Activation_ActivationServices_AllocateUninitializedClas if (mono_error_set_pending_exception (&error)) return NULL; - if (MONO_CLASS_IS_INTERFACE (klass) || (klass->flags & TYPE_ATTRIBUTE_ABSTRACT)) { + if (MONO_CLASS_IS_INTERFACE (klass) || mono_class_is_abstract (klass)) { mono_set_pending_exception (mono_get_exception_argument ("type", "Type cannot be instantiated")); return NULL; } @@ -7345,9 +7355,9 @@ ves_icall_MonoMethod_get_base_method (MonoReflectionMethod *m, gboolean definiti return m; klass = method->klass; - if (klass->generic_class) { + if (mono_class_is_ginst (klass)) { generic_inst = mono_class_get_context (klass); - klass = klass->generic_class->container_class; + klass = mono_class_get_generic_class (klass)->container_class; } retry: @@ -7384,9 +7394,9 @@ retry: return NULL; } } - if (parent->generic_class) { + if (mono_class_is_ginst (parent)) { parent_inst = mono_class_get_context (parent); - parent = parent->generic_class->container_class; + parent = mono_class_get_generic_class (parent)->container_class; } mono_class_setup_vtable (parent); @@ -7408,9 +7418,9 @@ retry: generic_inst = NULL; } - if (klass->generic_class) { + if (mono_class_is_ginst (klass)) { generic_inst = mono_class_get_context (klass); - klass = klass->generic_class->container_class; + klass = mono_class_get_generic_class (klass)->container_class; } } @@ -7959,38 +7969,6 @@ ves_icall_System_ComponentModel_Win32Exception_W32ErrorMessage (guint32 code) return message; } -ICALL_EXPORT gpointer -ves_icall_Microsoft_Win32_NativeMethods_GetCurrentProcess (void) -{ - return GetCurrentProcess (); -} - -ICALL_EXPORT MonoBoolean -ves_icall_Microsoft_Win32_NativeMethods_GetExitCodeProcess (gpointer handle, gint32 *exitcode) -{ - return GetExitCodeProcess (handle, (guint32*) exitcode); -} - -#ifndef HOST_WIN32 -static inline MonoBoolean -mono_icall_close_process (gpointer handle) -{ - return CloseProcess (handle); -} -#endif /* !HOST_WIN32 */ - -ICALL_EXPORT MonoBoolean -ves_icall_Microsoft_Win32_NativeMethods_CloseProcess (gpointer handle) -{ - return mono_icall_close_process (handle); -} - -ICALL_EXPORT MonoBoolean -ves_icall_Microsoft_Win32_NativeMethods_TerminateProcess (gpointer handle, gint32 exitcode) -{ - return TerminateProcess (handle, exitcode); -} - #ifndef HOST_WIN32 static inline gint32 mono_icall_wait_for_input_idle (gpointer handle, gint32 milliseconds) @@ -8005,74 +7983,12 @@ ves_icall_Microsoft_Win32_NativeMethods_WaitForInputIdle (gpointer handle, gint3 return mono_icall_wait_for_input_idle (handle, milliseconds); } -#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) -static inline MonoBoolean -mono_icall_get_process_working_set_size (gpointer handle, gsize *min, gsize *max) -{ - return GetProcessWorkingSetSize (handle, min, max); -} -#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ - -ICALL_EXPORT MonoBoolean -ves_icall_Microsoft_Win32_NativeMethods_GetProcessWorkingSetSize (gpointer handle, gsize *min, gsize *max) -{ - return mono_icall_get_process_working_set_size (handle, min, max); -} - -#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) -static inline MonoBoolean -mono_icall_set_process_working_set_size (gpointer handle, gsize min, gsize max) -{ - return SetProcessWorkingSetSize (handle, min, max); -} -#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ - -ICALL_EXPORT MonoBoolean -ves_icall_Microsoft_Win32_NativeMethods_SetProcessWorkingSetSize (gpointer handle, gsize min, gsize max) -{ - return mono_icall_set_process_working_set_size (handle, min, max); -} - -ICALL_EXPORT MonoBoolean -ves_icall_Microsoft_Win32_NativeMethods_GetProcessTimes (gpointer handle, gint64 *creationtime, gint64 *exittime, gint64 *kerneltime, gint64 *usertime) -{ - return GetProcessTimes (handle, (LPFILETIME) creationtime, (LPFILETIME) exittime, (LPFILETIME) kerneltime, (LPFILETIME) usertime); -} - ICALL_EXPORT gint32 ves_icall_Microsoft_Win32_NativeMethods_GetCurrentProcessId (void) { return mono_process_current_pid (); } -#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) -static inline gint32 -mono_icall_get_priority_class (gpointer handle) -{ - return GetPriorityClass (handle); -} -#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ - -ICALL_EXPORT gint32 -ves_icall_Microsoft_Win32_NativeMethods_GetPriorityClass (gpointer handle) -{ - return mono_icall_get_priority_class (handle); -} - -#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) -static inline MonoBoolean -mono_icall_set_priority_class (gpointer handle, gint32 priorityClass) -{ - return SetPriorityClass (handle, priorityClass); -} -#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ - -ICALL_EXPORT MonoBoolean -ves_icall_Microsoft_Win32_NativeMethods_SetPriorityClass (gpointer handle, gint32 priorityClass) -{ - return mono_icall_set_priority_class (handle, priorityClass); -} - ICALL_EXPORT MonoBoolean ves_icall_Mono_TlsProviderFactory_IsBtlsSupported (void) { diff --git a/mono/metadata/image.c b/mono/metadata/image.c index 7f3260c0bab..4fc6f218e17 100644 --- a/mono/metadata/image.c +++ b/mono/metadata/image.c @@ -761,7 +761,7 @@ class_key_extract (gpointer value) static gpointer* class_next_value (gpointer value) { - MonoClass *klass = (MonoClass *)value; + MonoClassDef *klass = (MonoClassDef *)value; return (gpointer*)&klass->next_class_cache; } diff --git a/mono/metadata/loader.c b/mono/metadata/loader.c index 3d85497bfe0..3d76058d233 100644 --- a/mono/metadata/loader.c +++ b/mono/metadata/loader.c @@ -319,7 +319,7 @@ mono_field_from_token_checked (MonoImage *image, guint32 token, MonoClass **retk } } - if (field && field->parent && !field->parent->generic_class && !field->parent->generic_container) { + if (field && field->parent && !mono_class_is_ginst (field->parent) && !mono_class_is_gtd (field->parent)) { mono_image_lock (image); mono_conc_hashtable_insert (image->field_cache, GUINT_TO_POINTER (token), field); mono_image_unlock (image); @@ -362,15 +362,16 @@ find_method_in_class (MonoClass *klass, const char *name, const char *qname, con /* Search directly in the metadata to avoid calling setup_methods () */ mono_error_init (error); - /* FIXME: !from_class->generic_class condition causes test failures. */ - if (klass->type_token && !image_is_dynamic (klass->image) && !klass->methods && !klass->rank && klass == from_class && !from_class->generic_class) { + /* FIXME: !mono_class_is_ginst (from_class) condition causes test failures. */ + if (klass->type_token && !image_is_dynamic (klass->image) && !klass->methods && !klass->rank && klass == from_class && !mono_class_is_ginst (from_class)) { + int first_idx = mono_class_get_first_method_idx (klass); for (i = 0; i < klass->method.count; ++i) { guint32 cols [MONO_METHOD_SIZE]; MonoMethod *method; const char *m_name; MonoMethodSignature *other_sig; - mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, klass->method.first + i, cols, MONO_METHOD_SIZE); + mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, first_idx + i, cols, MONO_METHOD_SIZE); m_name = mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]); @@ -379,7 +380,7 @@ find_method_in_class (MonoClass *klass, const char *name, const char *qname, con (name && !strcmp (m_name, name)))) continue; - method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass, NULL, error); + method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, error); if (!mono_error_ok (error)) //bail out if we hit a loader error return NULL; if (method) { @@ -668,7 +669,7 @@ mono_method_get_signature_checked (MonoMethod *method, MonoImage *image, guint32 return mono_method_signature_checked (method, error); } - if (method->klass->generic_class) + if (mono_class_is_ginst (method->klass)) return mono_method_signature_checked (method, error); if (image_is_dynamic (image)) { @@ -854,7 +855,7 @@ method_from_memberref (MonoImage *image, guint32 idx, MonoGenericContext *typesp type = &klass->byval_arg; if (type->type != MONO_TYPE_ARRAY && type->type != MONO_TYPE_SZARRAY) { - MonoClass *in_class = klass->generic_class ? klass->generic_class->container_class : klass; + MonoClass *in_class = mono_class_is_ginst (klass) ? mono_class_get_generic_class (klass)->container_class : klass; method = find_method (in_class, NULL, mname, sig, klass, error); break; } @@ -941,12 +942,12 @@ method_from_methodspec (MonoImage *image, MonoGenericContext *context, guint32 i klass = method->klass; - if (klass->generic_class) { + if (mono_class_is_ginst (klass)) { g_assert (method->is_inflated); method = ((MonoMethodInflated *) method)->declaring; } - new_context.class_inst = klass->generic_class ? klass->generic_class->context.class_inst : NULL; + new_context.class_inst = mono_class_is_ginst (klass) ? mono_class_get_generic_class (klass)->context.class_inst : NULL; new_context.method_inst = inst; method = mono_class_inflate_generic_method_full_checked (method, klass, &new_context, error); @@ -1659,7 +1660,7 @@ mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass, sig = mono_metadata_blob_heap (image, cols [4]); /* size = */ mono_metadata_decode_blob_size (sig, &sig); - container = klass->generic_container; + container = mono_class_try_get_generic_container (klass); /* * load_generic_params does a binary search so only call it if the method @@ -2374,10 +2375,10 @@ mono_method_signature_checked (MonoMethod *m, MonoError *error) sig = mono_metadata_blob_heap (img, sig_offset = mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_SIGNATURE)); - g_assert (!m->klass->generic_class); + g_assert (!mono_class_is_ginst (m->klass)); container = mono_method_get_generic_container (m); if (!container) - container = m->klass->generic_container; + container = mono_class_try_get_generic_container (m->klass); /* Generic signatures depend on the container so they cannot be cached */ /* icall/pinvoke signatures cannot be cached cause we modify them below */ @@ -2579,7 +2580,7 @@ mono_method_get_header_checked (MonoMethod *method, MonoError *error) */ container = mono_method_get_generic_container (method); if (!container) - container = method->klass->generic_container; + container = mono_class_try_get_generic_container (method->klass); return mono_metadata_parse_mh_full (img, container, (const char *)loc, error); } @@ -2620,12 +2621,13 @@ mono_method_get_index (MonoMethod *method) mono_class_setup_methods (klass); if (mono_class_has_failure (klass)) return 0; + int first_idx = mono_class_get_first_method_idx (klass); for (i = 0; i < klass->method.count; ++i) { if (method == klass->methods [i]) { if (klass->image->uncompressed_metadata) - return mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, klass->method.first + i + 1); + return mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, first_idx + i + 1); else - return klass->method.first + i + 1; + return first_idx + i + 1; } } return 0; diff --git a/mono/metadata/marshal-internals.h b/mono/metadata/marshal-internals.h index e19613a182f..1b4ff57b84b 100644 --- a/mono/metadata/marshal-internals.h +++ b/mono/metadata/marshal-internals.h @@ -32,7 +32,7 @@ void mono_marshal_free_hglobal (void *ptr); gpointer -mono_string_to_lpstr (MonoString *s); +mono_string_to_utf8str (MonoString *s); #endif /* HOST_WIN32 */ #endif /* __MONO_METADATA_MARSHAL_INTERNALS_H__ */ diff --git a/mono/metadata/marshal-windows.c b/mono/metadata/marshal-windows.c index 25868130411..69ee01dea9b 100644 --- a/mono/metadata/marshal-windows.c +++ b/mono/metadata/marshal-windows.c @@ -93,7 +93,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (MonoString } gpointer -mono_string_to_lpstr (MonoString *s) +mono_string_to_utf8str (MonoString *s) { char *as, *tmp; glong len; diff --git a/mono/metadata/marshal.c b/mono/metadata/marshal.c index a9a1042aee5..a743f83f630 100644 --- a/mono/metadata/marshal.c +++ b/mono/metadata/marshal.c @@ -82,6 +82,8 @@ static MonoNativeTlsKey load_type_info_tls_id; static gboolean use_aot_wrappers; +static int class_marshal_info_count; + static void ftnptr_eh_callback_default (guint32 gchandle); static MonoFtnPtrEHCallback ftnptr_eh_callback = ftnptr_eh_callback_default; @@ -107,8 +109,10 @@ mono_marshal_string_to_utf16 (MonoString *s); static void * mono_marshal_string_to_utf16_copy (MonoString *s); +#ifndef HOST_WIN32 static gpointer mono_string_to_utf8str (MonoString *string_obj); +#endif static MonoStringBuilder * mono_string_utf8_to_builder2 (char *text); @@ -352,6 +356,10 @@ mono_marshal_init (void) mono_cominterop_init (); mono_remoting_init (); + + mono_counters_register ("MonoClass::class_marshal_info_count count", + MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_marshal_info_count); + } } @@ -1074,6 +1082,7 @@ mono_string_builder_to_utf16 (MonoStringBuilder *sb) return str; } +#ifndef HOST_WIN32 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */ static gpointer mono_string_to_utf8str (MonoString *s) @@ -1083,6 +1092,7 @@ mono_string_to_utf8str (MonoString *s) mono_error_set_pending_exception (&error); return result; } +#endif gpointer mono_string_to_ansibstr (MonoString *string_obj) @@ -1964,7 +1974,7 @@ emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_obje } if (klass != mono_class_try_get_safehandle_class ()) { - if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) { + if (mono_class_is_auto_layout (klass)) { char *msg = g_strdup_printf ("Type %s which is passed to unmanaged code must have a StructLayout attribute.", mono_type_full_name (&klass->byval_arg)); mono_mb_emit_exception_marshal_directive (mb, msg); @@ -1999,7 +2009,7 @@ emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_obje * the layout to the managed structure as well. */ - if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && (usize == 0)) { + if (mono_class_is_explicit_layout (klass) && (usize == 0)) { if (MONO_TYPE_IS_REFERENCE (info->fields [i].field->type) || ((!last_field && MONO_TYPE_IS_REFERENCE (info->fields [i + 1].field->type)))) g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a " @@ -3264,7 +3274,7 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt MonoMethod *res; GHashTable *cache; gpointer cache_key = NULL; - SignaturePointerPair key; + SignaturePointerPair key = { NULL, NULL }; SignaturePointerPair *new_key; int local_i, local_len, local_delegates, local_d, local_target, local_res; int pos0, pos1, pos2; @@ -3322,7 +3332,7 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt container = mono_method_get_generic_container (method); if (!container) - container = method->klass->generic_container; + container = mono_class_try_get_generic_container (method->klass); //FIXME is this a case of a try? g_assert (container); invoke_sig = sig = mono_signature_no_pinvoke (method); @@ -4938,8 +4948,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, break; } - if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || - klass->blittable || klass->enumtype) + if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype) break; conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); @@ -4985,8 +4994,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, /* Have to change the signature since the vtype is passed byref */ m->csig->params [argnum - m->csig->hasthis] = &mono_defaults.int_class->byval_arg; - if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || - klass->blittable || klass->enumtype) + if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype) mono_mb_emit_ldarg_addr (mb, argnum); else mono_mb_emit_ldloc (mb, conv_arg); @@ -5001,8 +5009,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, break; } - if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || - klass->blittable || klass->enumtype) { + if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype) { mono_mb_emit_ldarg (mb, argnum); break; } @@ -5034,8 +5041,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, break; } - if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || - klass->blittable || klass->enumtype) + if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype) break; if (t->byref) { @@ -5063,8 +5069,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, break; case MARSHAL_ACTION_CONV_RESULT: - if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || - klass->blittable) { + if (mono_class_is_explicit_layout (klass) || klass->blittable) { mono_mb_emit_stloc (mb, 3); break; } @@ -5083,8 +5088,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, break; case MARSHAL_ACTION_MANAGED_CONV_IN: - if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || - klass->blittable || klass->enumtype) { + if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype) { conv_arg = 0; break; } @@ -5116,11 +5120,8 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, break; case MARSHAL_ACTION_MANAGED_CONV_OUT: - if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || - klass->blittable || klass->enumtype) { + if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype) break; - } - if (t->byref && (t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT)) break; @@ -5143,8 +5144,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, break; case MARSHAL_ACTION_MANAGED_CONV_RESULT: - if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || - klass->blittable || klass->enumtype) { + if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype) { mono_mb_emit_stloc (mb, 3); m->retobj_var = 0; break; @@ -5476,7 +5476,7 @@ emit_marshal_safehandle (EmitMarshalContext *m, int argnum, MonoType *t, MonoMethod *ctor = NULL; int intptr_handle_slot; - if (t->data.klass->flags & TYPE_ATTRIBUTE_ABSTRACT){ + if (mono_class_is_abstract (t->data.klass)) { mono_mb_emit_byte (mb, CEE_POP); mono_mb_emit_exception_marshal_directive (mb, g_strdup ("Returned SafeHandles should not be abstract")); break; @@ -5935,7 +5935,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, } /* The class can not have an automatic layout */ - if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) { + if (mono_class_is_auto_layout (klass)) { mono_mb_emit_auto_layout_exception (mb, klass); break; } @@ -6055,7 +6055,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, } /* The class can not have an automatic layout */ - if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) { + if (mono_class_is_auto_layout (klass)) { mono_mb_emit_auto_layout_exception (mb, klass); break; } @@ -7516,7 +7516,7 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM if (MONO_TYPE_ISSTRUCT (sig->ret)) { MonoClass *klass = mono_class_from_mono_type (sig->ret); mono_class_init (klass); - if (!(((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || klass->blittable)) { + if (!(mono_class_is_explicit_layout (klass) || klass->blittable)) { /* This is used by emit_marshal_vtype (), but it needs to go right before the call */ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); mono_mb_emit_byte (mb, CEE_MONO_VTADDR); @@ -8255,7 +8255,7 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i if (MONO_TYPE_ISSTRUCT (sig->ret)) { MonoClass *klass = mono_class_from_mono_type (sig->ret); mono_class_init (klass); - if (!(((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || klass->blittable)) { + if (!(mono_class_is_explicit_layout (klass) || klass->blittable)) { /* This is used by emit_marshal_vtype (), but it needs to go right before the call */ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); mono_mb_emit_byte (mb, CEE_MONO_VTADDR); @@ -9280,7 +9280,7 @@ mono_marshal_get_synchronized_inner_wrapper (MonoMethod *method) method = ((MonoMethodInflated*)method)->declaring; container = mono_method_get_generic_container (method); if (!container) - container = method->klass->generic_container; + container = mono_class_try_get_generic_container (method->klass); //FIXME is this a case of a try? g_assert (container); } @@ -9334,7 +9334,7 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method) method = ((MonoMethodInflated*)method)->declaring; container = mono_method_get_generic_container (method); if (!container) - container = method->klass->generic_container; + container = mono_class_try_get_generic_container (method->klass); //FIXME is this a case of a try? g_assert (container); } @@ -9561,7 +9561,7 @@ is_monomorphic_array (MonoClass *klass) return FALSE; element_class = klass->element_class; - return (element_class->flags & TYPE_ATTRIBUTE_SEALED) || element_class->valuetype; + return mono_class_is_sealed (element_class) || element_class->valuetype; } static int @@ -9581,7 +9581,7 @@ get_virtual_stelemref_kind (MonoClass *element_class) /*Arrays are sealed but are covariant on their element type, We can't use any of the fast paths.*/ if (mono_class_is_marshalbyref (element_class) || element_class->rank || mono_class_has_variant_generic_params (element_class)) return STELEMREF_COMPLEX; - if (element_class->flags & TYPE_ATTRIBUTE_SEALED) + if (mono_class_is_sealed (element_class)) return STELEMREF_SEALED_CLASS; return STELEMREF_CLASS; } @@ -9940,14 +9940,14 @@ get_virtual_stelemref_wrapper (int kind) /* uiid = klass->interface_id; */ mono_mb_emit_ldloc (mb, aklass); mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoClass, interface_id)); - mono_mb_emit_byte (mb, CEE_LDIND_U2); + mono_mb_emit_byte (mb, CEE_LDIND_U4); mono_mb_emit_stloc (mb, uiid); /*if (uiid > vt->max_interface_id)*/ mono_mb_emit_ldloc (mb, uiid); mono_mb_emit_ldloc (mb, vtable); mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id)); - mono_mb_emit_byte (mb, CEE_LDIND_U2); + mono_mb_emit_byte (mb, CEE_LDIND_U4); b2 = mono_mb_emit_branch (mb, CEE_BGT_UN); /* if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7)))) */ @@ -10798,7 +10798,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rty return 0; } - layout = (klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK); + layout = (mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK); if (type->type == MONO_TYPE_PTR || type->type == MONO_TYPE_FNPTR) { return sizeof (gpointer); @@ -11277,7 +11277,7 @@ mono_marshal_load_type_info (MonoClass* klass) count++; } - layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK; + layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK; /* The mempool is protected by the loader lock */ info = (MonoMarshalType *)mono_image_alloc0 (klass->image, MONO_SIZEOF_MARSHAL_TYPE + sizeof (MonoMarshalField) * count); @@ -11383,6 +11383,7 @@ mono_marshal_load_type_info (MonoClass* klass) /*We do double-checking locking on marshal_info */ mono_memory_barrier (); klass->marshal_info = info; + ++class_marshal_info_count; } mono_marshal_unlock (); @@ -11644,11 +11645,10 @@ mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding, int param_ klass = t->data.klass; - if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) + if (mono_class_is_auto_layout (klass)) break; - if (klass->valuetype && (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || - klass->blittable || klass->enumtype)) + if (klass->valuetype && (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype)) return mono_object_unbox (o); res = mono_marshal_alloc (mono_class_native_size (klass, NULL), &error); @@ -11709,8 +11709,7 @@ mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_e case MONO_TYPE_VALUETYPE: { klass = t->data.klass; - if (klass->valuetype && (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || - klass->blittable || klass->enumtype)) + if (klass->valuetype && (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype)) break; if (param_attrs & PARAM_ATTRIBUTE_OUT) { diff --git a/mono/metadata/metadata.c b/mono/metadata/metadata.c index 3a4c22860f7..36a954cd8b0 100644 --- a/mono/metadata/metadata.c +++ b/mono/metadata/metadata.c @@ -2937,7 +2937,7 @@ mono_metadata_get_generic_inst (int type_argc, MonoType **type_argv) static gboolean mono_metadata_is_type_builder_generic_type_definition (MonoClass *container_class, MonoGenericInst *inst, gboolean is_dynamic) { - MonoGenericContainer *container = container_class->generic_container; + MonoGenericContainer *container = mono_class_get_generic_container (container_class); if (!is_dynamic || container_class->wastypebuilder || container->type_argc != inst->type_argc) return FALSE; @@ -2959,6 +2959,8 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst MonoImageSet *set; CollectData data; + g_assert (mono_class_get_generic_container (container_class)->type_argc == inst->type_argc); + memset (&helper, 0, sizeof(helper)); // act like g_new0 helper.container_class = container_class; helper.context.class_inst = inst; @@ -2994,7 +2996,7 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst gclass->context.class_inst = inst; gclass->context.method_inst = NULL; gclass->owner = set; - if (inst == container_class->generic_container->context.class_inst && !is_tb_open) + if (inst == mono_class_get_generic_container (container_class)->context.class_inst && !is_tb_open) gclass->cached_class = container_class; g_hash_table_insert (set->gclass_cache, gclass, gclass); @@ -3089,7 +3091,7 @@ do_mono_metadata_parse_generic_class (MonoType *type, MonoImage *m, MonoGenericC return FALSE; gklass = mono_class_from_mono_type (gtype); - if (!gklass->generic_container) { + if (!mono_class_is_gtd (gklass)) { mono_error_set_bad_image (error, m, "Generic instance with non-generic definition"); return FALSE; } @@ -4804,7 +4806,7 @@ static gboolean _mono_metadata_generic_class_container_equal (const MonoGenericClass *g1, MonoClass *c2, gboolean signature_only) { MonoGenericInst *i1 = g1->context.class_inst; - MonoGenericInst *i2 = c2->generic_container->context.class_inst; + MonoGenericInst *i2 = mono_class_get_generic_container (c2)->context.class_inst; if (!mono_metadata_class_equal (g1->container_class, c2, signature_only)) return FALSE; @@ -4959,12 +4961,12 @@ mono_metadata_class_equal (MonoClass *c1, MonoClass *c2, gboolean signature_only { if (c1 == c2) return TRUE; - if (c1->generic_class && c2->generic_class) - return _mono_metadata_generic_class_equal (c1->generic_class, c2->generic_class, signature_only); - if (c1->generic_class && c2->generic_container) - return _mono_metadata_generic_class_container_equal (c1->generic_class, c2, signature_only); - if (c1->generic_container && c2->generic_class) - return _mono_metadata_generic_class_container_equal (c2->generic_class, c1, signature_only); + if (mono_class_is_ginst (c1) && mono_class_is_ginst (c2)) + return _mono_metadata_generic_class_equal (mono_class_get_generic_class (c1), mono_class_get_generic_class (c2), signature_only); + if (mono_class_is_ginst (c1) && mono_class_is_gtd (c2)) + return _mono_metadata_generic_class_container_equal (mono_class_get_generic_class (c1), c2, signature_only); + if (mono_class_is_gtd (c1) && mono_class_is_ginst (c2)) + return _mono_metadata_generic_class_container_equal (mono_class_get_generic_class (c2), c1, signature_only); if ((c1->byval_arg.type == MONO_TYPE_VAR) && (c2->byval_arg.type == MONO_TYPE_VAR)) return mono_metadata_generic_param_equal_internal ( c1->byval_arg.data.generic_param, c2->byval_arg.data.generic_param, signature_only); @@ -6610,10 +6612,10 @@ mono_metadata_get_corresponding_field_from_generic_type_definition (MonoClassFie MonoClass *gtd; int offset; - if (!field->parent->generic_class) + if (!mono_class_is_ginst (field->parent)) return field; - gtd = field->parent->generic_class->container_class; + gtd = mono_class_get_generic_class (field->parent)->container_class; offset = field - field->parent->fields; return gtd->fields + offset; } @@ -6628,10 +6630,10 @@ mono_metadata_get_corresponding_event_from_generic_type_definition (MonoEvent *e MonoClass *gtd; int offset; - if (!event->parent->generic_class) + if (!mono_class_is_ginst (event->parent)) return event; - gtd = event->parent->generic_class->container_class; + gtd = mono_class_get_generic_class (event->parent)->container_class; offset = event - event->parent->ext->events; return gtd->ext->events + offset; } @@ -6646,10 +6648,10 @@ mono_metadata_get_corresponding_property_from_generic_type_definition (MonoPrope MonoClass *gtd; int offset; - if (!property->parent->generic_class) + if (!mono_class_is_ginst (property->parent)) return property; - gtd = property->parent->generic_class->container_class; + gtd = mono_class_get_generic_class (property->parent)->container_class; offset = property - property->parent->ext->properties; return gtd->ext->properties + offset; } diff --git a/mono/metadata/metadata.h b/mono/metadata/metadata.h index 6036fe3ae7d..d8e48318b4d 100644 --- a/mono/metadata/metadata.h +++ b/mono/metadata/metadata.h @@ -15,9 +15,9 @@ MONO_BEGIN_DECLS #define MONO_TYPE_IS_POINTER(t) mono_type_is_pointer (t) #define MONO_TYPE_IS_REFERENCE(t) mono_type_is_reference (t) -#define MONO_CLASS_IS_INTERFACE(c) ((c->flags & TYPE_ATTRIBUTE_INTERFACE) || (c->byval_arg.type == MONO_TYPE_VAR) || (c->byval_arg.type == MONO_TYPE_MVAR)) +#define MONO_CLASS_IS_INTERFACE(c) ((mono_class_get_flags (c) & TYPE_ATTRIBUTE_INTERFACE) || (c->byval_arg.type == MONO_TYPE_VAR) || (c->byval_arg.type == MONO_TYPE_MVAR)) -#define MONO_CLASS_IS_IMPORT(c) ((c->flags & TYPE_ATTRIBUTE_IMPORT)) +#define MONO_CLASS_IS_IMPORT(c) ((mono_class_get_flags (c) & TYPE_ATTRIBUTE_IMPORT)) typedef struct _MonoClass MonoClass; typedef struct _MonoDomain MonoDomain; diff --git a/mono/metadata/object-internals.h b/mono/metadata/object-internals.h index b2cdf6a9fe9..1a60d2d85f3 100644 --- a/mono/metadata/object-internals.h +++ b/mono/metadata/object-internals.h @@ -349,7 +349,8 @@ typedef enum { struct _MonoInternalThread { MonoObject obj; volatile int lock_thread_id; /* to be used as the pre-shifted thread id in thin locks. Used for appdomain_ref push/pop */ - HANDLE handle; + MonoThreadHandle *handle; + HANDLE native_handle; MonoArray *cached_culture_info; gunichar2 *name; guint32 name_len; @@ -382,6 +383,7 @@ struct _MonoInternalThread { gsize abort_protected_block_count; gint32 priority; GPtrArray *owned_mutexes; + MonoOSEvent *suspended; /* * These fields are used to avoid having to increment corlib versions * when a new field is added to this structure. diff --git a/mono/metadata/object-offsets.h b/mono/metadata/object-offsets.h index e4965a512a7..5c78288ec8b 100644 --- a/mono/metadata/object-offsets.h +++ b/mono/metadata/object-offsets.h @@ -238,6 +238,8 @@ DECL_OFFSET(GSharedVtCallInfo, gsharedvt_in) #endif #if defined(TARGET_ARM64) +DECL_OFFSET (MonoContext, has_fregs) + DECL_OFFSET(GSharedVtCallInfo, stack_usage) DECL_OFFSET(GSharedVtCallInfo, gsharedvt_in) DECL_OFFSET(GSharedVtCallInfo, ret_marshal) diff --git a/mono/metadata/object.c b/mono/metadata/object.c index 5a57b2fc6d0..c25a107fdeb 100644 --- a/mono/metadata/object.c +++ b/mono/metadata/object.c @@ -1406,14 +1406,14 @@ build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) { MonoMethod *method; - if (slot_num >= 0 && iface->is_inflated) { + if (slot_num >= 0 && mono_class_is_ginst (iface)) { /* * The imt slot of the method is the same as for its declaring method, * see the comment in mono_method_get_imt_slot (), so we can * avoid inflating methods which will be discarded by * add_imt_builder_entry anyway. */ - method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface); + method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface); if (mono_method_get_imt_slot (method) != slot_num) { vt_slot ++; continue; @@ -1905,7 +1905,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro if (!klass->vtable_size) mono_class_setup_vtable (klass); - if (klass->generic_class && !klass->vtable) + if (mono_class_is_ginst (klass) && !klass->vtable) mono_class_check_vtable_constraints (klass, NULL); /* Initialize klass->has_finalize */ @@ -2202,7 +2202,8 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono MONO_REQ_GC_UNSAFE_MODE; MonoVTable *vt, *pvt; - int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0; + int i, j, vtsize, extra_interface_vtsize = 0; + guint32 max_interface_id; MonoClass *k; GSList *extra_interfaces = NULL; MonoClass *klass = remote_class->proxy_class; @@ -2290,7 +2291,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono pvt->vtable [i] = NULL; } - if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) { + if (mono_class_is_abstract (klass)) { /* create trampolines for abstract methods */ for (k = klass; k; k = k->parent) { MonoMethod* m; @@ -2448,7 +2449,7 @@ create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class) int i, j; if (remote_class == NULL) { - if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (extra_class)) { key = (void **)g_malloc (sizeof(gpointer) * 3); key [0] = GINT_TO_POINTER (2); key [1] = mono_defaults.marshalbyrefobject_class; @@ -2459,7 +2460,7 @@ create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class) key [1] = extra_class; } } else { - if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) { + if (extra_class != NULL && mono_class_is_interface (extra_class)) { key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3)); key [0] = GINT_TO_POINTER (remote_class->interface_count + 2); key [1] = remote_class->proxy_class; @@ -2548,7 +2549,7 @@ mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_ g_free (key); key = mp_key; - if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (proxy_class)) { rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*)); rc->interface_count = 1; rc->interfaces [0] = proxy_class; @@ -2595,7 +2596,7 @@ clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass g_free (key); key = mp_key; - if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (extra_class)) { int i,j; rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1)); rc->proxy_class = remote_class->proxy_class; @@ -2696,7 +2697,7 @@ mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoCla tproxy = (MonoTransparentProxy*) proxy_object; remote_class = tproxy->remote_class; - if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (klass)) { int i; redo_vtable = TRUE; for (i = 0; i < remote_class->interface_count && redo_vtable; i++) @@ -2767,7 +2768,7 @@ mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method) /* check method->slot is a valid index: perform isinstance? */ if (method->slot != -1) { - if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (method->klass)) { if (!is_proxy) { gboolean variance_used = FALSE; int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used); @@ -6487,7 +6488,7 @@ mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error) if (!klass->inited) mono_class_init (klass); - if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE)) { + if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) { result = mono_object_isinst_mbyref_checked (obj, klass, error); return result; } @@ -6523,7 +6524,7 @@ mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError vt = obj->vtable; - if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (klass)) { if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) { return obj; } @@ -7843,7 +7844,7 @@ mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, Mon ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr)); if (ji) { method = mono_jit_info_get_method (ji); - g_assert (!method->klass->generic_container); + g_assert (!mono_class_is_gtd (method->klass)); } return mono_delegate_ctor_with_method (this_obj, target, addr, method, error); diff --git a/mono/metadata/process-internals.h b/mono/metadata/process-internals.h deleted file mode 100644 index cfc34e8fd6c..00000000000 --- a/mono/metadata/process-internals.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2016 Microsoft - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ -#ifndef __MONO_METADATA_PROCESS_INTERNALS_H__ -#define __MONO_METADATA_PROCESS_INTERNALS_H__ - -#include -#include - -// On Windows platform implementation of bellow methods are hosted in separate source file -// process-windows.c or process-windows-*.c. On other platforms the implementation is still keept -// in process.c still declared as static and in some places even inlined. -#ifdef HOST_WIN32 -gchar* -mono_process_quote_path (const gchar *path); - -gchar* -mono_process_unquote_application_name (gchar *path); - -gboolean -mono_process_get_shell_arguments (MonoProcessStartInfo *proc_start_info, gunichar2 **shell_path, - MonoString **cmd); -#endif /* HOST_WIN32 */ - -// On platforms not using classic WIN API support the implementation of bellow methods are hosted in separate source file -// process-windows-*.c. On platforms using classic WIN API the implementation is still keept in process.c and still declared -// static and in some places even inlined. -#if !G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) -void -process_get_fileversion (MonoObject *filever, gunichar2 *filename, MonoError *error); - -void -mono_process_init_startup_info (HANDLE stdin_handle, HANDLE stdout_handle, - HANDLE stderr_handle,STARTUPINFO *startinfo); - -gboolean -mono_process_create_process (MonoProcInfo *mono_process_info, gunichar2 *shell_path, MonoString *cmd, - guint32 creation_flags, gchar *env_vars, gunichar2 *dir, STARTUPINFO *start_info, - PROCESS_INFORMATION *process_info); -#endif /* !G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ - -// Shared between all platforms and implemented in process.c. -gboolean -mono_process_complete_path (const gunichar2 *appname, gchar **completed); - -#endif /* __MONO_METADATA_PROCESS_INTERNALS_H__ */ diff --git a/mono/metadata/process-windows-internals.h b/mono/metadata/process-windows-internals.h deleted file mode 100644 index 68721fa2e23..00000000000 --- a/mono/metadata/process-windows-internals.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2016 Microsoft - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ -#ifndef __MONO_METADATA_PROCESS_WINDOWS_INTERNALS_H__ -#define __MONO_METADATA_PROCESS_WINDOWS_INTERNALS_H__ - -#include -#include - -#ifdef HOST_WIN32 -#include "mono/metadata/process.h" -#include "mono/metadata/process-internals.h" -#include "mono/metadata/object.h" -#include "mono/metadata/object-internals.h" -#include "mono/metadata/exception.h" - -// On platforms not using classic WIN API support the implementation of bellow methods are hosted in separate source file -// process-windows-*.c. On platforms using classic WIN API the implementation is still keept in process.c and still declared -// static and in some places even inlined. -#if !G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) -gboolean -mono_process_win_enum_processes (DWORD *pids, DWORD count, DWORD *needed); -#endif /* !G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ - -#endif /* HOST_WIN32 */ - -#endif /* __MONO_METADATA_PROCESS_WINDOWS_INTERNALS_H__ */ diff --git a/mono/metadata/process-windows-uwp.c b/mono/metadata/process-windows-uwp.c deleted file mode 100644 index 905555f4959..00000000000 --- a/mono/metadata/process-windows-uwp.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * process-windows-uwp.c: UWP process support for Mono. - * - * Copyright 2016 Microsoft - * Licensed under the MIT license. See LICENSE file in the project root for full license information. -*/ -#include -#include - -#if G_HAVE_API_SUPPORT(HAVE_UWP_WINAPI_SUPPORT) -#include -#include "mono/metadata/process-windows-internals.h" - -gboolean -mono_process_win_enum_processes (DWORD *pids, DWORD count, DWORD *needed) -{ - g_unsupported_api ("EnumProcesses"); - *needed = 0; - SetLastError (ERROR_NOT_SUPPORTED); - - return FALSE; -} - -HANDLE -ves_icall_System_Diagnostics_Process_GetProcess_internal (guint32 pid) -{ - HANDLE handle; - - /* GetCurrentProcess returns a pseudo-handle, so use - * OpenProcess instead - */ - handle = OpenProcess (PROCESS_ALL_ACCESS, TRUE, pid); - if (handle == NULL) - /* FIXME: Throw an exception */ - return NULL; - return handle; -} - -void -process_get_fileversion (MonoObject *filever, gunichar2 *filename, MonoError *error) -{ - g_unsupported_api ("GetFileVersionInfoSize, GetFileVersionInfo, VerQueryValue, VerLanguageName"); - - mono_error_init (error); - mono_error_set_not_supported (error, G_UNSUPPORTED_API, "GetFileVersionInfoSize, GetFileVersionInfo, VerQueryValue, VerLanguageName"); - - SetLastError (ERROR_NOT_SUPPORTED); -} - -MonoObject* -process_add_module (HANDLE process, HMODULE mod, gunichar2 *filename, gunichar2 *modulename, MonoClass *proc_class, MonoError *error) -{ - g_unsupported_api ("GetModuleInformation"); - - mono_error_init (error); - mono_error_set_not_supported (error, G_UNSUPPORTED_API, "GetModuleInformation"); - - SetLastError (ERROR_NOT_SUPPORTED); - - return NULL; -} - -MonoArray * -ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject *this_obj, HANDLE process) -{ - MonoError mono_error; - mono_error_init (&mono_error); - - g_unsupported_api ("EnumProcessModules, GetModuleBaseName, GetModuleFileNameEx"); - - mono_error_set_not_supported (&mono_error, G_UNSUPPORTED_API, "EnumProcessModules, GetModuleBaseName, GetModuleFileNameEx"); - mono_error_set_pending_exception (&mono_error); - - SetLastError (ERROR_NOT_SUPPORTED); - - return NULL; -} - -MonoBoolean -ves_icall_System_Diagnostics_Process_ShellExecuteEx_internal (MonoProcessStartInfo *proc_start_info, MonoProcInfo *process_info) -{ - MonoError mono_error; - mono_error_init (&mono_error); - - g_unsupported_api ("ShellExecuteEx"); - - mono_error_set_not_supported (&mono_error, G_UNSUPPORTED_API, "ShellExecuteEx"); - mono_error_set_pending_exception (&mono_error); - - process_info->pid = (guint32)(-ERROR_NOT_SUPPORTED); - SetLastError (ERROR_NOT_SUPPORTED); - - return FALSE; -} - -MonoString * -ves_icall_System_Diagnostics_Process_ProcessName_internal (HANDLE process) -{ - MonoError error; - MonoString *string; - gunichar2 name[MAX_PATH]; - guint32 len; - - len = GetModuleFileName (NULL, name, G_N_ELEMENTS (name)); - if (len == 0) - return NULL; - - string = mono_string_new_utf16_checked (mono_domain_get (), name, len, &error); - if (!mono_error_ok (&error)) - mono_error_set_pending_exception (&error); - - return string; -} - -void -mono_process_init_startup_info (HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle, STARTUPINFO *startinfo) -{ - startinfo->cb = sizeof(STARTUPINFO); - startinfo->dwFlags = 0; - startinfo->hStdInput = INVALID_HANDLE_VALUE; - startinfo->hStdOutput = INVALID_HANDLE_VALUE; - startinfo->hStdError = INVALID_HANDLE_VALUE; - return; -} - -gboolean -mono_process_create_process (MonoProcInfo *mono_process_info, gunichar2 *shell_path, MonoString *cmd, guint32 creation_flags, - gchar *env_vars, gunichar2 *dir, STARTUPINFO *start_info, PROCESS_INFORMATION *process_info) -{ - MonoError mono_error; - gchar *api_name = ""; - - if (mono_process_info->username) { - api_name = "CreateProcessWithLogonW"; - } else { - api_name = "CreateProcess"; - } - - memset (&process_info, 0, sizeof (PROCESS_INFORMATION)); - g_unsupported_api (api_name); - - mono_error_init (&mono_error); - mono_error_set_not_supported (&mono_error, G_UNSUPPORTED_API, api_name); - mono_error_set_pending_exception (&mono_error); - - SetLastError (ERROR_NOT_SUPPORTED); - - return FALSE; -} - -#else /* G_HAVE_API_SUPPORT(HAVE_UWP_WINAPI_SUPPORT) */ - -#ifdef _MSC_VER -// Quiet Visual Studio linker warning, LNK4221, in cases when this source file intentional ends up empty. -void __mono_win32_process_windows_uwp_quiet_lnk4221(void) {} -#endif -#endif /* G_HAVE_API_SUPPORT(HAVE_UWP_WINAPI_SUPPORT) */ diff --git a/mono/metadata/process-windows.c b/mono/metadata/process-windows.c deleted file mode 100644 index 5bf0b7d6906..00000000000 --- a/mono/metadata/process-windows.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * process-windows.c: Windows process support. - * - * Copyright 2016 Microsoft - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -#include -#include - -#if defined(HOST_WIN32) -#include -#include -#include "mono/metadata/process-windows-internals.h" - -#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) -static inline gboolean -mono_process_win_enum_processes (DWORD *pids, DWORD count, DWORD *needed) -{ - return EnumProcesses (pids, count, needed); -} -#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ - -MonoArray * -ves_icall_System_Diagnostics_Process_GetProcesses_internal (void) -{ - MonoError error; - MonoArray *procs; - gboolean ret; - DWORD needed; - int count; - DWORD *pids; - - count = 512; - do { - pids = g_new0 (DWORD, count); - ret = mono_process_win_enum_processes (pids, count * sizeof (guint32), &needed); - if (ret == FALSE) { - MonoException *exc; - - g_free (pids); - pids = NULL; - exc = mono_get_exception_not_supported ("This system does not support EnumProcesses"); - mono_set_pending_exception (exc); - return NULL; - } - if (needed < (count * sizeof (guint32))) - break; - g_free (pids); - pids = NULL; - count = (count * 3) / 2; - } while (TRUE); - - count = needed / sizeof (guint32); - procs = mono_array_new_checked (mono_domain_get (), mono_get_int32_class (), count, &error); - if (mono_error_set_pending_exception (&error)) { - g_free (pids); - return NULL; - } - - memcpy (mono_array_addr (procs, guint32, 0), pids, needed); - g_free (pids); - pids = NULL; - - return procs; -} - -gchar* -mono_process_quote_path (const gchar *path) -{ - gchar *res = g_shell_quote (path); - gchar *q = res; - while (*q) { - if (*q == '\'') - *q = '\"'; - q++; - } - return res; -} - -gchar* -mono_process_unquote_application_name (gchar *appname) -{ - size_t len = strlen (appname); - if (len) { - if (appname[len-1] == '\"') - appname[len-1] = '\0'; - if (appname[0] == '\"') - appname++; - } - - return appname; -} - -gboolean -mono_process_get_shell_arguments (MonoProcessStartInfo *proc_start_info, gunichar2 **shell_path, MonoString **cmd) -{ - gchar *spath = NULL; - gchar *new_cmd, *cmd_utf8; - MonoError mono_error; - - *shell_path = NULL; - *cmd = proc_start_info->arguments; - - mono_process_complete_path (mono_string_chars (proc_start_info->filename), &spath); - if (spath != NULL) { - /* Seems like our CreateProcess does not work as the windows one. - * This hack is needed to deal with paths containing spaces */ - if (*cmd) { - cmd_utf8 = mono_string_to_utf8_checked (*cmd, &mono_error); - if (!mono_error_set_pending_exception (&mono_error)) { - new_cmd = g_strdup_printf ("%s %s", spath, cmd_utf8); - *cmd = mono_string_new_wrapper (new_cmd); - g_free (cmd_utf8); - g_free (new_cmd); - } else { - *cmd = NULL; - } - } - else { - *cmd = mono_string_new_wrapper (spath); - } - - g_free (spath); - } - - return (*cmd != NULL) ? TRUE : FALSE; -} -#endif /* HOST_WIN32 */ diff --git a/mono/metadata/process.c b/mono/metadata/process.c deleted file mode 100644 index b1bff0b5eca..00000000000 --- a/mono/metadata/process.c +++ /dev/null @@ -1,921 +0,0 @@ -/* - * process.c: System.Diagnostics.Process support - * - * Author: - * Dick Porter (dick@ximian.com) - * - * Copyright 2002 Ximian, Inc. - * Copyright 2002-2006 Novell, Inc. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -/* FIXME: fix this code to not depend so much on the internals */ -#include -#include - -#define LOGDEBUG(...) -/* define LOGDEBUG(...) g_message(__VA_ARGS__) */ - -#if defined(HOST_WIN32) && G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) -#include -#endif - -#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) -HANDLE -ves_icall_System_Diagnostics_Process_GetProcess_internal (guint32 pid) -{ - HANDLE handle; - - /* GetCurrentProcess returns a pseudo-handle, so use - * OpenProcess instead - */ - handle = OpenProcess (PROCESS_ALL_ACCESS, TRUE, pid); - if (handle == NULL) - /* FIXME: Throw an exception */ - return NULL; - return handle; -} -#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */ - -static MonoImage *system_assembly; - -static void -stash_system_assembly (MonoObject *obj) -{ - if (!system_assembly) - system_assembly = obj->vtable->klass->image; -} - -//Hand coded version that loads from system -static MonoClass* -mono_class_get_file_version_info_class (void) -{ - static MonoClass *tmp_class; - MonoClass *klass = tmp_class; - if (!klass) { - klass = mono_class_load_from_name (system_assembly, "System.Diagnostics", "FileVersionInfo"); - mono_memory_barrier (); - tmp_class = klass; - } - return klass; -} - -static MonoClass* -mono_class_get_process_module_class (void) -{ - static MonoClass *tmp_class; - MonoClass *klass = tmp_class; - if (!klass) { - klass = mono_class_load_from_name (system_assembly, "System.Diagnostics", "ProcessModule"); - mono_memory_barrier (); - tmp_class = klass; - } - return klass; -} - -static guint32 -unicode_chars (const gunichar2 *str) -{ - guint32 len; - - for (len = 0; str [len] != '\0'; ++len) - ; - return len; -} - -static void -process_set_field_object (MonoObject *obj, const gchar *fieldname, - MonoObject *data) -{ - MonoClassField *field; - - LOGDEBUG (g_message ("%s: Setting field %s to object at %p", __func__, fieldname, data)); - - field = mono_class_get_field_from_name (mono_object_class (obj), - fieldname); - mono_gc_wbarrier_generic_store (((char *)obj) + field->offset, data); -} - -static void -process_set_field_string (MonoObject *obj, const gchar *fieldname, - const gunichar2 *val, guint32 len, MonoError *error) -{ - MonoClassField *field; - MonoString *string; - - mono_error_init (error); - - LOGDEBUG (g_message ("%s: Setting field %s to [%s]", __func__, fieldname, g_utf16_to_utf8 (val, len, NULL, NULL, NULL))); - - string = mono_string_new_utf16_checked (mono_object_domain (obj), val, len, error); - - field = mono_class_get_field_from_name (mono_object_class (obj), - fieldname); - mono_gc_wbarrier_generic_store (((char *)obj) + field->offset, (MonoObject*)string); -} - -static void -process_set_field_string_char (MonoObject *obj, const gchar *fieldname, - const gchar *val) -{ - MonoClassField *field; - MonoString *string; - - LOGDEBUG (g_message ("%s: Setting field %s to [%s]", __func__, fieldname, val)); - - string = mono_string_new (mono_object_domain (obj), val); - - field = mono_class_get_field_from_name (mono_object_class (obj), fieldname); - mono_gc_wbarrier_generic_store (((char *)obj) + field->offset, (MonoObject*)string); -} - -static void -process_set_field_int (MonoObject *obj, const gchar *fieldname, - guint32 val) -{ - MonoClassField *field; - - LOGDEBUG (g_message ("%s: Setting field %s to %d", __func__,fieldname, val)); - - field = mono_class_get_field_from_name (mono_object_class (obj), - fieldname); - *(guint32 *)(((char *)obj) + field->offset)=val; -} - -static void -process_set_field_intptr (MonoObject *obj, const gchar *fieldname, - gpointer val) -{ - MonoClassField *field; - - LOGDEBUG (g_message ("%s: Setting field %s to %p", __func__, fieldname, val)); - - field = mono_class_get_field_from_name (mono_object_class (obj), - fieldname); - *(gpointer *)(((char *)obj) + field->offset) = val; -} - -static void -process_set_field_bool (MonoObject *obj, const gchar *fieldname, - gboolean val) -{ - MonoClassField *field; - - LOGDEBUG (g_message ("%s: Setting field %s to %s", __func__, fieldname, val ? "TRUE":"FALSE")); - - field = mono_class_get_field_from_name (mono_object_class (obj), - fieldname); - *(guint8 *)(((char *)obj) + field->offset) = val; -} - -#define SFI_COMMENTS "\\StringFileInfo\\%02X%02X%02X%02X\\Comments" -#define SFI_COMPANYNAME "\\StringFileInfo\\%02X%02X%02X%02X\\CompanyName" -#define SFI_FILEDESCRIPTION "\\StringFileInfo\\%02X%02X%02X%02X\\FileDescription" -#define SFI_FILEVERSION "\\StringFileInfo\\%02X%02X%02X%02X\\FileVersion" -#define SFI_INTERNALNAME "\\StringFileInfo\\%02X%02X%02X%02X\\InternalName" -#define SFI_LEGALCOPYRIGHT "\\StringFileInfo\\%02X%02X%02X%02X\\LegalCopyright" -#define SFI_LEGALTRADEMARKS "\\StringFileInfo\\%02X%02X%02X%02X\\LegalTrademarks" -#define SFI_ORIGINALFILENAME "\\StringFileInfo\\%02X%02X%02X%02X\\OriginalFilename" -#define SFI_PRIVATEBUILD "\\StringFileInfo\\%02X%02X%02X%02X\\PrivateBuild" -#define SFI_PRODUCTNAME "\\StringFileInfo\\%02X%02X%02X%02X\\ProductName" -#define SFI_PRODUCTVERSION "\\StringFileInfo\\%02X%02X%02X%02X\\ProductVersion" -#define SFI_SPECIALBUILD "\\StringFileInfo\\%02X%02X%02X%02X\\SpecialBuild" -#define EMPTY_STRING (gunichar2*)"\000\000" - -#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) -static void -process_module_string_read (MonoObject *filever, gpointer data, - const gchar *fieldname, guchar lang_hi, guchar lang_lo, - const gchar *key, MonoError *error) -{ - gchar *lang_key_utf8; - gunichar2 *lang_key, *buffer; - UINT chars; - - mono_error_init (error); - - lang_key_utf8 = g_strdup_printf (key, lang_lo, lang_hi, 0x04, 0xb0); - - LOGDEBUG (g_message ("%s: asking for [%s]", __func__, lang_key_utf8)); - - lang_key = g_utf8_to_utf16 (lang_key_utf8, -1, NULL, NULL, NULL); - - if (VerQueryValue (data, lang_key, (gpointer *)&buffer, &chars) && chars > 0) { - LOGDEBUG (g_message ("%s: found %d chars of [%s]", __func__, chars, g_utf16_to_utf8 (buffer, chars, NULL, NULL, NULL))); - /* chars includes trailing null */ - process_set_field_string (filever, fieldname, buffer, chars - 1, error); - } else { - process_set_field_string (filever, fieldname, EMPTY_STRING, 0, error); - } - - g_free (lang_key); - g_free (lang_key_utf8); -} - -typedef struct { - const char *name; - const char *id; -} StringTableEntry; - -static StringTableEntry stringtable_entries [] = { - { "comments", SFI_COMMENTS }, - { "companyname", SFI_COMPANYNAME }, - { "filedescription", SFI_FILEDESCRIPTION }, - { "fileversion", SFI_FILEVERSION }, - { "internalname", SFI_INTERNALNAME }, - { "legalcopyright", SFI_LEGALCOPYRIGHT }, - { "legaltrademarks", SFI_LEGALTRADEMARKS }, - { "originalfilename", SFI_ORIGINALFILENAME }, - { "privatebuild", SFI_PRIVATEBUILD }, - { "productname", SFI_PRODUCTNAME }, - { "productversion", SFI_PRODUCTVERSION }, - { "specialbuild", SFI_SPECIALBUILD } -}; - -static void -process_module_stringtable (MonoObject *filever, gpointer data, - guchar lang_hi, guchar lang_lo, MonoError *error) -{ - int i; - - for (i = 0; i < G_N_ELEMENTS (stringtable_entries); ++i) { - process_module_string_read (filever, data, stringtable_entries [i].name, lang_hi, lang_lo, - stringtable_entries [i].id, error); - return_if_nok (error); - } -} - -static void -process_get_fileversion (MonoObject *filever, gunichar2 *filename, MonoError *error) -{ - DWORD verinfohandle; - VS_FIXEDFILEINFO *ffi; - gpointer data; - DWORD datalen; - guchar *trans_data; - gunichar2 *query; - UINT ffi_size, trans_size; - BOOL ok; - gunichar2 lang_buf[128]; - guint32 lang, lang_count; - - mono_error_init (error); - - datalen = GetFileVersionInfoSize (filename, &verinfohandle); - if (datalen) { - data = g_malloc0 (datalen); - ok = GetFileVersionInfo (filename, verinfohandle, datalen, - data); - if (ok) { - query = g_utf8_to_utf16 ("\\", -1, NULL, NULL, NULL); - if (query == NULL) { - g_free (data); - return; - } - - if (VerQueryValue (data, query, (gpointer *)&ffi, - &ffi_size)) { - LOGDEBUG (g_message ("%s: recording assembly: FileName [%s] FileVersionInfo [%d.%d.%d.%d]", __func__, g_utf16_to_utf8 (filename, -1, NULL, NULL, NULL), HIWORD (ffi->dwFileVersionMS), LOWORD (ffi->dwFileVersionMS), HIWORD (ffi->dwFileVersionLS), LOWORD (ffi->dwFileVersionLS))); - - process_set_field_int (filever, "filemajorpart", HIWORD (ffi->dwFileVersionMS)); - process_set_field_int (filever, "fileminorpart", LOWORD (ffi->dwFileVersionMS)); - process_set_field_int (filever, "filebuildpart", HIWORD (ffi->dwFileVersionLS)); - process_set_field_int (filever, "fileprivatepart", LOWORD (ffi->dwFileVersionLS)); - - process_set_field_int (filever, "productmajorpart", HIWORD (ffi->dwProductVersionMS)); - process_set_field_int (filever, "productminorpart", LOWORD (ffi->dwProductVersionMS)); - process_set_field_int (filever, "productbuildpart", HIWORD (ffi->dwProductVersionLS)); - process_set_field_int (filever, "productprivatepart", LOWORD (ffi->dwProductVersionLS)); - - process_set_field_bool (filever, "isdebug", ((ffi->dwFileFlags & ffi->dwFileFlagsMask) & VS_FF_DEBUG) != 0); - process_set_field_bool (filever, "isprerelease", ((ffi->dwFileFlags & ffi->dwFileFlagsMask) & VS_FF_PRERELEASE) != 0); - process_set_field_bool (filever, "ispatched", ((ffi->dwFileFlags & ffi->dwFileFlagsMask) & VS_FF_PATCHED) != 0); - process_set_field_bool (filever, "isprivatebuild", ((ffi->dwFileFlags & ffi->dwFileFlagsMask) & VS_FF_PRIVATEBUILD) != 0); - process_set_field_bool (filever, "isspecialbuild", ((ffi->dwFileFlags & ffi->dwFileFlagsMask) & VS_FF_SPECIALBUILD) != 0); - } - g_free (query); - - query = g_utf8_to_utf16 ("\\VarFileInfo\\Translation", -1, NULL, NULL, NULL); - if (query == NULL) { - g_free (data); - return; - } - - if (VerQueryValue (data, query, - (gpointer *)&trans_data, - &trans_size)) { - /* use the first language ID we see - */ - if (trans_size >= 4) { - LOGDEBUG (g_message("%s: %s has 0x%0x 0x%0x 0x%0x 0x%0x", __func__, g_utf16_to_utf8 (filename, -1, NULL, NULL, NULL), trans_data[0], trans_data[1], trans_data[2], trans_data[3])); - lang = (trans_data[0]) | - (trans_data[1] << 8) | - (trans_data[2] << 16) | - (trans_data[3] << 24); - /* Only give the lower 16 bits - * to VerLanguageName, as - * Windows gets confused - * otherwise - */ - lang_count = VerLanguageName (lang & 0xFFFF, lang_buf, 128); - if (lang_count) { - process_set_field_string (filever, "language", lang_buf, lang_count, error); - return_if_nok (error); - } - process_module_stringtable (filever, data, trans_data[0], trans_data[1], error); - return_if_nok (error); - } - } else { - int i; - - for (i = 0; i < G_N_ELEMENTS (stringtable_entries); ++i) { - /* No strings, so set every field to - * the empty string - */ - process_set_field_string (filever, - stringtable_entries [i].name, - EMPTY_STRING, 0, error); - return_if_nok (error); - } - - /* And language seems to be set to - * en_US according to bug 374600 - */ - lang_count = VerLanguageName (0x0409, lang_buf, 128); - if (lang_count) { - process_set_field_string (filever, "language", lang_buf, lang_count, error); - return_if_nok (error); - } - } - - g_free (query); - } - g_free (data); - } -} -#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ - -static void -process_get_assembly_fileversion (MonoObject *filever, MonoAssembly *assembly) -{ - process_set_field_int (filever, "filemajorpart", assembly->aname.major); - process_set_field_int (filever, "fileminorpart", assembly->aname.minor); - process_set_field_int (filever, "filebuildpart", assembly->aname.build); -} - -static MonoObject* -get_process_module (MonoAssembly *assembly, MonoClass *proc_class, MonoError *error) -{ - MonoObject *item, *filever; - MonoDomain *domain = mono_domain_get (); - char *filename; - const char *modulename = assembly->aname.name; - - mono_error_init (error); - - /* Build a System.Diagnostics.ProcessModule with the data. - */ - item = mono_object_new_checked (domain, proc_class, error); - return_val_if_nok (error, NULL); - filever = mono_object_new_checked (domain, mono_class_get_file_version_info_class (), error); - return_val_if_nok (error, NULL); - - filename = g_strdup_printf ("[In Memory] %s", modulename); - - process_get_assembly_fileversion (filever, assembly); - process_set_field_string_char (filever, "filename", filename); - process_set_field_object (item, "version_info", filever); - - process_set_field_intptr (item, "baseaddr", assembly->image->raw_data); - process_set_field_int (item, "memory_size", assembly->image->raw_data_len); - process_set_field_string_char (item, "filename", filename); - process_set_field_string_char (item, "modulename", modulename); - - g_free (filename); - - return item; -} - -#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) -static MonoObject* -process_add_module (HANDLE process, HMODULE mod, gunichar2 *filename, gunichar2 *modulename, MonoClass *proc_class, MonoError *error) -{ - MonoObject *item, *filever; - MonoDomain *domain = mono_domain_get (); - MODULEINFO modinfo; - BOOL ok; - - mono_error_init (error); - - /* Build a System.Diagnostics.ProcessModule with the data. - */ - item = mono_object_new_checked (domain, proc_class, error); - return_val_if_nok (error, NULL); - filever = mono_object_new_checked (domain, mono_class_get_file_version_info_class (), error); - return_val_if_nok (error, NULL); - - process_get_fileversion (filever, filename, error); - return_val_if_nok (error, NULL); - - process_set_field_string (filever, "filename", filename, - unicode_chars (filename), error); - return_val_if_nok (error, NULL); - ok = GetModuleInformation (process, mod, &modinfo, sizeof(MODULEINFO)); - if (ok) { - process_set_field_intptr (item, "baseaddr", - modinfo.lpBaseOfDll); - process_set_field_intptr (item, "entryaddr", - modinfo.EntryPoint); - process_set_field_int (item, "memory_size", - modinfo.SizeOfImage); - } - process_set_field_string (item, "filename", filename, - unicode_chars (filename), error); - return_val_if_nok (error, NULL); - process_set_field_string (item, "modulename", modulename, - unicode_chars (modulename), error); - return_val_if_nok (error, NULL); - process_set_field_object (item, "version_info", filever); - - return item; -} -#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ - -static GPtrArray* -get_domain_assemblies (MonoDomain *domain) -{ - GSList *tmp; - GPtrArray *assemblies; - - /* - * Make a copy of the list of assemblies because we can't hold the assemblies - * lock while creating objects etc. - */ - assemblies = g_ptr_array_new (); - mono_domain_assemblies_lock (domain); - for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) { - MonoAssembly *ass = (MonoAssembly *)tmp->data; - if (ass->image->fileio_used) - continue; - g_ptr_array_add (assemblies, ass); - } - mono_domain_assemblies_unlock (domain); - - return assemblies; -} - -/* Returns an array of System.Diagnostics.ProcessModule */ -#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) -MonoArray * -ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject *this_obj, HANDLE process) -{ - MonoError error; - MonoArray *temp_arr = NULL; - MonoArray *arr; - HMODULE mods[1024]; - gunichar2 filename[MAX_PATH]; - gunichar2 modname[MAX_PATH]; - DWORD needed; - guint32 count = 0, module_count = 0, assembly_count = 0; - guint32 i, num_added = 0; - GPtrArray *assemblies = NULL; - - stash_system_assembly (this_obj); - - if (GetProcessId (process) == mono_process_current_pid ()) { - assemblies = get_domain_assemblies (mono_domain_get ()); - assembly_count = assemblies->len; - } - - if (EnumProcessModules (process, mods, sizeof(mods), &needed)) { - module_count += needed / sizeof(HMODULE); - } - - count = module_count + assembly_count; - temp_arr = mono_array_new_checked (mono_domain_get (), mono_class_get_process_module_class (), count, &error); - if (mono_error_set_pending_exception (&error)) - return NULL; - - for (i = 0; i < module_count; i++) { - if (GetModuleBaseName (process, mods[i], modname, MAX_PATH) && - GetModuleFileNameEx (process, mods[i], filename, MAX_PATH)) { - MonoObject *module = process_add_module (process, mods[i], - filename, modname, mono_class_get_process_module_class (), &error); - if (!mono_error_ok (&error)) { - mono_error_set_pending_exception (&error); - return NULL; - } - mono_array_setref (temp_arr, num_added++, module); - } - } - - if (assemblies) { - for (i = 0; i < assembly_count; i++) { - MonoAssembly *ass = (MonoAssembly *)g_ptr_array_index (assemblies, i); - MonoObject *module = get_process_module (ass, mono_class_get_process_module_class (), &error); - if (!mono_error_ok (&error)) { - mono_error_set_pending_exception (&error); - return NULL; - } - mono_array_setref (temp_arr, num_added++, module); - } - g_ptr_array_free (assemblies, TRUE); - } - - if (count == num_added) { - arr = temp_arr; - } else { - /* shorter version of the array */ - arr = mono_array_new_checked (mono_domain_get (), mono_class_get_process_module_class (), num_added, &error); - if (mono_error_set_pending_exception (&error)) - return NULL; - - for (i = 0; i < num_added; i++) - mono_array_setref (arr, i, mono_array_get (temp_arr, MonoObject*, i)); - } - - return arr; -} -#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ - -void -ves_icall_System_Diagnostics_FileVersionInfo_GetVersionInfo_internal (MonoObject *this_obj, MonoString *filename) -{ - MonoError error; - - stash_system_assembly (this_obj); - - process_get_fileversion (this_obj, mono_string_chars (filename), &error); - if (!mono_error_ok (&error)) { - mono_error_set_pending_exception (&error); - return; - } - process_set_field_string (this_obj, "filename", - mono_string_chars (filename), - mono_string_length (filename), &error); - if (!mono_error_ok (&error)) { - mono_error_set_pending_exception (&error); - return; - } -} - -/* Only used when UseShellExecute is false */ -#ifndef HOST_WIN32 -static inline gchar * -mono_process_quote_path (const gchar *path) -{ - return g_shell_quote (path); -} - -static inline gchar * -mono_process_unquote_application_name (gchar *path) -{ - return path; -} -#endif /* !HOST_WIN32 */ - -/* Only used when UseShellExecute is false */ -gboolean -mono_process_complete_path (const gunichar2 *appname, gchar **completed) -{ - gchar *utf8app, *utf8appmemory; - gchar *found; - - utf8appmemory = g_utf16_to_utf8 (appname, -1, NULL, NULL, NULL); - utf8app = mono_process_unquote_application_name (utf8appmemory); - - if (g_path_is_absolute (utf8app)) { - *completed = mono_process_quote_path (utf8app); - g_free (utf8appmemory); - return TRUE; - } - - if (g_file_test (utf8app, G_FILE_TEST_IS_EXECUTABLE) && !g_file_test (utf8app, G_FILE_TEST_IS_DIR)) { - *completed = mono_process_quote_path (utf8app); - g_free (utf8appmemory); - return TRUE; - } - - found = g_find_program_in_path (utf8app); - if (found == NULL) { - *completed = NULL; - g_free (utf8appmemory); - return FALSE; - } - - *completed = mono_process_quote_path (found); - g_free (found); - g_free (utf8appmemory); - return TRUE; -} - -#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) -MonoBoolean -ves_icall_System_Diagnostics_Process_ShellExecuteEx_internal (MonoProcessStartInfo *proc_start_info, MonoProcInfo *process_info) -{ - SHELLEXECUTEINFO shellex = {0}; - gboolean ret; - - shellex.cbSize = sizeof(SHELLEXECUTEINFO); - shellex.fMask = (gulong)(SEE_MASK_FLAG_DDEWAIT | SEE_MASK_NOCLOSEPROCESS | SEE_MASK_UNICODE); - shellex.nShow = (gulong)proc_start_info->window_style; - shellex.nShow = (gulong)((shellex.nShow == 0) ? 1 : (shellex.nShow == 1 ? 0 : shellex.nShow)); - - if (proc_start_info->filename != NULL) { - shellex.lpFile = mono_string_chars (proc_start_info->filename); - } - - if (proc_start_info->arguments != NULL) { - shellex.lpParameters = mono_string_chars (proc_start_info->arguments); - } - - if (proc_start_info->verb != NULL && - mono_string_length (proc_start_info->verb) != 0) { - shellex.lpVerb = mono_string_chars (proc_start_info->verb); - } - - if (proc_start_info->working_directory != NULL && - mono_string_length (proc_start_info->working_directory) != 0) { - shellex.lpDirectory = mono_string_chars (proc_start_info->working_directory); - } - - if (proc_start_info->error_dialog) { - shellex.hwnd = proc_start_info->error_dialog_parent_handle; - } else { - shellex.fMask = (gulong)(shellex.fMask | SEE_MASK_FLAG_NO_UI); - } - - ret = ShellExecuteEx (&shellex); - if (ret == FALSE) { - process_info->pid = -GetLastError (); - } else { - process_info->process_handle = shellex.hProcess; - process_info->thread_handle = NULL; -#if !defined(MONO_CROSS_COMPILE) - process_info->pid = GetProcessId (shellex.hProcess); -#else - process_info->pid = 0; -#endif - process_info->tid = 0; - } - - return ret; -} -#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ - -#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) -static inline void -mono_process_init_startup_info (HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle, STARTUPINFO *startinfo) -{ - startinfo->cb = sizeof(STARTUPINFO); - startinfo->dwFlags = STARTF_USESTDHANDLES; - startinfo->hStdInput = stdin_handle; - startinfo->hStdOutput = stdout_handle; - startinfo->hStdError = stderr_handle; - return; -} -#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ - -#ifndef HOST_WIN32 -static gboolean -mono_process_get_shell_arguments (MonoProcessStartInfo *proc_start_info, gunichar2 **shell_path, MonoString **cmd) -{ - gchar *spath = NULL; - - *shell_path = NULL; - *cmd = proc_start_info->arguments; - - mono_process_complete_path (mono_string_chars (proc_start_info->filename), &spath); - if (spath != NULL) { - *shell_path = g_utf8_to_utf16 (spath, -1, NULL, NULL, NULL); - g_free (spath); - } - - return (*shell_path != NULL) ? TRUE : FALSE; -} -#endif /* !HOST_WIN32 */ - -#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) -static gboolean -mono_process_create_process (MonoProcInfo *mono_process_info, gunichar2 *shell_path, - MonoString *cmd, guint32 creation_flags, gchar *env_vars, - gunichar2 *dir, STARTUPINFO *start_info, PROCESS_INFORMATION *process_info) -{ - gboolean result = FALSE; - - if (mono_process_info->username) { - guint32 logon_flags = mono_process_info->load_user_profile ? LOGON_WITH_PROFILE : 0; - - result = CreateProcessWithLogonW (mono_string_chars (mono_process_info->username), - mono_process_info->domain ? mono_string_chars (mono_process_info->domain) : NULL, - (const gunichar2 *)mono_process_info->password, - logon_flags, - shell_path, - cmd ? mono_string_chars (cmd) : NULL, - creation_flags, - env_vars, dir, start_info, process_info); - - } else { - - result = CreateProcess (shell_path, - cmd ? mono_string_chars (cmd): NULL, - NULL, - NULL, - TRUE, - creation_flags, - env_vars, - dir, - start_info, - process_info); - - } - - return result; -} -#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ - -MonoBoolean -ves_icall_System_Diagnostics_Process_CreateProcess_internal (MonoProcessStartInfo *proc_start_info, HANDLE stdin_handle, - HANDLE stdout_handle, HANDLE stderr_handle, MonoProcInfo *process_info) -{ - gboolean ret; - gunichar2 *dir; - STARTUPINFO startinfo={0}; - PROCESS_INFORMATION procinfo; - gunichar2 *shell_path = NULL; - gchar *env_vars = NULL; - MonoString *cmd = NULL; - guint32 creation_flags; - - mono_process_init_startup_info (stdin_handle, stdout_handle, stderr_handle, &startinfo); - - creation_flags = CREATE_UNICODE_ENVIRONMENT; - if (proc_start_info->create_no_window) - creation_flags |= CREATE_NO_WINDOW; - - if (mono_process_get_shell_arguments (proc_start_info, &shell_path, &cmd) == FALSE) { - process_info->pid = -ERROR_FILE_NOT_FOUND; - return FALSE; - } - - if (process_info->env_keys) { - gint i, len; - MonoString *ms; - MonoString *key, *value; - gunichar2 *str, *ptr; - gunichar2 *equals16; - - for (len = 0, i = 0; i < mono_array_length (process_info->env_keys); i++) { - ms = mono_array_get (process_info->env_values, MonoString *, i); - if (ms == NULL) - continue; - - len += mono_string_length (ms) * sizeof (gunichar2); - ms = mono_array_get (process_info->env_keys, MonoString *, i); - len += mono_string_length (ms) * sizeof (gunichar2); - len += 2 * sizeof (gunichar2); - } - - equals16 = g_utf8_to_utf16 ("=", 1, NULL, NULL, NULL); - ptr = str = g_new0 (gunichar2, len + 1); - for (i = 0; i < mono_array_length (process_info->env_keys); i++) { - value = mono_array_get (process_info->env_values, MonoString *, i); - if (value == NULL) - continue; - - key = mono_array_get (process_info->env_keys, MonoString *, i); - memcpy (ptr, mono_string_chars (key), mono_string_length (key) * sizeof (gunichar2)); - ptr += mono_string_length (key); - - memcpy (ptr, equals16, sizeof (gunichar2)); - ptr++; - - memcpy (ptr, mono_string_chars (value), mono_string_length (value) * sizeof (gunichar2)); - ptr += mono_string_length (value); - ptr++; - } - - g_free (equals16); - env_vars = (gchar *) str; - } - - /* The default dir name is "". Turn that into NULL to mean - * "current directory" - */ - if (proc_start_info->working_directory == NULL || mono_string_length (proc_start_info->working_directory) == 0) - dir = NULL; - else - dir = mono_string_chars (proc_start_info->working_directory); - - ret = mono_process_create_process (process_info, shell_path, cmd, creation_flags, env_vars, dir, &startinfo, &procinfo); - - g_free (env_vars); - if (shell_path != NULL) - g_free (shell_path); - - if (ret) { - process_info->process_handle = procinfo.hProcess; - /*process_info->thread_handle=procinfo.hThread;*/ - process_info->thread_handle = NULL; - if (procinfo.hThread != NULL && procinfo.hThread != INVALID_HANDLE_VALUE) - CloseHandle (procinfo.hThread); - process_info->pid = procinfo.dwProcessId; - process_info->tid = procinfo.dwThreadId; - } else { - process_info->pid = -GetLastError (); - } - - return ret; -} - -#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) -MonoString * -ves_icall_System_Diagnostics_Process_ProcessName_internal (HANDLE process) -{ - MonoError error; - MonoString *string; - gunichar2 name[MAX_PATH]; - guint32 len; - gboolean ok; - HMODULE mod; - DWORD needed; - - ok = EnumProcessModules (process, &mod, sizeof(mod), &needed); - if (!ok) - return NULL; - - len = GetModuleBaseName (process, mod, name, MAX_PATH); - - if (len == 0) - return NULL; - - LOGDEBUG (g_message ("%s: process name is [%s]", __func__, g_utf16_to_utf8 (name, -1, NULL, NULL, NULL))); - - string = mono_string_new_utf16_checked (mono_domain_get (), name, len, &error); - if (!mono_error_ok (&error)) - mono_error_set_pending_exception (&error); - - return string; -} -#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ - -#ifndef HOST_WIN32 -/* Returns an array of pids */ -MonoArray * -ves_icall_System_Diagnostics_Process_GetProcesses_internal (void) -{ - MonoError error; - MonoArray *procs; - gpointer *pidarray; - int i, count; - - pidarray = mono_process_list (&count); - if (!pidarray) { - mono_set_pending_exception (mono_get_exception_not_supported ("This system does not support EnumProcesses")); - return NULL; - } - procs = mono_array_new_checked (mono_domain_get (), mono_get_int32_class (), count, &error); - if (mono_error_set_pending_exception (&error)) { - g_free (pidarray); - return NULL; - } - if (sizeof (guint32) == sizeof (gpointer)) { - memcpy (mono_array_addr (procs, guint32, 0), pidarray, count * sizeof (gint32)); - } else { - for (i = 0; i < count; ++i) - *(mono_array_addr (procs, guint32, i)) = GPOINTER_TO_UINT (pidarray [i]); - } - g_free (pidarray); - - return procs; -} -#endif /* !HOST_WIN32 */ - -gint64 -ves_icall_System_Diagnostics_Process_GetProcessData (int pid, gint32 data_type, gint32 *error) -{ - MonoProcessError perror; - guint64 res; - - res = mono_process_get_data_with_error (GINT_TO_POINTER (pid), (MonoProcessData)data_type, &perror); - if (error) - *error = perror; - return res; -} diff --git a/mono/metadata/process.h b/mono/metadata/process.h deleted file mode 100644 index bad20951a05..00000000000 --- a/mono/metadata/process.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * process.h: System.Diagnostics.Process support - * - * Author: - * Dick Porter (dick@ximian.com) - * - * (C) 2002 Ximian, Inc. - */ - -#ifndef _MONO_METADATA_PROCESS_H_ -#define _MONO_METADATA_PROCESS_H_ - -#include -#include - -#include -#include -#include "mono/utils/mono-compiler.h" - -typedef struct -{ - HANDLE process_handle; - HANDLE thread_handle; - guint32 pid; /* Contains GetLastError () on failure */ - guint32 tid; - MonoArray *env_keys; - MonoArray *env_values; - MonoString *username; - MonoString *domain; - gpointer password; /* BSTR from SecureString in 2.0 profile */ - MonoBoolean load_user_profile; -} MonoProcInfo; - -typedef struct -{ - MonoObject object; - MonoString *filename; - MonoString *arguments; - MonoString *working_directory; - MonoString *verb; - guint32 window_style; - MonoBoolean error_dialog; - gpointer error_dialog_parent_handle; - MonoBoolean use_shell_execute; - MonoString *username; - MonoString *domain; - MonoObject *password; /* SecureString in 2.0 profile, dummy in 1.x */ - MonoString *password_in_clear_text; - MonoBoolean load_user_profile; - MonoBoolean redirect_standard_input; - MonoBoolean redirect_standard_output; - MonoBoolean redirect_standard_error; - MonoObject *encoding_stdout; - MonoObject *encoding_stderr; - MonoBoolean create_no_window; - MonoObject *weak_parent_process; - MonoObject *envVars; -} MonoProcessStartInfo; - -G_BEGIN_DECLS - -HANDLE ves_icall_System_Diagnostics_Process_GetProcess_internal (guint32 pid); -MonoArray *ves_icall_System_Diagnostics_Process_GetProcesses_internal (void); -MonoArray *ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject *this_obj, HANDLE process); -void ves_icall_System_Diagnostics_FileVersionInfo_GetVersionInfo_internal (MonoObject *this_obj, MonoString *filename); -MonoBoolean ves_icall_System_Diagnostics_Process_ShellExecuteEx_internal (MonoProcessStartInfo *proc_start_info, MonoProcInfo *process_handle); -MonoBoolean ves_icall_System_Diagnostics_Process_CreateProcess_internal (MonoProcessStartInfo *proc_start_info, HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle, MonoProcInfo *process_handle); -MonoString *ves_icall_System_Diagnostics_Process_ProcessName_internal (HANDLE process); -gint64 ves_icall_System_Diagnostics_Process_GetProcessData (int pid, gint32 data_type, gint32 *error); - -G_END_DECLS - -#endif /* _MONO_METADATA_PROCESS_H_ */ - diff --git a/mono/metadata/reflection-internals.h b/mono/metadata/reflection-internals.h index 967867149ca..85e757fbf5d 100644 --- a/mono/metadata/reflection-internals.h +++ b/mono/metadata/reflection-internals.h @@ -41,13 +41,13 @@ MonoArray* mono_reflection_get_custom_attrs_blob_checked (MonoReflectionAssembly *assembly, MonoObject *ctor, MonoArray *ctorArgs, MonoArray *properties, MonoArray *propValues, MonoArray *fields, MonoArray* fieldValues, MonoError *error); MonoCustomAttrInfo* -mono_custom_attrs_from_index_checked (MonoImage *image, uint32_t idx, MonoError *error); +mono_custom_attrs_from_index_checked (MonoImage *image, uint32_t idx, gboolean ignore_missing, MonoError *error); MonoCustomAttrInfo* mono_custom_attrs_from_method_checked (MonoMethod *method, MonoError *error); MonoCustomAttrInfo* mono_custom_attrs_from_class_checked (MonoClass *klass, MonoError *error); MonoCustomAttrInfo* -mono_custom_attrs_from_assembly_checked (MonoAssembly *assembly, MonoError *error); +mono_custom_attrs_from_assembly_checked (MonoAssembly *assembly, gboolean ignore_missing, MonoError *error); MonoCustomAttrInfo* mono_custom_attrs_from_property_checked (MonoClass *klass, MonoProperty *property, MonoError *error); MonoCustomAttrInfo* diff --git a/mono/metadata/reflection.c b/mono/metadata/reflection.c index e17bf869208..88ecb5fddfd 100644 --- a/mono/metadata/reflection.c +++ b/mono/metadata/reflection.c @@ -46,6 +46,7 @@ #include #include #include +#include static void get_default_param_value_blobs (MonoMethod *method, char **blobs, guint32 *types); static MonoType* mono_reflection_get_type_with_rootimage (MonoImage *rootimage, MonoImage* image, MonoTypeNameParse *info, gboolean ignorecase, gboolean *type_resolve, MonoError *error); @@ -66,10 +67,17 @@ static GENERATE_GET_CLASS_WITH_CACHE (exception_handling_clause, System.Reflecti static GENERATE_GET_CLASS_WITH_CACHE (type_builder, System.Reflection.Emit, TypeBuilder); static GENERATE_GET_CLASS_WITH_CACHE (dbnull, System, DBNull); + +static int class_ref_info_handle_count; + void mono_reflection_init (void) { mono_reflection_emit_init (); + + mono_counters_register ("MonoClass::ref_info_handle count", + MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ref_info_handle_count); + } /* @@ -94,6 +102,7 @@ mono_class_set_ref_info (MonoClass *klass, gpointer obj) MONO_REQ_GC_UNSAFE_MODE; klass->ref_info_handle = mono_gchandle_new ((MonoObject*)obj, FALSE); + ++class_ref_info_handle_count; g_assert (klass->ref_info_handle != 0); } @@ -343,7 +352,7 @@ mono_type_normalize (MonoType *type) return type; gtd = gclass->container_class; - gcontainer = gtd->generic_container; + gcontainer = mono_class_get_generic_container (gtd); argv = g_newa (MonoType*, ginst->type_argc); for (i = 0; i < ginst->type_argc; ++i) { @@ -2147,12 +2156,20 @@ mono_reflection_bind_generic_parameters (MonoReflectionType *type, int type_argc } klass = mono_class_from_mono_type (t); - if (!klass->generic_container) { + if (!mono_class_is_gtd (klass)) { mono_loader_unlock (); mono_error_set_type_load_class (error, klass, "Cannot bind generic parameters of a non-generic type"); return NULL; } + guint gtd_type_argc = mono_class_get_generic_container (klass)->type_argc; + if (gtd_type_argc != type_argc) { + mono_loader_unlock (); + mono_error_set_argument (error, "types", "The generic type definition needs %d type arguments, but was instantiated with %d ", gtd_type_argc, type_argc); + return NULL; + } + + if (klass->wastypebuilder) is_dynamic = TRUE; @@ -2169,7 +2186,7 @@ mono_class_bind_generic_parameters (MonoClass *klass, int type_argc, MonoType ** MonoGenericClass *gclass; MonoGenericInst *inst; - g_assert (klass->generic_container); + g_assert (mono_class_is_gtd (klass)); inst = mono_metadata_get_generic_inst (type_argc, types); gclass = mono_metadata_lookup_generic_class (klass, inst, is_dynamic); @@ -2215,7 +2232,7 @@ reflection_bind_generic_method_parameters (MonoReflectionMethod *rmethod, MonoAr ginst = mono_metadata_get_generic_inst (count, type_argv); g_free (type_argv); - tmp_context.class_inst = klass->generic_class ? klass->generic_class->context.class_inst : NULL; + tmp_context.class_inst = mono_class_is_ginst (klass) ? mono_class_get_generic_class (klass)->context.class_inst : NULL; tmp_context.method_inst = ginst; inflated = mono_class_inflate_generic_method_checked (method, &tmp_context, error); @@ -2345,7 +2362,7 @@ mono_declsec_flags_from_method (MonoMethod *method) guint32 mono_declsec_flags_from_class (MonoClass *klass) { - if (klass->flags & TYPE_ATTRIBUTE_HAS_SECURITY) { + if (mono_class_get_flags (klass) & TYPE_ATTRIBUTE_HAS_SECURITY) { if (!klass->ext || !klass->ext->declsec_flags) { guint32 idx; diff --git a/mono/metadata/seq-points-data.c b/mono/metadata/seq-points-data.c index b6b59407129..4f996c727d7 100644 --- a/mono/metadata/seq-points-data.c +++ b/mono/metadata/seq-points-data.c @@ -450,6 +450,7 @@ mono_seq_point_data_write (SeqPointData *data, char *path) fwrite (buffer_orig, 1, buffer - buffer_orig, f); g_free (buffer_orig); + fclose (f); return TRUE; } diff --git a/mono/metadata/sgen-mono.c b/mono/metadata/sgen-mono.c index 6372084d21d..26e6a089b5d 100644 --- a/mono/metadata/sgen-mono.c +++ b/mono/metadata/sgen-mono.c @@ -212,6 +212,32 @@ sgen_has_critical_method (void) return sgen_has_managed_allocator (); } +static gboolean +ip_in_critical_region (MonoDomain *domain, gpointer ip) +{ + MonoJitInfo *ji; + MonoMethod *method; + + /* + * We pass false for 'try_aot' so this becomes async safe. + * It won't find aot methods whose jit info is not yet loaded, + * so we preload their jit info in the JIT. + */ + ji = mono_jit_info_table_find_internal (domain, ip, FALSE, FALSE); + if (!ji) + return FALSE; + + method = mono_jit_info_get_method (ji); + + return mono_runtime_is_critical_method (method) || sgen_is_critical_method (method); +} + +gboolean +mono_gc_is_critical_method (MonoMethod *method) +{ + return sgen_is_critical_method (method); +} + #ifndef DISABLE_JIT static void @@ -2285,12 +2311,6 @@ mono_gc_set_skip_thread (gboolean skip) UNLOCK_GC; } -static gboolean -is_critical_method (MonoMethod *method) -{ - return mono_runtime_is_critical_method (method) || sgen_is_critical_method (method); -} - static gboolean thread_in_critical_region (SgenThreadInfo *info) { @@ -2845,8 +2865,8 @@ sgen_client_init (void) cb.thread_detach = sgen_thread_detach; cb.thread_unregister = sgen_thread_unregister; cb.thread_attach = sgen_thread_attach; - cb.mono_method_is_critical = (gboolean (*)(void *))is_critical_method; cb.mono_thread_in_critical_region = thread_in_critical_region; + cb.ip_in_critical_region = ip_in_critical_region; mono_threads_init (&cb, sizeof (SgenThreadInfo)); diff --git a/mono/metadata/sgen-new-bridge.c b/mono/metadata/sgen-new-bridge.c index cdfbb64c027..8b51ccf588a 100644 --- a/mono/metadata/sgen-new-bridge.c +++ b/mono/metadata/sgen-new-bridge.c @@ -196,7 +196,7 @@ class_kind (MonoClass *klass) /* FIXME the bridge check can be quite expensive, cache it at the class level. */ /* An array of a sealed type that is not a bridge will never get to a bridge */ - if ((elem_class->flags & TYPE_ATTRIBUTE_SEALED) && !elem_class->has_references && !bridge_callbacks.bridge_class_kind (elem_class)) { + if ((mono_class_get_flags (elem_class) & TYPE_ATTRIBUTE_SEALED) && !elem_class->has_references && !bridge_callbacks.bridge_class_kind (elem_class)) { SGEN_LOG (6, "class %s is opaque\n", klass->name); return GC_BRIDGE_OPAQUE_CLASS; } diff --git a/mono/metadata/sgen-tarjan-bridge.c b/mono/metadata/sgen-tarjan-bridge.c index daa983e64ac..fc9a73de67d 100644 --- a/mono/metadata/sgen-tarjan-bridge.c +++ b/mono/metadata/sgen-tarjan-bridge.c @@ -62,7 +62,7 @@ class_kind (MonoClass *klass) /* FIXME the bridge check can be quite expensive, cache it at the class level. */ /* An array of a sealed type that is not a bridge will never get to a bridge */ - if ((elem_class->flags & TYPE_ATTRIBUTE_SEALED) && !elem_class->has_references && !bridge_callbacks.bridge_class_kind (elem_class)) { + if ((mono_class_get_flags (elem_class) & TYPE_ATTRIBUTE_SEALED) && !elem_class->has_references && !bridge_callbacks.bridge_class_kind (elem_class)) { SGEN_LOG (6, "class %s is opaque\n", klass->name); return GC_BRIDGE_OPAQUE_CLASS; } diff --git a/mono/metadata/socket-io.c b/mono/metadata/socket-io.c index 2df84e99c8f..b5866b73a22 100644 --- a/mono/metadata/socket-io.c +++ b/mono/metadata/socket-io.c @@ -62,7 +62,7 @@ #include #include #include -#include +#include #include #ifdef HAVE_SYS_TIME_H diff --git a/mono/metadata/sre-encode.c b/mono/metadata/sre-encode.c index 1d9e50ba93c..a412c156096 100644 --- a/mono/metadata/sre-encode.c +++ b/mono/metadata/sre-encode.c @@ -195,8 +195,8 @@ encode_type (MonoDynamicImage *assembly, MonoType *type, SigBuffer *buf) case MONO_TYPE_CLASS: { MonoClass *k = mono_class_from_mono_type (type); - if (k->generic_container) { - MonoGenericClass *gclass = mono_metadata_lookup_generic_class (k, k->generic_container->context.class_inst, TRUE); + if (mono_class_is_gtd (k)) { + MonoGenericClass *gclass = mono_metadata_lookup_generic_class (k, mono_class_get_generic_container (k)->context.class_inst, TRUE); encode_generic_class (assembly, gclass, buf); } else { /* @@ -571,7 +571,7 @@ handle_enum: return idx; } case MONO_TYPE_GENERICINST: - *ret_type = val->vtable->klass->generic_class->container_class->byval_arg.type; + *ret_type = mono_class_get_generic_class (val->vtable->klass)->container_class->byval_arg.type; goto handle_enum; default: g_error ("we don't encode constant type 0x%02x yet", *ret_type); @@ -616,12 +616,12 @@ mono_dynimage_encode_field_signature (MonoDynamicImage *assembly, MonoReflection goto fail; /* encode custom attributes before the type */ - if (klass->generic_container) + if (mono_class_is_gtd (klass)) typespec = create_typespec (assembly, type); if (typespec) { MonoGenericClass *gclass; - gclass = mono_metadata_lookup_generic_class (klass, klass->generic_container->context.class_inst, TRUE); + gclass = mono_metadata_lookup_generic_class (klass, mono_class_get_generic_container (klass)->context.class_inst, TRUE); encode_generic_class (assembly, gclass, &buf); } else { encode_type (assembly, type, &buf); @@ -712,7 +712,7 @@ create_typespec (MonoDynamicImage *assembly, MonoType *type) case MONO_TYPE_CLASS: case MONO_TYPE_VALUETYPE: { MonoClass *k = mono_class_from_mono_type (type); - if (!k || !k->generic_container) { + if (!k || !mono_class_is_gtd (k)) { sigbuffer_free (&buf); return 0; } @@ -756,8 +756,6 @@ mono_dynimage_encode_typedef_or_ref_full (MonoDynamicImage *assembly, MonoType * if (token) return token; klass = mono_class_from_mono_type (type); - if (!klass) - klass = mono_class_from_mono_type (type); /* * If it's in the same module and not a generic type parameter: diff --git a/mono/metadata/sre-save.c b/mono/metadata/sre-save.c index 3256f8cb199..2f32e315a42 100644 --- a/mono/metadata/sre-save.c +++ b/mono/metadata/sre-save.c @@ -1194,7 +1194,7 @@ mono_image_fill_export_table_from_class (MonoDomain *domain, MonoClass *klass, guint32 *values; guint32 visib, res; - visib = klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK; + visib = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK; if (! ((visib & TYPE_ATTRIBUTE_PUBLIC) || (visib & TYPE_ATTRIBUTE_NESTED_PUBLIC))) return 0; @@ -1203,7 +1203,7 @@ mono_image_fill_export_table_from_class (MonoDomain *domain, MonoClass *klass, alloc_table (table, table->rows); values = table->values + table->next_idx * MONO_EXP_TYPE_SIZE; - values [MONO_EXP_TYPE_FLAGS] = klass->flags; + values [MONO_EXP_TYPE_FLAGS] = mono_class_get_flags (klass); values [MONO_EXP_TYPE_TYPEDEF] = klass->type_token; if (klass->nested_in) values [MONO_EXP_TYPE_IMPLEMENTATION] = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE; @@ -1274,7 +1274,7 @@ mono_image_fill_export_table_from_module (MonoDomain *domain, MonoReflectionModu MonoClass *klass = mono_class_get_checked (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, i + 1), &error); g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */ - if (klass->flags & TYPE_ATTRIBUTE_PUBLIC) + if (mono_class_is_public (klass)) mono_image_fill_export_table_from_class (domain, klass, module_index, 0, assembly); } } @@ -1743,7 +1743,7 @@ fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicImage *asse } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod") || !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod")) { MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method; - g_assert (m->klass->generic_class || m->klass->generic_container); + g_assert (mono_class_is_ginst (m->klass) || mono_class_is_gtd (m->klass)); continue; } else if (!strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) { g_assert_not_reached (); diff --git a/mono/metadata/sre.c b/mono/metadata/sre.c index e2ec3395e5c..10a916758df 100644 --- a/mono/metadata/sre.c +++ b/mono/metadata/sre.c @@ -96,7 +96,7 @@ type_get_qualified_name (MonoType *type, MonoAssembly *ass) return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_REFLECTION); ta = klass->image->assembly; if (assembly_is_dynamic (ta) || (ta == ass)) { - if (klass->generic_class || klass->generic_container) + if (mono_class_is_ginst (klass) || mono_class_is_gtd (klass)) /* For generic type definitions, we want T, while REFLECTION returns T */ return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_FULL_NAME); else @@ -704,7 +704,7 @@ mono_image_get_varargs_method_token (MonoDynamicImage *assembly, guint32 origina static gboolean is_field_on_inst (MonoClassField *field) { - return field->parent->generic_class && field->parent->generic_class->is_dynamic; + return mono_class_is_ginst (field->parent) && mono_class_get_generic_class (field->parent)->is_dynamic; } #ifndef DISABLE_REFLECTION_EMIT @@ -721,9 +721,9 @@ mono_image_get_fieldref_token (MonoDynamicImage *assembly, MonoObject *f, MonoCl if (token) return token; - if (field->parent->generic_class && field->parent->generic_class->container_class && field->parent->generic_class->container_class->fields) { + if (mono_class_is_ginst (field->parent) && mono_class_get_generic_class (field->parent)->container_class && mono_class_get_generic_class (field->parent)->container_class->fields) { int index = field - field->parent->fields; - type = mono_field_get_type (&field->parent->generic_class->container_class->fields [index]); + type = mono_field_get_type (&mono_class_get_generic_class (field->parent)->container_class->fields [index]); } else { type = mono_field_get_type (field); } @@ -1138,7 +1138,7 @@ mono_image_create_token (MonoDynamicImage *assembly, MonoObject *obj, return_val_if_nok (error, 0); MonoClass *mc = mono_class_from_mono_type (type); token = mono_metadata_token_from_dor ( - mono_dynimage_encode_typedef_or_ref_full (assembly, type, mc->generic_container == NULL || create_open_instance)); + mono_dynimage_encode_typedef_or_ref_full (assembly, type, !mono_class_is_gtd (mc) || create_open_instance)); } else if (strcmp (klass->name, "MonoCMethod") == 0 || strcmp (klass->name, "MonoMethod") == 0) { MonoReflectionMethod *m = (MonoReflectionMethod *)obj; @@ -1148,7 +1148,7 @@ mono_image_create_token (MonoDynamicImage *assembly, MonoObject *obj, else token = mono_image_get_inflated_method_token (assembly, m->method); } else if ((m->method->klass->image == &assembly->image) && - !m->method->klass->generic_class) { + !mono_class_is_ginst (m->method->klass)) { static guint32 method_table_idx = 0xffffff; if (m->method->klass->wastypebuilder) { /* we use the same token as the one that was assigned @@ -1583,8 +1583,8 @@ mono_reflection_type_get_handle (MonoReflectionType* ref, MonoError *error) MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)(gparam->tbuilder), error); mono_error_assert_ok (error); MonoClass *owner = mono_class_from_mono_type (type); - g_assert (owner->generic_container); - param->param.owner = owner->generic_container; + g_assert (mono_class_is_gtd (owner)); + param->param.owner = mono_class_get_generic_container (owner); } pklass = mono_class_from_generic_parameter_internal ((MonoGenericParam *) param); @@ -2298,7 +2298,13 @@ reflection_setup_internal_class (MonoReflectionTypeBuilder *tb, MonoError *error return TRUE; } - klass = (MonoClass *)mono_image_alloc0 (&tb->module->dynamic_image->image, sizeof (MonoClass)); + /* + * The size calculation here warrants some explaining. + * reflection_setup_internal_class is called too early, well before we know whether the type will be a GTD or DEF, + * meaning we need to alloc enough space to morth a def into a gtd. + */ + klass = (MonoClass *)mono_image_alloc0 (&tb->module->dynamic_image->image, MAX (sizeof (MonoClassDef), sizeof (MonoClassGtd))); + klass->class_kind = MONO_CLASS_DEF; klass->image = &tb->module->dynamic_image->image; @@ -2310,7 +2316,7 @@ reflection_setup_internal_class (MonoReflectionTypeBuilder *tb, MonoError *error if (!is_ok (error)) goto failure; klass->type_token = MONO_TOKEN_TYPE_DEF | tb->table_idx; - klass->flags = tb->attrs; + mono_class_set_flags (klass, tb->attrs); mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD); @@ -2410,29 +2416,31 @@ reflection_create_generic_class (MonoReflectionTypeBuilder *tb, MonoError *error if (count == 0) return TRUE; - klass->generic_container = (MonoGenericContainer *)mono_image_alloc0 (klass->image, sizeof (MonoGenericContainer)); + MonoGenericContainer *generic_container = (MonoGenericContainer *)mono_image_alloc0 (klass->image, sizeof (MonoGenericContainer)); + + generic_container->owner.klass = klass; + generic_container->type_argc = count; + generic_container->type_params = (MonoGenericParamFull *)mono_image_alloc0 (klass->image, sizeof (MonoGenericParamFull) * count); - klass->generic_container->owner.klass = klass; - klass->generic_container->type_argc = count; - klass->generic_container->type_params = (MonoGenericParamFull *)mono_image_alloc0 (klass->image, sizeof (MonoGenericParamFull) * count); + klass->class_kind = MONO_CLASS_GTD; + mono_class_set_generic_container (klass, generic_container); - klass->is_generic = 1; for (i = 0; i < count; i++) { MonoReflectionGenericParam *gparam = (MonoReflectionGenericParam *)mono_array_get (tb->generic_params, gpointer, i); MonoType *param_type = mono_reflection_type_get_handle ((MonoReflectionType*)gparam, error); return_val_if_nok (error, FALSE); MonoGenericParamFull *param = (MonoGenericParamFull *) param_type->data.generic_param; - klass->generic_container->type_params [i] = *param; + generic_container->type_params [i] = *param; /*Make sure we are a diferent type instance */ - klass->generic_container->type_params [i].param.owner = klass->generic_container; - klass->generic_container->type_params [i].info.pklass = NULL; - klass->generic_container->type_params [i].info.flags = gparam->attrs; + generic_container->type_params [i].param.owner = generic_container; + generic_container->type_params [i].info.pklass = NULL; + generic_container->type_params [i].info.flags = gparam->attrs; - g_assert (klass->generic_container->type_params [i].param.owner); + g_assert (generic_container->type_params [i].param.owner); } - klass->generic_container->context.class_inst = mono_get_shared_generic_inst (klass->generic_container); + generic_container->context.class_inst = mono_get_shared_generic_inst (generic_container); return TRUE; } @@ -2573,7 +2581,7 @@ reflection_methodbuilder_to_mono_method (MonoClass *klass, image = dynamic ? NULL : klass->image; if (!dynamic) - g_assert (!klass->generic_class); + g_assert (!mono_class_is_ginst (klass)); mono_loader_lock (); @@ -2724,9 +2732,9 @@ reflection_methodbuilder_to_mono_method (MonoClass *klass, } } - if (klass->generic_container) { - container->parent = klass->generic_container; - container->context.class_inst = klass->generic_container->context.class_inst; + if (mono_class_is_gtd (klass)) { + container->parent = mono_class_get_generic_container (klass); + container->context.class_inst = mono_class_get_generic_container (klass)->context.class_inst; } container->context.method_inst = mono_get_shared_generic_inst (container); } @@ -2903,7 +2911,7 @@ methodbuilder_to_mono_method (MonoClass *klass, MonoReflectionMethodBuilder* mb, static gboolean fix_partial_generic_class (MonoClass *klass, MonoError *error) { - MonoClass *gklass = klass->generic_class->container_class; + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; int i; mono_error_init (error); @@ -2912,7 +2920,7 @@ fix_partial_generic_class (MonoClass *klass, MonoError *error) return TRUE; if (klass->parent != gklass->parent) { - MonoType *parent_type = mono_class_inflate_generic_type_checked (&gklass->parent->byval_arg, &klass->generic_class->context, error); + MonoType *parent_type = mono_class_inflate_generic_type_checked (&gklass->parent->byval_arg, &mono_class_get_generic_class (klass)->context, error); if (mono_error_ok (error)) { MonoClass *parent = mono_class_from_mono_type (parent_type); mono_metadata_free_type (parent_type); @@ -2928,7 +2936,7 @@ fix_partial_generic_class (MonoClass *klass, MonoError *error) } } - if (!klass->generic_class->need_sync) + if (!mono_class_get_generic_class (klass)->need_sync) return TRUE; if (klass->method.count != gklass->method.count) { @@ -2989,7 +2997,7 @@ fix_partial_generic_class (MonoClass *klass, MonoError *error) static gboolean ensure_generic_class_runtime_vtable (MonoClass *klass, MonoError *error) { - MonoClass *gklass = klass->generic_class->container_class; + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; mono_error_init (error); @@ -3015,7 +3023,7 @@ ensure_runtime_vtable (MonoClass *klass, MonoError *error) mono_error_init (error); - if (!image_is_dynamic (klass->image) || (!tb && !klass->generic_class) || klass->wastypebuilder) + if (!image_is_dynamic (klass->image) || (!tb && !mono_class_is_ginst (klass)) || klass->wastypebuilder) return TRUE; if (klass->parent) if (!ensure_runtime_vtable (klass->parent, error)) @@ -3054,14 +3062,14 @@ ensure_runtime_vtable (MonoClass *klass, MonoError *error) } klass->interfaces_inited = 1; } - } else if (klass->generic_class){ + } else if (mono_class_is_ginst (klass)){ if (!ensure_generic_class_runtime_vtable (klass, error)) { mono_class_set_type_load_failure (klass, "Could not initialize vtable for generic class due to: %s", mono_error_get_message (error)); return FALSE; } } - if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (klass)) { int slot_num = 0; for (i = 0; i < klass->method.count; ++i) { MonoMethod *im = klass->methods [i]; @@ -3191,7 +3199,6 @@ typebuilder_setup_fields (MonoClass *klass, MonoError *error) } klass->field.count = tb->num_fields; - klass->field.first = 0; mono_error_init (error); @@ -3216,6 +3223,7 @@ typebuilder_setup_fields (MonoClass *klass, MonoError *error) MonoArray *rva_data; fb = (MonoReflectionFieldBuilder *)mono_array_get (tb->fields, gpointer, i); field = &klass->fields [i]; + field->parent = klass; field->name = mono_string_to_utf8_image (image, fb->name, error); if (!mono_error_ok (error)) return; @@ -3238,7 +3246,6 @@ typebuilder_setup_fields (MonoClass *klass, MonoError *error) } if (fb->offset != -1) field->offset = fb->offset; - field->parent = klass; fb->handle = field; mono_save_custom_attrs (klass->image, field, fb->cattrs); @@ -3428,7 +3435,7 @@ ves_icall_TypeBuilder_create_runtime_class (MonoReflectionTypeBuilder *tb) * Fields to set in klass: * the various flags: delegate/unicode/contextbound etc. */ - klass->flags = tb->attrs; + mono_class_set_flags (klass, tb->attrs); klass->has_cctor = 1; mono_class_setup_parent (klass, klass->parent); @@ -3490,7 +3497,7 @@ ves_icall_TypeBuilder_create_runtime_class (MonoReflectionTypeBuilder *tb) * * Together with this we must ensure the contents of all instances to match the created type. */ - if (domain->type_hash && klass->generic_container) { + if (domain->type_hash && mono_class_is_gtd (klass)) { struct remove_instantiations_user_data data; data.klass = klass; data.error = &error; @@ -3741,8 +3748,8 @@ ensure_complete_type (MonoClass *klass, MonoError *error) //g_assert (klass->wastypebuilder); } - if (klass->generic_class) { - MonoGenericInst *inst = klass->generic_class->context.class_inst; + if (mono_class_is_ginst (klass)) { + MonoGenericInst *inst = mono_class_get_generic_class (klass)->context.class_inst; int i; for (i = 0; i < inst->type_argc; ++i) { diff --git a/mono/metadata/threadpool-ms.c b/mono/metadata/threadpool-ms.c index d22470415e8..afd2bcc9e36 100644 --- a/mono/metadata/threadpool-ms.c +++ b/mono/metadata/threadpool-ms.c @@ -424,18 +424,20 @@ domain_remove (ThreadPoolDomain *tpdomain) static ThreadPoolDomain * domain_get (MonoDomain *domain, gboolean create) { - ThreadPoolDomain *tpdomain = NULL; guint i; g_assert (domain); for (i = 0; i < threadpool->domains->len; ++i) { + ThreadPoolDomain *tpdomain; + tpdomain = (ThreadPoolDomain *)g_ptr_array_index (threadpool->domains, i); if (tpdomain->domain == domain) return tpdomain; } if (create) { + ThreadPoolDomain *tpdomain; ThreadPoolDomainCleanupSemaphore *cleanup_semaphore; cleanup_semaphore = g_new0 (ThreadPoolDomainCleanupSemaphore, 1); cleanup_semaphore->ref = 2; @@ -447,9 +449,11 @@ domain_get (MonoDomain *domain, gboolean create) tpdomain = g_new0 (ThreadPoolDomain, 1); tpdomain->domain = domain; domain_add (tpdomain); + + return tpdomain; } - return tpdomain; + return NULL; } static void diff --git a/mono/metadata/threads-types.h b/mono/metadata/threads-types.h index a7fd76f1f1c..84f2c15e98f 100644 --- a/mono/metadata/threads-types.h +++ b/mono/metadata/threads-types.h @@ -70,7 +70,7 @@ void mono_threads_install_cleanup (MonoThreadCleanupFunc func); void ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj); HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this_obj, MonoObject *start); -void ves_icall_System_Threading_InternalThread_Thread_free_internal(MonoInternalThread *this_obj, HANDLE thread); +void ves_icall_System_Threading_InternalThread_Thread_free_internal(MonoInternalThread *this_obj); void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms); gboolean ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms); gint32 ves_icall_System_Threading_Thread_GetDomainID (void); diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c index 2ae43aab0ae..315183a7762 100644 --- a/mono/metadata/threads.c +++ b/mono/metadata/threads.c @@ -44,7 +44,9 @@ #include #include #include -#include +#include +#include +#include #include #include @@ -213,7 +215,7 @@ static mono_mutex_t interlocked_mutex; static gint32 thread_interruption_requested = 0; /* Event signaled when a thread changes its background mode */ -static HANDLE background_change_event; +static MonoOSEvent background_change_event; static gboolean shutting_down = FALSE; @@ -539,22 +541,18 @@ set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, M } static MonoThread* -create_thread_object (MonoDomain *domain) +create_thread_object (MonoDomain *domain, MonoInternalThread *internal) { + MonoThread *thread; + MonoVTable *vtable; MonoError error; - MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class); - MonoThread *t = (MonoThread*)mono_object_new_mature (vt, &error); - /* only possible failure mode is OOM, from which we don't expect to recover. */ - mono_error_assert_ok (&error); - return t; -} -static MonoThread* -new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal) -{ - MonoThread *thread; + vtable = mono_class_vtable (domain, mono_defaults.thread_class); + g_assert (vtable); - thread = create_thread_object (domain); + thread = (MonoThread*)mono_object_new_mature (vtable, &error); + /* only possible failure mode is OOM, from which we don't expect to recover. */ + mono_error_assert_ok (&error); MONO_OBJECT_SETREF (thread, internal_thread, internal); @@ -562,7 +560,7 @@ new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal) } static MonoInternalThread* -create_internal_thread (void) +create_internal_thread_object (void) { MonoError error; MonoInternalThread *thread; @@ -585,6 +583,9 @@ create_internal_thread (void) thread->priority = MONO_THREAD_PRIORITY_NORMAL; + thread->suspended = g_new0 (MonoOSEvent, 1); + mono_os_event_init (thread->suspended, TRUE, TRUE); + return thread; } @@ -592,7 +593,6 @@ static void mono_thread_internal_set_priority (MonoInternalThread *internal, MonoThreadPriority priority) { g_assert (internal); - g_assert (internal->handle); g_assert (priority >= MONO_THREAD_PRIORITY_LOWEST); g_assert (priority <= MONO_THREAD_PRIORITY_HIGHEST); @@ -601,7 +601,9 @@ mono_thread_internal_set_priority (MonoInternalThread *internal, MonoThreadPrior #ifdef HOST_WIN32 BOOL res; - res = SetThreadPriority (internal->handle, priority - 2); + g_assert (internal->native_handle); + + res = SetThreadPriority (internal->native_handle, priority - 2); if (!res) g_error ("%s: SetThreadPriority failed, error %d", __func__, GetLastError ()); #else /* HOST_WIN32 */ @@ -676,7 +678,10 @@ mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean info = mono_thread_info_current (); internal = thread->internal_thread; - internal->handle = mono_thread_info_duplicate_handle (info); + internal->handle = mono_threads_open_thread_handle (info->handle); +#ifdef HOST_WIN32 + internal->native_handle = OpenThread (THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId ()); +#endif internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()); internal->thread_info = info; internal->small_id = info->small_id; @@ -727,7 +732,7 @@ mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean g_assert (!internal->root_domain_thread); if (domain != root_domain) - MONO_OBJECT_SETREF (internal, root_domain_thread, new_thread_with_internal (root_domain, internal)); + MONO_OBJECT_SETREF (internal, root_domain_thread, create_thread_object (root_domain, internal)); else MONO_OBJECT_SETREF (internal, root_domain_thread, thread); @@ -890,9 +895,6 @@ static gsize WINAPI start_wrapper(void *data) { volatile gsize dummy; - /* Avoid scanning the frames above this frame during a GC */ - mono_gc_set_stack_end ((void*)&dummy); - return start_wrapper_internal ((StartInfo*) data, (gsize*) &dummy); } @@ -907,7 +909,7 @@ create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *sta gboolean threadpool_thread, guint32 stack_size, MonoError *error) { StartInfo *start_info = NULL; - HANDLE thread_handle; + MonoThreadHandle *thread_handle; MonoNativeThreadId tid; gboolean ret; gsize stack_set_size; @@ -1029,11 +1031,9 @@ mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gb mono_error_init (error); - thread = create_thread_object (domain); + internal = create_internal_thread_object (); - internal = create_internal_thread (); - - MONO_OBJECT_SETREF (thread, internal_thread, internal); + thread = create_thread_object (domain, internal); LOCK_THREAD (internal); @@ -1088,9 +1088,9 @@ mono_thread_attach_full (MonoDomain *domain, gboolean force_attach) tid=mono_native_thread_id_get (); - internal = create_internal_thread (); + internal = create_internal_thread_object (); - thread = new_thread_with_internal (domain, internal); + thread = create_thread_object (domain, internal); if (!mono_thread_attach_internal (thread, force_attach, TRUE, &stack_ptr)) { /* Mono is shutting down, so just wait for the end */ @@ -1197,7 +1197,7 @@ mono_thread_exit (void) if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) exit (mono_environment_exitcode_get ()); - mono_thread_info_exit (); + mono_thread_info_exit (0); } void @@ -1205,7 +1205,7 @@ ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj) { MonoInternalThread *internal; - internal = create_internal_thread (); + internal = create_internal_thread_object (); internal->state = ThreadState_Unstarted; @@ -1258,17 +1258,23 @@ ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj, * This is called from the finalizer of the internal thread object. */ void -ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread) +ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj) { - THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread)); + THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, this_obj->handle)); /* * Since threads keep a reference to their thread object while running, by the time this function is called, * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown, * when thread_cleanup () can be called after this. */ - if (thread) - mono_threads_close_thread_handle (thread); + if (this_obj->handle) { + mono_threads_close_thread_handle (this_obj->handle); + this_obj->handle = NULL; + } + +#if HOST_WIN32 + CloseHandle (this_obj->native_handle); +#endif if (this_obj->synch_cs) { MonoCoopMutex *synch_cs = this_obj->synch_cs; @@ -1282,6 +1288,11 @@ ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThre this_obj->name = NULL; g_free (name); } + + g_assert (this_obj->suspended); + mono_os_event_destroy (this_obj->suspended); + g_free (this_obj->suspended); + this_obj->suspended = NULL; } void @@ -1515,7 +1526,7 @@ ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priorit LOCK_THREAD (internal); internal->priority = priority; - if (internal->handle != NULL) + if (internal->thread_info != NULL) mono_thread_internal_set_priority (internal, priority); UNLOCK_THREAD (internal); } @@ -1569,7 +1580,7 @@ mono_thread_current (void) if (!*current_thread_ptr) { g_assert (domain != mono_get_root_domain ()); - *current_thread_ptr = new_thread_with_internal (domain, internal); + *current_thread_ptr = create_thread_object (domain, internal); } return *current_thread_ptr; } @@ -1586,7 +1597,7 @@ mono_thread_current_for_thread (MonoInternalThread *internal) if (!*current_thread_ptr) { g_assert (domain != mono_get_root_domain ()); - *current_thread_ptr = new_thread_with_internal (domain, internal); + *current_thread_ptr = create_thread_object (domain, internal); } return *current_thread_ptr; } @@ -1603,7 +1614,7 @@ gboolean ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms) { MonoInternalThread *thread = this_obj->internal_thread; - HANDLE handle = thread->handle; + MonoThreadHandle *handle = thread->handle; MonoInternalThread *cur_thread = mono_thread_internal_current (); gboolean ret; @@ -1629,12 +1640,12 @@ ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms) mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin); MONO_ENTER_GC_SAFE; - ret=WaitForSingleObjectEx (handle, ms, TRUE); + ret=mono_thread_info_wait_one_handle (handle, ms, TRUE); MONO_EXIT_GC_SAFE; mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin); - if(ret==WAIT_OBJECT_0) { + if(ret==MONO_THREAD_INFO_WAIT_RET_SUCCESS_0) { THREAD_DEBUG (g_message ("%s: join successful", __func__)); return(TRUE); @@ -2072,7 +2083,7 @@ ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint3 * be notified, since it has to rebuild the list of threads to * wait for. */ - mono_w32event_set (background_change_event); + mono_os_event_set (&background_change_event); } } @@ -2086,7 +2097,7 @@ ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint3 * be notified, since it has to rebuild the list of threads to * wait for. */ - mono_w32event_set (background_change_event); + mono_os_event_set (&background_change_event); } } @@ -2324,6 +2335,8 @@ mono_thread_suspend (MonoInternalThread *thread) } thread->state |= ThreadState_SuspendRequested; + if (mono_threads_is_coop_enabled ()) + mono_os_event_reset (thread->suspended); if (thread == mono_thread_internal_current ()) { /* calls UNLOCK_THREAD (thread) */ @@ -2350,6 +2363,9 @@ static gboolean mono_thread_resume (MonoInternalThread *thread) { if ((thread->state & ThreadState_SuspendRequested) != 0) { + // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (1) thread %p\n", thread_get_tid (thread)); + if (mono_threads_is_coop_enabled ()) + mono_os_event_set (thread->suspended); thread->state &= ~ThreadState_SuspendRequested; return TRUE; } @@ -2359,16 +2375,23 @@ mono_thread_resume (MonoInternalThread *thread) (thread->state & ThreadState_Aborted) != 0 || (thread->state & ThreadState_Stopped) != 0) { + // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (2) thread %p\n", thread_get_tid (thread)); return FALSE; } - UNLOCK_THREAD (thread); + // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (3) thread %p\n", thread_get_tid (thread)); - /* Awake the thread */ - if (!mono_thread_info_resume (thread_get_tid (thread))) - return FALSE; + if (mono_threads_is_coop_enabled ()) { + mono_os_event_set (thread->suspended); + } else { + UNLOCK_THREAD (thread); - LOCK_THREAD (thread); + /* Awake the thread */ + if (!mono_thread_info_resume (thread_get_tid (thread))) + return FALSE; + + LOCK_THREAD (thread); + } thread->state &= ~ThreadState_Suspended; @@ -2837,8 +2860,7 @@ void mono_thread_init (MonoThreadStartCB start_cb, mono_os_mutex_init_recursive(&interlocked_mutex); mono_os_mutex_init_recursive(&joinable_threads_mutex); - background_change_event = mono_w32event_create (TRUE, FALSE); - g_assert(background_change_event != NULL); + mono_os_event_init (&background_change_event, TRUE, FALSE); mono_init_static_data_info (&thread_static_info); mono_init_static_data_info (&context_static_info); @@ -2847,25 +2869,18 @@ void mono_thread_init (MonoThreadStartCB start_cb, mono_thread_start_cb = start_cb; mono_thread_attach_cb = attach_cb; - - /* Get a pseudo handle to the current process. This is just a - * kludge so that wapi can build a process handle if needed. - * As a pseudo handle is returned, we don't need to clean - * anything up. - */ - GetCurrentProcess (); } void mono_thread_cleanup (void) { -#if !defined(RUN_IN_SUBTHREAD) +#if !defined(RUN_IN_SUBTHREAD) && !defined(HOST_WIN32) /* The main thread must abandon any held mutexes (particularly * important for named mutexes as they are shared across * processes, see bug 74680.) This will happen when the * thread exits, but if it's not running in a subthread it * won't exit in time. */ - mono_thread_info_set_exited (mono_thread_info_current ()); + mono_w32mutex_abandon (); #endif #if 0 @@ -2877,7 +2892,7 @@ void mono_thread_cleanup (void) mono_os_mutex_destroy (&interlocked_mutex); mono_os_mutex_destroy (&delayed_free_table_mutex); mono_os_mutex_destroy (&small_id_mutex); - CloseHandle (background_change_event); + mono_os_event_destroy (&background_change_event); #endif mono_native_tls_free (current_object_key); @@ -2909,7 +2924,7 @@ static void print_tids (gpointer key, gpointer value, gpointer user) struct wait_data { - HANDLE handles[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS]; + MonoThreadHandle *handles[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS]; MonoInternalThread *threads[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS]; guint32 num; }; @@ -2917,15 +2932,16 @@ struct wait_data static void wait_for_tids (struct wait_data *wait, guint32 timeout) { - guint32 i, ret; + guint32 i; + MonoThreadInfoWaitRet ret; THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num)); MONO_ENTER_GC_SAFE; - ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE); + ret = mono_thread_info_wait_multiple_handle(wait->handles, wait->num, NULL, TRUE, timeout, TRUE); MONO_EXIT_GC_SAFE; - if(ret==WAIT_FAILED) { + if(ret==MONO_THREAD_INFO_WAIT_RET_FAILED) { /* See the comment in build_wait_tids() */ THREAD_DEBUG (g_message ("%s: Wait failed", __func__)); return; @@ -2934,7 +2950,7 @@ wait_for_tids (struct wait_data *wait, guint32 timeout) for(i=0; inum; i++) mono_threads_close_thread_handle (wait->handles [i]); - if (ret == WAIT_TIMEOUT) + if (ret == MONO_THREAD_INFO_WAIT_RET_TIMEOUT) return; for(i=0; inum; i++) { @@ -2951,24 +2967,19 @@ wait_for_tids (struct wait_data *wait, guint32 timeout) static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout) { - guint32 i, ret, count; + guint32 i; + MonoThreadInfoWaitRet ret; THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num)); - /* Add the thread state change event, so it wakes up if a thread changes - * to background mode. - */ - count = wait->num; - if (count < MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) { - wait->handles [count] = background_change_event; - count++; - } + /* Add the thread state change event, so it wakes + * up if a thread changes to background mode. */ MONO_ENTER_GC_SAFE; - ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE); + ret = mono_thread_info_wait_multiple_handle (wait->handles, wait->num, &background_change_event, FALSE, timeout, TRUE); MONO_EXIT_GC_SAFE; - if(ret==WAIT_FAILED) { + if(ret==MONO_THREAD_INFO_WAIT_RET_FAILED) { /* See the comment in build_wait_tids() */ THREAD_DEBUG (g_message ("%s: Wait failed", __func__)); return; @@ -2977,7 +2988,7 @@ static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeo for(i=0; inum; i++) mono_threads_close_thread_handle (wait->handles [i]); - if (ret == WAIT_TIMEOUT) + if (ret == MONO_THREAD_INFO_WAIT_RET_TIMEOUT) return; if (ret < wait->num) { @@ -2996,8 +3007,7 @@ static void build_wait_tids (gpointer key, gpointer value, gpointer user) { struct wait_data *wait=(struct wait_data *)user; - if(wait->numnumhandle, thread_get_tid (thread)); - if (handle == NULL) { - THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid)); - return; - } - THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread)); if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) { - wait->handles[wait->num]=handle; + wait->handles[wait->num]=mono_threads_open_thread_handle (thread->handle); wait->threads[wait->num]=thread; wait->num++; @@ -3058,7 +3062,6 @@ remove_and_abort_threads (gpointer key, gpointer value, gpointer user) struct wait_data *wait=(struct wait_data *)user; MonoNativeThreadId self = mono_native_thread_id_get (); MonoInternalThread *thread = (MonoInternalThread *)value; - HANDLE handle; if (wait->num >= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) return FALSE; @@ -3068,11 +3071,7 @@ remove_and_abort_threads (gpointer key, gpointer value, gpointer user) && (thread->state & ThreadState_Background) != 0 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0 ) { - handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread)); - if (handle == NULL) - return FALSE; - - wait->handles[wait->num] = handle; + wait->handles[wait->num] = mono_threads_open_thread_handle (thread->handle); wait->threads[wait->num] = thread; wait->num++; @@ -3120,7 +3119,7 @@ mono_threads_set_shutting_down (void) mono_thread_detach_internal (current_thread); /* Wake up other threads potentially waiting for us */ - mono_thread_info_exit (); + mono_thread_info_exit (0); } else { shutting_down = TRUE; @@ -3128,7 +3127,7 @@ mono_threads_set_shutting_down (void) * interrupt the main thread if it is waiting for all * the other threads. */ - mono_w32event_set (background_change_event); + mono_os_event_set (&background_change_event); mono_threads_unlock (); } @@ -3161,7 +3160,7 @@ void mono_thread_manage (void) THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads)); mono_g_hash_table_foreach (threads, print_tids, NULL)); - mono_w32event_reset (background_change_event); + mono_os_event_reset (&background_change_event); wait->num=0; /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/ memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P); @@ -3215,7 +3214,6 @@ collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data) { MonoInternalThread *thread = (MonoInternalThread*)value; struct wait_data *wait = (struct wait_data*)user_data; - HANDLE handle; /* * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS @@ -3227,11 +3225,7 @@ collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data) return; if (wait->numhandle, thread_get_tid (thread)); - if (handle == NULL) - return; - - wait->handles [wait->num] = handle; + wait->handles [wait->num] = mono_threads_open_thread_handle (thread->handle); wait->threads [wait->num] = thread; wait->num++; } @@ -3317,6 +3311,8 @@ void mono_thread_suspend_all_other_threads (void) thread->state &= ~ThreadState_AbortRequested; thread->state |= ThreadState_SuspendRequested; + if (mono_threads_is_coop_enabled ()) + mono_os_event_reset (thread->suspended); /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */ async_suspend_internal (thread, TRUE); @@ -3755,10 +3751,7 @@ collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data) /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */ if(data->wait.numhandle, thread_get_tid (thread)); - if (handle == NULL) - return; - data->wait.handles [data->wait.num] = handle; + data->wait.handles [data->wait.num] = mono_threads_open_thread_handle (thread->handle); data->wait.threads [data->wait.num] = thread; data->wait.num++; } else { @@ -4417,7 +4410,7 @@ mono_thread_request_interruption (gboolean running_managed) or similar */ /* Our implementation of this function ignores the func argument */ #ifdef HOST_WIN32 - QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL); + QueueUserAPC ((PAPCFUNC)dummy_apc, thread->native_handle, (ULONG_PTR)NULL); #else mono_thread_info_self_interrupt (); #endif @@ -4644,11 +4637,24 @@ mono_runtime_has_tls_get (void) static void self_interrupt_thread (void *_unused) { - MonoThreadInfo *info = mono_thread_info_current (); - MonoException *exc = mono_thread_execute_interruption (); - if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/ - mono_raise_exception_with_context (exc, &info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx); /* FIXME using thread_saved_state [ASYNC_SUSPEND_STATE_INDEX] can race with another suspend coming in. */ - g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/ + MonoException *exc; + MonoThreadInfo *info; + + exc = mono_thread_execute_interruption (); + if (!exc) { + if (mono_threads_is_coop_enabled ()) { + /* We can return from an async call in coop, as + * it's simply called when exiting the safepoint */ + return; + } + + g_error ("%s: we can't resume from an async call", __func__); + } + + info = mono_thread_info_current (); + + /* We must use _with_context since we didn't trampoline into the runtime */ + mono_raise_exception_with_context (exc, &info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx); /* FIXME using thread_saved_state [ASYNC_SUSPEND_STATE_INDEX] can race with another suspend coming in. */ } static gboolean @@ -4799,9 +4805,14 @@ async_suspend_critical (MonoThreadInfo *info, gpointer ud) running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx)); if (running_managed && !protected_wrapper) { - thread->state &= ~ThreadState_SuspendRequested; - thread->state |= ThreadState_Suspended; - return KeepSuspended; + if (mono_threads_is_coop_enabled ()) { + mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL); + return MonoResumeThread; + } else { + thread->state &= ~ThreadState_SuspendRequested; + thread->state |= ThreadState_Suspended; + return KeepSuspended; + } } else { if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0) InterlockedIncrement (&thread_interruption_requested); @@ -4820,6 +4831,8 @@ async_suspend_internal (MonoInternalThread *thread, gboolean interrupt) g_assert (thread != mono_thread_internal_current ()); + // MOSTLY_ASYNC_SAFE_PRINTF ("ASYNC SUSPEND thread %p\n", thread_get_tid (thread)); + data.thread = thread; data.interrupt = interrupt; data.interrupt_token = NULL; @@ -4839,13 +4852,29 @@ self_suspend_internal (void) thread = mono_thread_internal_current (); - mono_thread_info_begin_self_suspend (); + // MOSTLY_ASYNC_SAFE_PRINTF ("SELF SUSPEND thread %p\n", thread_get_tid (thread)); + + if (!mono_threads_is_coop_enabled ()) + mono_thread_info_begin_self_suspend (); + thread->state &= ~ThreadState_SuspendRequested; thread->state |= ThreadState_Suspended; UNLOCK_THREAD (thread); - mono_thread_info_end_self_suspend (); + if (!mono_threads_is_coop_enabled ()) + mono_thread_info_end_self_suspend (); + else { + MonoOSEvent *event; + MonoOSEventWaitRet res; + + event = thread->suspended; + + MONO_ENTER_GC_SAFE; + res = mono_os_event_wait_one (event, MONO_INFINITE_WAIT); + g_assert (res == MONO_OS_EVENT_WAIT_RET_SUCCESS_0); + MONO_EXIT_GC_SAFE; + } } /* diff --git a/mono/metadata/verify.c b/mono/metadata/verify.c index 7be7267baa5..baed2947614 100644 --- a/mono/metadata/verify.c +++ b/mono/metadata/verify.c @@ -529,7 +529,7 @@ mono_type_is_valid_type_in_context_full (MonoType *type, MonoGenericContext *con if (klass->byval_arg.type != type->type) return mono_type_is_valid_type_in_context_full (&klass->byval_arg, context, check_gtd); - if (check_gtd && klass->generic_container) + if (check_gtd && mono_class_is_gtd (klass)) return FALSE; break; } @@ -597,11 +597,11 @@ is_valid_generic_instantiation (MonoGenericContainer *gc, MonoGenericContext *co * The type A has a parent B, that is inflated into the GTD B<>. * Since A is open, thus not instantiatable, this is valid. */ - if (paramClass->generic_container && param_type->type != MONO_TYPE_GENERICINST && !ginst->is_open) + if (mono_class_is_gtd (paramClass) && param_type->type != MONO_TYPE_GENERICINST && !ginst->is_open) return FALSE; /*it's not safe to call mono_class_init from here*/ - if (paramClass->generic_class && !paramClass->inited) { + if (mono_class_is_ginst (paramClass) && !paramClass->inited) { if (!mono_class_is_valid_generic_instantiation (NULL, paramClass)) return FALSE; } @@ -754,9 +754,9 @@ verifier_get_generic_param_from_type (VerifyContext *ctx, MonoType *type) if (type->type == MONO_TYPE_VAR) { MonoClass *gtd = method->klass; - if (gtd->generic_class) - gtd = gtd->generic_class->container_class; - gc = gtd->generic_container; + if (mono_class_is_ginst (gtd)) + gtd = mono_class_get_generic_class (gtd)->container_class; + gc = mono_class_try_get_generic_container (gtd); } else { //MVAR MonoMethod *gmd = method; if (method->is_inflated) @@ -831,9 +831,9 @@ mono_method_repect_method_constraints (VerifyContext *ctx, MonoMethod *method) static gboolean mono_class_repect_method_constraints (VerifyContext *ctx, MonoClass *klass) { - MonoGenericClass *gklass = klass->generic_class; + MonoGenericClass *gklass = mono_class_get_generic_class (klass); MonoGenericInst *ginst = gklass->context.class_inst; - MonoGenericContainer *gc = gklass->container_class->generic_container; + MonoGenericContainer *gc = mono_class_get_generic_container (gklass->container_class); return !gc || generic_arguments_respect_constraints (ctx, gc, &gklass->context, ginst); } @@ -854,9 +854,9 @@ mono_method_is_valid_generic_instantiation (VerifyContext *ctx, MonoMethod *meth static gboolean mono_class_is_valid_generic_instantiation (VerifyContext *ctx, MonoClass *klass) { - MonoGenericClass *gklass = klass->generic_class; + MonoGenericClass *gklass = mono_class_get_generic_class (klass); MonoGenericInst *ginst = gklass->context.class_inst; - MonoGenericContainer *gc = gklass->container_class->generic_container; + MonoGenericContainer *gc = mono_class_get_generic_container (gklass->container_class); if (ctx && !is_valid_generic_instantiation_in_context (ctx, ginst, TRUE)) return FALSE; return is_valid_generic_instantiation (gc, &gklass->context, ginst); @@ -887,19 +887,19 @@ mono_type_is_valid_in_context (VerifyContext *ctx, MonoType *type) klass = mono_class_from_mono_type (type); mono_class_init (klass); if (mono_class_has_failure (klass)) { - if (klass->generic_class && !mono_class_is_valid_generic_instantiation (NULL, klass)) + if (mono_class_is_ginst (klass) && !mono_class_is_valid_generic_instantiation (NULL, klass)) ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic instantiation of type %s.%s at 0x%04x", klass->name_space, klass->name, ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD); else ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Could not load type %s.%s at 0x%04x", klass->name_space, klass->name, ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD); return FALSE; } - if (klass->generic_class && mono_class_has_failure (klass->generic_class->container_class)) { + if (mono_class_is_ginst (klass) && mono_class_has_failure (mono_class_get_generic_class (klass)->container_class)) { ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Could not load type %s.%s at 0x%04x", klass->name_space, klass->name, ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD); return FALSE; } - if (!klass->generic_class) + if (!mono_class_is_ginst (klass)) return TRUE; if (!mono_class_is_valid_generic_instantiation (ctx, klass)) { @@ -1678,7 +1678,7 @@ get_boxable_mono_type (VerifyContext* ctx, int token, const char *opcode) if (!(klass = mono_class_from_mono_type (type))) ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not retrieve type token for %s at 0x%04x", opcode, ctx->ip_offset)); - if (klass->generic_container && type->type != MONO_TYPE_GENERICINST) + if (mono_class_is_gtd (klass) && type->type != MONO_TYPE_GENERICINST) CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use the generic type definition in a boxable type position for %s at 0x%04x", opcode, ctx->ip_offset)); check_unverifiable_type (ctx, type); @@ -2188,14 +2188,14 @@ verifier_class_is_assignable_from (MonoClass *target, MonoClass *candidate) if (mono_class_is_assignable_from (target, candidate)) return TRUE; - if (!MONO_CLASS_IS_INTERFACE (target) || !target->generic_class || candidate->rank != 1) + if (!MONO_CLASS_IS_INTERFACE (target) || !mono_class_is_ginst (target) || candidate->rank != 1) return FALSE; - iface_gtd = target->generic_class->container_class; + iface_gtd = mono_class_get_generic_class (target)->container_class; if (iface_gtd != mono_defaults.generic_ilist_class && iface_gtd != get_icollection_class () && iface_gtd != get_ienumerable_class ()) return FALSE; - target = mono_class_from_mono_type (target->generic_class->context.class_inst->type_argv [0]); + target = mono_class_from_mono_type (mono_class_get_generic_class (target)->context.class_inst->type_argv [0]); candidate = candidate->element_class; return TRUE; @@ -2674,7 +2674,7 @@ verify_ldftn_delegate (VerifyContext *ctx, MonoClass *delegate, ILStackDesc *val * the object is a this arg (comes from a ldarg.0), and there is no starg.0. * This rules doesn't apply if the object on stack is a boxed valuetype. */ - if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL) && !(method->klass->flags & TYPE_ATTRIBUTE_SEALED) && !stack_slot_is_boxed_value (value)) { + if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL) && !mono_class_is_sealed (method->klass) && !stack_slot_is_boxed_value (value)) { /*A stdarg 0 must not happen, we fail here only in fail fast mode to avoid double error reports*/ if (IS_FAIL_FAST_MODE (ctx) && ctx->has_this_store) CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid ldftn with virtual function in method with stdarg 0 at 0x%04x", ctx->ip_offset)); @@ -3166,7 +3166,7 @@ do_invoke_method (VerifyContext *ctx, int method_token, gboolean virtual_) if (method->flags & METHOD_ATTRIBUTE_ABSTRACT) CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use call with an abstract method at 0x%04x", ctx->ip_offset)); - if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL) && !(method->klass->flags & TYPE_ATTRIBUTE_SEALED)) { + if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL) && !mono_class_is_sealed (method->klass)) { virt_check_this = TRUE; ctx->code [ctx->ip_offset].flags |= IL_CODE_CALL_NONFINAL_VIRTUAL; } @@ -3811,7 +3811,7 @@ do_newobj (VerifyContext *ctx, int token) return; } - if (method->klass->flags & (TYPE_ATTRIBUTE_ABSTRACT | TYPE_ATTRIBUTE_INTERFACE)) + if (mono_class_get_flags (method->klass) & (TYPE_ATTRIBUTE_ABSTRACT | TYPE_ATTRIBUTE_INTERFACE)) CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Trying to instantiate an abstract or interface type at 0x%04x", ctx->ip_offset)); if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL)) { @@ -4643,7 +4643,7 @@ merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean sta } /* if old class is an interface that new class implements */ - if (old_class->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (old_class)) { if (verifier_class_is_assignable_from (old_class, new_class)) { match_class = old_class; goto match_found; @@ -4656,7 +4656,7 @@ merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean sta } } - if (new_class->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (new_class)) { if (verifier_class_is_assignable_from (new_class, old_class)) { match_class = new_class; goto match_found; @@ -4848,7 +4848,7 @@ mono_method_verify (MonoMethod *method, int level) finish_collect_stats (); return ctx.list; } - if (!method->is_generic && !method->klass->is_generic && ctx.signature->has_type_parameters) { + if (!method->is_generic && !mono_class_is_gtd (method->klass) && ctx.signature->has_type_parameters) { ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Method and signature don't match in terms of genericity")); finish_collect_stats (); return ctx.list; @@ -4895,11 +4895,11 @@ mono_method_verify (MonoMethod *method, int level) if (ctx.signature->is_inflated) ctx.generic_context = generic_context = mono_method_get_context (method); - if (!generic_context && (method->klass->generic_container || method->is_generic)) { + if (!generic_context && (mono_class_is_gtd (method->klass) || method->is_generic)) { if (method->is_generic) ctx.generic_context = generic_context = &(mono_method_get_generic_container (method)->context); else - ctx.generic_context = generic_context = &method->klass->generic_container->context; + ctx.generic_context = generic_context = &mono_class_get_generic_container (method->klass)->context; } for (i = 0; i < ctx.num_locals; ++i) { @@ -6102,7 +6102,7 @@ verify_class_for_overlapping_reference_fields (MonoClass *klass) MonoClassField *field; gboolean is_fulltrust = mono_verifier_is_class_full_trust (klass); /*We can't skip types with !has_references since this is calculated after we have run.*/ - if (!((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT)) + if (!mono_class_is_explicit_layout (klass)) return TRUE; @@ -6156,8 +6156,8 @@ verify_class_fields (MonoClass *klass) MonoClassField *field; MonoGenericContext *context = mono_class_get_context (klass); GHashTable *unique_fields = g_hash_table_new_full (&field_hash, &field_equals, NULL, NULL); - if (klass->generic_container) - context = &klass->generic_container->context; + if (mono_class_is_gtd (klass)) + context = &mono_class_get_generic_container (klass)->context; while ((field = mono_class_get_fields (klass, &iter)) != NULL) { if (!mono_type_is_valid_type_in_context (field->type, context)) { @@ -6180,7 +6180,7 @@ verify_interfaces (MonoClass *klass) int i; for (i = 0; i < klass->interface_count; ++i) { MonoClass *iface = klass->interfaces [i]; - if (!(iface->flags & TYPE_ATTRIBUTE_INTERFACE)) + if (!mono_class_get_flags (iface)) return FALSE; } return TRUE; @@ -6259,7 +6259,7 @@ static gboolean verify_generic_parameters (MonoClass *klass) { int i; - MonoGenericContainer *gc = klass->generic_container; + MonoGenericContainer *gc = mono_class_get_generic_container (klass); MonoBitSet *used_args = mono_bitset_new (gc->type_argc, 0); for (i = 0; i < gc->type_argc; ++i) { @@ -6284,7 +6284,7 @@ verify_generic_parameters (MonoClass *klass) if (mono_type_is_generic_argument (constraint_type) && !recursive_mark_constraint_args (used_args, gc, constraint_type)) goto fail; - if (ctr->generic_class && !mono_class_is_valid_generic_instantiation (NULL, ctr)) + if (mono_class_is_ginst (ctr) && !mono_class_is_valid_generic_instantiation (NULL, ctr)) goto fail; } } @@ -6317,25 +6317,25 @@ mono_verifier_verify_class (MonoClass *klass) if (klass->parent) { if (MONO_CLASS_IS_INTERFACE (klass->parent)) return FALSE; - if (!klass->generic_class && klass->parent->generic_container) + if (!mono_class_is_ginst (klass) && mono_class_is_gtd (klass->parent)) return FALSE; - if (klass->parent->generic_class && !klass->generic_class) { + if (mono_class_is_ginst (klass->parent) && !mono_class_is_ginst (klass)) { MonoGenericContext *context = mono_class_get_context (klass); - if (klass->generic_container) - context = &klass->generic_container->context; + if (mono_class_is_gtd (klass)) + context = &mono_class_get_generic_container (klass)->context; if (!mono_type_is_valid_type_in_context (&klass->parent->byval_arg, context)) return FALSE; } } - if (klass->generic_container && (klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) + if (mono_class_is_gtd (klass) && (mono_class_is_explicit_layout (klass))) return FALSE; - if (klass->generic_container && !verify_generic_parameters (klass)) + if (mono_class_is_gtd (klass) && !verify_generic_parameters (klass)) return FALSE; if (!verify_class_for_overlapping_reference_fields (klass)) return FALSE; - if (klass->generic_class && !mono_class_is_valid_generic_instantiation (NULL, klass)) + if (mono_class_is_ginst (klass) && !mono_class_is_valid_generic_instantiation (NULL, klass)) return FALSE; - if (klass->generic_class == NULL && !verify_class_fields (klass)) + if (!mono_class_is_ginst (klass) && !verify_class_fields (klass)) return FALSE; if (klass->valuetype && !verify_valuetype_layout (klass)) return FALSE; diff --git a/mono/metadata/w32event-unix.c b/mono/metadata/w32event-unix.c index 5644ce7d27b..35b6ce787cc 100644 --- a/mono/metadata/w32event-unix.c +++ b/mono/metadata/w32event-unix.c @@ -12,7 +12,7 @@ #include "w32handle-namespace.h" #include "mono/io-layer/io-layer.h" #include "mono/utils/mono-logger-internals.h" -#include "mono/utils/w32handle.h" +#include "mono/metadata/w32handle.h" typedef struct { gboolean manual; diff --git a/mono/metadata/w32handle-namespace.h b/mono/metadata/w32handle-namespace.h index 5a2547774d4..75797a80d65 100644 --- a/mono/metadata/w32handle-namespace.h +++ b/mono/metadata/w32handle-namespace.h @@ -5,7 +5,7 @@ #include #include -#include "mono/utils/w32handle.h" +#include "mono/metadata/w32handle.h" #define MONO_W32HANDLE_NAMESPACE_MAX_PATH 260 diff --git a/mono/metadata/w32handle.c b/mono/metadata/w32handle.c new file mode 100644 index 00000000000..6e2a7659ab2 --- /dev/null +++ b/mono/metadata/w32handle.c @@ -0,0 +1,1546 @@ +/* + * w32handle.c: Generic and internal operations on handles + * + * Author: + * Dick Porter (dick@ximian.com) + * Ludovic Henry (luhenry@microsoft.com) + * + * (C) 2002-2011 Novell, Inc. + * Copyright 2011 Xamarin Inc + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +#include + +#if !defined(HOST_WIN32) + +#include +#include +#include +#include +#ifdef HAVE_SIGNAL_H +#include +#endif +#include +#include +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_SYS_UN_H +# include +#endif +#ifdef HAVE_SYS_MMAN_H +# include +#endif +#ifdef HAVE_DIRENT_H +# include +#endif +#include +#ifdef HAVE_SYS_RESOURCE_H +# include +#endif + +#include "w32handle.h" + +#include "utils/atomic.h" +#include "utils/mono-logger-internals.h" +#include "utils/mono-os-mutex.h" +#include "utils/mono-proclib.h" +#include "utils/mono-threads.h" +#include "utils/mono-time.h" + +#undef DEBUG_REFS + +#define SLOT_MAX (1024 * 16) + +/* must be a power of 2 */ +#define HANDLE_PER_SLOT (256) + +#define INFINITE 0xFFFFFFFF + +typedef struct { + MonoW32HandleType type; + guint ref; + gboolean signalled; + mono_mutex_t signal_mutex; + mono_cond_t signal_cond; + gpointer specific; +} MonoW32HandleBase; + +static MonoW32HandleCapability handle_caps [MONO_W32HANDLE_COUNT]; +static MonoW32HandleOps *handle_ops [MONO_W32HANDLE_COUNT]; + +/* + * We can hold SLOT_MAX * HANDLE_PER_SLOT handles. + * If 4M handles are not enough... Oh, well... we will crash. + */ +#define SLOT_INDEX(x) (x / HANDLE_PER_SLOT) +#define SLOT_OFFSET(x) (x % HANDLE_PER_SLOT) + +static MonoW32HandleBase *private_handles [SLOT_MAX]; +static guint32 private_handles_count = 0; +static guint32 private_handles_slots_count = 0; + +guint32 mono_w32handle_fd_reserve; + +/* + * This is an internal handle which is used for handling waiting for multiple handles. + * Threads which wait for multiple handles wait on this one handle, and when a handle + * is signalled, this handle is signalled too. + */ +static mono_mutex_t global_signal_mutex; +static mono_cond_t global_signal_cond; + +static mono_mutex_t scan_mutex; + +static gboolean shutting_down = FALSE; + +static gboolean +type_is_fd (MonoW32HandleType type) +{ + switch (type) { + case MONO_W32HANDLE_FILE: + case MONO_W32HANDLE_CONSOLE: + case MONO_W32HANDLE_SOCKET: + case MONO_W32HANDLE_PIPE: + return TRUE; + default: + return FALSE; + } +} + +static gboolean +mono_w32handle_lookup_data (gpointer handle, MonoW32HandleBase **handle_data) +{ + gsize index, offset; + + g_assert (handle_data); + + index = SLOT_INDEX ((gsize) handle); + if (index >= SLOT_MAX) + return FALSE; + if (!private_handles [index]) + return FALSE; + + offset = SLOT_OFFSET ((gsize) handle); + if (private_handles [index][offset].type == MONO_W32HANDLE_UNUSED) + return FALSE; + + *handle_data = &private_handles [index][offset]; + return TRUE; +} + +MonoW32HandleType +mono_w32handle_get_type (gpointer handle) +{ + MonoW32HandleBase *handle_data; + + if (!mono_w32handle_lookup_data (handle, &handle_data)) + return MONO_W32HANDLE_UNUSED; /* An impossible type */ + + return handle_data->type; +} + +void +mono_w32handle_set_signal_state (gpointer handle, gboolean state, gboolean broadcast) +{ + MonoW32HandleBase *handle_data; + + if (!mono_w32handle_lookup_data (handle, &handle_data)) { + return; + } + +#ifdef DEBUG + g_message ("%s: setting state of %p to %s (broadcast %s)", __func__, + handle, state?"TRUE":"FALSE", broadcast?"TRUE":"FALSE"); +#endif + + if (state == TRUE) { + /* Tell everyone blocking on a single handle */ + + /* The condition the global signal cond is waiting on is the signalling of + * _any_ handle. So lock it before setting the signalled state. + */ + mono_os_mutex_lock (&global_signal_mutex); + + /* This function _must_ be called with + * handle->signal_mutex locked + */ + handle_data->signalled=state; + + if (broadcast == TRUE) { + mono_os_cond_broadcast (&handle_data->signal_cond); + } else { + mono_os_cond_signal (&handle_data->signal_cond); + } + + /* Tell everyone blocking on multiple handles that something + * was signalled + */ + mono_os_cond_broadcast (&global_signal_cond); + + mono_os_mutex_unlock (&global_signal_mutex); + } else { + handle_data->signalled=state; + } +} + +gboolean +mono_w32handle_issignalled (gpointer handle) +{ + MonoW32HandleBase *handle_data; + + if (!mono_w32handle_lookup_data (handle, &handle_data)) { + return(FALSE); + } + + return handle_data->signalled; +} + +static int +mono_w32handle_lock_signal_mutex (void) +{ +#ifdef DEBUG + g_message ("%s: lock global signal mutex", __func__); +#endif + + mono_os_mutex_lock (&global_signal_mutex); + + return 0; +} + +static int +mono_w32handle_unlock_signal_mutex (void) +{ +#ifdef DEBUG + g_message ("%s: unlock global signal mutex", __func__); +#endif + + mono_os_mutex_unlock (&global_signal_mutex); + + return 0; +} + +int +mono_w32handle_lock_handle (gpointer handle) +{ + MonoW32HandleBase *handle_data; + +#ifdef DEBUG + g_message ("%s: locking handle %p", __func__, handle); +#endif + + if (!mono_w32handle_lookup_data (handle, &handle_data)) { + return(0); + } + + mono_w32handle_ref (handle); + + mono_os_mutex_lock (&handle_data->signal_mutex); + + return 0; +} + +int +mono_w32handle_trylock_handle (gpointer handle) +{ + MonoW32HandleBase *handle_data; + int ret; + +#ifdef DEBUG + g_message ("%s: locking handle %p", __func__, handle); +#endif + + if (!mono_w32handle_lookup_data (handle, &handle_data)) { + return(0); + } + + mono_w32handle_ref (handle); + + ret = mono_os_mutex_trylock (&handle_data->signal_mutex); + if (ret != 0) { + mono_w32handle_unref (handle); + } + + return(ret); +} + +int +mono_w32handle_unlock_handle (gpointer handle) +{ + MonoW32HandleBase *handle_data; + +#ifdef DEBUG + g_message ("%s: unlocking handle %p", __func__, handle); +#endif + + if (!mono_w32handle_lookup_data (handle, &handle_data)) { + return(0); + } + + mono_os_mutex_unlock (&handle_data->signal_mutex); + + mono_w32handle_unref (handle); + + return 0; +} + +/* + * wapi_init: + * + * Initialize the io-layer. + */ +void +mono_w32handle_init (void) +{ + static gboolean initialized = FALSE; + + if (initialized) + return; + + g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0])) + == MONO_W32HANDLE_COUNT); + + /* This is needed by the code in mono_w32handle_new_internal */ + mono_w32handle_fd_reserve = (eg_getdtablesize () + (HANDLE_PER_SLOT - 1)) & ~(HANDLE_PER_SLOT - 1); + + do { + /* + * The entries in private_handles reserved for fds are allocated lazily to + * save memory. + */ + + private_handles_count += HANDLE_PER_SLOT; + private_handles_slots_count ++; + } while(mono_w32handle_fd_reserve > private_handles_count); + + mono_os_mutex_init (&scan_mutex); + + mono_os_cond_init (&global_signal_cond); + mono_os_mutex_init (&global_signal_mutex); + + initialized = TRUE; +} + +void +mono_w32handle_cleanup (void) +{ + int i, j, k; + + g_assert (!shutting_down); + shutting_down = TRUE; + + /* Every shared handle we were using ought really to be closed + * by now, but to make sure just blow them all away. The + * exiting finalizer thread in particular races us to the + * program exit and doesn't always win, so it can be left + * cluttering up the shared file. Anything else left over is + * really a bug. + */ + for(i = SLOT_INDEX (0); private_handles[i] != NULL; i++) { + for(j = SLOT_OFFSET (0); j < HANDLE_PER_SLOT; j++) { + MonoW32HandleBase *handle_data = &private_handles[i][j]; + gpointer handle = GINT_TO_POINTER (i*HANDLE_PER_SLOT+j); + + for(k = handle_data->ref; k > 0; k--) { + mono_w32handle_unref (handle); + } + } + } + + for (i = 0; i < SLOT_MAX; ++i) + g_free (private_handles [i]); +} + +static void mono_w32handle_init_handle (MonoW32HandleBase *handle, + MonoW32HandleType type, gpointer handle_specific) +{ + g_assert (handle->ref == 0); + + handle->type = type; + handle->signalled = FALSE; + handle->ref = 1; + + mono_os_cond_init (&handle->signal_cond); + mono_os_mutex_init (&handle->signal_mutex); + + if (handle_specific) + handle->specific = g_memdup (handle_specific, mono_w32handle_ops_typesize (type)); +} + +/* + * mono_w32handle_new_internal: + * @type: Init handle to this type + * + * Search for a free handle and initialize it. Return the handle on + * success and 0 on failure. This is only called from + * mono_w32handle_new, and scan_mutex must be held. + */ +static guint32 mono_w32handle_new_internal (MonoW32HandleType type, + gpointer handle_specific) +{ + guint32 i, k, count; + static guint32 last = 0; + gboolean retry = FALSE; + + /* A linear scan should be fast enough. Start from the last + * allocation, assuming that handles are allocated more often + * than they're freed. Leave the space reserved for file + * descriptors + */ + + if (last < mono_w32handle_fd_reserve) { + last = mono_w32handle_fd_reserve; + } else { + retry = TRUE; + } + +again: + count = last; + for(i = SLOT_INDEX (count); i < private_handles_slots_count; i++) { + if (private_handles [i]) { + for (k = SLOT_OFFSET (count); k < HANDLE_PER_SLOT; k++) { + MonoW32HandleBase *handle = &private_handles [i][k]; + + if(handle->type == MONO_W32HANDLE_UNUSED) { + last = count + 1; + + mono_w32handle_init_handle (handle, type, handle_specific); + return (count); + } + count++; + } + } + } + + if(retry && last > mono_w32handle_fd_reserve) { + /* Try again from the beginning */ + last = mono_w32handle_fd_reserve; + goto again; + } + + /* Will need to expand the array. The caller will sort it out */ + + return(0); +} + +gpointer +mono_w32handle_new (MonoW32HandleType type, gpointer handle_specific) +{ + guint32 handle_idx = 0; + gpointer handle; + + g_assert (!shutting_down); + + g_assert(!type_is_fd(type)); + + mono_os_mutex_lock (&scan_mutex); + + while ((handle_idx = mono_w32handle_new_internal (type, handle_specific)) == 0) { + /* Try and expand the array, and have another go */ + int idx = SLOT_INDEX (private_handles_count); + if (idx >= SLOT_MAX) { + break; + } + + private_handles [idx] = g_new0 (MonoW32HandleBase, HANDLE_PER_SLOT); + + private_handles_count += HANDLE_PER_SLOT; + private_handles_slots_count ++; + } + + mono_os_mutex_unlock (&scan_mutex); + + if (handle_idx == 0) { + /* We ran out of slots */ + handle = INVALID_HANDLE_VALUE; + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to create %s handle", __func__, mono_w32handle_ops_typename (type)); + goto done; + } + + /* Make sure we left the space for fd mappings */ + g_assert (handle_idx >= mono_w32handle_fd_reserve); + + handle = GUINT_TO_POINTER (handle_idx); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: create %s handle %p", __func__, mono_w32handle_ops_typename (type), handle); + +done: + return(handle); +} + +gpointer mono_w32handle_new_fd (MonoW32HandleType type, int fd, + gpointer handle_specific) +{ + MonoW32HandleBase *handle_data; + int fd_index, fd_offset; + + g_assert (!shutting_down); + + g_assert(type_is_fd(type)); + + if (fd >= mono_w32handle_fd_reserve) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to create %s handle, fd is too big", __func__, mono_w32handle_ops_typename (type)); + + return(GUINT_TO_POINTER (INVALID_HANDLE_VALUE)); + } + + fd_index = SLOT_INDEX (fd); + fd_offset = SLOT_OFFSET (fd); + + /* Initialize the array entries on demand */ + if (!private_handles [fd_index]) { + mono_os_mutex_lock (&scan_mutex); + + if (!private_handles [fd_index]) + private_handles [fd_index] = g_new0 (MonoW32HandleBase, HANDLE_PER_SLOT); + + mono_os_mutex_unlock (&scan_mutex); + } + + handle_data = &private_handles [fd_index][fd_offset]; + + if (handle_data->type != MONO_W32HANDLE_UNUSED) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to create %s handle, fd is already in use", __func__, mono_w32handle_ops_typename (type)); + /* FIXME: clean up this handle? We can't do anything + * with the fd, cos thats the new one + */ + return(GUINT_TO_POINTER (INVALID_HANDLE_VALUE)); + } + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: create %s handle %p", __func__, mono_w32handle_ops_typename (type), GUINT_TO_POINTER(fd)); + + mono_w32handle_init_handle (handle_data, type, handle_specific); + + return(GUINT_TO_POINTER(fd)); +} + +gboolean +mono_w32handle_lookup (gpointer handle, MonoW32HandleType type, + gpointer *handle_specific) +{ + MonoW32HandleBase *handle_data; + + g_assert (handle_specific); + + if (!mono_w32handle_lookup_data (handle, &handle_data)) { + return(FALSE); + } + + if (handle_data->type != type) { + return(FALSE); + } + + *handle_specific = handle_data->specific; + + return(TRUE); +} + +static gboolean +mono_w32handle_ref_core (gpointer handle, MonoW32HandleBase *handle_data); + +static gboolean +mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data, guint minimum); + +void +mono_w32handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpointer user_data), gpointer user_data) +{ + guint32 i, k; + + mono_os_mutex_lock (&scan_mutex); + + for (i = SLOT_INDEX (0); i < private_handles_slots_count; i++) { + if (!private_handles [i]) + continue; + for (k = SLOT_OFFSET (0); k < HANDLE_PER_SLOT; k++) { + MonoW32HandleBase *handle_data = NULL; + gpointer handle; + gboolean destroy, finished; + + handle_data = &private_handles [i][k]; + if (handle_data->type == MONO_W32HANDLE_UNUSED) + continue; + + handle = GUINT_TO_POINTER (i * HANDLE_PER_SLOT + k); + + if (!mono_w32handle_ref_core (handle, handle_data)) { + /* we are racing with mono_w32handle_unref: + * the handle ref has been decremented, but it + * hasn't yet been destroyed. */ + continue; + } + + finished = on_each (handle, handle_data->specific, user_data); + + /* we do not want to have to destroy the handle here, + * as it would means the ref/unref are unbalanced */ + destroy = mono_w32handle_unref_core (handle, handle_data, 2); + g_assert (!destroy); + + if (finished) + goto done; + } + } + +done: + mono_os_mutex_unlock (&scan_mutex); +} + +typedef struct { + MonoW32HandleType type; + gboolean (*search_user_callback)(gpointer handle, gpointer data); + gpointer search_user_data; + gpointer handle; + gpointer handle_specific; +} SearchData; + +static gboolean +search_callback (gpointer handle, gpointer handle_specific, gpointer user_data) +{ + SearchData *search_data = (SearchData*) user_data; + + if (search_data->type != mono_w32handle_get_type (handle)) + return FALSE; + + if (!search_data->search_user_callback (handle, search_data->search_user_data)) + return FALSE; + + mono_w32handle_ref (handle); + search_data->handle = handle; + search_data->handle_specific = handle_specific; + return TRUE; +} + +/* This might list some shared handles twice if they are already + * opened by this process, and the check function returns FALSE the + * first time. Shared handles that are created during the search are + * unreffed if the check function returns FALSE, so callers must not + * rely on the handle persisting (unless the check function returns + * TRUE) + * The caller owns the returned handle. + */ +gpointer mono_w32handle_search (MonoW32HandleType type, + gboolean (*check)(gpointer test, gpointer user), + gpointer user_data, + gpointer *handle_specific, + gboolean search_shared) +{ + SearchData search_data; + + memset (&search_data, 0, sizeof (search_data)); + search_data.type = type; + search_data.search_user_callback = check; + search_data.search_user_data = user_data; + mono_w32handle_foreach (search_callback, &search_data); + if (handle_specific) + *handle_specific = search_data.handle_specific; + return search_data.handle; +} + +static gboolean +mono_w32handle_ref_core (gpointer handle, MonoW32HandleBase *handle_data) +{ + guint old, new; + + do { + old = handle_data->ref; + if (old == 0) + return FALSE; + + new = old + 1; + } while (InterlockedCompareExchange ((gint32*) &handle_data->ref, new, old) != old); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: ref %s handle %p, ref: %d -> %d", + __func__, mono_w32handle_ops_typename (handle_data->type), handle, old, new); + + return TRUE; +} + +static gboolean +mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data, guint minimum) +{ + MonoW32HandleType type; + guint old, new; + + type = handle_data->type; + + do { + old = handle_data->ref; + if (!(old >= minimum)) + g_error ("%s: handle %p has ref %d, it should be >= %d", __func__, handle, old, minimum); + + new = old - 1; + } while (InterlockedCompareExchange ((gint32*) &handle_data->ref, new, old) != old); + + /* handle_data might contain invalid data from now on, if + * another thread is unref'ing this handle at the same time */ + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: unref %s handle %p, ref: %d -> %d destroy: %s", + __func__, mono_w32handle_ops_typename (type), handle, old, new, new == 0 ? "true" : "false"); + + return new == 0; +} + +void mono_w32handle_ref (gpointer handle) +{ + MonoW32HandleBase *handle_data; + + if (!mono_w32handle_lookup_data (handle, &handle_data)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to ref handle %p, unknown handle", __func__, handle); + return; + } + + if (!mono_w32handle_ref_core (handle, handle_data)) + g_error ("%s: failed to ref handle %p", __func__, handle); +} + +static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer, gpointer); + +/* The handle must not be locked on entry to this function */ +void +mono_w32handle_unref (gpointer handle) +{ + MonoW32HandleBase *handle_data; + gboolean destroy; + + if (!mono_w32handle_lookup_data (handle, &handle_data)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to unref handle %p, unknown handle", + __func__, handle); + return; + } + + destroy = mono_w32handle_unref_core (handle, handle_data, 1); + + if (destroy) { + /* Need to copy the handle info, reset the slot in the + * array, and _only then_ call the close function to + * avoid race conditions (eg file descriptors being + * closed, and another file being opened getting the + * same fd racing the memset()) + */ + MonoW32HandleType type; + gpointer handle_specific; + void (*close_func)(gpointer, gpointer); + + type = handle_data->type; + handle_specific = handle_data->specific; + + mono_os_mutex_lock (&scan_mutex); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: destroy %s handle %p", __func__, mono_w32handle_ops_typename (type), handle); + + mono_os_mutex_destroy (&handle_data->signal_mutex); + mono_os_cond_destroy (&handle_data->signal_cond); + + memset (handle_data, 0, sizeof (MonoW32HandleBase)); + + mono_os_mutex_unlock (&scan_mutex); + + close_func = _wapi_handle_ops_get_close_func (type); + if (close_func != NULL) { + close_func (handle, handle_specific); + } + + g_free (handle_specific); + } +} + +void +mono_w32handle_register_ops (MonoW32HandleType type, MonoW32HandleOps *ops) +{ + handle_ops [type] = ops; +} + +void mono_w32handle_register_capabilities (MonoW32HandleType type, + MonoW32HandleCapability caps) +{ + handle_caps[type] = caps; +} + +gboolean mono_w32handle_test_capabilities (gpointer handle, + MonoW32HandleCapability caps) +{ + MonoW32HandleBase *handle_data; + MonoW32HandleType type; + + if (!mono_w32handle_lookup_data (handle, &handle_data)) { + return(FALSE); + } + + type = handle_data->type; + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: testing 0x%x against 0x%x (%d)", __func__, + handle_caps[type], caps, handle_caps[type] & caps); + + return((handle_caps[type] & caps) != 0); +} + +static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer, gpointer) +{ + if (handle_ops[type] != NULL && + handle_ops[type]->close != NULL) { + return (handle_ops[type]->close); + } + + return (NULL); +} + +void mono_w32handle_ops_close (gpointer handle, gpointer data) +{ + MonoW32HandleBase *handle_data; + MonoW32HandleType type; + + if (!mono_w32handle_lookup_data (handle, &handle_data)) { + return; + } + + type = handle_data->type; + + if (handle_ops[type] != NULL && + handle_ops[type]->close != NULL) { + handle_ops[type]->close (handle, data); + } +} + +void mono_w32handle_ops_details (MonoW32HandleType type, gpointer data) +{ + if (handle_ops[type] != NULL && + handle_ops[type]->details != NULL) { + handle_ops[type]->details (data); + } +} + +const gchar* mono_w32handle_ops_typename (MonoW32HandleType type) +{ + g_assert (handle_ops [type]); + g_assert (handle_ops [type]->typename); + return handle_ops [type]->typename (); +} + +gsize mono_w32handle_ops_typesize (MonoW32HandleType type) +{ + g_assert (handle_ops [type]); + g_assert (handle_ops [type]->typesize); + return handle_ops [type]->typesize (); +} + +void mono_w32handle_ops_signal (gpointer handle) +{ + MonoW32HandleBase *handle_data; + MonoW32HandleType type; + + if (!mono_w32handle_lookup_data (handle, &handle_data)) { + return; + } + + type = handle_data->type; + + if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) { + handle_ops[type]->signal (handle); + } +} + +gboolean mono_w32handle_ops_own (gpointer handle, guint32 *statuscode) +{ + MonoW32HandleBase *handle_data; + MonoW32HandleType type; + + if (!mono_w32handle_lookup_data (handle, &handle_data)) { + return(FALSE); + } + + type = handle_data->type; + + if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) { + return(handle_ops[type]->own_handle (handle, statuscode)); + } else { + return(FALSE); + } +} + +gboolean mono_w32handle_ops_isowned (gpointer handle) +{ + MonoW32HandleBase *handle_data; + MonoW32HandleType type; + + if (!mono_w32handle_lookup_data (handle, &handle_data)) { + return(FALSE); + } + + type = handle_data->type; + + if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) { + return(handle_ops[type]->is_owned (handle)); + } else { + return(FALSE); + } +} + +guint32 mono_w32handle_ops_specialwait (gpointer handle, guint32 timeout, gboolean *alerted) +{ + MonoW32HandleBase *handle_data; + MonoW32HandleType type; + + if (!mono_w32handle_lookup_data (handle, &handle_data)) { + return(WAIT_FAILED); + } + + type = handle_data->type; + + if (handle_ops[type] != NULL && + handle_ops[type]->special_wait != NULL) { + return(handle_ops[type]->special_wait (handle, timeout, alerted)); + } else { + return(WAIT_FAILED); + } +} + +void mono_w32handle_ops_prewait (gpointer handle) +{ + MonoW32HandleBase *handle_data; + MonoW32HandleType type; + + if (!mono_w32handle_lookup_data (handle, &handle_data)) { + return; + } + + type = handle_data->type; + + if (handle_ops[type] != NULL && + handle_ops[type]->prewait != NULL) { + handle_ops[type]->prewait (handle); + } +} + +static void +spin (guint32 ms) +{ + struct timespec sleepytime; + + g_assert (ms < 1000); + + sleepytime.tv_sec = 0; + sleepytime.tv_nsec = ms * 1000000; + nanosleep (&sleepytime, NULL); +} + +static void +mono_w32handle_lock_handles (gpointer *handles, gsize numhandles) +{ + guint32 i, iter=0; + int thr_ret; + + /* Lock all the handles, with backoff */ +again: + for(i=0; isignal_cond; + mutex = &handle_data->signal_mutex; + + mono_os_mutex_lock (mutex); + mono_os_cond_broadcast (cond); + mono_os_mutex_unlock (mutex); + + mono_w32handle_unref (handle); +} + +static int +mono_w32handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboolean poll, gboolean *alerted) +{ + MonoW32HandleBase *handle_data; + int res; + + if (!mono_w32handle_lookup_data (handle, &handle_data)) + g_error ("cannot wait on unknown handle %p", handle); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: waiting for %p (type %s)", __func__, handle, + mono_w32handle_ops_typename (mono_w32handle_get_type (handle))); + + if (alerted) + *alerted = FALSE; + + if (alerted) { + mono_thread_info_install_interrupt (signal_handle_and_unref, handle, alerted); + if (*alerted) + return 0; + mono_w32handle_ref (handle); + } + + res = mono_w32handle_timedwait_signal_naked (&handle_data->signal_cond, &handle_data->signal_mutex, timeout, poll, alerted); + + if (alerted) { + mono_thread_info_uninstall_interrupt (alerted); + if (!*alerted) { + /* if it is alerted, then the handle is unref in the interrupt callback */ + mono_w32handle_unref (handle); + } + } + + return res; +} + +static gboolean +dump_callback (gpointer handle, gpointer handle_specific, gpointer user_data) +{ + MonoW32HandleBase *handle_data; + + if (!mono_w32handle_lookup_data (handle, &handle_data)) + g_error ("cannot dump unknown handle %p", handle); + + g_print ("%p [%7s] signalled: %5s ref: %3d ", + handle, mono_w32handle_ops_typename (handle_data->type), handle_data->signalled ? "true" : "false", handle_data->ref); + mono_w32handle_ops_details (handle_data->type, handle_data->specific); + g_print ("\n"); + + return FALSE; +} + +void mono_w32handle_dump (void) +{ + mono_w32handle_foreach (dump_callback, NULL); +} + +static gboolean +own_if_signalled (gpointer handle, guint32 *statuscode) +{ + if (!mono_w32handle_issignalled (handle)) + return FALSE; + + *statuscode = WAIT_OBJECT_0; + mono_w32handle_ops_own (handle, statuscode); + return TRUE; +} + +static gboolean +own_if_owned( gpointer handle, guint32 *statuscode) +{ + if (!mono_w32handle_ops_isowned (handle)) + return FALSE; + + *statuscode = WAIT_OBJECT_0; + mono_w32handle_ops_own (handle, statuscode); + return TRUE; +} + +MonoW32HandleWaitRet +mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable) +{ + MonoW32HandleWaitRet ret; + gboolean alerted; + gint64 start; + gint thr_ret; + guint32 statuscode = 0; + + alerted = FALSE; + + if (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_SPECIAL_WAIT)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p has special wait", + __func__, handle); + + switch (mono_w32handle_ops_specialwait (handle, timeout, alertable ? &alerted : NULL)) { + case WAIT_OBJECT_0: + ret = MONO_W32HANDLE_WAIT_RET_SUCCESS_0; + break; + case WAIT_ABANDONED_0: + ret = MONO_W32HANDLE_WAIT_RET_ABANDONED_0; + break; + case WAIT_IO_COMPLETION: + ret = MONO_W32HANDLE_WAIT_RET_ALERTED; + break; + case WAIT_TIMEOUT: + ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; + break; + case WAIT_FAILED: + ret = MONO_W32HANDLE_WAIT_RET_FAILED; + break; + default: + g_assert_not_reached (); + } + + if (alerted) + ret = MONO_W32HANDLE_WAIT_RET_ALERTED; + + return ret; + } + + if (!mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_WAIT)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p can't be waited for", + __func__, handle); + + return MONO_W32HANDLE_WAIT_RET_FAILED; + } + + thr_ret = mono_w32handle_lock_handle (handle); + g_assert (thr_ret == 0); + + if (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_OWN)) { + if (own_if_owned (handle, &statuscode)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p already owned", + __func__, handle); + + ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; + goto done; + } + } + + if (timeout != INFINITE) + start = mono_msec_ticks (); + + for (;;) { + gint waited; + + if (own_if_signalled (handle, &statuscode)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p signalled", + __func__, handle); + + ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; + goto done; + } + + mono_w32handle_ops_prewait (handle); + + if (timeout == INFINITE) { + waited = mono_w32handle_timedwait_signal_handle (handle, INFINITE, FALSE, alertable ? &alerted : NULL); + } else { + gint64 elapsed; + + elapsed = mono_msec_ticks () - start; + if (elapsed > timeout) { + ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; + goto done; + } + + waited = mono_w32handle_timedwait_signal_handle (handle, timeout - elapsed, FALSE, alertable ? &alerted : NULL); + } + + if (alerted) { + ret = MONO_W32HANDLE_WAIT_RET_ALERTED; + goto done; + } + + if (waited != 0) { + ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; + goto done; + } + } + +done: + thr_ret = mono_w32handle_unlock_handle (handle); + g_assert (thr_ret == 0); + + return ret; +} + +MonoW32HandleWaitRet +mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waitall, guint32 timeout, gboolean alertable) +{ + MonoW32HandleWaitRet ret; + gboolean alerted, poll; + gint i, thr_ret; + gint64 start; + gpointer handles_sorted [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS]; + guint32 statuscodes [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS] = {0}; + + if (nhandles == 0) + return MONO_W32HANDLE_WAIT_RET_FAILED; + + if (nhandles == 1) + return mono_w32handle_wait_one (handles [0], timeout, alertable); + + alerted = FALSE; + + if (nhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: too many handles: %zd", + __func__, nhandles); + + return MONO_W32HANDLE_WAIT_RET_FAILED; + } + + for (i = 0; i < nhandles; ++i) { + if (!mono_w32handle_test_capabilities (handles[i], MONO_W32HANDLE_CAP_WAIT) + && !mono_w32handle_test_capabilities (handles[i], MONO_W32HANDLE_CAP_SPECIAL_WAIT)) + { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p can't be waited for", + __func__, handles [i]); + + return MONO_W32HANDLE_WAIT_RET_FAILED; + } + + handles_sorted [i] = handles [i]; + } + + qsort (handles_sorted, nhandles, sizeof (gpointer), g_direct_equal); + for (i = 1; i < nhandles; ++i) { + if (handles_sorted [i - 1] == handles_sorted [i]) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p is duplicated", + __func__, handles_sorted [i]); + + return MONO_W32HANDLE_WAIT_RET_FAILED; + } + } + + poll = FALSE; + for (i = 0; i < nhandles; ++i) { + if (mono_w32handle_get_type (handles [i]) == MONO_W32HANDLE_PROCESS) { + /* Can't wait for a process handle + another handle without polling */ + poll = TRUE; + } + } + + if (timeout != INFINITE) + start = mono_msec_ticks (); + + for (i = 0; i < nhandles; ++i) { + /* Add a reference, as we need to ensure the handle wont + * disappear from under us while we're waiting in the loop + * (not lock, as we don't want exclusive access here) */ + mono_w32handle_ref (handles [i]); + } + + for (;;) { + gsize count, lowest; + gboolean signalled; + gint waited; + + count = 0; + lowest = nhandles; + + mono_w32handle_lock_handles (handles, nhandles); + + for (i = 0; i < nhandles; i++) { + if ((mono_w32handle_test_capabilities (handles [i], MONO_W32HANDLE_CAP_OWN) && mono_w32handle_ops_isowned (handles [i])) + || mono_w32handle_issignalled (handles [i])) + { + count ++; + + if (i < lowest) + lowest = i; + } + } + + signalled = (waitall && count == nhandles) || (!waitall && count > 0); + + if (signalled) { + for (i = 0; i < nhandles; i++) + own_if_signalled (handles [i], &statuscodes [i]); + } + + mono_w32handle_unlock_handles (handles, nhandles); + + if (signalled) { + ret = MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + lowest; + for (i = lowest; i < nhandles; i++) { + if (statuscodes [i] == WAIT_ABANDONED_0) { + ret = MONO_W32HANDLE_WAIT_RET_ABANDONED_0 + lowest; + break; + } + } + goto done; + } + + for (i = 0; i < nhandles; i++) { + mono_w32handle_ops_prewait (handles[i]); + + if (mono_w32handle_test_capabilities (handles [i], MONO_W32HANDLE_CAP_SPECIAL_WAIT) + && !mono_w32handle_issignalled (handles [i])) + { + mono_w32handle_ops_specialwait (handles [i], 0, alertable ? &alerted : NULL); + } + } + + thr_ret = mono_w32handle_lock_signal_mutex (); + g_assert (thr_ret == 0); + + if (waitall) { + signalled = TRUE; + for (i = 0; i < nhandles; ++i) { + if (!mono_w32handle_issignalled (handles [i])) { + signalled = FALSE; + break; + } + } + } else { + signalled = FALSE; + for (i = 0; i < nhandles; ++i) { + if (mono_w32handle_issignalled (handles [i])) { + signalled = TRUE; + break; + } + } + } + + waited = 0; + + if (!signalled) { + if (timeout == INFINITE) { + waited = mono_w32handle_timedwait_signal (INFINITE, poll, alertable ? &alerted : NULL); + } else { + gint64 elapsed; + + elapsed = mono_msec_ticks () - start; + if (elapsed > timeout) { + ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; + + thr_ret = mono_w32handle_unlock_signal_mutex (); + g_assert (thr_ret == 0); + + goto done; + } + + waited = mono_w32handle_timedwait_signal (timeout - elapsed, poll, alertable ? &alerted : NULL); + } + } + + thr_ret = mono_w32handle_unlock_signal_mutex (); + g_assert (thr_ret == 0); + + if (alerted) { + ret = MONO_W32HANDLE_WAIT_RET_ALERTED; + goto done; + } + + if (waited != 0) { + ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; + goto done; + } + } + +done: + for (i = 0; i < nhandles; i++) { + /* Unref everything we reffed above */ + mono_w32handle_unref (handles [i]); + } + + return ret; +} + +MonoW32HandleWaitRet +mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, guint32 timeout, gboolean alertable) +{ + MonoW32HandleWaitRet ret; + gint64 start; + gboolean alerted; + gint thr_ret; + guint32 statuscode = 0; + + alerted = FALSE; + + if (!mono_w32handle_test_capabilities (signal_handle, MONO_W32HANDLE_CAP_SIGNAL)) + return MONO_W32HANDLE_WAIT_RET_FAILED; + if (!mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_WAIT)) + return MONO_W32HANDLE_WAIT_RET_FAILED; + + if (mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_SPECIAL_WAIT)) { + g_warning ("%s: handle %p has special wait, implement me!!", __func__, wait_handle); + return MONO_W32HANDLE_WAIT_RET_FAILED; + } + + thr_ret = mono_w32handle_lock_handle (wait_handle); + g_assert (thr_ret == 0); + + mono_w32handle_ops_signal (signal_handle); + + if (mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_OWN)) { + if (own_if_owned (wait_handle, &statuscode)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p already owned", + __func__, wait_handle); + + ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; + goto done; + } + } + + if (timeout != INFINITE) + start = mono_msec_ticks (); + + for (;;) { + gint waited; + + if (own_if_signalled (wait_handle, &statuscode)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p signalled", + __func__, wait_handle); + + ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; + goto done; + } + + mono_w32handle_ops_prewait (wait_handle); + + if (timeout == INFINITE) { + waited = mono_w32handle_timedwait_signal_handle (wait_handle, INFINITE, FALSE, alertable ? &alerted : NULL); + } else { + gint64 elapsed; + + elapsed = mono_msec_ticks () - start; + if (elapsed > timeout) { + ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; + goto done; + } + + waited = mono_w32handle_timedwait_signal_handle (wait_handle, timeout - elapsed, FALSE, alertable ? &alerted : NULL); + } + + if (alerted) { + ret = MONO_W32HANDLE_WAIT_RET_ALERTED; + goto done; + } + + if (waited != 0) { + ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; + goto done; + } + } + +done: + thr_ret = mono_w32handle_unlock_handle (wait_handle); + g_assert (thr_ret == 0); + + return ret; +} + +#endif /* !defined(HOST_WIN32) */ diff --git a/mono/metadata/w32handle.h b/mono/metadata/w32handle.h new file mode 100644 index 00000000000..92cf87ba119 --- /dev/null +++ b/mono/metadata/w32handle.h @@ -0,0 +1,186 @@ + +#ifndef _MONO_METADATA_W32HANDLE_H_ +#define _MONO_METADATA_W32HANDLE_H_ + +#include +#include + +#ifndef INVALID_HANDLE_VALUE +#define INVALID_HANDLE_VALUE (gpointer)-1 +#endif + +#define MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS 64 + +typedef enum { + MONO_W32HANDLE_UNUSED = 0, + MONO_W32HANDLE_FILE, + MONO_W32HANDLE_CONSOLE, + MONO_W32HANDLE_THREAD, + MONO_W32HANDLE_SEM, + MONO_W32HANDLE_MUTEX, + MONO_W32HANDLE_EVENT, + MONO_W32HANDLE_SOCKET, + MONO_W32HANDLE_FIND, + MONO_W32HANDLE_PROCESS, + MONO_W32HANDLE_PIPE, + MONO_W32HANDLE_NAMEDMUTEX, + MONO_W32HANDLE_NAMEDSEM, + MONO_W32HANDLE_NAMEDEVENT, + MONO_W32HANDLE_COUNT +} MonoW32HandleType; + +typedef struct +{ + void (*close)(gpointer handle, gpointer data); + + /* SignalObjectAndWait */ + void (*signal)(gpointer signal); + + /* Called by WaitForSingleObject and WaitForMultipleObjects, + * with the handle locked (shared handles aren't locked.) + * Returns TRUE if ownership was established, false otherwise. + * If TRUE, *statuscode contains a status code such as + * WAIT_OBJECT_0 or WAIT_ABANDONED_0. + */ + gboolean (*own_handle)(gpointer handle, guint32 *statuscode); + + /* Called by WaitForSingleObject and WaitForMultipleObjects, if the + * handle in question is "ownable" (ie mutexes), to see if the current + * thread already owns this handle + */ + gboolean (*is_owned)(gpointer handle); + + /* Called by WaitForSingleObject and WaitForMultipleObjects, + * if the handle in question needs a special wait function + * instead of using the normal handle signal mechanism. + * Returns the WaitForSingleObject return code. + */ + guint32 (*special_wait)(gpointer handle, guint32 timeout, gboolean *alerted); + + /* Called by WaitForSingleObject and WaitForMultipleObjects, + * if the handle in question needs some preprocessing before the + * signal wait. + */ + void (*prewait)(gpointer handle); + + /* Called when dumping the handles */ + void (*details)(gpointer data); + + /* Called to get the name of the handle type */ + const gchar* (*typename) (void); + + /* Called to get the size of the handle type */ + gsize (*typesize) (void); +} MonoW32HandleOps; + +typedef enum { + MONO_W32HANDLE_CAP_WAIT = 0x01, + MONO_W32HANDLE_CAP_SIGNAL = 0x02, + MONO_W32HANDLE_CAP_OWN = 0x04, + MONO_W32HANDLE_CAP_SPECIAL_WAIT = 0x08, +} MonoW32HandleCapability; + +extern guint32 mono_w32handle_fd_reserve; + +void +mono_w32handle_init (void); + +void +mono_w32handle_cleanup (void); + +void +mono_w32handle_register_ops (MonoW32HandleType type, MonoW32HandleOps *ops); + +gpointer +mono_w32handle_new (MonoW32HandleType type, gpointer handle_specific); + +gpointer +mono_w32handle_new_fd (MonoW32HandleType type, int fd, gpointer handle_specific); + +MonoW32HandleType +mono_w32handle_get_type (gpointer handle); + +gboolean +mono_w32handle_lookup (gpointer handle, MonoW32HandleType type, gpointer *handle_specific); + +gpointer +mono_w32handle_search (MonoW32HandleType type, gboolean (*check)(gpointer, gpointer), gpointer user_data, gpointer *handle_specific, gboolean search_shared); + +void +mono_w32handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpointer user_data), gpointer user_data); + +void +mono_w32handle_dump (void); + +void +mono_w32handle_ref (gpointer handle); + +void +mono_w32handle_unref (gpointer handle); + +void +mono_w32handle_register_capabilities (MonoW32HandleType type, MonoW32HandleCapability caps); + +gboolean +mono_w32handle_test_capabilities (gpointer handle, MonoW32HandleCapability caps); + +void +mono_w32handle_ops_close (gpointer handle, gpointer data); + +void +mono_w32handle_ops_signal (gpointer handle); + +gboolean +mono_w32handle_ops_own (gpointer handle, guint32 *statuscode); + +gboolean +mono_w32handle_ops_isowned (gpointer handle); + +guint32 +mono_w32handle_ops_specialwait (gpointer handle, guint32 timeout, gboolean *alerted); + +void +mono_w32handle_ops_prewait (gpointer handle); + +void +mono_w32handle_ops_details (MonoW32HandleType type, gpointer data); + +const gchar* +mono_w32handle_ops_typename (MonoW32HandleType type); + +gsize +mono_w32handle_ops_typesize (MonoW32HandleType type); + +void +mono_w32handle_set_signal_state (gpointer handle, gboolean state, gboolean broadcast); + +gboolean +mono_w32handle_issignalled (gpointer handle); + +int +mono_w32handle_lock_handle (gpointer handle); + +int +mono_w32handle_trylock_handle (gpointer handle); + +int +mono_w32handle_unlock_handle (gpointer handle); + +typedef enum { + MONO_W32HANDLE_WAIT_RET_SUCCESS_0 = 0, + MONO_W32HANDLE_WAIT_RET_ABANDONED_0 = MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS, + MONO_W32HANDLE_WAIT_RET_ALERTED = -1, + MONO_W32HANDLE_WAIT_RET_TIMEOUT = -2, + MONO_W32HANDLE_WAIT_RET_FAILED = -3, +} MonoW32HandleWaitRet; + +MonoW32HandleWaitRet +mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable); + +MonoW32HandleWaitRet +mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waitall, guint32 timeout, gboolean alertable); + +MonoW32HandleWaitRet +mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, guint32 timeout, gboolean alertable); + +#endif /* _MONO_METADATA_W32HANDLE_H_ */ diff --git a/mono/metadata/w32mutex-unix.c b/mono/metadata/w32mutex-unix.c index fbf1f6177a8..37e8e5c462d 100644 --- a/mono/metadata/w32mutex-unix.c +++ b/mono/metadata/w32mutex-unix.c @@ -16,7 +16,7 @@ #include "mono/metadata/object-internals.h" #include "mono/utils/mono-logger-internals.h" #include "mono/utils/mono-threads.h" -#include "mono/utils/w32handle.h" +#include "mono/metadata/w32handle.h" typedef struct { MonoNativeThreadId tid; diff --git a/mono/metadata/w32process-internals.h b/mono/metadata/w32process-internals.h new file mode 100644 index 00000000000..ad59f4c6d8b --- /dev/null +++ b/mono/metadata/w32process-internals.h @@ -0,0 +1,29 @@ + +#ifndef _MONO_METADATA_W32PROCESS_INTERNALS_H_ +#define _MONO_METADATA_W32PROCESS_INTERNALS_H_ + +#include +#include + +#include "io-layer/io-layer.h" + +#if !defined(HOST_WIN32) + +guint32 +mono_w32process_get_pid (gpointer handle); + +gboolean +mono_w32process_try_get_modules (gpointer process, gpointer *modules, guint32 size, guint32 *needed); + +guint32 +mono_w32process_module_get_name (gpointer process, gpointer module, gunichar2 *basename, guint32 size); + +guint32 +mono_w32process_module_get_filename (gpointer process, gpointer module, gunichar2 *basename, guint32 size); + +gboolean +mono_w32process_module_get_information (gpointer process, gpointer module, MODULEINFO *modinfo, guint32 size); + +#endif /* !defined(HOST_WIN32) */ + +#endif /* _MONO_METADATA_W32PROCESS_INTERNALS_H_ */ diff --git a/mono/metadata/w32process-unix-bsd.c b/mono/metadata/w32process-unix-bsd.c new file mode 100644 index 00000000000..79655b952b6 --- /dev/null +++ b/mono/metadata/w32process-unix-bsd.c @@ -0,0 +1,151 @@ + +#include "w32process.h" +#include "w32process-unix-internals.h" + +#ifdef USE_BSD_BACKEND + +#include +#include +#include +#if !defined(__OpenBSD__) +#include +#endif +#if defined(__FreeBSD__) +#include /* struct kinfo_proc */ +#endif + +#include + +#include "utils/mono-logger-internals.h" + +gchar* +mono_w32process_get_name (pid_t pid) +{ + gint mib [6]; + gsize size; + struct kinfo_proc *pi; + gchar *ret; + +#if defined(__FreeBSD__) + mib [0] = CTL_KERN; + mib [1] = KERN_PROC; + mib [2] = KERN_PROC_PID; + mib [3] = pid; + if (sysctl(mib, 4, NULL, &size, NULL, 0) < 0) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sysctl() failed: %d", __func__, errno); + return NULL; + } + + if ((pi = g_malloc (size)) == NULL) + return NULL; + + if (sysctl (mib, 4, pi, &size, NULL, 0) < 0) { + if (errno == ENOMEM) { + g_free (pi); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Didn't allocate enough memory for kproc info", __func__); + } + return NULL; + } + + ret = strlen (pi->ki_comm) > 0 ? g_strdup (pi->ki_comm) : NULL; + + g_free (pi); +#elif defined(__OpenBSD__) + mib [0] = CTL_KERN; + mib [1] = KERN_PROC; + mib [2] = KERN_PROC_PID; + mib [3] = pid; + mib [4] = sizeof(struct kinfo_proc); + mib [5] = 0; + +retry: + if (sysctl(mib, 6, NULL, &size, NULL, 0) < 0) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sysctl() failed: %d", __func__, errno); + return NULL; + } + + if ((pi = g_malloc (size)) == NULL) + return NULL; + + mib[5] = (int)(size / sizeof(struct kinfo_proc)); + + if ((sysctl (mib, 6, pi, &size, NULL, 0) < 0) || + (size != sizeof (struct kinfo_proc))) { + if (errno == ENOMEM) { + g_free (pi); + goto retry; + } + return NULL; + } + + ret = strlen (pi->p_comm) > 0 ? g_strdup (pi->p_comm) : NULL; + + g_free (pi); +#endif + + return ret; +} + +gchar* +mono_w32process_get_path (pid_t pid) +{ + return mono_w32process_get_name (pid); +} + +static gint +mono_w32process_get_modules_callback (struct dl_phdr_info *info, gsize size, gpointer ptr) +{ + if (size < offsetof (struct dl_phdr_info, dlpi_phnum) + sizeof (info->dlpi_phnum)) + return (-1); + + struct dl_phdr_info *cpy = g_calloc (1, sizeof(struct dl_phdr_info)); + if (!cpy) + return (-1); + + memcpy(cpy, info, sizeof(*info)); + + g_ptr_array_add ((GPtrArray *)ptr, cpy); + + return (0); +} + +GSList* +mono_w32process_get_modules (pid_t pid) +{ + GSList *ret = NULL; + MonoW32ProcessModule *mod; + GPtrArray *dlarray = g_ptr_array_new(); + gint i; + + if (dl_iterate_phdr (mono_w32process_get_modules_callback, dlarray) < 0) + return NULL; + + for (i = 0; i < dlarray->len; i++) { + struct dl_phdr_info *info = g_ptr_array_index (dlarray, i); + + mod = g_new0 (MonoW32ProcessModule, 1); + mod->address_start = (gpointer)(info->dlpi_addr + info->dlpi_phdr[0].p_vaddr); + mod->address_end = (gpointer)(info->dlpi_addr + info->dlpi_phdr[info->dlpi_phnum - 1].p_vaddr); + mod->perms = g_strdup ("r--p"); + mod->address_offset = 0; + mod->inode = i; + mod->filename = g_strdup (info->dlpi_name); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: inode=%d, filename=%s, address_start=%p, address_end=%p", + __func__, mod->inode, mod->filename, mod->address_start, mod->address_end); + + g_free (info); + + if (g_slist_find_custom (ret, mod, mono_w32process_module_equals) == NULL) { + ret = g_slist_prepend (ret, mod); + } else { + mono_w32process_module_free (mod); + } + } + + g_ptr_array_free (dlarray, TRUE); + + return g_slist_reverse (ret); +} + +#endif diff --git a/mono/metadata/w32process-unix-default.c b/mono/metadata/w32process-unix-default.c new file mode 100644 index 00000000000..0b48370f369 --- /dev/null +++ b/mono/metadata/w32process-unix-default.c @@ -0,0 +1,256 @@ + +#include "w32process.h" +#include "w32process-unix-internals.h" + +#ifdef USE_DEFAULT_BACKEND + +#include + +#ifdef PLATFORM_SOLARIS +/* procfs.h cannot be included if this define is set, but it seems to work fine if it is undefined */ +#if _FILE_OFFSET_BITS == 64 +#undef _FILE_OFFSET_BITS +#include +#define _FILE_OFFSET_BITS 64 +#else +#include +#endif +#endif + +#include "utils/mono-logger-internals.h" + +#ifndef MAXPATHLEN +#define MAXPATHLEN 242 +#endif + +gchar* +mono_w32process_get_name (pid_t pid) +{ + FILE *fp; + gchar *filename; + gchar buf[256]; + gchar *ret = NULL; + +#if defined(PLATFORM_SOLARIS) + filename = g_strdup_printf ("/proc/%d/psinfo", pid); + if ((fp = fopen (filename, "r")) != NULL) { + struct psinfo info; + int nread; + + nread = fread (&info, sizeof (info), 1, fp); + if (nread == 1) { + ret = g_strdup (info.pr_fname); + } + + fclose (fp); + } + g_free (filename); +#else + memset (buf, '\0', sizeof(buf)); + filename = g_strdup_printf ("/proc/%d/exe", pid); + if (readlink (filename, buf, 255) > 0) { + ret = g_strdup (buf); + } + g_free (filename); + + if (ret != NULL) { + return(ret); + } + + filename = g_strdup_printf ("/proc/%d/cmdline", pid); + if ((fp = fopen (filename, "r")) != NULL) { + if (fgets (buf, 256, fp) != NULL) { + ret = g_strdup (buf); + } + + fclose (fp); + } + g_free (filename); + + if (ret != NULL) { + return(ret); + } + + filename = g_strdup_printf ("/proc/%d/stat", pid); + if ((fp = fopen (filename, "r")) != NULL) { + if (fgets (buf, 256, fp) != NULL) { + char *start, *end; + + start = strchr (buf, '('); + if (start != NULL) { + end = strchr (start + 1, ')'); + + if (end != NULL) { + ret = g_strndup (start + 1, + end - start - 1); + } + } + } + + fclose (fp); + } + g_free (filename); +#endif + + return ret; +} + +gchar* +mono_w32process_get_path (pid_t pid) +{ + return mono_w32process_get_name (pid); +} + +static FILE * +open_process_map (int pid, const char *mode) +{ + gint i; + const gchar *proc_path[] = { + "/proc/%d/maps", /* GNU/Linux */ + "/proc/%d/map", /* FreeBSD */ + NULL + }; + + for (i = 0; proc_path [i]; i++) { + gchar *filename; + FILE *fp; + + filename = g_strdup_printf (proc_path[i], pid); + fp = fopen (filename, mode); + g_free (filename); + + if (fp) + return fp; + } + + return NULL; +} + + +GSList* +mono_w32process_get_modules (pid_t pid) +{ + GSList *ret = NULL; + FILE *fp; + MonoW32ProcessModule *mod; + gchar buf[MAXPATHLEN + 1], *p, *endp; + gchar *start_start, *end_start, *prot_start, *offset_start; + gchar *maj_dev_start, *min_dev_start, *inode_start, prot_buf[5]; + gpointer address_start, address_end, address_offset; + guint32 maj_dev, min_dev; + guint64 inode; + guint64 device; + + fp = open_process_map (pid, "r"); + if (!fp) + return NULL; + + while (fgets (buf, sizeof(buf), fp)) { + p = buf; + while (g_ascii_isspace (*p)) ++p; + start_start = p; + if (!g_ascii_isxdigit (*start_start)) { + continue; + } + address_start = (gpointer)strtoul (start_start, &endp, 16); + p = endp; + if (*p != '-') { + continue; + } + + ++p; + end_start = p; + if (!g_ascii_isxdigit (*end_start)) { + continue; + } + address_end = (gpointer)strtoul (end_start, &endp, 16); + p = endp; + if (!g_ascii_isspace (*p)) { + continue; + } + + while (g_ascii_isspace (*p)) ++p; + prot_start = p; + if (*prot_start != 'r' && *prot_start != '-') { + continue; + } + memcpy (prot_buf, prot_start, 4); + prot_buf[4] = '\0'; + while (!g_ascii_isspace (*p)) ++p; + + while (g_ascii_isspace (*p)) ++p; + offset_start = p; + if (!g_ascii_isxdigit (*offset_start)) { + continue; + } + address_offset = (gpointer)strtoul (offset_start, &endp, 16); + p = endp; + if (!g_ascii_isspace (*p)) { + continue; + } + + while(g_ascii_isspace (*p)) ++p; + maj_dev_start = p; + if (!g_ascii_isxdigit (*maj_dev_start)) { + continue; + } + maj_dev = strtoul (maj_dev_start, &endp, 16); + p = endp; + if (*p != ':') { + continue; + } + + ++p; + min_dev_start = p; + if (!g_ascii_isxdigit (*min_dev_start)) { + continue; + } + min_dev = strtoul (min_dev_start, &endp, 16); + p = endp; + if (!g_ascii_isspace (*p)) { + continue; + } + + while (g_ascii_isspace (*p)) ++p; + inode_start = p; + if (!g_ascii_isxdigit (*inode_start)) { + continue; + } + inode = (guint64)strtol (inode_start, &endp, 10); + p = endp; + if (!g_ascii_isspace (*p)) { + continue; + } + + device = makedev ((int)maj_dev, (int)min_dev); + if ((device == 0) && (inode == 0)) { + continue; + } + + while(g_ascii_isspace (*p)) ++p; + /* p now points to the filename */ + + mod = g_new0 (MonoW32ProcessModule, 1); + mod->address_start = address_start; + mod->address_end = address_end; + mod->perms = g_strdup (prot_buf); + mod->address_offset = address_offset; + mod->device = device; + mod->inode = inode; + mod->filename = g_strdup (g_strstrip (p)); + + if (g_slist_find_custom (ret, mod, mono_w32process_module_equals) == NULL) { + ret = g_slist_prepend (ret, mod); + } else { + mono_w32process_module_free (mod); + } + } + + ret = g_slist_reverse (ret); + + fclose (fp); + + return(ret); +} + +#endif diff --git a/mono/metadata/w32process-unix-haiku.c b/mono/metadata/w32process-unix-haiku.c new file mode 100644 index 00000000000..4311993bb10 --- /dev/null +++ b/mono/metadata/w32process-unix-haiku.c @@ -0,0 +1,56 @@ + +#include "w32process.h" +#include "w32process-unix-internals.h" + +#ifdef USE_HAIKU_BACKEND + +#include + +gchar* +mono_w32process_get_name (pid_t pid) +{ + image_info imageInfo; + int32 cookie = 0; + + if (get_next_image_info ((team_id) pid, &cookie, &imageInfo) != B_OK) + return NULL; + + return g_strdup (imageInfo.name); +} + +gchar* +mono_w32process_get_path (pid_t pid) +{ + return mono_w32process_get_name (pid); +} + +GSList* +mono_w32process_get_modules (pid_t pid) +{ + GSList *ret = NULL; + MonoW32ProcessModule *mod; + gint32 cookie = 0; + image_info imageInfo; + + while (get_next_image_info (B_CURRENT_TEAM, &cookie, &imageInfo) == B_OK) { + mod = g_new0 (MonoW32ProcessModule, 1); + mod->device = imageInfo.device; + mod->inode = imageInfo.node; + mod->filename = g_strdup (imageInfo.name); + mod->address_start = MIN (imageInfo.text, imageInfo.data); + mod->address_end = MAX ((uint8_t*)imageInfo.text + imageInfo.text_size, + (uint8_t*)imageInfo.data + imageInfo.data_size); + mod->perms = g_strdup ("r--p"); + mod->address_offset = 0; + + if (g_slist_find_custom (ret, mod, mono_w32process_module_equals) == NULL) { + ret = g_slist_prepend (ret, mod); + } else { + mono_w32process_module_free (mod); + } + } + + return g_slist_reverse (ret); +} + +#endif diff --git a/mono/metadata/w32process-unix-internals.h b/mono/metadata/w32process-unix-internals.h new file mode 100644 index 00000000000..71226c3109d --- /dev/null +++ b/mono/metadata/w32process-unix-internals.h @@ -0,0 +1,57 @@ + +#ifndef _MONO_METADATA_W32PROCESS_UNIX_INTERNALS_H_ +#define _MONO_METADATA_W32PROCESS_UNIX_INTERNALS_H_ + +#include +#include + +/* + * FOR EXCLUSIVE USE BY w32process-unix.c + */ + +#if defined(PLATFORM_MACOSX) +#define USE_OSX_BACKEND +#elif (defined(__OpenBSD__) || defined(__FreeBSD__)) && defined(HAVE_LINK_H) +#define USE_BSD_BACKEND +#elif defined(__HAIKU__) +#define USE_HAIKU_BACKEND +#else +#define USE_DEFAULT_BACKEND +#endif + +typedef struct { + gpointer address_start; + gpointer address_end; + gchar *perms; + gpointer address_offset; + guint64 device; + guint64 inode; + gchar *filename; +} MonoW32ProcessModule; + +gchar* +mono_w32process_get_name (pid_t pid); + +GSList* +mono_w32process_get_modules (pid_t pid); + +static void +mono_w32process_module_free (MonoW32ProcessModule *module) +{ + g_free (module->perms); + g_free (module->filename); + g_free (module); +} + +/* + * Used to look through the GSList* returned by mono_w32process_get_modules + */ +static gint +mono_w32process_module_equals (gconstpointer a, gconstpointer b) +{ + MonoW32ProcessModule *want = (MonoW32ProcessModule *)a; + MonoW32ProcessModule *compare = (MonoW32ProcessModule *)b; + return (want->device == compare->device && want->inode == compare->inode) ? 0 : 1; +} + +#endif /* _MONO_METADATA_W32PROCESS_UNIX_INTERNALS_H_ */ diff --git a/mono/metadata/w32process-unix-osx.c b/mono/metadata/w32process-unix-osx.c new file mode 100644 index 00000000000..eb3d5b70b08 --- /dev/null +++ b/mono/metadata/w32process-unix-osx.c @@ -0,0 +1,160 @@ + +#include "w32process.h" +#include "w32process-unix-internals.h" + +#ifdef USE_OSX_BACKEND + +#include +#include +#include +#include +#include +#include +#include + +/* sys/resource.h (for rusage) is required when using osx 10.3 (but not 10.4) */ +#ifdef __APPLE__ +#include +#include +#ifdef HAVE_LIBPROC_H +/* proc_name */ +#include +#endif +#endif + +#include "utils/mono-logger-internals.h" + +gchar* +mono_w32process_get_name (pid_t pid) +{ + gchar *ret = NULL; + +#if defined (__mono_ppc__) || !defined (TARGET_OSX) + size_t size; + struct kinfo_proc *pi; + gint mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid }; + + if (sysctl(mib, 4, NULL, &size, NULL, 0) < 0) + return(ret); + + if ((pi = g_malloc (size)) == NULL) + return(ret); + + if (sysctl (mib, 4, pi, &size, NULL, 0) < 0) { + if (errno == ENOMEM) { + g_free (pi); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Didn't allocate enough memory for kproc info", __func__); + } + return(ret); + } + + if (strlen (pi->kp_proc.p_comm) > 0) + ret = g_strdup (pi->kp_proc.p_comm); + + g_free (pi); +#else + gchar buf[256]; + + /* No proc name on OSX < 10.5 nor ppc nor iOS */ + memset (buf, '\0', sizeof(buf)); + proc_name (pid, buf, sizeof(buf)); + + // Fixes proc_name triming values to 15 characters #32539 + if (strlen (buf) >= MAXCOMLEN - 1) { + gchar path_buf [PROC_PIDPATHINFO_MAXSIZE]; + gchar *name_buf; + gint path_len; + + memset (path_buf, '\0', sizeof(path_buf)); + path_len = proc_pidpath (pid, path_buf, sizeof(path_buf)); + + if (path_len > 0 && path_len < sizeof(path_buf)) { + name_buf = path_buf + path_len; + for(;name_buf > path_buf; name_buf--) { + if (name_buf [0] == '/') { + name_buf++; + break; + } + } + + if (memcmp (buf, name_buf, MAXCOMLEN - 1) == 0) + ret = g_strdup (name_buf); + } + } + + if (ret == NULL && strlen (buf) > 0) + ret = g_strdup (buf); +#endif + + return ret; +} + +gchar* +mono_w32process_get_path (pid_t pid) +{ +#if defined(__mono_ppc__) || !defined(TARGET_OSX) + return mono_w32process_get_name (pid); +#else + gchar buf [PROC_PIDPATHINFO_MAXSIZE]; + gint res; + + res = proc_pidpath (pid, buf, sizeof (buf)); + if (res <= 0) + return NULL; + if (buf [0] == '\0') + return NULL; + return g_strdup (buf); +#endif +} + +GSList* +mono_w32process_get_modules (pid_t pid) +{ + GSList *ret = NULL; + MonoW32ProcessModule *mod; + guint32 count = _dyld_image_count (); + int i = 0; + + for (i = 0; i < count; i++) { +#if SIZEOF_VOID_P == 8 + const struct mach_header_64 *hdr; + const struct section_64 *sec; +#else + const struct mach_header *hdr; + const struct section *sec; +#endif + const char *name; + + name = _dyld_get_image_name (i); +#if SIZEOF_VOID_P == 8 + hdr = (const struct mach_header_64*)_dyld_get_image_header (i); + sec = getsectbynamefromheader_64 (hdr, SEG_DATA, SECT_DATA); +#else + hdr = _dyld_get_image_header (i); + sec = getsectbynamefromheader (hdr, SEG_DATA, SECT_DATA); +#endif + + /* Some dynlibs do not have data sections on osx (#533893) */ + if (sec == 0) + continue; + + mod = g_new0 (MonoW32ProcessModule, 1); + mod->address_start = GINT_TO_POINTER (sec->addr); + mod->address_end = GINT_TO_POINTER (sec->addr+sec->size); + mod->perms = g_strdup ("r--p"); + mod->address_offset = 0; + mod->device = makedev (0, 0); + mod->inode = i; + mod->filename = g_strdup (name); + + if (g_slist_find_custom (ret, mod, mono_w32process_module_equals) == NULL) { + ret = g_slist_prepend (ret, mod); + } else { + mono_w32process_module_free (mod); + } + } + + return g_slist_reverse (ret); +} + +#endif diff --git a/mono/metadata/w32process-unix.c b/mono/metadata/w32process-unix.c new file mode 100644 index 00000000000..f4ae2a5b09f --- /dev/null +++ b/mono/metadata/w32process-unix.c @@ -0,0 +1,2366 @@ +/* + * process.c: System.Diagnostics.Process support + * + * Author: + * Dick Porter (dick@ximian.com) + * + * Copyright 2002 Ximian, Inc. + * Copyright 2002-2006 Novell, Inc. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SIGNAL_H +#include +#endif +#include +#include +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#include + +#ifdef HAVE_SYS_WAIT_H +#include +#endif +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif + +#ifdef HAVE_SYS_MKDEV_H +#include +#endif + +#ifdef HAVE_UTIME_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef MAXPATHLEN +#define MAXPATHLEN 242 +#endif + +#define STILL_ACTIVE ((int) 0x00000103) + +#define LOGDEBUG(...) +/* define LOGDEBUG(...) g_message(__VA_ARGS__) */ + +/* The process' environment strings */ +#if defined(__APPLE__) +#if defined (TARGET_OSX) +/* Apple defines this in crt_externs.h but doesn't provide that header for + * arm-apple-darwin9. We'll manually define the symbol on Apple as it does + * in fact exist on all implementations (so far) + */ +gchar ***_NSGetEnviron(void); +#define environ (*_NSGetEnviron()) +#else +static char *mono_environ[1] = { NULL }; +#define environ mono_environ +#endif /* defined (TARGET_OSX) */ +#else +extern char **environ; +#endif + +/* + * Handles > _WAPI_PROCESS_UNHANDLED are pseudo handles which represent processes + * not started by the runtime. + */ +/* This marks a system process that we don't have a handle on */ +/* FIXME: Cope with PIDs > sizeof guint */ +#define _WAPI_PROCESS_UNHANDLED (1 << (8*sizeof(pid_t)-1)) + +#define WAPI_IS_PSEUDO_PROCESS_HANDLE(handle) ((GPOINTER_TO_UINT(handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) +#define WAPI_PID_TO_HANDLE(pid) GINT_TO_POINTER (_WAPI_PROCESS_UNHANDLED + (pid)) +#define WAPI_HANDLE_TO_PID(handle) (GPOINTER_TO_UINT ((handle)) - _WAPI_PROCESS_UNHANDLED) + +typedef enum { + STARTF_USESHOWWINDOW=0x001, + STARTF_USESIZE=0x002, + STARTF_USEPOSITION=0x004, + STARTF_USECOUNTCHARS=0x008, + STARTF_USEFILLATTRIBUTE=0x010, + STARTF_RUNFULLSCREEN=0x020, + STARTF_FORCEONFEEDBACK=0x040, + STARTF_FORCEOFFFEEDBACK=0x080, + STARTF_USESTDHANDLES=0x100 +} StartupFlags; + +typedef struct { + gpointer input; + gpointer output; + gpointer error; +} StartupHandles; + +typedef struct { +#if G_BYTE_ORDER == G_BIG_ENDIAN + guint32 highDateTime; + guint32 lowDateTime; +#else + guint32 lowDateTime; + guint32 highDateTime; +#endif +} ProcessTime; + +/* + * MonoProcess describes processes we create. + * It contains a semaphore that can be waited on in order to wait + * for process termination. It's accessed in our SIGCHLD handler, + * when status is updated (and pid cleared, to not clash with + * subsequent processes that may get executed). + */ +typedef struct _MonoProcess MonoProcess; +struct _MonoProcess { + pid_t pid; /* the pid of the process. This value is only valid until the process has exited. */ + MonoSemType exit_sem; /* this semaphore will be released when the process exits */ + int status; /* the exit status */ + gint32 handle_count; /* the number of handles to this mono_process instance */ + /* we keep a ref to the creating _WapiHandle_process handle until + * the process has exited, so that the information there isn't lost. + */ + gpointer handle; + gboolean freeable; + MonoProcess *next; +}; + +/* MonoW32HandleProcess is a structure containing all the required information for process handling. */ +typedef struct { + pid_t id; + guint32 exitstatus; + gpointer main_thread; + WapiFileTime create_time; + WapiFileTime exit_time; + char *proc_name; + size_t min_working_set; + size_t max_working_set; + gboolean exited; + MonoProcess *mono_process; +} MonoW32HandleProcess; + +#if HAVE_SIGACTION +static mono_lazy_init_t process_sig_chld_once = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED; +#endif + +static gchar *cli_launcher; + +/* The signal-safe logic to use mono_processes goes like this: + * - The list must be safe to traverse for the signal handler at all times. + * It's safe to: prepend an entry (which is a single store to 'mono_processes'), + * unlink an entry (assuming the unlinked entry isn't freed and doesn't + * change its 'next' pointer so that it can still be traversed). + * When cleaning up we first unlink an entry, then we verify that + * the read lock isn't locked. Then we can free the entry, since + * we know that nobody is using the old version of the list (including + * the unlinked entry). + * We also need to lock when adding and cleaning up so that those two + * operations don't mess with eachother. (This lock is not used in the + * signal handler) */ +static MonoProcess *mono_processes; +static mono_mutex_t mono_processes_mutex; +static volatile gint32 mono_processes_cleaning_up; + +static gpointer current_process; + +static const gunichar2 utf16_space_bytes [2] = { 0x20, 0 }; +static const gunichar2 *utf16_space = utf16_space_bytes; +static const gunichar2 utf16_quote_bytes [2] = { 0x22, 0 }; +static const gunichar2 *utf16_quote = utf16_quote_bytes; + +static void +process_details (gpointer data) +{ + MonoW32HandleProcess *process_handle = (MonoW32HandleProcess *) data; + g_print ("id: %d, exited: %s, exitstatus: %d", + process_handle->id, process_handle->exited ? "true" : "false", process_handle->exitstatus); +} + +static const gchar* +process_typename (void) +{ + return "Process"; +} + +static gsize +process_typesize (void) +{ + return sizeof (MonoW32HandleProcess); +} + +static guint32 +process_wait (gpointer handle, guint32 timeout, gboolean *alerted) +{ + MonoW32HandleProcess *process_handle; + pid_t pid G_GNUC_UNUSED, ret; + int status; + gint64 start, now; + MonoProcess *mp; + gboolean res; + + /* FIXME: We can now easily wait on processes that aren't our own children, + * but WaitFor*Object won't call us for pseudo handles. */ + g_assert ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) != _WAPI_PROCESS_UNHANDLED); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u)", __func__, handle, timeout); + + if (alerted) + *alerted = FALSE; + + res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); + if (!res) { + g_warning ("%s: error looking up process handle %p", __func__, handle); + return WAIT_FAILED; + } + + if (process_handle->exited) { + /* We've already done this one */ + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): Process already exited", __func__, handle, timeout); + return WAIT_OBJECT_0; + } + + pid = process_handle->id; + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): PID: %d", __func__, handle, timeout, pid); + + /* We don't need to lock mono_processes here, the entry + * has a handle_count > 0 which means it will not be freed. */ + mp = process_handle->mono_process; + if (!mp) { + pid_t res; + + if (pid == mono_process_current_pid ()) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): waiting on current process", __func__, handle, timeout); + return WAIT_TIMEOUT; + } + + /* This path is used when calling Process.HasExited, so + * it is only used to poll the state of the process, not + * to actually wait on it to exit */ + g_assert (timeout == 0); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): waiting on non-child process", __func__, handle, timeout); + + res = waitpid (pid, &status, WNOHANG); + if (res == 0) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): non-child process WAIT_TIMEOUT", __func__, handle, timeout); + return WAIT_TIMEOUT; + } + if (res > 0) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): non-child process waited successfully", __func__, handle, timeout); + return WAIT_OBJECT_0; + } + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): non-child process WAIT_FAILED, error : %s (%d))", __func__, handle, timeout, g_strerror (errno), errno); + return WAIT_FAILED; + } + + start = mono_msec_ticks (); + now = start; + + while (1) { + if (timeout != INFINITE) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): waiting on semaphore for %li ms...", + __func__, handle, timeout, (long)(timeout - (now - start))); + ret = mono_os_sem_timedwait (&mp->exit_sem, (timeout - (now - start)), alerted ? MONO_SEM_FLAGS_ALERTABLE : MONO_SEM_FLAGS_NONE); + } else { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): waiting on semaphore forever...", + __func__, handle, timeout); + ret = mono_os_sem_wait (&mp->exit_sem, alerted ? MONO_SEM_FLAGS_ALERTABLE : MONO_SEM_FLAGS_NONE); + } + + if (ret == MONO_SEM_TIMEDWAIT_RET_SUCCESS) { + /* Success, process has exited */ + mono_os_sem_post (&mp->exit_sem); + break; + } + + if (ret == MONO_SEM_TIMEDWAIT_RET_TIMEDOUT) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): WAIT_TIMEOUT (timeout = 0)", __func__, handle, timeout); + return WAIT_TIMEOUT; + } + + now = mono_msec_ticks (); + if (now - start >= timeout) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): WAIT_TIMEOUT", __func__, handle, timeout); + return WAIT_TIMEOUT; + } + + if (alerted && ret == MONO_SEM_TIMEDWAIT_RET_ALERTED) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): WAIT_IO_COMPLETION", __func__, handle, timeout); + *alerted = TRUE; + return WAIT_IO_COMPLETION; + } + } + + /* Process must have exited */ + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): Waited successfully", __func__, handle, timeout); + + status = mp ? mp->status : 0; + if (WIFSIGNALED (status)) + process_handle->exitstatus = 128 + WTERMSIG (status); + else + process_handle->exitstatus = WEXITSTATUS (status); + _wapi_time_t_to_filetime (time (NULL), &process_handle->exit_time); + + process_handle->exited = TRUE; + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): Setting pid %d signalled, exit status %d", + __func__, handle, timeout, process_handle->id, process_handle->exitstatus); + + mono_w32handle_set_signal_state (handle, TRUE, TRUE); + + return WAIT_OBJECT_0; +} + +static void +processes_cleanup (void) +{ + MonoProcess *mp; + MonoProcess *prev = NULL; + GSList *finished = NULL; + GSList *l; + gpointer unref_handle; + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s", __func__); + + /* Ensure we're not in here in multiple threads at once, nor recursive. */ + if (InterlockedCompareExchange (&mono_processes_cleaning_up, 1, 0) != 0) + return; + + for (mp = mono_processes; mp; mp = mp->next) { + if (mp->pid == 0 && mp->handle) { + /* This process has exited and we need to remove the artifical ref + * on the handle */ + mono_os_mutex_lock (&mono_processes_mutex); + unref_handle = mp->handle; + mp->handle = NULL; + mono_os_mutex_unlock (&mono_processes_mutex); + if (unref_handle) + mono_w32handle_unref (unref_handle); + } + } + + /* + * Remove processes which exited from the mono_processes list. + * We need to synchronize with the sigchld handler here, which runs + * asynchronously. The handler requires that the mono_processes list + * remain valid. + */ + mono_os_mutex_lock (&mono_processes_mutex); + + mp = mono_processes; + while (mp) { + if (mp->handle_count == 0 && mp->freeable) { + /* + * Unlink the entry. + * This code can run parallel with the sigchld handler, but the + * modifications it makes are safe. + */ + if (mp == mono_processes) + mono_processes = mp->next; + else + prev->next = mp->next; + finished = g_slist_prepend (finished, mp); + + mp = mp->next; + } else { + prev = mp; + mp = mp->next; + } + } + + mono_memory_barrier (); + + for (l = finished; l; l = l->next) { + /* + * All the entries in the finished list are unlinked from mono_processes, and + * they have the 'finished' flag set, which means the sigchld handler is done + * accessing them. + */ + mp = (MonoProcess *)l->data; + mono_os_sem_destroy (&mp->exit_sem); + g_free (mp); + } + g_slist_free (finished); + + mono_os_mutex_unlock (&mono_processes_mutex); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s done", __func__); + + InterlockedDecrement (&mono_processes_cleaning_up); +} + +static void +process_close (gpointer handle, gpointer data) +{ + MonoW32HandleProcess *process_handle; + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s", __func__); + + process_handle = (MonoW32HandleProcess *) data; + g_free (process_handle->proc_name); + process_handle->proc_name = NULL; + if (process_handle->mono_process) + InterlockedDecrement (&process_handle->mono_process->handle_count); + processes_cleanup (); +} + +static MonoW32HandleOps process_ops = { + process_close, /* close_shared */ + NULL, /* signal */ + NULL, /* own */ + NULL, /* is_owned */ + process_wait, /* special_wait */ + NULL, /* prewait */ + process_details, /* details */ + process_typename, /* typename */ + process_typesize, /* typesize */ +}; + +static void +process_set_defaults (MonoW32HandleProcess *process_handle) +{ + /* These seem to be the defaults on w2k */ + process_handle->min_working_set = 204800; + process_handle->max_working_set = 1413120; + + _wapi_time_t_to_filetime (time (NULL), &process_handle->create_time); +} + +static void +process_set_name (MonoW32HandleProcess *process_handle) +{ + char *progname, *utf8_progname, *slash; + + progname = g_get_prgname (); + utf8_progname = mono_utf8_from_external (progname); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: using [%s] as prog name", __func__, progname); + + if (utf8_progname) { + slash = strrchr (utf8_progname, '/'); + if (slash) + process_handle->proc_name = g_strdup (slash+1); + else + process_handle->proc_name = g_strdup (utf8_progname); + g_free (utf8_progname); + } +} + +void +mono_w32process_init (void) +{ + MonoW32HandleProcess process_handle; + + mono_w32handle_register_ops (MONO_W32HANDLE_PROCESS, &process_ops); + + mono_w32handle_register_capabilities (MONO_W32HANDLE_PROCESS, + (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SPECIAL_WAIT)); + + memset (&process_handle, 0, sizeof (process_handle)); + process_handle.id = wapi_getpid (); + process_set_defaults (&process_handle); + process_set_name (&process_handle); + + current_process = mono_w32handle_new (MONO_W32HANDLE_PROCESS, &process_handle); + g_assert (current_process); + + mono_os_mutex_init (&mono_processes_mutex); +} + +void +mono_w32process_cleanup (void) +{ + g_free (cli_launcher); +} + +/* Check if a pid is valid - i.e. if a process exists with this pid. */ +static gboolean +is_pid_valid (pid_t pid) +{ + gboolean result = FALSE; + +#if defined(HOST_WATCHOS) + result = TRUE; // TODO: Rewrite using sysctl +#elif defined(PLATFORM_MACOSX) || defined(__OpenBSD__) || defined(__FreeBSD__) + if (((kill(pid, 0) == 0) || (errno == EPERM)) && pid != 0) + result = TRUE; +#elif defined(__HAIKU__) + team_info teamInfo; + if (get_team_info ((team_id)pid, &teamInfo) == B_OK) + result = TRUE; +#else + char *dir = g_strdup_printf ("/proc/%d", pid); + if (!access (dir, F_OK)) + result = TRUE; + g_free (dir); +#endif + + return result; +} + +static int +len16 (const gunichar2 *str) +{ + int len = 0; + + while (*str++ != 0) + len++; + + return len; +} + +static gunichar2 * +utf16_concat (const gunichar2 *first, ...) +{ + va_list args; + int total = 0, i; + const gunichar2 *s; + const gunichar2 *p; + gunichar2 *ret; + + va_start (args, first); + total += len16 (first); + for (s = va_arg (args, gunichar2 *); s != NULL; s = va_arg(args, gunichar2 *)) + total += len16 (s); + va_end (args); + + ret = g_new (gunichar2, total + 1); + if (ret == NULL) + return NULL; + + ret [total] = 0; + i = 0; + for (s = first; *s != 0; s++) + ret [i++] = *s; + va_start (args, first); + for (s = va_arg (args, gunichar2 *); s != NULL; s = va_arg (args, gunichar2 *)){ + for (p = s; *p != 0; p++) + ret [i++] = *p; + } + va_end (args); + + return ret; +} + +guint32 +mono_w32process_get_pid (gpointer handle) +{ + MonoW32HandleProcess *process_handle; + gboolean res; + + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)) { + /* This is a pseudo handle */ + return WAPI_HANDLE_TO_PID (handle); + } + + res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); + if (!res) { + SetLastError (ERROR_INVALID_HANDLE); + return 0; + } + + return process_handle->id; +} + +static gboolean +process_open_compare (gpointer handle, gpointer user_data) +{ + gboolean res; + MonoW32HandleProcess *process_handle; + pid_t wanted_pid, checking_pid; + + g_assert (!WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)); + + res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); + if (!res) + g_error ("%s: unknown process handle %p", __func__, handle); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: looking at process %d", __func__, process_handle->id); + + checking_pid = process_handle->id; + if (checking_pid == 0) + return FALSE; + + wanted_pid = GPOINTER_TO_UINT (user_data); + + /* It's possible to have more than one process handle with the + * same pid, but only the one running process can be + * unsignalled. + * If the handle is blown away in the window between + * returning TRUE here and mono_w32handle_search pinging + * the timestamp, the search will continue. */ + return checking_pid == wanted_pid && !mono_w32handle_issignalled (handle); +} + +HANDLE +ves_icall_System_Diagnostics_Process_GetProcess_internal (guint32 pid) +{ + gpointer handle; + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: looking for process %d", __func__, pid); + + handle = mono_w32handle_search (MONO_W32HANDLE_PROCESS, process_open_compare, GUINT_TO_POINTER (pid), NULL, TRUE); + if (handle) { + /* mono_w32handle_search () already added a ref */ + return handle; + } + + if (is_pid_valid (pid)) { + /* Return a pseudo handle for processes we don't have handles for */ + return WAPI_PID_TO_HANDLE (pid); + } else { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find pid %d", __func__, pid); + + SetLastError (ERROR_PROC_NOT_FOUND); + return NULL; + } +} + +static gboolean +match_procname_to_modulename (char *procname, char *modulename) +{ + char* lastsep = NULL; + char* lastsep2 = NULL; + char* pname = NULL; + char* mname = NULL; + gboolean result = FALSE; + + if (procname == NULL || modulename == NULL) + return (FALSE); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: procname=\"%s\", modulename=\"%s\"", __func__, procname, modulename); + pname = mono_path_resolve_symlinks (procname); + mname = mono_path_resolve_symlinks (modulename); + + if (!strcmp (pname, mname)) + result = TRUE; + + if (!result) { + lastsep = strrchr (mname, '/'); + if (lastsep) + if (!strcmp (lastsep+1, pname)) + result = TRUE; + if (!result) { + lastsep2 = strrchr (pname, '/'); + if (lastsep2){ + if (lastsep) { + if (!strcmp (lastsep+1, lastsep2+1)) + result = TRUE; + } else { + if (!strcmp (mname, lastsep2+1)) + result = TRUE; + } + } + } + } + + g_free (pname); + g_free (mname); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: result is %d", __func__, result); + return result; +} + +gboolean +mono_w32process_try_get_modules (gpointer process, gpointer *modules, guint32 size, guint32 *needed) +{ + MonoW32HandleProcess *process_handle; + GSList *mods = NULL; + MonoW32ProcessModule *module; + guint32 count, avail = size / sizeof(gpointer); + int i; + pid_t pid; + char *proc_name = NULL; + gboolean res; + + /* Store modules in an array of pointers (main module as + * modules[0]), using the load address for each module as a + * token. (Use 'NULL' as an alternative for the main module + * so that the simple implementation can just return one item + * for now.) Get the info from /proc//maps on linux, + * /proc//map on FreeBSD, other systems will have to + * implement /dev/kmem reading or whatever other horrid + * technique is needed. + */ + if (size < sizeof(gpointer)) + return FALSE; + + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) { + pid = WAPI_HANDLE_TO_PID (process); + proc_name = mono_w32process_get_name (pid); + } else { + res = mono_w32handle_lookup (process, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); + if (!res) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, process); + return FALSE; + } + + pid = process_handle->id; + proc_name = g_strdup (process_handle->proc_name); + } + + if (!proc_name) { + modules[0] = NULL; + *needed = sizeof(gpointer); + return TRUE; + } + + mods = mono_w32process_get_modules (pid); + if (!mods) { + modules[0] = NULL; + *needed = sizeof(gpointer); + g_free (proc_name); + return TRUE; + } + + count = g_slist_length (mods); + + /* count + 1 to leave slot 0 for the main module */ + *needed = sizeof(gpointer) * (count + 1); + + /* + * Use the NULL shortcut, as the first line in + * /proc//maps isn't the executable, and we need + * that first in the returned list. Check the module name + * to see if it ends with the proc name and substitute + * the first entry with it. FIXME if this turns out to + * be a problem. + */ + modules[0] = NULL; + for (i = 0; i < (avail - 1) && i < count; i++) { + module = (MonoW32ProcessModule *)g_slist_nth_data (mods, i); + if (modules[0] != NULL) + modules[i] = module->address_start; + else if (match_procname_to_modulename (proc_name, module->filename)) + modules[0] = module->address_start; + else + modules[i + 1] = module->address_start; + } + + for (i = 0; i < count; i++) { + mono_w32process_module_free ((MonoW32ProcessModule *)g_slist_nth_data (mods, i)); + } + g_slist_free (mods); + g_free (proc_name); + + return TRUE; +} + +guint32 +mono_w32process_module_get_filename (gpointer process, gpointer module, gunichar2 *basename, guint32 size) +{ + gint pid, len; + gsize bytes; + gchar *path; + gunichar2 *proc_path; + + size *= sizeof (gunichar2); /* adjust for unicode characters */ + + if (basename == NULL || size == 0) + return 0; + + pid = mono_w32process_get_pid (process); + + path = mono_w32process_get_path (pid); + if (path == NULL) + return 0; + + proc_path = mono_unicode_from_external (path, &bytes); + g_free (path); + + if (proc_path == NULL) + return 0; + + len = (bytes / 2); + + /* Add the terminator */ + bytes += 2; + + if (size < bytes) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Size %d smaller than needed (%ld); truncating", __func__, size, bytes); + memcpy (basename, proc_path, size); + } else { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Size %d larger than needed (%ld)", __func__, size, bytes); + memcpy (basename, proc_path, bytes); + } + + g_free (proc_path); + + return len; +} + +guint32 +mono_w32process_module_get_name (gpointer process, gpointer module, gunichar2 *basename, guint32 size) +{ + MonoW32HandleProcess *process_handle; + pid_t pid; + gunichar2 *procname; + char *procname_ext = NULL; + glong len; + gsize bytes; + GSList *mods = NULL; + MonoW32ProcessModule *found_module; + guint32 count; + int i; + char *proc_name = NULL; + gboolean res; + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Getting module base name, process handle %p module %p", + __func__, process, module); + + size = size * sizeof (gunichar2); /* adjust for unicode characters */ + + if (basename == NULL || size == 0) + return 0; + + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) { + /* This is a pseudo handle */ + pid = (pid_t)WAPI_HANDLE_TO_PID (process); + proc_name = mono_w32process_get_name (pid); + } else { + res = mono_w32handle_lookup (process, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); + if (!res) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, process); + return 0; + } + + pid = process_handle->id; + proc_name = g_strdup (process_handle->proc_name); + } + + mods = mono_w32process_get_modules (pid); + if (!mods) { + g_free (proc_name); + return 0; + } + + count = g_slist_length (mods); + + /* If module != NULL compare the address. + * If module == NULL we are looking for the main module. + * The best we can do for now check it the module name end with the process name. + */ + for (i = 0; i < count; i++) { + found_module = (MonoW32ProcessModule *)g_slist_nth_data (mods, i); + if (procname_ext == NULL && + ((module == NULL && match_procname_to_modulename (proc_name, found_module->filename)) || + (module != NULL && found_module->address_start == module))) { + procname_ext = g_path_get_basename (found_module->filename); + } + + mono_w32process_module_free (found_module); + } + + if (procname_ext == NULL) { + /* If it's *still* null, we might have hit the + * case where reading /proc/$pid/maps gives an + * empty file for this user. + */ + procname_ext = mono_w32process_get_name (pid); + } + + g_slist_free (mods); + g_free (proc_name); + + if (procname_ext) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Process name is [%s]", __func__, + procname_ext); + + procname = mono_unicode_from_external (procname_ext, &bytes); + if (procname == NULL) { + /* bugger */ + g_free (procname_ext); + return 0; + } + + len = (bytes / 2); + + /* Add the terminator */ + bytes += 2; + + if (size < bytes) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Size %d smaller than needed (%ld); truncating", __func__, size, bytes); + + memcpy (basename, procname, size); + } else { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Size %d larger than needed (%ld)", + __func__, size, bytes); + + memcpy (basename, procname, bytes); + } + + g_free (procname); + g_free (procname_ext); + + return len; + } + + return 0; +} + +gboolean +mono_w32process_module_get_information (gpointer process, gpointer module, WapiModuleInfo *modinfo, guint32 size) +{ + MonoW32HandleProcess *process_handle; + pid_t pid; + GSList *mods = NULL; + MonoW32ProcessModule *found_module; + guint32 count; + int i; + gboolean ret = FALSE; + char *proc_name = NULL; + gboolean res; + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Getting module info, process handle %p module %p", + __func__, process, module); + + if (modinfo == NULL || size < sizeof (WapiModuleInfo)) + return FALSE; + + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) { + pid = (pid_t)WAPI_HANDLE_TO_PID (process); + proc_name = mono_w32process_get_name (pid); + } else { + res = mono_w32handle_lookup (process, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); + if (!res) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, process); + return FALSE; + } + + pid = process_handle->id; + proc_name = g_strdup (process_handle->proc_name); + } + + mods = mono_w32process_get_modules (pid); + if (!mods) { + g_free (proc_name); + return FALSE; + } + + count = g_slist_length (mods); + + /* If module != NULL compare the address. + * If module == NULL we are looking for the main module. + * The best we can do for now check it the module name end with the process name. + */ + for (i = 0; i < count; i++) { + found_module = (MonoW32ProcessModule *)g_slist_nth_data (mods, i); + if (ret == FALSE && + ((module == NULL && match_procname_to_modulename (proc_name, found_module->filename)) || + (module != NULL && found_module->address_start == module))) { + modinfo->lpBaseOfDll = found_module->address_start; + modinfo->SizeOfImage = (gsize)(found_module->address_end) - (gsize)(found_module->address_start); + modinfo->EntryPoint = found_module->address_offset; + ret = TRUE; + } + + mono_w32process_module_free (found_module); + } + + g_slist_free (mods); + g_free (proc_name); + + return ret; +} + +static void +switch_dir_separators (char *path) +{ + size_t i, pathLength = strlen(path); + + /* Turn all the slashes round the right way, except for \' */ + /* There are probably other characters that need to be excluded as well. */ + for (i = 0; i < pathLength; i++) { + if (path[i] == '\\' && i < pathLength - 1 && path[i+1] != '\'' ) + path[i] = '/'; + } +} + +#if HAVE_SIGACTION + +MONO_SIGNAL_HANDLER_FUNC (static, mono_sigchld_signal_handler, (int _dummy, siginfo_t *info, void *context)) +{ + int status; + int pid; + MonoProcess *p; + + do { + do { + pid = waitpid (-1, &status, WNOHANG); + } while (pid == -1 && errno == EINTR); + + if (pid <= 0) + break; + + /* + * This can run concurrently with the code in the rest of this module. + */ + for (p = mono_processes; p; p = p->next) { + if (p->pid == pid) { + break; + } + } + if (p) { + p->pid = 0; /* this pid doesn't exist anymore, clear it */ + p->status = status; + mono_os_sem_post (&p->exit_sem); + mono_memory_barrier (); + /* Mark this as freeable, the pointer becomes invalid afterwards */ + p->freeable = TRUE; + } + } while (1); +} + +static void +process_add_sigchld_handler (void) +{ + struct sigaction sa; + + sa.sa_sigaction = mono_sigchld_signal_handler; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_NOCLDSTOP | SA_SIGINFO; + g_assert (sigaction (SIGCHLD, &sa, NULL) != -1); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "Added SIGCHLD handler"); +} + +#endif + +static gboolean +is_readable_or_executable (const char *prog) +{ + struct stat buf; + int a = access (prog, R_OK); + int b = access (prog, X_OK); + if (a != 0 && b != 0) + return FALSE; + if (stat (prog, &buf)) + return FALSE; + if (S_ISREG (buf.st_mode)) + return TRUE; + return FALSE; +} + +static gboolean +is_executable (const char *prog) +{ + struct stat buf; + if (access (prog, X_OK) != 0) + return FALSE; + if (stat (prog, &buf)) + return FALSE; + if (S_ISREG (buf.st_mode)) + return TRUE; + return FALSE; +} + +static gboolean +is_managed_binary (const char *filename) +{ + int original_errno = errno; +#if defined(HAVE_LARGE_FILE_SUPPORT) && defined(O_LARGEFILE) + int file = open (filename, O_RDONLY | O_LARGEFILE); +#else + int file = open (filename, O_RDONLY); +#endif + off_t new_offset; + unsigned char buffer[8]; + off_t file_size, optional_header_offset; + off_t pe_header_offset, clr_header_offset; + gboolean managed = FALSE; + int num_read; + guint32 first_word, second_word, magic_number; + + /* If we are unable to open the file, then we definitely + * can't say that it is managed. The child mono process + * probably wouldn't be able to open it anyway. + */ + if (file < 0) { + errno = original_errno; + return FALSE; + } + + /* Retrieve the length of the file for future sanity checks. */ + file_size = lseek (file, 0, SEEK_END); + lseek (file, 0, SEEK_SET); + + /* We know we need to read a header field at offset 60. */ + if (file_size < 64) + goto leave; + + num_read = read (file, buffer, 2); + + if ((num_read != 2) || (buffer[0] != 'M') || (buffer[1] != 'Z')) + goto leave; + + new_offset = lseek (file, 60, SEEK_SET); + + if (new_offset != 60) + goto leave; + + num_read = read (file, buffer, 4); + + if (num_read != 4) + goto leave; + pe_header_offset = buffer[0] + | (buffer[1] << 8) + | (buffer[2] << 16) + | (buffer[3] << 24); + + if (pe_header_offset + 24 > file_size) + goto leave; + + new_offset = lseek (file, pe_header_offset, SEEK_SET); + + if (new_offset != pe_header_offset) + goto leave; + + num_read = read (file, buffer, 4); + + if ((num_read != 4) || (buffer[0] != 'P') || (buffer[1] != 'E') || (buffer[2] != 0) || (buffer[3] != 0)) + goto leave; + + /* + * Verify that the header we want in the optional header data + * is present in this binary. + */ + new_offset = lseek (file, pe_header_offset + 20, SEEK_SET); + + if (new_offset != pe_header_offset + 20) + goto leave; + + num_read = read (file, buffer, 2); + + if ((num_read != 2) || ((buffer[0] | (buffer[1] << 8)) < 216)) + goto leave; + + optional_header_offset = pe_header_offset + 24; + + /* Read the PE magic number */ + new_offset = lseek (file, optional_header_offset, SEEK_SET); + + if (new_offset != optional_header_offset) + goto leave; + + num_read = read (file, buffer, 2); + + if (num_read != 2) + goto leave; + + magic_number = (buffer[0] | (buffer[1] << 8)); + + if (magic_number == 0x10B) // PE32 + clr_header_offset = 208; + else if (magic_number == 0x20B) // PE32+ + clr_header_offset = 224; + else + goto leave; + + /* Read the CLR header address and size fields. These will be + * zero if the binary is not managed. + */ + new_offset = lseek (file, optional_header_offset + clr_header_offset, SEEK_SET); + + if (new_offset != optional_header_offset + clr_header_offset) + goto leave; + + num_read = read (file, buffer, 8); + + /* We are not concerned with endianness, only with + * whether it is zero or not. + */ + first_word = *(guint32 *)&buffer[0]; + second_word = *(guint32 *)&buffer[4]; + + if ((num_read != 8) || (first_word == 0) || (second_word == 0)) + goto leave; + + managed = TRUE; + +leave: + close (file); + errno = original_errno; + return managed; +} + +static gboolean +process_create (const gunichar2 *appname, const gunichar2 *cmdline, gpointer new_environ, + const gunichar2 *cwd, StartupHandles *startup_handles, MonoW32ProcessInfo *process_info) +{ +#if defined (HAVE_FORK) && defined (HAVE_EXECVE) + char *cmd = NULL, *prog = NULL, *full_prog = NULL, *args = NULL, *args_after_prog = NULL; + char *dir = NULL, **env_strings = NULL, **argv = NULL; + guint32 i, env_count = 0; + gboolean ret = FALSE; + gpointer handle = NULL; + MonoW32HandleProcess process_handle = {0}, *process_handle_data; + GError *gerr = NULL; + int in_fd, out_fd, err_fd; + pid_t pid = 0; + int startup_pipe [2] = {-1, -1}; + int dummy; + MonoProcess *mono_process; + gboolean fork_failed = FALSE; + gboolean res; + +#if HAVE_SIGACTION + mono_lazy_initialize (&process_sig_chld_once, process_add_sigchld_handler); +#endif + + /* appname and cmdline specify the executable and its args: + * + * If appname is not NULL, it is the name of the executable. + * Otherwise the executable is the first token in cmdline. + * + * Executable searching: + * + * If appname is not NULL, it can specify the full path and + * file name, or else a partial name and the current directory + * will be used. There is no additional searching. + * + * If appname is NULL, the first whitespace-delimited token in + * cmdline is used. If the name does not contain a full + * directory path, the search sequence is: + * + * 1) The directory containing the current process + * 2) The current working directory + * 3) The windows system directory (Ignored) + * 4) The windows directory (Ignored) + * 5) $PATH + * + * Just to make things more interesting, tokens can contain + * white space if they are surrounded by quotation marks. I'm + * beginning to understand just why windows apps are generally + * so crap, with an API like this :-( + */ + if (appname != NULL) { + cmd = mono_unicode_to_external (appname); + if (cmd == NULL) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", + __func__); + + SetLastError (ERROR_PATH_NOT_FOUND); + goto free_strings; + } + + switch_dir_separators(cmd); + } + + if (cmdline != NULL) { + args = mono_unicode_to_external (cmdline); + if (args == NULL) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__); + + SetLastError (ERROR_PATH_NOT_FOUND); + goto free_strings; + } + } + + if (cwd != NULL) { + dir = mono_unicode_to_external (cwd); + if (dir == NULL) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__); + + SetLastError (ERROR_PATH_NOT_FOUND); + goto free_strings; + } + + /* Turn all the slashes round the right way */ + switch_dir_separators(dir); + } + + + /* We can't put off locating the executable any longer :-( */ + if (cmd != NULL) { + char *unquoted; + if (g_ascii_isalpha (cmd[0]) && (cmd[1] == ':')) { + /* Strip off the drive letter. I can't + * believe that CP/M holdover is still + * visible... + */ + g_memmove (cmd, cmd+2, strlen (cmd)-2); + cmd[strlen (cmd)-2] = '\0'; + } + + unquoted = g_shell_unquote (cmd, NULL); + if (unquoted[0] == '/') { + /* Assume full path given */ + prog = g_strdup (unquoted); + + /* Executable existing ? */ + if (!is_readable_or_executable (prog)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Couldn't find executable %s", + __func__, prog); + g_free (unquoted); + SetLastError (ERROR_FILE_NOT_FOUND); + goto free_strings; + } + } else { + /* Search for file named by cmd in the current + * directory + */ + char *curdir = g_get_current_dir (); + + prog = g_strdup_printf ("%s/%s", curdir, unquoted); + g_free (curdir); + + /* And make sure it's readable */ + if (!is_readable_or_executable (prog)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Couldn't find executable %s", + __func__, prog); + g_free (unquoted); + SetLastError (ERROR_FILE_NOT_FOUND); + goto free_strings; + } + } + g_free (unquoted); + + args_after_prog = args; + } else { + char *token = NULL; + char quote; + + /* Dig out the first token from args, taking quotation + * marks into account + */ + + /* First, strip off all leading whitespace */ + args = g_strchug (args); + + /* args_after_prog points to the contents of args + * after token has been set (otherwise argv[0] is + * duplicated) + */ + args_after_prog = args; + + /* Assume the opening quote will always be the first + * character + */ + if (args[0] == '\"' || args [0] == '\'') { + quote = args [0]; + for (i = 1; args[i] != '\0' && args[i] != quote; i++); + if (args [i + 1] == '\0' || g_ascii_isspace (args[i+1])) { + /* We found the first token */ + token = g_strndup (args+1, i-1); + args_after_prog = g_strchug (args + i + 1); + } else { + /* Quotation mark appeared in the + * middle of the token. Just give the + * whole first token, quotes and all, + * to exec. + */ + } + } + + if (token == NULL) { + /* No quote mark, or malformed */ + for (i = 0; args[i] != '\0'; i++) { + if (g_ascii_isspace (args[i])) { + token = g_strndup (args, i); + args_after_prog = args + i + 1; + break; + } + } + } + + if (token == NULL && args[0] != '\0') { + /* Must be just one token in the string */ + token = g_strdup (args); + args_after_prog = NULL; + } + + if (token == NULL) { + /* Give up */ + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Couldn't find what to exec", __func__); + + SetLastError (ERROR_PATH_NOT_FOUND); + goto free_strings; + } + + /* Turn all the slashes round the right way. Only for + * the prg. name + */ + switch_dir_separators(token); + + if (g_ascii_isalpha (token[0]) && (token[1] == ':')) { + /* Strip off the drive letter. I can't + * believe that CP/M holdover is still + * visible... + */ + g_memmove (token, token+2, strlen (token)-2); + token[strlen (token)-2] = '\0'; + } + + if (token[0] == '/') { + /* Assume full path given */ + prog = g_strdup (token); + + /* Executable existing ? */ + if (!is_readable_or_executable (prog)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Couldn't find executable %s", + __func__, token); + g_free (token); + SetLastError (ERROR_FILE_NOT_FOUND); + goto free_strings; + } + } else { + char *curdir = g_get_current_dir (); + + /* FIXME: Need to record the directory + * containing the current process, and check + * that for the new executable as the first + * place to look + */ + + prog = g_strdup_printf ("%s/%s", curdir, token); + g_free (curdir); + + /* I assume X_OK is the criterion to use, + * rather than F_OK + * + * X_OK is too strict *if* the target is a CLR binary + */ + if (!is_readable_or_executable (prog)) { + g_free (prog); + prog = g_find_program_in_path (token); + if (prog == NULL) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Couldn't find executable %s", __func__, token); + + g_free (token); + SetLastError (ERROR_FILE_NOT_FOUND); + goto free_strings; + } + } + } + + g_free (token); + } + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Exec prog [%s] args [%s]", + __func__, prog, args_after_prog); + + /* Check for CLR binaries; if found, we will try to invoke + * them using the same mono binary that started us. + */ + if (is_managed_binary (prog)) { + gunichar2 *newapp, *newcmd; + gsize bytes_ignored; + + newapp = mono_unicode_from_external (cli_launcher ? cli_launcher : "mono", &bytes_ignored); + if (newapp) { + if (appname) + newcmd = utf16_concat (utf16_quote, newapp, utf16_quote, utf16_space, appname, utf16_space, cmdline, NULL); + else + newcmd = utf16_concat (utf16_quote, newapp, utf16_quote, utf16_space, cmdline, NULL); + + g_free (newapp); + + if (newcmd) { + ret = process_create (NULL, newcmd, new_environ, cwd, startup_handles, process_info); + + g_free (newcmd); + + goto free_strings; + } + } + } else { + if (!is_executable (prog)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Executable permisson not set on %s", __func__, prog); + SetLastError (ERROR_ACCESS_DENIED); + goto free_strings; + } + } + + if (args_after_prog != NULL && *args_after_prog) { + char *qprog; + + qprog = g_shell_quote (prog); + full_prog = g_strconcat (qprog, " ", args_after_prog, NULL); + g_free (qprog); + } else { + full_prog = g_shell_quote (prog); + } + + ret = g_shell_parse_argv (full_prog, NULL, &argv, &gerr); + if (ret == FALSE) { + g_message ("process_create: %s\n", gerr->message); + g_error_free (gerr); + gerr = NULL; + goto free_strings; + } + + if (startup_handles) { + in_fd = GPOINTER_TO_UINT (startup_handles->input); + out_fd = GPOINTER_TO_UINT (startup_handles->output); + err_fd = GPOINTER_TO_UINT (startup_handles->error); + } else { + in_fd = GPOINTER_TO_UINT (GetStdHandle (STD_INPUT_HANDLE)); + out_fd = GPOINTER_TO_UINT (GetStdHandle (STD_OUTPUT_HANDLE)); + err_fd = GPOINTER_TO_UINT (GetStdHandle (STD_ERROR_HANDLE)); + } + + process_handle.proc_name = g_strdup (prog); + + process_set_defaults (&process_handle); + + handle = mono_w32handle_new (MONO_W32HANDLE_PROCESS, &process_handle); + if (handle == INVALID_HANDLE_VALUE) { + g_warning ("%s: error creating process handle", __func__); + + ret = FALSE; + SetLastError (ERROR_OUTOFMEMORY); + goto free_strings; + } + + /* new_environ is a block of NULL-terminated strings, which + * is itself NULL-terminated. Of course, passing an array of + * string pointers would have made things too easy :-( + * + * If new_environ is not NULL it specifies the entire set of + * environment variables in the new process. Otherwise the + * new process inherits the same environment. + */ + if (new_environ) { + gunichar2 *new_environp; + + /* Count the number of strings */ + for (new_environp = (gunichar2 *)new_environ; *new_environp; new_environp++) { + env_count++; + while (*new_environp) + new_environp++; + } + + /* +2: one for the process handle value, and the last + * one is NULL + */ + env_strings = g_new0 (char *, env_count + 2); + + /* Copy each environ string into 'strings' turning it + * into utf8 (or the requested encoding) at the same + * time + */ + env_count = 0; + for (new_environp = (gunichar2 *)new_environ; *new_environp; new_environp++) { + env_strings[env_count] = mono_unicode_to_external (new_environp); + env_count++; + while (*new_environp) { + new_environp++; + } + } + } else { + for (i = 0; environ[i] != NULL; i++) + env_count++; + + /* +2: one for the process handle value, and the last + * one is NULL + */ + env_strings = g_new0 (char *, env_count + 2); + + /* Copy each environ string into 'strings' turning it + * into utf8 (or the requested encoding) at the same + * time + */ + env_count = 0; + for (i = 0; environ[i] != NULL; i++) { + env_strings[env_count] = g_strdup (environ[i]); + env_count++; + } + } + + /* Create a pipe to make sure the child doesn't exit before + * we can add the process to the linked list of mono_processes */ + if (pipe (startup_pipe) == -1) { + /* Could not create the pipe to synchroniz process startup. We'll just not synchronize. + * This is just for a very hard to hit race condition in the first place */ + startup_pipe [0] = startup_pipe [1] = -1; + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: new process startup not synchronized. We may not notice if the newly created process exits immediately.", __func__); + } + + switch (pid = fork ()) { + case -1: /* Error */ { + SetLastError (ERROR_OUTOFMEMORY); + ret = FALSE; + fork_failed = TRUE; + break; + } + case 0: /* Child */ { + if (startup_pipe [0] != -1) { + /* Wait until the parent has updated it's internal data */ + ssize_t _i G_GNUC_UNUSED = read (startup_pipe [0], &dummy, 1); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: child: parent has completed its setup", __func__); + close (startup_pipe [0]); + close (startup_pipe [1]); + } + + /* should we detach from the process group? */ + + /* Connect stdin, stdout and stderr */ + dup2 (in_fd, 0); + dup2 (out_fd, 1); + dup2 (err_fd, 2); + + /* Close all file descriptors */ + for (i = mono_w32handle_fd_reserve - 1; i > 2; i--) + close (i); + +#ifdef DEBUG_ENABLED + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: exec()ing [%s] in dir [%s]", __func__, cmd, + dir == NULL?".":dir); + for (i = 0; argv[i] != NULL; i++) + g_message ("arg %d: [%s]", i, argv[i]); + + for (i = 0; env_strings[i] != NULL; i++) + g_message ("env %d: [%s]", i, env_strings[i]); +#endif + + /* set cwd */ + if (dir != NULL && chdir (dir) == -1) { + /* set error */ + _exit (-1); + } + + /* exec */ + execve (argv[0], argv, env_strings); + + /* set error */ + _exit (-1); + + break; + } + default: /* Parent */ { + res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle_data); + if (!res) { + g_warning ("%s: error looking up process handle %p", __func__, handle); + mono_w32handle_unref (handle); + } else { + process_handle_data->id = pid; + + /* Add our mono_process into the linked list of mono_processes */ + mono_process = (MonoProcess *) g_malloc0 (sizeof (MonoProcess)); + mono_process->pid = pid; + mono_process->handle_count = 1; + mono_os_sem_init (&mono_process->exit_sem, 0); + + /* Keep the process handle artificially alive until the process + * exits so that the information in the handle isn't lost. */ + mono_w32handle_ref (handle); + mono_process->handle = handle; + + process_handle_data->mono_process = mono_process; + + mono_os_mutex_lock (&mono_processes_mutex); + mono_process->next = mono_processes; + mono_processes = mono_process; + mono_os_mutex_unlock (&mono_processes_mutex); + + if (process_info != NULL) { + process_info->process_handle = handle; + process_info->pid = pid; + + /* FIXME: we might need to handle the thread info some day */ + process_info->thread_handle = INVALID_HANDLE_VALUE; + process_info->tid = 0; + } + } + + break; + } + } + + if (fork_failed) + mono_w32handle_unref (handle); + + if (startup_pipe [1] != -1) { + /* Write 1 byte, doesn't matter what */ + ssize_t _i G_GNUC_UNUSED = write (startup_pipe [1], startup_pipe, 1); + close (startup_pipe [0]); + close (startup_pipe [1]); + } + +free_strings: + if (cmd) + g_free (cmd); + if (full_prog) + g_free (full_prog); + if (prog) + g_free (prog); + if (args) + g_free (args); + if (dir) + g_free (dir); + if (env_strings) + g_strfreev (env_strings); + if (argv) + g_strfreev (argv); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning handle %p for pid %d", __func__, handle, pid); + + /* Check if something needs to be cleaned up. */ + processes_cleanup (); + + return ret; +#else + SetLastError (ERROR_NOT_SUPPORTED); + return FALSE; +#endif // defined (HAVE_FORK) && defined (HAVE_EXECVE) +} + +MonoBoolean +ves_icall_System_Diagnostics_Process_ShellExecuteEx_internal (MonoW32ProcessStartInfo *proc_start_info, MonoW32ProcessInfo *process_info) +{ + const gunichar2 *lpFile; + const gunichar2 *lpParameters; + const gunichar2 *lpDirectory; + gunichar2 *args; + gboolean ret; + + if (!proc_start_info->filename) { + /* w2k returns TRUE for this, for some reason. */ + ret = TRUE; + goto done; + } + + lpFile = proc_start_info->filename ? mono_string_chars (proc_start_info->filename) : NULL; + lpParameters = proc_start_info->arguments ? mono_string_chars (proc_start_info->arguments) : NULL; + lpDirectory = proc_start_info->working_directory && mono_string_length (proc_start_info->working_directory) != 0 ? + mono_string_chars (proc_start_info->working_directory) : NULL; + + /* Put both executable and parameters into the second argument + * to process_create (), so it searches $PATH. The conversion + * into and back out of utf8 is because there is no + * g_strdup_printf () equivalent for gunichar2 :-( + */ + args = utf16_concat (utf16_quote, lpFile, utf16_quote, lpParameters == NULL ? NULL : utf16_space, lpParameters, NULL); + if (args == NULL) { + SetLastError (ERROR_INVALID_DATA); + ret = FALSE; + goto done; + } + ret = process_create (NULL, args, NULL, lpDirectory, NULL, process_info); + g_free (args); + + if (!ret && GetLastError () == ERROR_OUTOFMEMORY) + goto done; + + if (!ret) { + static char *handler; + static gunichar2 *handler_utf16; + + if (handler_utf16 == (gunichar2 *)-1) { + ret = FALSE; + goto done; + } + +#ifdef PLATFORM_MACOSX + handler = g_strdup ("/usr/bin/open"); +#else + /* + * On Linux, try: xdg-open, the FreeDesktop standard way of doing it, + * if that fails, try to use gnome-open, then kfmclient + */ + handler = g_find_program_in_path ("xdg-open"); + if (handler == NULL){ + handler = g_find_program_in_path ("gnome-open"); + if (handler == NULL){ + handler = g_find_program_in_path ("kfmclient"); + if (handler == NULL){ + handler_utf16 = (gunichar2 *) -1; + ret = FALSE; + goto done; + } else { + /* kfmclient needs exec argument */ + char *old = handler; + handler = g_strconcat (old, " exec", + NULL); + g_free (old); + } + } + } +#endif + handler_utf16 = g_utf8_to_utf16 (handler, -1, NULL, NULL, NULL); + g_free (handler); + + /* Put quotes around the filename, in case it's a url + * that contains #'s (process_create() calls + * g_shell_parse_argv(), which deliberately throws + * away anything after an unquoted #). Fixes bug + * 371567. + */ + args = utf16_concat (handler_utf16, utf16_space, utf16_quote, lpFile, utf16_quote, + lpParameters == NULL ? NULL : utf16_space, lpParameters, NULL); + if (args == NULL) { + SetLastError (ERROR_INVALID_DATA); + ret = FALSE; + goto done; + } + ret = process_create (NULL, args, NULL, lpDirectory, NULL, process_info); + g_free (args); + if (!ret) { + if (GetLastError () != ERROR_OUTOFMEMORY) + SetLastError (ERROR_INVALID_DATA); + ret = FALSE; + goto done; + } + /* Shell exec should not return a process handle when it spawned a GUI thing, like a browser. */ + CloseHandle (process_info->process_handle); + process_info->process_handle = NULL; + } + +done: + if (ret == FALSE) { + process_info->pid = -GetLastError (); + } else { + process_info->thread_handle = NULL; +#if !defined(MONO_CROSS_COMPILE) + process_info->pid = mono_w32process_get_pid (process_info->process_handle); +#else + process_info->pid = 0; +#endif + process_info->tid = 0; + } + + return ret; +} + +/* Only used when UseShellExecute is false */ +static gboolean +process_get_complete_path (const gunichar2 *appname, gchar **completed) +{ + gchar *utf8app; + gchar *found; + + utf8app = g_utf16_to_utf8 (appname, -1, NULL, NULL, NULL); + + if (g_path_is_absolute (utf8app)) { + *completed = g_shell_quote (utf8app); + g_free (utf8app); + return TRUE; + } + + if (g_file_test (utf8app, G_FILE_TEST_IS_EXECUTABLE) && !g_file_test (utf8app, G_FILE_TEST_IS_DIR)) { + *completed = g_shell_quote (utf8app); + g_free (utf8app); + return TRUE; + } + + found = g_find_program_in_path (utf8app); + if (found == NULL) { + *completed = NULL; + g_free (utf8app); + return FALSE; + } + + *completed = g_shell_quote (found); + g_free (found); + g_free (utf8app); + return TRUE; +} + +static gboolean +process_get_shell_arguments (MonoW32ProcessStartInfo *proc_start_info, gunichar2 **shell_path, MonoString **cmd) +{ + gchar *spath = NULL; + + *shell_path = NULL; + *cmd = proc_start_info->arguments; + + process_get_complete_path (mono_string_chars (proc_start_info->filename), &spath); + if (spath != NULL) { + *shell_path = g_utf8_to_utf16 (spath, -1, NULL, NULL, NULL); + g_free (spath); + } + + return (*shell_path != NULL) ? TRUE : FALSE; +} + +MonoBoolean +ves_icall_System_Diagnostics_Process_CreateProcess_internal (MonoW32ProcessStartInfo *proc_start_info, + HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle, MonoW32ProcessInfo *process_info) +{ + gboolean ret; + gunichar2 *dir; + StartupHandles startup_handles; + gunichar2 *shell_path = NULL; + gchar *env_vars = NULL; + MonoString *cmd = NULL; + + memset (&startup_handles, 0, sizeof (startup_handles)); + startup_handles.input = stdin_handle; + startup_handles.output = stdout_handle; + startup_handles.error = stderr_handle; + + if (process_get_shell_arguments (proc_start_info, &shell_path, &cmd) == FALSE) { + process_info->pid = -ERROR_FILE_NOT_FOUND; + return FALSE; + } + + if (process_info->env_keys) { + gint i, len; + MonoString *ms; + MonoString *key, *value; + gunichar2 *str, *ptr; + gunichar2 *equals16; + + for (len = 0, i = 0; i < mono_array_length (process_info->env_keys); i++) { + ms = mono_array_get (process_info->env_values, MonoString *, i); + if (ms == NULL) + continue; + + len += mono_string_length (ms) * sizeof (gunichar2); + ms = mono_array_get (process_info->env_keys, MonoString *, i); + len += mono_string_length (ms) * sizeof (gunichar2); + len += 2 * sizeof (gunichar2); + } + + equals16 = g_utf8_to_utf16 ("=", 1, NULL, NULL, NULL); + ptr = str = g_new0 (gunichar2, len + 1); + for (i = 0; i < mono_array_length (process_info->env_keys); i++) { + value = mono_array_get (process_info->env_values, MonoString *, i); + if (value == NULL) + continue; + + key = mono_array_get (process_info->env_keys, MonoString *, i); + memcpy (ptr, mono_string_chars (key), mono_string_length (key) * sizeof (gunichar2)); + ptr += mono_string_length (key); + + memcpy (ptr, equals16, sizeof (gunichar2)); + ptr++; + + memcpy (ptr, mono_string_chars (value), mono_string_length (value) * sizeof (gunichar2)); + ptr += mono_string_length (value); + ptr++; + } + + g_free (equals16); + env_vars = (gchar *) str; + } + + /* The default dir name is "". Turn that into NULL to mean "current directory" */ + dir = proc_start_info->working_directory && mono_string_length (proc_start_info->working_directory) > 0 ? + mono_string_chars (proc_start_info->working_directory) : NULL; + + ret = process_create (shell_path, cmd ? mono_string_chars (cmd): NULL, env_vars, dir, &startup_handles, process_info); + + g_free (env_vars); + if (shell_path != NULL) + g_free (shell_path); + + if (!ret) + process_info->pid = -GetLastError (); + + return ret; +} + +/* Returns an array of pids */ +MonoArray * +ves_icall_System_Diagnostics_Process_GetProcesses_internal (void) +{ + MonoError error; + MonoArray *procs; + gpointer *pidarray; + int i, count; + + pidarray = mono_process_list (&count); + if (!pidarray) { + mono_set_pending_exception (mono_get_exception_not_supported ("This system does not support EnumProcesses")); + return NULL; + } + procs = mono_array_new_checked (mono_domain_get (), mono_get_int32_class (), count, &error); + if (mono_error_set_pending_exception (&error)) { + g_free (pidarray); + return NULL; + } + if (sizeof (guint32) == sizeof (gpointer)) { + memcpy (mono_array_addr (procs, guint32, 0), pidarray, count * sizeof (gint32)); + } else { + for (i = 0; i < count; ++i) + *(mono_array_addr (procs, guint32, i)) = GPOINTER_TO_UINT (pidarray [i]); + } + g_free (pidarray); + + return procs; +} + +void +mono_w32process_set_cli_launcher (gchar *path) +{ + g_free (cli_launcher); + cli_launcher = g_strdup (path); +} + +gpointer +ves_icall_Microsoft_Win32_NativeMethods_GetCurrentProcess (void) +{ + mono_w32handle_ref (current_process); + return current_process; +} + +MonoBoolean +ves_icall_Microsoft_Win32_NativeMethods_GetExitCodeProcess (gpointer handle, gint32 *exitcode) +{ + MonoW32HandleProcess *process_handle; + guint32 pid; + gboolean res; + + if (!exitcode) + return FALSE; + + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)) { + pid = WAPI_HANDLE_TO_PID (handle); + /* This is a pseudo handle, so we don't know what the exit + * code was, but we can check whether it's alive or not */ + if (is_pid_valid (pid)) { + *exitcode = STILL_ACTIVE; + return TRUE; + } else { + *exitcode = -1; + return TRUE; + } + } + + res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); + if (!res) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, handle); + return FALSE; + } + + if (process_handle->id == wapi_getpid ()) { + *exitcode = STILL_ACTIVE; + return TRUE; + } + + /* A process handle is only signalled if the process has exited + * and has been waited for. Make sure any process exit has been + * noticed before checking if the process is signalled. + * Fixes bug 325463. */ + mono_w32handle_wait_one (handle, 0, TRUE); + + *exitcode = mono_w32handle_issignalled (handle) ? process_handle->exitstatus : STILL_ACTIVE; + return TRUE; +} + +MonoBoolean +ves_icall_Microsoft_Win32_NativeMethods_CloseProcess (gpointer handle) +{ + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)) + return TRUE; + return CloseHandle (handle); +} + +MonoBoolean +ves_icall_Microsoft_Win32_NativeMethods_TerminateProcess (gpointer handle, gint32 exitcode) +{ +#ifdef HAVE_KILL + MonoW32HandleProcess *process_handle; + int ret; + pid_t pid; + + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)) { + /* This is a pseudo handle */ + pid = (pid_t)WAPI_HANDLE_TO_PID (handle); + } else { + gboolean res; + + res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); + if (!res) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, handle); + SetLastError (ERROR_INVALID_HANDLE); + return FALSE; + } + + pid = process_handle->id; + } + + ret = kill (pid, exitcode == -1 ? SIGKILL : SIGTERM); + if (ret == 0) + return TRUE; + + switch (errno) { + case EINVAL: SetLastError (ERROR_INVALID_PARAMETER); break; + case EPERM: SetLastError (ERROR_ACCESS_DENIED); break; + case ESRCH: SetLastError (ERROR_PROC_NOT_FOUND); break; + default: SetLastError (ERROR_GEN_FAILURE); break; + } + + return FALSE; +#else + g_error ("kill() is not supported by this platform"); +#endif +} + +MonoBoolean +ves_icall_Microsoft_Win32_NativeMethods_GetProcessWorkingSetSize (gpointer handle, gsize *min, gsize *max) +{ + MonoW32HandleProcess *process_handle; + gboolean res; + + if (!min || !max) + return FALSE; + + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)) + return FALSE; + + res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); + if (!res) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, handle); + return FALSE; + } + + *min = process_handle->min_working_set; + *max = process_handle->max_working_set; + return TRUE; +} + +MonoBoolean +ves_icall_Microsoft_Win32_NativeMethods_SetProcessWorkingSetSize (gpointer handle, gsize min, gsize max) +{ + MonoW32HandleProcess *process_handle; + gboolean res; + + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)) + return FALSE; + + res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); + if (!res) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, handle); + return FALSE; + } + + process_handle->min_working_set = min; + process_handle->max_working_set = max; + return TRUE; +} + +gint32 +ves_icall_Microsoft_Win32_NativeMethods_GetPriorityClass (gpointer handle) +{ +#ifdef HAVE_GETPRIORITY + MonoW32HandleProcess *process_handle; + gint ret; + pid_t pid; + + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)) { + /* This is a pseudo handle */ + pid = (pid_t)WAPI_HANDLE_TO_PID (handle); + } else { + gboolean res; + + res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); + if (!res) { + SetLastError (ERROR_INVALID_HANDLE); + return 0; + } + + pid = process_handle->id; + } + + errno = 0; + ret = getpriority (PRIO_PROCESS, pid); + if (ret == -1 && errno != 0) { + switch (errno) { + case EPERM: + case EACCES: + SetLastError (ERROR_ACCESS_DENIED); + break; + case ESRCH: + SetLastError (ERROR_PROC_NOT_FOUND); + break; + default: + SetLastError (ERROR_GEN_FAILURE); + } + return 0; + } + + if (ret == 0) + return MONO_W32PROCESS_PRIORITY_CLASS_NORMAL; + else if (ret < -15) + return MONO_W32PROCESS_PRIORITY_CLASS_REALTIME; + else if (ret < -10) + return MONO_W32PROCESS_PRIORITY_CLASS_HIGH; + else if (ret < 0) + return MONO_W32PROCESS_PRIORITY_CLASS_ABOVE_NORMAL; + else if (ret > 10) + return MONO_W32PROCESS_PRIORITY_CLASS_IDLE; + else if (ret > 0) + return MONO_W32PROCESS_PRIORITY_CLASS_BELOW_NORMAL; + + return MONO_W32PROCESS_PRIORITY_CLASS_NORMAL; +#else + SetLastError (ERROR_NOT_SUPPORTED); + return 0; +#endif +} + +MonoBoolean +ves_icall_Microsoft_Win32_NativeMethods_SetPriorityClass (gpointer handle, gint32 priorityClass) +{ +#ifdef HAVE_SETPRIORITY + MonoW32HandleProcess *process_handle; + int ret; + int prio; + pid_t pid; + + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)) { + /* This is a pseudo handle */ + pid = (pid_t)WAPI_HANDLE_TO_PID (handle); + } else { + gboolean res; + + res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); + if (!res) { + SetLastError (ERROR_INVALID_HANDLE); + return FALSE; + } + + pid = process_handle->id; + } + + switch (priorityClass) { + case MONO_W32PROCESS_PRIORITY_CLASS_IDLE: + prio = 19; + break; + case MONO_W32PROCESS_PRIORITY_CLASS_BELOW_NORMAL: + prio = 10; + break; + case MONO_W32PROCESS_PRIORITY_CLASS_NORMAL: + prio = 0; + break; + case MONO_W32PROCESS_PRIORITY_CLASS_ABOVE_NORMAL: + prio = -5; + break; + case MONO_W32PROCESS_PRIORITY_CLASS_HIGH: + prio = -11; + break; + case MONO_W32PROCESS_PRIORITY_CLASS_REALTIME: + prio = -20; + break; + default: + SetLastError (ERROR_INVALID_PARAMETER); + return FALSE; + } + + ret = setpriority (PRIO_PROCESS, pid, prio); + if (ret == -1) { + switch (errno) { + case EPERM: + case EACCES: + SetLastError (ERROR_ACCESS_DENIED); + break; + case ESRCH: + SetLastError (ERROR_PROC_NOT_FOUND); + break; + default: + SetLastError (ERROR_GEN_FAILURE); + } + } + + return ret == 0; +#else + SetLastError (ERROR_NOT_SUPPORTED); + return FALSE; +#endif +} + +static void +ticks_to_processtime (guint64 ticks, ProcessTime *processtime) +{ + processtime->lowDateTime = ticks & 0xFFFFFFFF; + processtime->highDateTime = ticks >> 32; +} + +static void +wapifiletime_to_processtime (WapiFileTime wapi_filetime, ProcessTime *processtime) +{ + processtime->lowDateTime = wapi_filetime.dwLowDateTime; + processtime->highDateTime = wapi_filetime.dwHighDateTime; +} + +MonoBoolean +ves_icall_Microsoft_Win32_NativeMethods_GetProcessTimes (gpointer handle, gint64 *creation_time, gint64 *exit_time, gint64 *kernel_time, gint64 *user_time) +{ + MonoW32HandleProcess *process_handle; + ProcessTime *creation_processtime, *exit_processtime, *kernel_processtime, *user_processtime; + gboolean res; + + if (!creation_time || !exit_time || !kernel_time || !user_time) { + /* Not sure if w32 allows NULLs here or not */ + return FALSE; + } + + creation_processtime = (ProcessTime*) creation_time; + exit_processtime = (ProcessTime*) exit_time; + kernel_processtime = (ProcessTime*) kernel_time; + user_processtime = (ProcessTime*) user_time; + + memset (creation_processtime, 0, sizeof (ProcessTime)); + memset (exit_processtime, 0, sizeof (ProcessTime)); + memset (kernel_processtime, 0, sizeof (ProcessTime)); + memset (user_processtime, 0, sizeof (ProcessTime)); + + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)) { + gint64 start_ticks, user_ticks, kernel_ticks; + + mono_process_get_times (GINT_TO_POINTER (WAPI_HANDLE_TO_PID (handle)), + &start_ticks, &user_ticks, &kernel_ticks); + + ticks_to_processtime (start_ticks, creation_processtime); + ticks_to_processtime (user_ticks, kernel_processtime); + ticks_to_processtime (kernel_ticks, user_processtime); + return TRUE; + } + + res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); + if (!res) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, handle); + return FALSE; + } + + wapifiletime_to_processtime (process_handle->create_time, creation_processtime); + + /* A process handle is only signalled if the process has + * exited, otherwise exit_processtime isn't set */ + if (mono_w32handle_issignalled (handle)) + wapifiletime_to_processtime (process_handle->exit_time, exit_processtime); + +#ifdef HAVE_GETRUSAGE + if (process_handle->id == getpid ()) { + struct rusage time_data; + if (getrusage (RUSAGE_SELF, &time_data) == 0) { + ticks_to_processtime ((guint64)time_data.ru_utime.tv_sec * 10000000 + (guint64)time_data.ru_utime.tv_usec * 10, user_processtime); + ticks_to_processtime ((guint64)time_data.ru_stime.tv_sec * 10000000 + (guint64)time_data.ru_stime.tv_usec * 10, kernel_processtime); + } + } +#endif + + return TRUE; +} diff --git a/mono/metadata/w32process-win32-internals.h b/mono/metadata/w32process-win32-internals.h new file mode 100644 index 00000000000..1699f957533 --- /dev/null +++ b/mono/metadata/w32process-win32-internals.h @@ -0,0 +1,40 @@ +/* + * Copyright 2016 Microsoft + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ +#ifndef __MONO_METADATA_PROCESS_INTERNALS_H__ +#define __MONO_METADATA_PROCESS_INTERNALS_H__ + +#include +#include + +// On platforms not using classic WIN API support the implementation of bellow methods are hosted in separate source file +// process-windows-*.c. On platforms using classic WIN API the implementation is still keept in process.c and still declared +// static and in some places even inlined. +#if !G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) +void +mono_w32process_get_fileversion (MonoObject *filever, gunichar2 *filename, MonoError *error); + +void +mono_process_init_startup_info (HANDLE stdin_handle, HANDLE stdout_handle, + HANDLE stderr_handle,STARTUPINFO *startinfo); + +gboolean +mono_process_create_process (MonoProcInfo *mono_process_info, gunichar2 *shell_path, MonoString *cmd, + guint32 creation_flags, gchar *env_vars, gunichar2 *dir, STARTUPINFO *start_info, + PROCESS_INFORMATION *process_info); + +MonoBoolean +mono_icall_get_process_working_set_size (gpointer handle, gsize *min, gsize *max); + +MonoBoolean +mono_icall_set_process_working_set_size (gpointer handle, gsize min, gsize max); + +gint32 +mono_icall_get_priority_class (gpointer handle); + +MonoBoolean +mono_icall_set_priority_class (gpointer handle, gint32 priorityClass); +#endif /* !G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ + +#endif /* __MONO_METADATA_PROCESS_INTERNALS_H__ */ diff --git a/mono/metadata/w32process-win32-uwp.c b/mono/metadata/w32process-win32-uwp.c new file mode 100644 index 00000000000..9fc329ad7a2 --- /dev/null +++ b/mono/metadata/w32process-win32-uwp.c @@ -0,0 +1,221 @@ +/* + * process-windows-uwp.c: UWP process support for Mono. + * + * Copyright 2016 Microsoft + * Licensed under the MIT license. See LICENSE file in the project root for full license information. +*/ +#include +#include + +#if G_HAVE_API_SUPPORT(HAVE_UWP_WINAPI_SUPPORT) +#include +#include "mono/metadata/w32process-win32-internals.h" + +gboolean +mono_process_win_enum_processes (DWORD *pids, DWORD count, DWORD *needed) +{ + g_unsupported_api ("EnumProcesses"); + *needed = 0; + SetLastError (ERROR_NOT_SUPPORTED); + + return FALSE; +} + +HANDLE +ves_icall_System_Diagnostics_Process_GetProcess_internal (guint32 pid) +{ + HANDLE handle; + + /* GetCurrentProcess returns a pseudo-handle, so use + * OpenProcess instead + */ + handle = OpenProcess (PROCESS_ALL_ACCESS, TRUE, pid); + if (handle == NULL) + /* FIXME: Throw an exception */ + return NULL; + return handle; +} + +void +mono_w32process_get_fileversion (MonoObject *filever, gunichar2 *filename, MonoError *error) +{ + g_unsupported_api ("GetFileVersionInfoSize, GetFileVersionInfo, VerQueryValue, VerLanguageName"); + + mono_error_init (error); + mono_error_set_not_supported (error, G_UNSUPPORTED_API, "GetFileVersionInfoSize, GetFileVersionInfo, VerQueryValue, VerLanguageName"); + + SetLastError (ERROR_NOT_SUPPORTED); +} + +MonoObject* +process_add_module (HANDLE process, HMODULE mod, gunichar2 *filename, gunichar2 *modulename, MonoClass *proc_class, MonoError *error) +{ + g_unsupported_api ("GetModuleInformation"); + + mono_error_init (error); + mono_error_set_not_supported (error, G_UNSUPPORTED_API, "GetModuleInformation"); + + SetLastError (ERROR_NOT_SUPPORTED); + + return NULL; +} + +MonoArray * +ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject *this_obj, HANDLE process) +{ + MonoError mono_error; + mono_error_init (&mono_error); + + g_unsupported_api ("EnumProcessModules, GetModuleBaseName, GetModuleFileNameEx"); + + mono_error_set_not_supported (&mono_error, G_UNSUPPORTED_API, "EnumProcessModules, GetModuleBaseName, GetModuleFileNameEx"); + mono_error_set_pending_exception (&mono_error); + + SetLastError (ERROR_NOT_SUPPORTED); + + return NULL; +} + +MonoBoolean +ves_icall_System_Diagnostics_Process_ShellExecuteEx_internal (MonoProcessStartInfo *proc_start_info, MonoProcInfo *process_info) +{ + MonoError mono_error; + mono_error_init (&mono_error); + + g_unsupported_api ("ShellExecuteEx"); + + mono_error_set_not_supported (&mono_error, G_UNSUPPORTED_API, "ShellExecuteEx"); + mono_error_set_pending_exception (&mono_error); + + process_info->pid = (guint32)(-ERROR_NOT_SUPPORTED); + SetLastError (ERROR_NOT_SUPPORTED); + + return FALSE; +} + +MonoString * +ves_icall_System_Diagnostics_Process_ProcessName_internal (HANDLE process) +{ + MonoError error; + MonoString *string; + gunichar2 name[MAX_PATH]; + guint32 len; + + len = GetModuleFileName (NULL, name, G_N_ELEMENTS (name)); + if (len == 0) + return NULL; + + string = mono_string_new_utf16_checked (mono_domain_get (), name, len, &error); + if (!mono_error_ok (&error)) + mono_error_set_pending_exception (&error); + + return string; +} + +void +mono_process_init_startup_info (HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle, STARTUPINFO *startinfo) +{ + startinfo->cb = sizeof(STARTUPINFO); + startinfo->dwFlags = 0; + startinfo->hStdInput = INVALID_HANDLE_VALUE; + startinfo->hStdOutput = INVALID_HANDLE_VALUE; + startinfo->hStdError = INVALID_HANDLE_VALUE; + return; +} + +gboolean +mono_process_create_process (MonoProcInfo *mono_process_info, gunichar2 *shell_path, MonoString *cmd, guint32 creation_flags, + gchar *env_vars, gunichar2 *dir, STARTUPINFO *start_info, PROCESS_INFORMATION *process_info) +{ + MonoError mono_error; + gchar *api_name = ""; + + if (mono_process_info->username) { + api_name = "CreateProcessWithLogonW"; + } else { + api_name = "CreateProcess"; + } + + memset (&process_info, 0, sizeof (PROCESS_INFORMATION)); + g_unsupported_api (api_name); + + mono_error_init (&mono_error); + mono_error_set_not_supported (&mono_error, G_UNSUPPORTED_API, api_name); + mono_error_set_pending_exception (&mono_error); + + SetLastError (ERROR_NOT_SUPPORTED); + + return FALSE; +} + +MonoBoolean +mono_icall_get_process_working_set_size (gpointer handle, gsize *min, gsize *max) +{ + MonoError mono_error; + mono_error_init (&mono_error); + + g_unsupported_api ("GetProcessWorkingSetSize"); + + mono_error_set_not_supported(&mono_error, G_UNSUPPORTED_API, "GetProcessWorkingSetSize"); + mono_error_set_pending_exception (&mono_error); + + SetLastError (ERROR_NOT_SUPPORTED); + + return FALSE; +} + +MonoBoolean +mono_icall_set_process_working_set_size (gpointer handle, gsize min, gsize max) +{ + MonoError mono_error; + mono_error_init (&mono_error); + + g_unsupported_api ("SetProcessWorkingSetSize"); + + mono_error_set_not_supported (&mono_error, G_UNSUPPORTED_API, "SetProcessWorkingSetSize"); + mono_error_set_pending_exception (&mono_error); + + SetLastError (ERROR_NOT_SUPPORTED); + + return FALSE; +} + +gint32 +mono_icall_get_priority_class (gpointer handle) +{ + MonoError mono_error; + mono_error_init (&mono_error); + + g_unsupported_api ("GetPriorityClass"); + + mono_error_set_not_supported (&mono_error, G_UNSUPPORTED_API, "GetPriorityClass"); + mono_error_set_pending_exception (&mono_error); + + SetLastError (ERROR_NOT_SUPPORTED); + + return FALSE; +} + +MonoBoolean +mono_icall_set_priority_class (gpointer handle, gint32 priorityClass) +{ + MonoError mono_error; + mono_error_init (&mono_error); + + g_unsupported_api ("SetPriorityClass"); + + mono_error_set_not_supported(&mono_error, G_UNSUPPORTED_API, "SetPriorityClass"); + mono_error_set_pending_exception (&mono_error); + + SetLastError (ERROR_NOT_SUPPORTED); + + return FALSE; +} + +#else /* G_HAVE_API_SUPPORT(HAVE_UWP_WINAPI_SUPPORT) */ + +#ifdef _MSC_VER +// Quiet Visual Studio linker warning, LNK4221, in cases when this source file intentional ends up empty. +void __mono_win32_process_windows_uwp_quiet_lnk4221(void) {} +#endif +#endif /* G_HAVE_API_SUPPORT(HAVE_UWP_WINAPI_SUPPORT) */ diff --git a/mono/metadata/w32process-win32.c b/mono/metadata/w32process-win32.c new file mode 100644 index 00000000000..15cfd4d61a2 --- /dev/null +++ b/mono/metadata/w32process-win32.c @@ -0,0 +1,500 @@ +/* + * process.c: System.Diagnostics.Process support + * + * Author: + * Dick Porter (dick@ximian.com) + * + * Copyright 2002 Ximian, Inc. + * Copyright 2002-2006 Novell, Inc. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* FIXME: fix this code to not depend so much on the internals */ +#include +#include + +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) +#include +#endif + +void +mono_w32process_init (void) +{ +} + +void +mono_w32process_cleanup (void) +{ +} + +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) +HANDLE +ves_icall_System_Diagnostics_Process_GetProcess_internal (guint32 pid) +{ + HANDLE handle; + + /* GetCurrentProcess returns a pseudo-handle, so use + * OpenProcess instead + */ + handle = OpenProcess (PROCESS_ALL_ACCESS, TRUE, pid); + if (handle == NULL) + /* FIXME: Throw an exception */ + return NULL; + return handle; +} +#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */ + +static gchar* +mono_process_unquote_application_name (gchar *appname) +{ + size_t len = strlen (appname); + if (len) { + if (appname[len-1] == '\"') + appname[len-1] = '\0'; + if (appname[0] == '\"') + appname++; + } + + return appname; +} + +static gchar* +mono_process_quote_path (const gchar *path) +{ + gchar *res = g_shell_quote (path); + gchar *q = res; + while (*q) { + if (*q == '\'') + *q = '\"'; + q++; + } + return res; +} + +/* Only used when UseShellExecute is false */ +static gboolean +mono_process_complete_path (const gunichar2 *appname, gchar **completed) +{ + gchar *utf8app, *utf8appmemory; + gchar *found; + + utf8appmemory = g_utf16_to_utf8 (appname, -1, NULL, NULL, NULL); + utf8app = mono_process_unquote_application_name (utf8appmemory); + + if (g_path_is_absolute (utf8app)) { + *completed = mono_process_quote_path (utf8app); + g_free (utf8appmemory); + return TRUE; + } + + if (g_file_test (utf8app, G_FILE_TEST_IS_EXECUTABLE) && !g_file_test (utf8app, G_FILE_TEST_IS_DIR)) { + *completed = mono_process_quote_path (utf8app); + g_free (utf8appmemory); + return TRUE; + } + + found = g_find_program_in_path (utf8app); + if (found == NULL) { + *completed = NULL; + g_free (utf8appmemory); + return FALSE; + } + + *completed = mono_process_quote_path (found); + g_free (found); + g_free (utf8appmemory); + return TRUE; +} + +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) +MonoBoolean +ves_icall_System_Diagnostics_Process_ShellExecuteEx_internal (MonoW32ProcessStartInfo *proc_start_info, MonoW32ProcessInfo *process_info) +{ + SHELLEXECUTEINFO shellex = {0}; + gboolean ret; + + shellex.cbSize = sizeof(SHELLEXECUTEINFO); + shellex.fMask = (gulong)(SEE_MASK_FLAG_DDEWAIT | SEE_MASK_NOCLOSEPROCESS | SEE_MASK_UNICODE); + shellex.nShow = (gulong)proc_start_info->window_style; + shellex.nShow = (gulong)((shellex.nShow == 0) ? 1 : (shellex.nShow == 1 ? 0 : shellex.nShow)); + + if (proc_start_info->filename != NULL) { + shellex.lpFile = mono_string_chars (proc_start_info->filename); + } + + if (proc_start_info->arguments != NULL) { + shellex.lpParameters = mono_string_chars (proc_start_info->arguments); + } + + if (proc_start_info->verb != NULL && + mono_string_length (proc_start_info->verb) != 0) { + shellex.lpVerb = mono_string_chars (proc_start_info->verb); + } + + if (proc_start_info->working_directory != NULL && + mono_string_length (proc_start_info->working_directory) != 0) { + shellex.lpDirectory = mono_string_chars (proc_start_info->working_directory); + } + + if (proc_start_info->error_dialog) { + shellex.hwnd = proc_start_info->error_dialog_parent_handle; + } else { + shellex.fMask = (gulong)(shellex.fMask | SEE_MASK_FLAG_NO_UI); + } + + ret = ShellExecuteEx (&shellex); + if (ret == FALSE) { + process_info->pid = -GetLastError (); + } else { + process_info->process_handle = shellex.hProcess; + process_info->thread_handle = NULL; +#if !defined(MONO_CROSS_COMPILE) + process_info->pid = GetProcessId (shellex.hProcess); +#else + process_info->pid = 0; +#endif + process_info->tid = 0; + } + + return ret; +} +#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ + +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) +static inline void +mono_process_init_startup_info (HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle, STARTUPINFO *startinfo) +{ + startinfo->cb = sizeof(STARTUPINFO); + startinfo->dwFlags = STARTF_USESTDHANDLES; + startinfo->hStdInput = stdin_handle; + startinfo->hStdOutput = stdout_handle; + startinfo->hStdError = stderr_handle; + return; +} +#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ + +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) +static gboolean +mono_process_create_process (MonoW32ProcessInfo *mono_process_info, gunichar2 *shell_path, + MonoString *cmd, guint32 creation_flags, gchar *env_vars, + gunichar2 *dir, STARTUPINFO *start_info, PROCESS_INFORMATION *process_info) +{ + gboolean result = FALSE; + + if (mono_process_info->username) { + guint32 logon_flags = mono_process_info->load_user_profile ? LOGON_WITH_PROFILE : 0; + + result = CreateProcessWithLogonW (mono_string_chars (mono_process_info->username), + mono_process_info->domain ? mono_string_chars (mono_process_info->domain) : NULL, + (const gunichar2 *)mono_process_info->password, + logon_flags, + shell_path, + cmd ? mono_string_chars (cmd) : NULL, + creation_flags, + env_vars, dir, start_info, process_info); + + } else { + + result = CreateProcess (shell_path, + cmd ? mono_string_chars (cmd): NULL, + NULL, + NULL, + TRUE, + creation_flags, + env_vars, + dir, + start_info, + process_info); + + } + + return result; +} +#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ + +static gboolean +mono_process_get_shell_arguments (MonoW32ProcessStartInfo *proc_start_info, gunichar2 **shell_path, MonoString **cmd) +{ + gchar *spath = NULL; + gchar *new_cmd, *cmd_utf8; + MonoError mono_error; + + *shell_path = NULL; + *cmd = proc_start_info->arguments; + + mono_process_complete_path (mono_string_chars (proc_start_info->filename), &spath); + if (spath != NULL) { + /* Seems like our CreateProcess does not work as the windows one. + * This hack is needed to deal with paths containing spaces */ + if (*cmd) { + cmd_utf8 = mono_string_to_utf8_checked (*cmd, &mono_error); + if (!mono_error_set_pending_exception (&mono_error)) { + new_cmd = g_strdup_printf ("%s %s", spath, cmd_utf8); + *cmd = mono_string_new_wrapper (new_cmd); + g_free (cmd_utf8); + g_free (new_cmd); + } else { + *cmd = NULL; + } + } + else { + *cmd = mono_string_new_wrapper (spath); + } + + g_free (spath); + } + + return (*cmd != NULL) ? TRUE : FALSE; +} + +MonoBoolean +ves_icall_System_Diagnostics_Process_CreateProcess_internal (MonoW32ProcessStartInfo *proc_start_info, HANDLE stdin_handle, + HANDLE stdout_handle, HANDLE stderr_handle, MonoW32ProcessInfo *process_info) +{ + gboolean ret; + gunichar2 *dir; + STARTUPINFO startinfo={0}; + PROCESS_INFORMATION procinfo; + gunichar2 *shell_path = NULL; + gchar *env_vars = NULL; + MonoString *cmd = NULL; + guint32 creation_flags; + + mono_process_init_startup_info (stdin_handle, stdout_handle, stderr_handle, &startinfo); + + creation_flags = CREATE_UNICODE_ENVIRONMENT; + if (proc_start_info->create_no_window) + creation_flags |= CREATE_NO_WINDOW; + + if (mono_process_get_shell_arguments (proc_start_info, &shell_path, &cmd) == FALSE) { + process_info->pid = -ERROR_FILE_NOT_FOUND; + return FALSE; + } + + if (process_info->env_keys) { + gint i, len; + MonoString *ms; + MonoString *key, *value; + gunichar2 *str, *ptr; + gunichar2 *equals16; + + for (len = 0, i = 0; i < mono_array_length (process_info->env_keys); i++) { + ms = mono_array_get (process_info->env_values, MonoString *, i); + if (ms == NULL) + continue; + + len += mono_string_length (ms) * sizeof (gunichar2); + ms = mono_array_get (process_info->env_keys, MonoString *, i); + len += mono_string_length (ms) * sizeof (gunichar2); + len += 2 * sizeof (gunichar2); + } + + equals16 = g_utf8_to_utf16 ("=", 1, NULL, NULL, NULL); + ptr = str = g_new0 (gunichar2, len + 1); + for (i = 0; i < mono_array_length (process_info->env_keys); i++) { + value = mono_array_get (process_info->env_values, MonoString *, i); + if (value == NULL) + continue; + + key = mono_array_get (process_info->env_keys, MonoString *, i); + memcpy (ptr, mono_string_chars (key), mono_string_length (key) * sizeof (gunichar2)); + ptr += mono_string_length (key); + + memcpy (ptr, equals16, sizeof (gunichar2)); + ptr++; + + memcpy (ptr, mono_string_chars (value), mono_string_length (value) * sizeof (gunichar2)); + ptr += mono_string_length (value); + ptr++; + } + + g_free (equals16); + env_vars = (gchar *) str; + } + + /* The default dir name is "". Turn that into NULL to mean + * "current directory" + */ + if (proc_start_info->working_directory == NULL || mono_string_length (proc_start_info->working_directory) == 0) + dir = NULL; + else + dir = mono_string_chars (proc_start_info->working_directory); + + ret = mono_process_create_process (process_info, shell_path, cmd, creation_flags, env_vars, dir, &startinfo, &procinfo); + + g_free (env_vars); + if (shell_path != NULL) + g_free (shell_path); + + if (ret) { + process_info->process_handle = procinfo.hProcess; + /*process_info->thread_handle=procinfo.hThread;*/ + process_info->thread_handle = NULL; + if (procinfo.hThread != NULL && procinfo.hThread != INVALID_HANDLE_VALUE) + CloseHandle (procinfo.hThread); + process_info->pid = procinfo.dwProcessId; + process_info->tid = procinfo.dwThreadId; + } else { + process_info->pid = -GetLastError (); + } + + return ret; +} + +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) +static inline gboolean +mono_process_win_enum_processes (DWORD *pids, DWORD count, DWORD *needed) +{ + return EnumProcesses (pids, count, needed); +} +#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ + +MonoArray * +ves_icall_System_Diagnostics_Process_GetProcesses_internal (void) +{ + MonoError error; + MonoArray *procs; + gboolean ret; + DWORD needed; + int count; + DWORD *pids; + + count = 512; + do { + pids = g_new0 (DWORD, count); + ret = mono_process_win_enum_processes (pids, count * sizeof (guint32), &needed); + if (ret == FALSE) { + MonoException *exc; + + g_free (pids); + pids = NULL; + exc = mono_get_exception_not_supported ("This system does not support EnumProcesses"); + mono_set_pending_exception (exc); + return NULL; + } + if (needed < (count * sizeof (guint32))) + break; + g_free (pids); + pids = NULL; + count = (count * 3) / 2; + } while (TRUE); + + count = needed / sizeof (guint32); + procs = mono_array_new_checked (mono_domain_get (), mono_get_int32_class (), count, &error); + if (mono_error_set_pending_exception (&error)) { + g_free (pids); + return NULL; + } + + memcpy (mono_array_addr (procs, guint32, 0), pids, needed); + g_free (pids); + pids = NULL; + + return procs; +} + +MonoBoolean +ves_icall_Microsoft_Win32_NativeMethods_CloseProcess (gpointer handle) +{ + return CloseHandle (handle); +} + +MonoBoolean +ves_icall_Microsoft_Win32_NativeMethods_TerminateProcess (gpointer handle, gint32 exitcode) +{ + return TerminateProcess (handle, exitcode); +} + +MonoBoolean +ves_icall_Microsoft_Win32_NativeMethods_GetExitCodeProcess (gpointer handle, gint32 *exitcode) +{ + return GetExitCodeProcess (handle, exitcode); +} + +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) +static inline MonoBoolean +mono_icall_get_process_working_set_size (gpointer handle, gsize *min, gsize *max) +{ + return GetProcessWorkingSetSize (handle, min, max); +} +#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ + +MonoBoolean +ves_icall_Microsoft_Win32_NativeMethods_GetProcessWorkingSetSize (gpointer handle, gsize *min, gsize *max) +{ + return mono_icall_get_process_working_set_size (handle, min, max); +} + +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) +static inline MonoBoolean +mono_icall_set_process_working_set_size (gpointer handle, gsize min, gsize max) +{ + return SetProcessWorkingSetSize (handle, min, max); +} +#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ + +MonoBoolean +ves_icall_Microsoft_Win32_NativeMethods_SetProcessWorkingSetSize (gpointer handle, gsize min, gsize max) +{ + return mono_icall_set_process_working_set_size (handle, min, max); +} + +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) +static inline gint32 +mono_icall_get_priority_class (gpointer handle) +{ + return GetPriorityClass (handle); +} +#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ + +gint32 +ves_icall_Microsoft_Win32_NativeMethods_GetPriorityClass (gpointer handle) +{ + return mono_icall_get_priority_class (handle); +} + +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) +static inline MonoBoolean +mono_icall_set_priority_class (gpointer handle, gint32 priorityClass) +{ + return SetPriorityClass (handle, (guint32) priorityClass); +} +#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ + +MonoBoolean +ves_icall_Microsoft_Win32_NativeMethods_SetPriorityClass (gpointer handle, gint32 priorityClass) +{ + return mono_icall_set_priority_class (handle, priorityClass); +} + +MonoBoolean +ves_icall_Microsoft_Win32_NativeMethods_GetProcessTimes (gpointer handle, gint64 *creationtime, gint64 *exittime, gint64 *kerneltime, gint64 *usertime) +{ + return GetProcessTimes (handle, (LPFILETIME) creationtime, (LPFILETIME) exittime, (LPFILETIME) kerneltime, (LPFILETIME) usertime); +} + +gpointer +ves_icall_Microsoft_Win32_NativeMethods_GetCurrentProcess (void) +{ + return GetCurrentProcess (); +} diff --git a/mono/metadata/w32process.c b/mono/metadata/w32process.c new file mode 100644 index 00000000000..614168ed587 --- /dev/null +++ b/mono/metadata/w32process.c @@ -0,0 +1,624 @@ + +#include + +#include "w32process.h" +#include "w32process-internals.h" +#include "w32process-win32-internals.h" +#include "object.h" +#include "object-internals.h" +#include "class.h" +#include "class-internals.h" +#include "image.h" +#include "utils/mono-proclib.h" + +#define LOGDEBUG(...) +/* define LOGDEBUG(...) g_message(__VA_ARGS__) */ + +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) && defined(HOST_WIN32) + +static guint32 +mono_w32process_get_pid (gpointer handle) +{ + return GetProcessId (handle); +} + +static gboolean +mono_w32process_try_get_modules (gpointer process, gpointer *modules, guint32 size, guint32 *needed) +{ + return EnumProcessModules (process, (HMODULE *) modules, size, (LPDWORD) needed); +} + +static guint32 +mono_w32process_module_get_name (gpointer process, gpointer module, gunichar2 *basename, guint32 size) +{ + return GetModuleBaseName (process, module, basename, size); +} + +static guint32 +mono_w32process_module_get_filename (gpointer process, gpointer module, gunichar2 *basename, guint32 size) +{ + return GetModuleFileNameEx (process, module, basename, size); +} + +static gboolean +mono_w32process_module_get_information (gpointer process, gpointer module, MODULEINFO *modinfo, guint32 size) +{ + return GetModuleInformation (process, module, modinfo, size); +} + +#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) && defined(HOST_WIN32) */ + +static MonoImage *system_image; + +static void +stash_system_image (MonoImage *image) +{ + system_image = image; +} + +static MonoClass* +get_file_version_info_class (void) +{ + static MonoClass *file_version_info_class; + + if (file_version_info_class) + return file_version_info_class; + + g_assert (system_image); + + return file_version_info_class = mono_class_load_from_name ( + system_image, "System.Diagnostics", "FileVersionInfo"); +} + +static MonoClass* +get_process_module_class (void) +{ + static MonoClass *process_module_class; + + if (process_module_class) + return process_module_class; + + g_assert (system_image); + + return process_module_class = mono_class_load_from_name ( + system_image, "System.Diagnostics", "ProcessModule"); +} + +static guint32 +unicode_chars (const gunichar2 *str) +{ + guint32 len; + for (len = 0; str [len] != '\0'; ++len) {} + return len; +} + +static void +process_set_field_object (MonoObject *obj, const gchar *fieldname, MonoObject *data) +{ + MonoClass *klass; + MonoClassField *field; + + LOGDEBUG (g_message ("%s: Setting field %s to object at %p", __func__, fieldname, data)); + + klass = mono_object_class (obj); + g_assert (klass); + + field = mono_class_get_field_from_name (klass, fieldname); + g_assert (field); + + mono_gc_wbarrier_generic_store (((char *)obj) + field->offset, data); +} + +static void +process_set_field_string (MonoObject *obj, const gchar *fieldname, const gunichar2 *val, guint32 len, MonoError *error) +{ + MonoDomain *domain; + MonoClass *klass; + MonoClassField *field; + MonoString *string; + + mono_error_init (error); + + LOGDEBUG (g_message ("%s: Setting field %s to [%s]", __func__, fieldname, g_utf16_to_utf8 (val, len, NULL, NULL, NULL))); + + domain = mono_object_domain (obj); + g_assert (domain); + + klass = mono_object_class (obj); + g_assert (klass); + + field = mono_class_get_field_from_name (klass, fieldname); + g_assert (field); + + string = mono_string_new_utf16_checked (domain, val, len, error); + return_if_nok (error); + + mono_gc_wbarrier_generic_store (((char *)obj) + field->offset, (MonoObject*)string); +} + +static void +process_set_field_string_char (MonoObject *obj, const gchar *fieldname, const gchar *val) +{ + MonoDomain *domain; + MonoClass *klass; + MonoClassField *field; + MonoString *string; + + LOGDEBUG (g_message ("%s: Setting field %s to [%s]", __func__, fieldname, val)); + + domain = mono_object_domain (obj); + g_assert (domain); + + klass = mono_object_class (obj); + g_assert (klass); + + field = mono_class_get_field_from_name (klass, fieldname); + g_assert (field); + + string = mono_string_new (domain, val); + + mono_gc_wbarrier_generic_store (((char *)obj) + field->offset, (MonoObject*)string); +} + +static void +process_set_field_int (MonoObject *obj, const gchar *fieldname, guint32 val) +{ + MonoClass *klass; + MonoClassField *field; + + LOGDEBUG (g_message ("%s: Setting field %s to %d", __func__,fieldname, val)); + + klass = mono_object_class (obj); + g_assert (klass); + + field = mono_class_get_field_from_name (klass, fieldname); + g_assert (field); + + *(guint32 *)(((char *)obj) + field->offset)=val; +} + +static void +process_set_field_intptr (MonoObject *obj, const gchar *fieldname, gpointer val) +{ + MonoClass *klass; + MonoClassField *field; + + LOGDEBUG (g_message ("%s: Setting field %s to %p", __func__, fieldname, val)); + + klass = mono_object_class (obj); + g_assert (klass); + + field = mono_class_get_field_from_name (klass, fieldname); + g_assert (field); + + *(gpointer *)(((char *)obj) + field->offset) = val; +} + +static void +process_set_field_bool (MonoObject *obj, const gchar *fieldname, gboolean val) +{ + MonoClass *klass; + MonoClassField *field; + + LOGDEBUG (g_message ("%s: Setting field %s to %s", __func__, fieldname, val ? "TRUE":"FALSE")); + + klass = mono_object_class (obj); + g_assert (klass); + + field = mono_class_get_field_from_name (klass, fieldname); + g_assert (field); + + *(guint8 *)(((char *)obj) + field->offset) = val; +} + +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) + +#define SFI_COMMENTS "\\StringFileInfo\\%02X%02X%02X%02X\\Comments" +#define SFI_COMPANYNAME "\\StringFileInfo\\%02X%02X%02X%02X\\CompanyName" +#define SFI_FILEDESCRIPTION "\\StringFileInfo\\%02X%02X%02X%02X\\FileDescription" +#define SFI_FILEVERSION "\\StringFileInfo\\%02X%02X%02X%02X\\FileVersion" +#define SFI_INTERNALNAME "\\StringFileInfo\\%02X%02X%02X%02X\\InternalName" +#define SFI_LEGALCOPYRIGHT "\\StringFileInfo\\%02X%02X%02X%02X\\LegalCopyright" +#define SFI_LEGALTRADEMARKS "\\StringFileInfo\\%02X%02X%02X%02X\\LegalTrademarks" +#define SFI_ORIGINALFILENAME "\\StringFileInfo\\%02X%02X%02X%02X\\OriginalFilename" +#define SFI_PRIVATEBUILD "\\StringFileInfo\\%02X%02X%02X%02X\\PrivateBuild" +#define SFI_PRODUCTNAME "\\StringFileInfo\\%02X%02X%02X%02X\\ProductName" +#define SFI_PRODUCTVERSION "\\StringFileInfo\\%02X%02X%02X%02X\\ProductVersion" +#define SFI_SPECIALBUILD "\\StringFileInfo\\%02X%02X%02X%02X\\SpecialBuild" +#define EMPTY_STRING (gunichar2*)"\000\000" + +typedef struct { + const char *name; + const char *id; +} StringTableEntry; + +static StringTableEntry stringtable_entries [] = { + { "comments", SFI_COMMENTS }, + { "companyname", SFI_COMPANYNAME }, + { "filedescription", SFI_FILEDESCRIPTION }, + { "fileversion", SFI_FILEVERSION }, + { "internalname", SFI_INTERNALNAME }, + { "legalcopyright", SFI_LEGALCOPYRIGHT }, + { "legaltrademarks", SFI_LEGALTRADEMARKS }, + { "originalfilename", SFI_ORIGINALFILENAME }, + { "privatebuild", SFI_PRIVATEBUILD }, + { "productname", SFI_PRODUCTNAME }, + { "productversion", SFI_PRODUCTVERSION }, + { "specialbuild", SFI_SPECIALBUILD } +}; + +static void +process_module_string_read (MonoObject *filever, gpointer data, const gchar *fieldname, + guchar lang_hi, guchar lang_lo, const gchar *key, MonoError *error) +{ + gchar *lang_key_utf8; + gunichar2 *lang_key, *buffer; + UINT chars; + + mono_error_init (error); + + lang_key_utf8 = g_strdup_printf (key, lang_lo, lang_hi, 0x04, 0xb0); + + LOGDEBUG (g_message ("%s: asking for [%s]", __func__, lang_key_utf8)); + + lang_key = g_utf8_to_utf16 (lang_key_utf8, -1, NULL, NULL, NULL); + + if (VerQueryValue (data, lang_key, (gpointer *)&buffer, &chars) && chars > 0) { + LOGDEBUG (g_message ("%s: found %d chars of [%s]", __func__, chars, g_utf16_to_utf8 (buffer, chars, NULL, NULL, NULL))); + /* chars includes trailing null */ + process_set_field_string (filever, fieldname, buffer, chars - 1, error); + } else { + process_set_field_string (filever, fieldname, EMPTY_STRING, 0, error); + } + + g_free (lang_key); + g_free (lang_key_utf8); +} + +static void +process_module_stringtable (MonoObject *filever, gpointer data, guchar lang_hi, guchar lang_lo, MonoError *error) +{ + for (int i = 0; i < G_N_ELEMENTS (stringtable_entries); ++i) { + process_module_string_read (filever, data, stringtable_entries [i].name, + lang_hi, lang_lo, stringtable_entries [i].id, error); + return_if_nok (error); + } +} + +static void +mono_w32process_get_fileversion (MonoObject *filever, gunichar2 *filename, MonoError *error) +{ + DWORD verinfohandle; + VS_FIXEDFILEINFO *ffi; + gpointer data; + DWORD datalen; + guchar *trans_data; + gunichar2 *query; + UINT ffi_size, trans_size; + BOOL ok; + gunichar2 lang_buf[128]; + guint32 lang, lang_count; + + mono_error_init (error); + + datalen = GetFileVersionInfoSize (filename, &verinfohandle); + if (datalen) { + data = g_malloc0 (datalen); + ok = GetFileVersionInfo (filename, verinfohandle, datalen, data); + if (ok) { + query = g_utf8_to_utf16 ("\\", -1, NULL, NULL, NULL); + if (query == NULL) { + g_free (data); + return; + } + + if (VerQueryValue (data, query, (gpointer *)&ffi, &ffi_size)) { + LOGDEBUG (g_message ("%s: recording assembly: FileName [%s] FileVersionInfo [%d.%d.%d.%d]", __func__, g_utf16_to_utf8 (filename, -1, NULL, NULL, NULL), HIWORD (ffi->dwFileVersionMS), LOWORD (ffi->dwFileVersionMS), HIWORD (ffi->dwFileVersionLS), LOWORD (ffi->dwFileVersionLS))); + + process_set_field_int (filever, "filemajorpart", HIWORD (ffi->dwFileVersionMS)); + process_set_field_int (filever, "fileminorpart", LOWORD (ffi->dwFileVersionMS)); + process_set_field_int (filever, "filebuildpart", HIWORD (ffi->dwFileVersionLS)); + process_set_field_int (filever, "fileprivatepart", LOWORD (ffi->dwFileVersionLS)); + + process_set_field_int (filever, "productmajorpart", HIWORD (ffi->dwProductVersionMS)); + process_set_field_int (filever, "productminorpart", LOWORD (ffi->dwProductVersionMS)); + process_set_field_int (filever, "productbuildpart", HIWORD (ffi->dwProductVersionLS)); + process_set_field_int (filever, "productprivatepart", LOWORD (ffi->dwProductVersionLS)); + + process_set_field_bool (filever, "isdebug", ((ffi->dwFileFlags & ffi->dwFileFlagsMask) & VS_FF_DEBUG) != 0); + process_set_field_bool (filever, "isprerelease", ((ffi->dwFileFlags & ffi->dwFileFlagsMask) & VS_FF_PRERELEASE) != 0); + process_set_field_bool (filever, "ispatched", ((ffi->dwFileFlags & ffi->dwFileFlagsMask) & VS_FF_PATCHED) != 0); + process_set_field_bool (filever, "isprivatebuild", ((ffi->dwFileFlags & ffi->dwFileFlagsMask) & VS_FF_PRIVATEBUILD) != 0); + process_set_field_bool (filever, "isspecialbuild", ((ffi->dwFileFlags & ffi->dwFileFlagsMask) & VS_FF_SPECIALBUILD) != 0); + } + g_free (query); + + query = g_utf8_to_utf16 ("\\VarFileInfo\\Translation", -1, NULL, NULL, NULL); + if (query == NULL) { + g_free (data); + return; + } + + if (VerQueryValue (data, query, (gpointer *)&trans_data, &trans_size)) { + /* use the first language ID we see */ + if (trans_size >= 4) { + LOGDEBUG (g_message("%s: %s has 0x%0x 0x%0x 0x%0x 0x%0x", __func__, g_utf16_to_utf8 (filename, -1, NULL, NULL, NULL), trans_data[0], trans_data[1], trans_data[2], trans_data[3])); + lang = (trans_data[0]) | (trans_data[1] << 8) | (trans_data[2] << 16) | (trans_data[3] << 24); + /* Only give the lower 16 bits to VerLanguageName, as Windows gets confused otherwise */ + lang_count = VerLanguageName (lang & 0xFFFF, lang_buf, 128); + if (lang_count) { + process_set_field_string (filever, "language", lang_buf, lang_count, error); + return_if_nok (error); + } + process_module_stringtable (filever, data, trans_data[0], trans_data[1], error); + return_if_nok (error); + } + } else { + int i; + + for (i = 0; i < G_N_ELEMENTS (stringtable_entries); ++i) { + /* No strings, so set every field to the empty string */ + process_set_field_string (filever, stringtable_entries [i].name, EMPTY_STRING, 0, error); + return_if_nok (error); + } + + /* And language seems to be set to en_US according to bug 374600 */ + lang_count = VerLanguageName (0x0409, lang_buf, 128); + if (lang_count) { + process_set_field_string (filever, "language", lang_buf, lang_count, error); + return_if_nok (error); + } + } + + g_free (query); + } + g_free (data); + } +} + +#endif /* #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ + +void +ves_icall_System_Diagnostics_FileVersionInfo_GetVersionInfo_internal (MonoObject *this_obj, MonoString *filename) +{ + MonoError error; + + stash_system_image (mono_object_class (this_obj)->image); + + mono_w32process_get_fileversion (this_obj, mono_string_chars (filename), &error); + if (!mono_error_ok (&error)) { + mono_error_set_pending_exception (&error); + return; + } + + process_set_field_string (this_obj, "filename", mono_string_chars (filename), mono_string_length (filename), &error); + if (!mono_error_ok (&error)) { + mono_error_set_pending_exception (&error); + } +} + +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) + +static GPtrArray* +get_domain_assemblies (MonoDomain *domain) +{ + GSList *tmp; + GPtrArray *assemblies; + + /* + * Make a copy of the list of assemblies because we can't hold the assemblies + * lock while creating objects etc. + */ + assemblies = g_ptr_array_new (); + mono_domain_assemblies_lock (domain); + for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) { + MonoAssembly *ass = (MonoAssembly *)tmp->data; + if (ass->image->fileio_used) + continue; + g_ptr_array_add (assemblies, ass); + } + mono_domain_assemblies_unlock (domain); + + return assemblies; +} + +static MonoObject* +process_add_module (HANDLE process, HMODULE mod, gunichar2 *filename, gunichar2 *modulename, MonoClass *proc_class, MonoError *error) +{ + MonoObject *item, *filever; + MonoDomain *domain = mono_domain_get (); + MODULEINFO modinfo; + BOOL ok; + + mono_error_init (error); + + /* Build a System.Diagnostics.ProcessModule with the data. */ + item = mono_object_new_checked (domain, proc_class, error); + return_val_if_nok (error, NULL); + + filever = mono_object_new_checked (domain, get_file_version_info_class (), error); + return_val_if_nok (error, NULL); + + mono_w32process_get_fileversion (filever, filename, error); + return_val_if_nok (error, NULL); + + process_set_field_string (filever, "filename", filename, unicode_chars (filename), error); + return_val_if_nok (error, NULL); + + ok = mono_w32process_module_get_information (process, mod, &modinfo, sizeof(MODULEINFO)); + if (ok) { + process_set_field_intptr (item, "baseaddr", modinfo.lpBaseOfDll); + process_set_field_intptr (item, "entryaddr", modinfo.EntryPoint); + process_set_field_int (item, "memory_size", modinfo.SizeOfImage); + } + + process_set_field_string (item, "filename", filename, unicode_chars (filename), error); + return_val_if_nok (error, NULL); + + process_set_field_string (item, "modulename", modulename, unicode_chars (modulename), error); + return_val_if_nok (error, NULL); + + process_set_field_object (item, "version_info", filever); + + return item; +} + +static void +process_get_assembly_fileversion (MonoObject *filever, MonoAssembly *assembly) +{ + process_set_field_int (filever, "filemajorpart", assembly->aname.major); + process_set_field_int (filever, "fileminorpart", assembly->aname.minor); + process_set_field_int (filever, "filebuildpart", assembly->aname.build); +} + +static MonoObject* +process_get_module (MonoAssembly *assembly, MonoClass *proc_class, MonoError *error) +{ + MonoObject *item, *filever; + MonoDomain *domain; + gchar *filename; + const gchar *modulename; + + mono_error_init (error); + + domain = mono_domain_get (); + + modulename = assembly->aname.name; + + /* Build a System.Diagnostics.ProcessModule with the data. */ + item = mono_object_new_checked (domain, proc_class, error); + return_val_if_nok (error, NULL); + + filever = mono_object_new_checked (domain, get_file_version_info_class (), error); + return_val_if_nok (error, NULL); + + filename = g_strdup_printf ("[In Memory] %s", modulename); + + process_get_assembly_fileversion (filever, assembly); + process_set_field_string_char (filever, "filename", filename); + process_set_field_object (item, "version_info", filever); + + process_set_field_intptr (item, "baseaddr", assembly->image->raw_data); + process_set_field_int (item, "memory_size", assembly->image->raw_data_len); + process_set_field_string_char (item, "filename", filename); + process_set_field_string_char (item, "modulename", modulename); + + g_free (filename); + + return item; +} + +/* Returns an array of System.Diagnostics.ProcessModule */ +MonoArray * +ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject *this_obj, HANDLE process) +{ + MonoError error; + MonoArray *temp_arr = NULL; + MonoArray *arr; + HMODULE mods[1024]; + gunichar2 filename[MAX_PATH]; + gunichar2 modname[MAX_PATH]; + DWORD needed; + guint32 count = 0, module_count = 0, assembly_count = 0; + guint32 i, num_added = 0; + GPtrArray *assemblies = NULL; + + stash_system_image (mono_object_class (this_obj)->image); + + if (mono_w32process_get_pid (process) == mono_process_current_pid ()) { + assemblies = get_domain_assemblies (mono_domain_get ()); + assembly_count = assemblies->len; + } + + if (mono_w32process_try_get_modules (process, mods, sizeof(mods), &needed)) + module_count += needed / sizeof(HMODULE); + + count = module_count + assembly_count; + temp_arr = mono_array_new_checked (mono_domain_get (), get_process_module_class (), count, &error); + if (mono_error_set_pending_exception (&error)) + return NULL; + + for (i = 0; i < module_count; i++) { + if (mono_w32process_module_get_name (process, mods[i], modname, MAX_PATH) + && mono_w32process_module_get_filename (process, mods[i], filename, MAX_PATH)) + { + MonoObject *module = process_add_module (process, mods[i], filename, modname, get_process_module_class (), &error); + if (!mono_error_ok (&error)) { + mono_error_set_pending_exception (&error); + return NULL; + } + mono_array_setref (temp_arr, num_added++, module); + } + } + + if (assemblies) { + for (i = 0; i < assembly_count; i++) { + MonoAssembly *ass = (MonoAssembly *)g_ptr_array_index (assemblies, i); + MonoObject *module = process_get_module (ass, get_process_module_class (), &error); + if (!mono_error_ok (&error)) { + mono_error_set_pending_exception (&error); + return NULL; + } + mono_array_setref (temp_arr, num_added++, module); + } + g_ptr_array_free (assemblies, TRUE); + } + + if (count == num_added) { + arr = temp_arr; + } else { + /* shorter version of the array */ + arr = mono_array_new_checked (mono_domain_get (), get_process_module_class (), num_added, &error); + if (mono_error_set_pending_exception (&error)) + return NULL; + + for (i = 0; i < num_added; i++) + mono_array_setref (arr, i, mono_array_get (temp_arr, MonoObject*, i)); + } + + return arr; +} + +#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ + +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) + +MonoString * +ves_icall_System_Diagnostics_Process_ProcessName_internal (HANDLE process) +{ + MonoError error; + MonoString *string; + gunichar2 name[MAX_PATH]; + guint32 len; + gboolean ok; + HMODULE mod; + DWORD needed; + + ok = mono_w32process_try_get_modules (process, &mod, sizeof(mod), &needed); + if (!ok) + return NULL; + + len = mono_w32process_module_get_name (process, mod, name, MAX_PATH); + if (len == 0) + return NULL; + + string = mono_string_new_utf16_checked (mono_domain_get (), name, len, &error); + if (!mono_error_ok (&error)) + mono_error_set_pending_exception (&error); + + return string; +} + +#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */ + +gint64 +ves_icall_System_Diagnostics_Process_GetProcessData (int pid, gint32 data_type, gint32 *error) +{ + MonoProcessError perror; + guint64 res; + + res = mono_process_get_data_with_error (GINT_TO_POINTER (pid), (MonoProcessData)data_type, &perror); + if (error) + *error = perror; + return res; +} diff --git a/mono/metadata/w32process.h b/mono/metadata/w32process.h new file mode 100644 index 00000000000..7df9caf67f7 --- /dev/null +++ b/mono/metadata/w32process.h @@ -0,0 +1,142 @@ +/* + * w32process.h: System.Diagnostics.Process support + * + * Author: + * Dick Porter (dick@ximian.com) + * + * (C) 2002 Ximian, Inc. + */ + +#ifndef _MONO_METADATA_W32PROCESS_H_ +#define _MONO_METADATA_W32PROCESS_H_ + +#include +#include + +#if HAVE_SYS_TYPES_H +#include +#endif + +#include + +G_BEGIN_DECLS + +typedef enum { + MONO_W32PROCESS_PRIORITY_CLASS_NORMAL = 0x0020, + MONO_W32PROCESS_PRIORITY_CLASS_IDLE = 0x0040, + MONO_W32PROCESS_PRIORITY_CLASS_HIGH = 0x0080, + MONO_W32PROCESS_PRIORITY_CLASS_REALTIME = 0x0100, + MONO_W32PROCESS_PRIORITY_CLASS_BELOW_NORMAL = 0x4000, + MONO_W32PROCESS_PRIORITY_CLASS_ABOVE_NORMAL = 0x8000, +} MonoW32ProcessPriorityClass; + +typedef struct +{ + gpointer process_handle; + gpointer thread_handle; + guint32 pid; /* Contains GetLastError () on failure */ + guint32 tid; + MonoArray *env_keys; + MonoArray *env_values; + MonoString *username; + MonoString *domain; + gpointer password; /* BSTR from SecureString in 2.0 profile */ + MonoBoolean load_user_profile; +} MonoW32ProcessInfo; + +typedef struct +{ + MonoObject object; + MonoString *filename; + MonoString *arguments; + MonoString *working_directory; + MonoString *verb; + guint32 window_style; + MonoBoolean error_dialog; + gpointer error_dialog_parent_handle; + MonoBoolean use_shell_execute; + MonoString *username; + MonoString *domain; + MonoObject *password; /* SecureString in 2.0 profile, dummy in 1.x */ + MonoString *password_in_clear_text; + MonoBoolean load_user_profile; + MonoBoolean redirect_standard_input; + MonoBoolean redirect_standard_output; + MonoBoolean redirect_standard_error; + MonoObject *encoding_stdout; + MonoObject *encoding_stderr; + MonoBoolean create_no_window; + MonoObject *weak_parent_process; + MonoObject *envVars; +} MonoW32ProcessStartInfo; + +void +mono_w32process_init (void); + +void +mono_w32process_cleanup (void); + +#ifndef HOST_WIN32 + +void +mono_w32process_set_cli_launcher (gchar *path); + +gchar* +mono_w32process_get_path (pid_t pid); + +#endif + +gpointer +ves_icall_System_Diagnostics_Process_GetProcess_internal (guint32 pid); + +MonoArray* +ves_icall_System_Diagnostics_Process_GetProcesses_internal (void); + +MonoArray* +ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject *this_obj, gpointer process); + +void +ves_icall_System_Diagnostics_FileVersionInfo_GetVersionInfo_internal (MonoObject *this_obj, MonoString *filename); + +MonoBoolean +ves_icall_System_Diagnostics_Process_ShellExecuteEx_internal (MonoW32ProcessStartInfo *proc_start_info, MonoW32ProcessInfo *process_handle); + +MonoBoolean +ves_icall_System_Diagnostics_Process_CreateProcess_internal (MonoW32ProcessStartInfo *proc_start_info, gpointer stdin_handle, + gpointer stdout_handle, gpointer stderr_handle, MonoW32ProcessInfo *process_handle); + +MonoString* +ves_icall_System_Diagnostics_Process_ProcessName_internal (gpointer process); + +gint64 +ves_icall_System_Diagnostics_Process_GetProcessData (int pid, gint32 data_type, gint32 *error); + +gpointer +ves_icall_Microsoft_Win32_NativeMethods_GetCurrentProcess (void); + +MonoBoolean +ves_icall_Microsoft_Win32_NativeMethods_GetExitCodeProcess (gpointer handle, gint32 *exitcode); + +MonoBoolean +ves_icall_Microsoft_Win32_NativeMethods_CloseProcess (gpointer handle); + +MonoBoolean +ves_icall_Microsoft_Win32_NativeMethods_TerminateProcess (gpointer handle, gint32 exitcode); + +MonoBoolean +ves_icall_Microsoft_Win32_NativeMethods_GetProcessWorkingSetSize (gpointer handle, gsize *min, gsize *max); +MonoBoolean +ves_icall_Microsoft_Win32_NativeMethods_SetProcessWorkingSetSize (gpointer handle, gsize min, gsize max); + +gint32 +ves_icall_Microsoft_Win32_NativeMethods_GetPriorityClass (gpointer handle); +MonoBoolean +ves_icall_Microsoft_Win32_NativeMethods_SetPriorityClass (gpointer handle, gint32 priorityClass); + +MonoBoolean +ves_icall_Microsoft_Win32_NativeMethods_GetProcessTimes (gpointer handle, gint64 *creationtime, gint64 *exittime, gint64 *kerneltime, gint64 *usertime); + +G_END_DECLS + +#endif /* _MONO_METADATA_W32PROCESS_H_ */ + diff --git a/mono/metadata/w32semaphore-unix.c b/mono/metadata/w32semaphore-unix.c index 21e7921127a..3e87ad8ad3f 100644 --- a/mono/metadata/w32semaphore-unix.c +++ b/mono/metadata/w32semaphore-unix.c @@ -12,7 +12,7 @@ #include "w32handle-namespace.h" #include "mono/io-layer/io-layer.h" #include "mono/utils/mono-logger-internals.h" -#include "mono/utils/w32handle.h" +#include "mono/metadata/w32handle.h" typedef struct { guint32 val; diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c index 57835f473e9..ce15318d225 100644 --- a/mono/mini/aot-compiler.c +++ b/mono/mini/aot-compiler.c @@ -1432,7 +1432,6 @@ arch_emit_got_access (MonoAotCompile *acfg, const char *got_symbol, guint8 *code #elif defined(TARGET_POWERPC) { guint8 buf [32]; - guint8 *code; emit_bytes (acfg, code, mono_arch_get_patch_offset (code)); code = buf; @@ -2491,7 +2490,7 @@ mono_get_field_token (MonoClassField *field) for (i = 0; i < klass->field.count; ++i) { if (field == &klass->fields [i]) - return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i); + return MONO_TOKEN_FIELD_DEF | (mono_class_get_first_field_idx (klass) + 1 + i); } g_assert_not_reached (); @@ -2770,7 +2769,7 @@ encode_klass_ref_inner (MonoAotCompile *acfg, MonoClass *klass, guint8 *buf, gui * information. */ - if (klass->generic_class) { + if (mono_class_is_ginst (klass)) { guint32 token; g_assert (klass->type_token); @@ -2780,8 +2779,8 @@ encode_klass_ref_inner (MonoAotCompile *acfg, MonoClass *klass, guint8 *buf, gui encode_value (MONO_AOT_TYPEREF_TYPESPEC_TOKEN, p, &p); encode_value (token, p, &p); } else { - MonoClass *gclass = klass->generic_class->container_class; - MonoGenericInst *inst = klass->generic_class->context.class_inst; + MonoClass *gclass = mono_class_get_generic_class (klass)->container_class; + MonoGenericInst *inst = mono_class_get_generic_class (klass)->context.class_inst; static int count = 0; guint8 *p1 = p; @@ -2855,7 +2854,7 @@ encode_klass_ref (MonoAotCompile *acfg, MonoClass *klass, guint8 *buf, guint8 ** /* * The encoding of generic instances is large so emit them only once. */ - if (klass->generic_class) { + if (mono_class_is_ginst (klass)) { guint32 token; g_assert (klass->type_token); @@ -3616,7 +3615,7 @@ can_marshal_struct (MonoClass *klass) MonoMarshalType *info; int i; - if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) + if (mono_class_is_auto_layout (klass)) return FALSE; info = mono_marshal_load_type_info (klass); @@ -3688,8 +3687,8 @@ create_gsharedvt_inst (MonoAotCompile *acfg, MonoMethod *method, MonoGenericCont memset (ctx, 0, sizeof (MonoGenericContext)); - if (method->klass->generic_container) { - shared_context = method->klass->generic_container->context; + if (mono_class_is_gtd (method->klass)) { + shared_context = mono_class_get_generic_container (method->klass)->context; inst = shared_context.class_inst; args = g_new0 (MonoType*, inst->type_argc); @@ -3968,7 +3967,7 @@ add_wrappers (MonoAotCompile *acfg) if (!klass->delegate || klass == mono_defaults.delegate_class || klass == mono_defaults.multicastdelegate_class) continue; - if (!klass->generic_container) { + if (!mono_class_is_gtd (klass)) { method = mono_get_delegate_invoke (klass); m = mono_marshal_get_delegate_invoke (method, NULL); @@ -4008,7 +4007,7 @@ add_wrappers (MonoAotCompile *acfg) add_method (acfg, del_invoke); } } - } else if ((acfg->opts & MONO_OPT_GSHAREDVT) && klass->generic_container) { + } else if ((acfg->opts & MONO_OPT_GSHAREDVT) && mono_class_is_gtd (klass)) { MonoError error; MonoGenericContext ctx; MonoMethod *inst, *gshared; @@ -4102,7 +4101,7 @@ add_wrappers (MonoAotCompile *acfg) if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) { if (method->is_generic) { // FIXME: - } else if ((acfg->opts & MONO_OPT_GSHAREDVT) && method->klass->generic_container) { + } else if ((acfg->opts & MONO_OPT_GSHAREDVT) && mono_class_is_gtd (method->klass)) { MonoError error; MonoGenericContext ctx; MonoMethod *inst, *gshared, *m; @@ -4276,7 +4275,7 @@ add_wrappers (MonoAotCompile *acfg) continue; } - if (klass->valuetype && !klass->generic_container && can_marshal_struct (klass) && + if (klass->valuetype && !mono_class_is_gtd (klass) && can_marshal_struct (klass) && !(klass->nested_in && strstr (klass->nested_in->name, "") == klass->nested_in->name)) { add_method (acfg, mono_marshal_get_struct_to_ptr (klass)); add_method (acfg, mono_marshal_get_ptr_to_struct (klass)); @@ -4291,8 +4290,8 @@ has_type_vars (MonoClass *klass) return TRUE; if (klass->rank) return has_type_vars (klass->element_class); - if (klass->generic_class) { - MonoGenericContext *context = &klass->generic_class->context; + if (mono_class_is_ginst (klass)) { + MonoGenericContext *context = &mono_class_get_generic_class (klass)->context; if (context->class_inst) { int i; @@ -4301,7 +4300,7 @@ has_type_vars (MonoClass *klass) return TRUE; } } - if (klass->generic_container) + if (mono_class_is_gtd (klass)) return TRUE; return FALSE; } @@ -4411,13 +4410,13 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth, mono_class_init (klass); - if (klass->generic_class && klass->generic_class->context.class_inst->is_open) + if (mono_class_is_ginst (klass) && mono_class_get_generic_class (klass)->context.class_inst->is_open) return; if (has_type_vars (klass)) return; - if (!klass->generic_class && !klass->rank) + if (!mono_class_is_ginst (klass) && !klass->rank) return; if (mono_class_has_failure (klass)) @@ -4441,7 +4440,7 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth, * Use gsharedvt for generic collections with vtype arguments to avoid code blowup. * Enable this only for some classes since gsharedvt might not support all methods. */ - if ((acfg->opts & MONO_OPT_GSHAREDVT) && klass->image == mono_defaults.corlib && klass->generic_class && klass->generic_class->context.class_inst && is_vt_inst (klass->generic_class->context.class_inst) && + if ((acfg->opts & MONO_OPT_GSHAREDVT) && klass->image == mono_defaults.corlib && mono_class_is_ginst (klass) && mono_class_get_generic_class (klass)->context.class_inst && is_vt_inst (mono_class_get_generic_class (klass)->context.class_inst) && (!strcmp (klass->name, "Dictionary`2") || !strcmp (klass->name, "List`1") || !strcmp (klass->name, "ReadOnlyCollection`1"))) use_gsharedvt = TRUE; @@ -4498,7 +4497,7 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth, */ if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") && (!strcmp(klass->name, "ICollection`1") || !strcmp (klass->name, "IEnumerable`1") || !strcmp (klass->name, "IList`1") || !strcmp (klass->name, "IEnumerator`1") || !strcmp (klass->name, "IReadOnlyList`1"))) { - MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]); + MonoClass *tclass = mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]); MonoClass *array_class = mono_bounded_array_class_get (tclass, 1, FALSE); gpointer iter; char *name_prefix; @@ -4519,7 +4518,7 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth, break; } g_assert (nclass); - nclass = mono_class_inflate_generic_class_checked (nclass, mono_generic_class_get_context (klass->generic_class), &error); + nclass = mono_class_inflate_generic_class_checked (nclass, mono_generic_class_get_context (mono_class_get_generic_class (klass)), &error); mono_error_assert_ok (&error); /* FIXME don't swallow the error */ add_generic_class (acfg, nclass, FALSE, "ICollection"); } @@ -4539,7 +4538,7 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth, /* Add an instance of GenericComparer which is created dynamically by Comparer */ if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") && !strcmp (klass->name, "Comparer`1")) { MonoError error; - MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]); + MonoClass *tclass = mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]); MonoClass *icomparable, *gcomparer, *icomparable_inst; MonoGenericContext ctx; MonoType *args [16]; @@ -4567,7 +4566,7 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth, /* Add an instance of GenericEqualityComparer which is created dynamically by EqualityComparer */ if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") && !strcmp (klass->name, "EqualityComparer`1")) { MonoError error; - MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]); + MonoClass *tclass = mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]); MonoClass *iface, *gcomparer, *iface_inst; MonoGenericContext ctx; MonoType *args [16]; @@ -4596,7 +4595,7 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth, /* Add an instance of EnumComparer which is created dynamically by EqualityComparer for enums */ if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") && !strcmp (klass->name, "EqualityComparer`1")) { MonoClass *enum_comparer; - MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]); + MonoClass *tclass = mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]); MonoGenericContext ctx; MonoType *args [16]; @@ -4618,7 +4617,7 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth, /* Add an instance of ObjectComparer which is created dynamically by Comparer for enums */ if (klass->image == mono_defaults.corlib && !strcmp (klass->name_space, "System.Collections.Generic") && !strcmp (klass->name, "Comparer`1")) { MonoClass *comparer; - MonoClass *tclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]); + MonoClass *tclass = mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]); MonoGenericContext ctx; MonoType *args [16]; @@ -4794,7 +4793,7 @@ add_generic_instances (MonoAotCompile *acfg) g_free (type_argv); } - if (method->is_generic || method->klass->generic_container) + if (method->is_generic || mono_class_is_gtd (method->klass)) declaring_method = method; else declaring_method = mono_method_get_declaring_generic_method (method); @@ -5013,7 +5012,7 @@ is_direct_callable (MonoAotCompile *acfg, MonoMethod *method, MonoJumpInfo *patc if (callee_cfg) { gboolean direct_callable = TRUE; - if (direct_callable && !(!callee_cfg->has_got_slots && (callee_cfg->method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT))) + if (direct_callable && !(!callee_cfg->has_got_slots && mono_class_is_before_field_init (callee_cfg->method->klass))) direct_callable = FALSE; if ((callee_cfg->method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) && (!method || method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)) // FIXME: Maybe call the wrapper directly ? @@ -5809,6 +5808,7 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint encode_method_ref (acfg, patch_info->data.virt_method->method, p, &p); break; case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG: + case MONO_PATCH_INFO_GET_TLS_TRAMP: break; default: g_warning ("unable to handle jump info %d", patch_info->type); @@ -6272,11 +6272,11 @@ emit_klass_info (MonoAotCompile *acfg, guint32 token) mono_class_has_finalizer (klass); - if (klass->generic_container || cant_encode) { + if (mono_class_is_gtd (klass) || cant_encode) { encode_value (-1, p, &p); } else { encode_value (klass->vtable_size, p, &p); - encode_value ((klass->generic_container ? (1 << 8) : 0) | (no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | ((klass->ext && klass->ext->nested_classes) ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p); + encode_value ((mono_class_is_gtd (klass) ? (1 << 8) : 0) | (no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | ((klass->ext && klass->ext->nested_classes) ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p); if (klass->has_cctor) encode_method_ref (acfg, mono_class_get_cctor (klass), p, &p); if (klass->has_finalize) @@ -7329,7 +7329,7 @@ is_concrete_type (MonoType *t) if (!MONO_TYPE_ISSTRUCT (t)) return TRUE; klass = mono_class_from_mono_type (t); - orig_ctx = &klass->generic_class->context; + orig_ctx = &mono_class_get_generic_class (klass)->context; inst = orig_ctx->class_inst; if (inst) { @@ -7466,7 +7466,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method) InterlockedIncrement (&acfg->stats.mcount); #if 0 - if (method->is_generic || method->klass->generic_container) { + if (method->is_generic || mono_class_is_gtd (method->klass)) { InterlockedIncrement (&acfg->stats.genericcount); return; } @@ -7645,7 +7645,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method) case MONO_PATCH_INFO_VTABLE: { MonoClass *klass = patch_info->data.klass; - if (klass->generic_class && !mini_class_is_generic_sharable (klass)) + if (mono_class_is_ginst (klass) && !mini_class_is_generic_sharable (klass)) add_generic_class_with_depth (acfg, klass, depth + 5, "vtable"); break; } @@ -7653,7 +7653,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method) MonoClass *klass = patch_info->data.field->parent; /* The .cctor needs to run at runtime. */ - if (klass->generic_class && !mono_generic_context_is_sharable_full (&klass->generic_class->context, FALSE, FALSE) && mono_class_get_cctor (klass)) + if (mono_class_is_ginst (klass) && !mono_generic_context_is_sharable_full (&mono_class_get_generic_class (klass)->context, FALSE, FALSE) && mono_class_get_cctor (klass)) add_extra_method_with_depth (acfg, mono_class_get_cctor (klass), depth + 1); break; } @@ -8192,7 +8192,7 @@ mono_aot_patch_info_dup (MonoJumpInfo* ji) static int execute_system (const char * command) { - int status; + int status = 0; #if _WIN32 // We need an extra set of quotes around the whole command to properly handle commands @@ -8630,8 +8630,8 @@ mono_aot_method_hash (MonoMethod *method) sig = mono_method_signature (method); - if (method->klass->generic_class) - class_ginst = method->klass->generic_class->context.class_inst; + if (mono_class_is_ginst (method->klass)) + class_ginst = mono_class_get_generic_class (method->klass)->context.class_inst; if (method->is_inflated) ginst = ((MonoMethodInflated*)method)->context.method_inst; @@ -8648,8 +8648,8 @@ mono_aot_method_hash (MonoMethod *method) if (!method->wrapper_type) { char *full_name; - if (klass->generic_class) - full_name = mono_type_full_name (&klass->generic_class->container_class->byval_arg); + if (mono_class_is_ginst (klass)) + full_name = mono_type_full_name (&mono_class_get_generic_class (klass)->container_class->byval_arg); else full_name = mono_type_full_name (&klass->byval_arg); @@ -9746,7 +9746,7 @@ collect_methods (MonoAotCompile *acfg) } */ - if (method->is_generic || method->klass->generic_container) + if (method->is_generic || mono_class_is_gtd (method->klass)) /* Compile the ref shared version instead */ method = mini_get_shared_method (method); @@ -9767,7 +9767,7 @@ collect_methods (MonoAotCompile *acfg) method = mono_get_method_checked (acfg->image, token, NULL, NULL, &error); report_loader_error (acfg, &error, "Failed to load method token 0x%x due to %s\n", i, mono_error_get_message (&error)); - if (method->is_generic || method->klass->generic_container) { + if (method->is_generic || mono_class_is_gtd (method->klass)) { MonoMethod *gshared; gshared = mini_get_shared_method_full (method, TRUE, TRUE); @@ -9791,7 +9791,7 @@ compile_methods (MonoAotCompile *acfg) GPtrArray *frag; int len, j; GPtrArray *threads; - HANDLE handle; + MonoThreadHandle *thread_handle; gpointer *user_data; MonoMethod **methods; @@ -9824,13 +9824,13 @@ compile_methods (MonoAotCompile *acfg) user_data [1] = acfg; user_data [2] = frag; - handle = mono_threads_create_thread (compile_thread_main, (gpointer) user_data, NULL, NULL); - g_ptr_array_add (threads, handle); + thread_handle = mono_threads_create_thread (compile_thread_main, (gpointer) user_data, NULL, NULL); + g_ptr_array_add (threads, thread_handle); } g_free (methods); for (i = 0; i < threads->len; ++i) { - WaitForSingleObjectEx (g_ptr_array_index (threads, i), INFINITE, FALSE); + mono_thread_info_wait_one_handle (g_ptr_array_index (threads, i), INFINITE, FALSE); mono_threads_close_thread_handle (g_ptr_array_index (threads, i)); } } else { @@ -10382,6 +10382,11 @@ add_preinit_got_slots (MonoAotCompile *acfg) get_got_offset (acfg, FALSE, ji); get_got_offset (acfg, TRUE, ji); + ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo)); + ji->type = MONO_PATCH_INFO_GET_TLS_TRAMP; + get_got_offset (acfg, FALSE, ji); + get_got_offset (acfg, TRUE, ji); + for (i = 0; i < sizeof (preinited_jit_icalls) / sizeof (char*); ++i) { ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoAotCompile)); ji->type = MONO_PATCH_INFO_INTERNAL_METHOD; @@ -10647,7 +10652,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) acfg->tmpfname = g_strdup_printf ("%s", acfg->aot_opts.outfile); else acfg->tmpfname = g_strdup_printf ("%s.s", acfg->image->name); - acfg->fp = fopen (acfg->tmpfname, "w+"); + acfg->fp = fopen (acfg->tmpfname, "w+"); } else { int i = g_file_open_tmp ("mono_aot_XXXXXX", &acfg->tmpfname, NULL); acfg->fp = fdopen (i, "w+"); diff --git a/mono/mini/aot-runtime.c b/mono/mini/aot-runtime.c index 0da4ad6168d..c531afce043 100644 --- a/mono/mini/aot-runtime.c +++ b/mono/mini/aot-runtime.c @@ -473,7 +473,7 @@ decode_klass_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf, MonoError gclass = decode_klass_ref (module, p, &p, error); if (!gclass) return NULL; - g_assert (gclass->generic_container); + g_assert (mono_class_is_gtd (gclass)); memset (&ctx, 0, sizeof (ctx)); ctx.class_inst = decode_generic_inst (module, p, &p, error); @@ -528,7 +528,7 @@ decode_klass_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf, MonoError if (!class_def) return NULL; - container = class_def->generic_container; + container = mono_class_try_get_generic_container (class_def); //FIXME is this a case for a try_get? } } else { // We didn't decode is_method, so we have to infer it from type enum. @@ -684,7 +684,7 @@ decode_type (MonoAotModule *module, guint8 *buf, guint8 **endbuf, MonoError *err gclass = decode_klass_ref (module, p, &p, error); if (!gclass) goto fail; - g_assert (gclass->generic_container); + g_assert (mono_class_is_gtd (gclass)); memset (&ctx, 0, sizeof (ctx)); ctx.class_inst = decode_generic_inst (module, p, &p, error); @@ -694,7 +694,7 @@ decode_type (MonoAotModule *module, guint8 *buf, guint8 **endbuf, MonoError *err if (!type) goto fail; klass = mono_class_from_mono_type (type); - t->data.generic_class = klass->generic_class; + t->data.generic_class = mono_class_get_generic_class (klass); break; } case MONO_TYPE_ARRAY: { @@ -1259,8 +1259,8 @@ decode_method_ref_with_target (MonoAotModule *module, MethodRef *ref, MonoMethod memset (&ctx, 0, sizeof (ctx)); - if (FALSE && klass->generic_class) { - ctx.class_inst = klass->generic_class->context.class_inst; + if (FALSE && mono_class_is_ginst (klass)) { + ctx.class_inst = mono_class_get_generic_class (klass)->context.class_inst; ctx.method_inst = NULL; ref->method = mono_class_inflate_generic_method_full_checked (ref->method, klass, &ctx, error); @@ -2444,7 +2444,7 @@ mono_aot_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res) guint8 *p; gboolean err; - if (klass->rank || !amodule) + if (klass->rank || !klass->type_token || !amodule) return FALSE; p = (guint8*)&amodule->blob [mono_aot_get_offset (amodule->class_info_offsets, mono_metadata_token_index (klass->type_token) - 1)]; @@ -3702,6 +3702,7 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin break; } case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG: + case MONO_PATCH_INFO_GET_TLS_TRAMP: break; case MONO_PATCH_INFO_AOT_JIT_INFO: ji->data.index = decode_value (p, &p); @@ -4212,7 +4213,7 @@ init_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, M gboolean inited_ok = TRUE; if (init_class) inited_ok = mono_runtime_class_init_full (mono_class_vtable (domain, init_class), error); - else if (from_plt && klass_to_run_ctor && !klass_to_run_ctor->generic_container) + else if (from_plt && klass_to_run_ctor && !mono_class_is_gtd (klass_to_run_ctor)) inited_ok = mono_runtime_class_init_full (mono_class_vtable (domain, klass_to_run_ctor), error); if (!inited_ok) return FALSE; @@ -4279,10 +4280,10 @@ mono_aot_init_gshared_method_mrgctx (gpointer aot_module, guint32 method_index, MonoGenericContext context = { NULL, NULL }; MonoClass *klass = rgctx->class_vtable->klass; - if (klass->generic_class) - context.class_inst = klass->generic_class->context.class_inst; - else if (klass->generic_container) - context.class_inst = klass->generic_container->context.class_inst; + if (mono_class_is_ginst (klass)) + context.class_inst = mono_class_get_generic_class (klass)->context.class_inst; + else if (mono_class_is_gtd (klass)) + context.class_inst = mono_class_get_generic_container (klass)->context.class_inst; context.method_inst = rgctx->method_inst; init_llvmonly_method (amodule, method_index, NULL, rgctx->class_vtable->klass, &context); diff --git a/mono/mini/branch-opts.c b/mono/mini/branch-opts.c index cab90f84d3d..c85bd5e0f1d 100644 --- a/mono/mini/branch-opts.c +++ b/mono/mini/branch-opts.c @@ -8,10 +8,11 @@ * Copyright 2011 Xamarin Inc. http://www.xamarin.com * Licensed under the MIT license. See LICENSE file in the project root for full license information. */ - #include "mini.h" +#include "config.h" #ifndef DISABLE_JIT - + +#include "mini.h" /* * Returns true if @bb is a basic block which falls through the next block. diff --git a/mono/mini/debugger-agent.c b/mono/mini/debugger-agent.c index 8ba135ce132..ec40de9a8bc 100644 --- a/mono/mini/debugger-agent.c +++ b/mono/mini/debugger-agent.c @@ -669,7 +669,7 @@ static MonoGHashTable *tid_to_thread_obj; static MonoNativeThreadId debugger_thread_id; -static HANDLE debugger_thread_handle; +static MonoThreadHandle *debugger_thread_handle; static int log_level; @@ -6683,7 +6683,7 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8 if (!m->klass->valuetype && !(m->flags & METHOD_ATTRIBUTE_STATIC) && !this_arg) { if (!strcmp (m->name, ".ctor")) { - if (m->klass->flags & TYPE_ATTRIBUTE_ABSTRACT) + if (mono_class_is_abstract (m->klass)) return ERR_INVALID_ARGUMENT; else { MonoError error; @@ -8036,7 +8036,7 @@ type_commands_internal (int command, MonoClass *klass, MonoDomain *domain, guint buffer_add_id (buf, 0); buffer_add_int (buf, klass->type_token); buffer_add_byte (buf, klass->rank); - buffer_add_int (buf, klass->flags); + buffer_add_int (buf, mono_class_get_flags (klass)); b = 0; type = &klass->byval_arg; // FIXME: Can't decide whenever a class represents a byref type @@ -8050,9 +8050,9 @@ type_commands_internal (int command, MonoClass *klass, MonoDomain *domain, guint b |= (1 << 3); if (klass->enumtype) b |= (1 << 4); - if (klass->generic_container) + if (mono_class_is_gtd (klass)) b |= (1 << 5); - if (klass->generic_container || klass->generic_class) + if (mono_class_is_gtd (klass) || mono_class_is_ginst (klass)) b |= (1 << 6); buffer_add_byte (buf, b); nnested = 0; @@ -8064,25 +8064,25 @@ type_commands_internal (int command, MonoClass *klass, MonoDomain *domain, guint while ((nested = mono_class_get_nested_types (klass, &iter))) buffer_add_typeid (buf, domain, nested); if (CHECK_PROTOCOL_VERSION (2, 12)) { - if (klass->generic_container) + if (mono_class_is_gtd (klass)) buffer_add_typeid (buf, domain, klass); - else if (klass->generic_class) - buffer_add_typeid (buf, domain, klass->generic_class->container_class); + else if (mono_class_is_ginst (klass)) + buffer_add_typeid (buf, domain, mono_class_get_generic_class (klass)->container_class); else buffer_add_id (buf, 0); } if (CHECK_PROTOCOL_VERSION (2, 15)) { int count, i; - if (klass->generic_class) { - MonoGenericInst *inst = klass->generic_class->context.class_inst; + if (mono_class_is_ginst (klass)) { + MonoGenericInst *inst = mono_class_get_generic_class (klass)->context.class_inst; count = inst->type_argc; buffer_add_int (buf, count); for (i = 0; i < count; i++) buffer_add_typeid (buf, domain, mono_class_from_mono_type (inst->type_argv [i])); - } else if (klass->generic_container) { - MonoGenericContainer *container = klass->generic_container; + } else if (mono_class_is_gtd (klass)) { + MonoGenericContainer *container = mono_class_get_generic_container (klass); MonoClass *pklass; count = container->type_argc; @@ -8911,7 +8911,7 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g } ginst = mono_metadata_get_generic_inst (type_argc, type_argv); g_free (type_argv); - tmp_context.class_inst = method->klass->generic_class ? method->klass->generic_class->context.class_inst : NULL; + tmp_context.class_inst = mono_class_is_ginst (method->klass) ? mono_class_get_generic_class (method->klass)->context.class_inst : NULL; tmp_context.method_inst = ginst; inflated = mono_class_inflate_generic_method_checked (method, &tmp_context, &error); diff --git a/mono/mini/driver.c b/mono/mini/driver.c index 14c97cbae30..7d0716dad90 100644 --- a/mono/mini/driver.c +++ b/mono/mini/driver.c @@ -49,10 +49,11 @@ #include #include #include +#include #include "mono/utils/mono-counters.h" #include "mono/utils/mono-hwcap.h" #include "mono/utils/mono-logger-internals.h" -#include "mono/utils/w32handle.h" +#include "mono/metadata/w32handle.h" #include "mini.h" #include "jit.h" @@ -934,7 +935,7 @@ compile_all_methods_thread_main_inner (CompileAllThreadArgs *args) (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) continue; - if (method->klass->generic_container) + if (mono_class_is_gtd (method->klass)) continue; sig = mono_method_signature (method); if (!sig) { @@ -1956,9 +1957,9 @@ mono_main (int argc, char* argv[]) { char *runtime_path; - runtime_path = wapi_process_get_path (getpid ()); + runtime_path = mono_w32process_get_path (getpid ()); if (runtime_path) { - wapi_process_set_cli_launcher (runtime_path); + mono_w32process_set_cli_launcher (runtime_path); g_free (runtime_path); } } diff --git a/mono/mini/exceptions-arm64.c b/mono/mini/exceptions-arm64.c index fe210faa3a2..9b7f762e991 100644 --- a/mono/mini/exceptions-arm64.c +++ b/mono/mini/exceptions-arm64.c @@ -29,15 +29,21 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; int i, ctx_reg, size; + guint8 *labels [16]; size = 256; code = start = mono_global_codeman_reserve (size); arm_movx (code, ARMREG_IP0, ARMREG_R0); ctx_reg = ARMREG_IP0; + /* Restore fregs */ + arm_ldrx (code, ARMREG_IP1, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, has_fregs)); + labels [0] = code; + arm_cbzx (code, ARMREG_IP1, 0); for (i = 0; i < 32; ++i) arm_ldrfpx (code, i, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, fregs) + (i * 8)); + mono_arm_patch (labels [0], code, MONO_R_ARM64_CBZ); /* Restore gregs */ // FIXME: Restore less registers // FIXME: fp should be restored later @@ -69,9 +75,10 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) { guint8 *code; guint8* start; - int size, offset, gregs_offset, fregs_offset, ctx_offset, num_fregs, frame_size; + int i, size, offset, gregs_offset, fregs_offset, ctx_offset, num_fregs, frame_size; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; + guint8 *labels [16]; size = 512; start = code = mono_global_codeman_reserve (size); @@ -105,10 +112,19 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) arm_strx (code, ARMREG_R0, ARMREG_FP, ctx_offset); /* Save gregs */ code = mono_arm_emit_store_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS | (1 << ARMREG_FP), ARMREG_FP, gregs_offset); - /* No need to save/restore fregs, since we don't currently use them */ + /* Save fregs */ + for (i = 0; i < num_fregs; ++i) + arm_strfpx (code, ARMREG_D8 + i, ARMREG_FP, fregs_offset + (i * 8)); /* Load regs from ctx */ code = mono_arm_emit_load_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, regs)); + /* Load fregs */ + arm_ldrx (code, ARMREG_IP0, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, has_fregs)); + labels [0] = code; + arm_cbzx (code, ARMREG_IP0, 0); + for (i = 0; i < num_fregs; ++i) + arm_ldrfpx (code, ARMREG_D8 + i, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, fregs) + (i * 8)); + mono_arm_patch (labels [0], code, MONO_R_ARM64_CBZ); /* Load fp */ arm_ldrx (code, ARMREG_FP, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_FP * 8)); @@ -126,6 +142,9 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) /* Restore regs */ code = mono_arm_emit_load_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS, ARMREG_FP, gregs_offset); + /* Restore fregs */ + for (i = 0; i < num_fregs; ++i) + arm_ldrfpx (code, ARMREG_D8 + i, ARMREG_FP, fregs_offset + (i * 8)); /* Destroy frame */ code = mono_arm_emit_destroy_frame (code, frame_size, (1 << ARMREG_IP0)); arm_retx (code, ARMREG_LR); @@ -374,6 +393,7 @@ mono_arm_throw_exception (gpointer arg, mgreg_t pc, mgreg_t *int_regs, gdouble * memset (&ctx, 0, sizeof (MonoContext)); memcpy (&(ctx.regs [0]), int_regs, sizeof (mgreg_t) * 32); memcpy (&(ctx.fregs [ARMREG_D8]), fp_regs, sizeof (double) * 8); + ctx.has_fregs = 1; ctx.pc = pc; if (mono_object_isinst_checked (exc, mono_defaults.exception_class, &error)) { @@ -402,6 +422,7 @@ mono_arm_resume_unwind (gpointer arg, mgreg_t pc, mgreg_t *int_regs, gdouble *fp memset (&ctx, 0, sizeof (MonoContext)); memcpy (&(ctx.regs [0]), int_regs, sizeof (mgreg_t) * 32); memcpy (&(ctx.fregs [ARMREG_D8]), fp_regs, sizeof (double) * 8); + ctx.has_fregs = 1; ctx.pc = pc; mono_resume_unwind (&ctx); diff --git a/mono/mini/jit-icalls.c b/mono/mini/jit-icalls.c index bb9c73c0400..225b9f3b236 100644 --- a/mono/mini/jit-icalls.c +++ b/mono/mini/jit-icalls.c @@ -72,10 +72,10 @@ ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared) if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) { MonoGenericContext context = { NULL, NULL }; - if (res->klass->generic_class) - context.class_inst = res->klass->generic_class->context.class_inst; - else if (res->klass->generic_container) - context.class_inst = res->klass->generic_container->context.class_inst; + if (mono_class_is_ginst (res->klass)) + context.class_inst = mono_class_get_generic_class (res->klass)->context.class_inst; + else if (mono_class_is_gtd (res->klass)) + context.class_inst = mono_class_get_generic_container (res->klass)->context.class_inst; context.method_inst = mono_method_get_context (method)->method_inst; res = mono_class_inflate_generic_method_checked (res, &context, &error); @@ -1108,8 +1108,8 @@ mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointe return NULL; } vmethod = mono_object_get_virtual_method (obj, method); - g_assert (!vmethod->klass->generic_container); - g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open); + g_assert (!mono_class_is_gtd (vmethod->klass)); + g_assert (!mono_class_is_ginst (vmethod->klass) || !mono_class_get_generic_class (vmethod->klass)->context.class_inst->is_open); g_assert (!context->method_inst || !context->method_inst->is_open); addr = mono_compile_method_checked (vmethod, &error); @@ -1334,7 +1334,7 @@ constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *k mono_error_init (error); - if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (klass)) { MonoObject *this_obj; /* Have to use the receiver's type instead of klass, the receiver is a ref type */ @@ -1352,7 +1352,7 @@ constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *k mono_class_setup_vtable (klass); g_assert (klass->vtable); vt_slot = mono_method_get_vtable_slot (cmethod); - if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (cmethod->klass)) { iface_offset = mono_class_interface_offset (klass, cmethod->klass); g_assert (iface_offset != -1); vt_slot += iface_offset; @@ -1608,10 +1608,10 @@ resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_a else declaring = m; - if (m->klass->generic_class) - context.class_inst = m->klass->generic_class->context.class_inst; + if (mono_class_is_ginst (m->klass)) + context.class_inst = mono_class_get_generic_class (m->klass)->context.class_inst; else - g_assert (!m->klass->generic_container); + g_assert (!mono_class_is_gtd (m->klass)); generic_virtual = imt_method; g_assert (generic_virtual); @@ -1692,10 +1692,10 @@ mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic else declaring = m; - if (m->klass->generic_class) - context.class_inst = m->klass->generic_class->context.class_inst; + if (mono_class_is_ginst (m->klass)) + context.class_inst = mono_class_get_generic_class (m->klass)->context.class_inst; else - g_assert (!m->klass->generic_container); + g_assert (!mono_class_is_gtd (m->klass)); g_assert (generic_virtual->is_inflated); context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst; diff --git a/mono/mini/main.c b/mono/mini/main.c index 8d73080631e..77f8bc9578c 100644 --- a/mono/mini/main.c +++ b/mono/mini/main.c @@ -151,7 +151,7 @@ bundle_save_library_initialize () bundle_save_library_initialized = 1; char *path = g_build_filename (g_get_tmp_dir (), "mono-bundle-XXXXXX", NULL); bundled_dylibrary_directory = g_mkdtemp (path); - g_free (path); + /* don't free path - mkdtemp modifies it in place, and bundled_dylibrary_directory is an alias of it */ if (bundled_dylibrary_directory == NULL) return; atexit (delete_bundled_libraries); @@ -280,9 +280,10 @@ probe_embedded (const char *program, int *ref_argc, char **ref_argv []) mono_register_bundled_assemblies ((const MonoBundledAssembly **) assemblies->data); new_argv = g_new (char *, (*ref_argc)+1); - for (j = 0; j < *ref_argc; j++) - new_argv [j] = (*ref_argv)[j]; - new_argv [j] = entry_point; + new_argv [0] = (*ref_argv)[0]; + new_argv [1] = entry_point; + for (j = 1; j < *ref_argc; j++) + new_argv [j+1] = (*ref_argv)[j]; *ref_argv = new_argv; (*ref_argc)++; diff --git a/mono/mini/method-to-ir.c b/mono/mini/method-to-ir.c index 297516cb32c..3143431b6c4 100644 --- a/mono/mini/method-to-ir.c +++ b/mono/mini/method-to-ir.c @@ -1657,7 +1657,7 @@ mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *kla { int max_iid_reg = alloc_preg (cfg); - MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id)); + MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id)); mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target); } @@ -1668,7 +1668,7 @@ mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass { int max_iid_reg = alloc_preg (cfg); - MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id)); + MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id)); mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target); } @@ -1794,7 +1794,7 @@ mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClas mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class); } else if (klass->cast_class == mono_defaults.enum_class) { mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class); - } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) { + } else if (mono_class_is_interface (klass->cast_class)) { mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL); } else { // Pass -1 as obj_reg to skip the check below for arrays of arrays @@ -2550,7 +2550,7 @@ check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_ gboolean pass_mrgctx = FALSE; if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) && - (cmethod->klass->generic_class || cmethod->klass->generic_container)) { + (mono_class_is_ginst (cmethod->klass) || mono_class_is_gtd (cmethod->klass))) { gboolean sharable = FALSE; if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) @@ -2791,7 +2791,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign if (!sig) sig = mono_method_signature (method); - if (cfg->llvm_only && (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) + if (cfg->llvm_only && (mono_class_is_interface (method->klass))) g_assert_not_reached (); if (rgctx_arg) { @@ -2829,7 +2829,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) return emit_llvmonly_virtual_call (cfg, method, sig, 0, args); - need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE); + need_unbox_trampoline = method->klass == mono_defaults.object_class || mono_class_is_interface (method->klass); call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline); @@ -2918,7 +2918,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign } else { vtable_reg = alloc_preg (cfg); MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable)); - if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (method->klass)) { guint32 imt_slot = mono_method_get_imt_slot (method); emit_imt_argument (cfg, call, call->method, imt_arg); slot_reg = vtable_reg; @@ -4258,7 +4258,7 @@ handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_ EMIT_NEW_CLASSCONST (cfg, iargs [1], klass); alloc_ftn = ves_icall_object_new; - } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) { + } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !mono_class_is_ginst (klass)) { /* This happens often in argument checking code, eg. throw new FooException... */ /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */ EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token)); @@ -4432,11 +4432,11 @@ mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass * MonoGenericContainer *container; MonoGenericInst *ginst; - if (klass->generic_class) { - container = klass->generic_class->container_class->generic_container; - ginst = klass->generic_class->context.class_inst; - } else if (klass->generic_container && context_used) { - container = klass->generic_container; + if (mono_class_is_ginst (klass)) { + container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class); + ginst = mono_class_get_generic_class (klass)->context.class_inst; + } else if (mono_class_is_gtd (klass) && context_used) { + container = mono_class_get_generic_container (klass); ginst = container->context.class_inst; } else { return FALSE; @@ -4495,7 +4495,7 @@ method_needs_stack_walk (MonoCompile *cfg, MonoMethod *cmethod) return FALSE; } -#define is_complex_isinst(klass) ((klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR) +#define is_complex_isinst(klass) (mono_class_is_interface (klass) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || mono_class_is_sealed (klass) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR) static MonoInst* emit_isinst_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args) @@ -4605,7 +4605,7 @@ handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context save_cast_details (cfg, klass, obj_reg, FALSE); - if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (klass)) { MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable)); mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL); } else { @@ -4613,7 +4613,7 @@ handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable)); - if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) { + if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) { /* the remoting code is broken, access the class for now */ if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/ MonoVTable *vt = mono_class_vtable (cfg->domain, klass); @@ -4686,7 +4686,7 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_us MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable)); - if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (klass)) { g_assert (!context_used); /* the is_null_bb target simply copies the input register to the output */ mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb); @@ -4716,7 +4716,7 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_us } else if (klass->cast_class == mono_defaults.enum_class) { mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb); MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb); - } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) { + } else if (mono_class_is_interface (klass->cast_class)) { mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb); } else { if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) { @@ -4736,7 +4736,7 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_us /* the is_null_bb target simply copies the input register to the output */ mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb); } else { - if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) { + if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) { g_assert (!context_used); /* the remoting code is broken, access the class for now */ if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/ @@ -4805,7 +4805,7 @@ handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src) MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0); MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb); - if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (klass)) { #ifndef DISABLE_REMOTING NEW_BBLOCK (cfg, interface_fail_bb); #endif @@ -4909,7 +4909,7 @@ handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src) save_cast_details (cfg, klass, obj_reg, FALSE); - if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (klass)) { #ifndef DISABLE_REMOTING NEW_BBLOCK (cfg, interface_fail_bb); @@ -5186,7 +5186,7 @@ handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMe * This is hard to do with the current call code, since we would have to emit a branch and two different calls. So instead, we * pack the arguments into an array, and do the rest of the work in in an icall. */ - if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) && + if (((cmethod->klass == mono_defaults.object_class) || mono_class_is_interface (cmethod->klass) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) && (MONO_TYPE_IS_VOID (fsig->ret) || MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_IS_REFERENCE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret) || mini_is_gsharedvt_type (fsig->ret)) && (fsig->param_count == 0 || (!fsig->hasthis && fsig->param_count == 1) || (fsig->param_count == 1 && (MONO_TYPE_IS_REFERENCE (fsig->params [0]) || fsig->params [0]->byref || mini_is_gsharedvt_type (fsig->params [0]))))) { MonoInst *args [16]; @@ -5359,7 +5359,7 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method) return FALSE; } } - } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) { + } else if (mono_class_is_before_field_init (method->klass)) { if (cfg->run_cctors && method->klass->has_cctor) { /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */ if (!method->klass->runtime_info) @@ -5395,7 +5395,7 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method) * the cctor will need to be run at aot method load time, for example, * or at the end of the compilation of the inlining method. */ - if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT))) + if (mono_class_needs_cctor_run (method->klass, NULL) && !mono_class_is_before_field_init (method->klass)) return FALSE; } @@ -5425,7 +5425,7 @@ mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoCla return FALSE; } - if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) { + if (mono_class_is_before_field_init (klass)) { if (cfg->method == method) return FALSE; } @@ -7716,7 +7716,7 @@ emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig MonoInst *icall_args [16]; MonoInst *call_target, *ins, *vtable_ins; int arg_reg, this_reg, vtable_reg; - gboolean is_iface = cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE; + gboolean is_iface = mono_class_is_interface (cmethod->klass); gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig); gboolean variant_iface = FALSE; guint32 slot; @@ -7952,7 +7952,7 @@ is_jit_optimizer_disabled (MonoMethod *m) return FALSE; } - attrs = mono_custom_attrs_from_assembly_checked (ass, &error); + attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error); mono_error_cleanup (&error); /* FIXME don't swallow the error */ if (attrs) { for (i = 0; i < attrs->num_attrs; ++i) { @@ -9381,7 +9381,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b n = fsig->param_count + fsig->hasthis; - if (!cfg->gshared && cmethod->klass->generic_container) + if (!cfg->gshared && mono_class_is_gtd (cmethod->klass)) UNVERIFIED; if (!cfg->gshared) @@ -9400,7 +9400,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (mini_is_gsharedvt_klass (constrained_class)) { if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) { /* The 'Own method' case below */ - } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) { + } else if (cmethod->klass->image != mono_defaults.corlib && !mono_class_is_interface (cmethod->klass) && !cmethod->klass->valuetype) { /* 'The type parameter is instantiated as a reference type' case below. */ } else { ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen); @@ -9421,7 +9421,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b * A simple solution would be to box always and make a normal virtual call, but that would * be bad performance wise. */ - if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) { + if (mono_class_is_interface (cmethod->klass) && mono_class_is_ginst (cmethod->klass)) { /* * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary. */ @@ -9474,7 +9474,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b nonbox_call->dreg = ins->dreg; goto call_end; } else { - g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE); + g_assert (mono_class_is_interface (cmethod->klass)); addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE); ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL); goto call_end; @@ -9549,7 +9549,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b * If the callee is a shared method, then its static cctor * might not get called after the call was patched. */ - if (cfg->gshared && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) { + if (cfg->gshared && cmethod->klass != method->klass && mono_class_is_ginst (cmethod->klass) && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) { emit_class_init (cfg, cmethod->klass); CHECK_TYPELOAD (cmethod->klass); } @@ -9561,7 +9561,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b context_used = mini_method_check_context_used (cfg, cmethod); - if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) { + if (context_used && mono_class_is_interface (cmethod->klass)) { /* Generic method interface calls are resolved via a helper function and don't @@ -9804,13 +9804,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid * patching gshared method addresses into a gsharedvt method. */ - if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) && + if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || mono_class_is_ginst (cmethod->klass)) && !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) && (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) { MonoRgctxInfoType info_type; if (virtual_) { - //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) + //if (mono_class_is_interface (cmethod->klass)) //GSHAREDVT_FAILURE (*ip); // disable for possible remoting calls if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)) @@ -9823,7 +9823,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b cmethod, MONO_RGCTX_INFO_METHOD); /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */ vtable_arg = NULL; - } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) { + } else if (mono_class_is_interface (cmethod->klass) && !imt_arg) { /* This can happen when we call a fully instantiated iface method */ imt_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD); @@ -10858,7 +10858,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (mono_security_core_clr_enabled ()) ensure_method_is_allowed_to_call_method (cfg, method, cmethod); - if (cfg->gshared && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) { + if (cfg->gshared && cmethod && cmethod->klass != method->klass && mono_class_is_ginst (cmethod->klass) && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) { emit_class_init (cfg, cmethod->klass); CHECK_TYPELOAD (cmethod->klass); } @@ -12175,7 +12175,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg); MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg)); MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg); - } else if (cfg->compile_aot) { + } else { int const_reg = alloc_preg (cfg); int type_reg = alloc_preg (cfg); @@ -12183,9 +12183,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg); MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg)); MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg); - } else { - MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg); - MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass); } MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg); @@ -15128,7 +15125,7 @@ mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins) ret = emit_isinst_with_cache_nonshared (cfg, source, klass); else ret = emit_castclass_with_cache_nonshared (cfg, source, klass); - } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) { + } else if (!context_used && (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass))) { MonoInst *iargs [1]; int costs; diff --git a/mono/mini/mini-arm.c b/mono/mini/mini-arm.c index 82795e5b8e8..13a3ffee37f 100644 --- a/mono/mini/mini-arm.c +++ b/mono/mini/mini-arm.c @@ -127,6 +127,7 @@ static int vfp_scratch2 = ARM_VFP_D1; static int i8_align; static gpointer single_step_tramp, breakpoint_tramp; +static gpointer get_tls_tramp; /* * The code generated for sequence points reads from this location, which is @@ -167,6 +168,9 @@ int mono_exc_esp_offset = 0; static void mono_arch_compute_omit_fp (MonoCompile *cfg); #endif +static guint8* +emit_aotconst (MonoCompile *cfg, guint8 *code, int dreg, int patch_type, gpointer data); + const char* mono_arch_regname (int reg) { @@ -330,9 +334,21 @@ mono_arm_emit_tls_get (MonoCompile *cfg, guint8* code, int dreg, int tls_offset) { #ifdef HAVE_FAST_TLS code = mono_arm_emit_load_imm (code, ARMREG_R0, tls_offset); - mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, - "mono_get_tls_key"); - code = emit_call_seq (cfg, code); + if (cfg->compile_aot) { + /* + * This opcode is generated by CEE_MONO_JIT_ATTACH, so it can execute on + * threads which are not yet attached to the runtime. This means we can't + * call it directly, since the call would go through the trampoline code + * which assumes the thread is attached. So use a separate patch info type + * for it, and load it from a preinitialized GOT slot. + */ + code = emit_aotconst (cfg, code, ARMREG_R1, MONO_PATCH_INFO_GET_TLS_TRAMP, NULL); + code = emit_call_reg (code, ARMREG_R1); + } else { + mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, + "mono_get_tls_key"); + code = emit_call_seq (cfg, code); + } if (dreg != ARMREG_R0) ARM_MOV_REG_REG (code, dreg, ARMREG_R0); #else @@ -347,9 +363,14 @@ mono_arm_emit_tls_get_reg (MonoCompile *cfg, guint8* code, int dreg, int tls_off #ifdef HAVE_FAST_TLS if (tls_offset_reg != ARMREG_R0) ARM_MOV_REG_REG (code, ARMREG_R0, tls_offset_reg); - mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, - "mono_get_tls_key"); - code = emit_call_seq (cfg, code); + if (cfg->compile_aot) { + code = emit_aotconst (cfg, code, ARMREG_R1, MONO_PATCH_INFO_GET_TLS_TRAMP, NULL); + code = emit_call_reg (code, ARMREG_R1); + } else { + mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, + "mono_get_tls_key"); + code = emit_call_seq (cfg, code); + } if (dreg != ARMREG_R0) ARM_MOV_REG_REG (code, dreg, ARMREG_R0); #else @@ -5989,6 +6010,8 @@ mono_arch_register_lowlevel_calls (void) mono_register_jit_icall (tls_imp.get_tls_thunk, "mono_get_tls_key", mono_create_icall_signature ("ptr ptr"), TRUE); mono_register_jit_icall (tls_imp.set_tls_thunk, "mono_set_tls_key", mono_create_icall_signature ("void ptr ptr"), TRUE); + get_tls_tramp = tls_imp.get_tls_thunk; + if (tls_imp.get_tls_thunk_end) { mono_tramp_info_register ( mono_tramp_info_create ( @@ -7512,3 +7535,23 @@ mono_arch_get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) { return get_call_info (mp, sig); } + +gpointer +mono_arch_get_get_tls_tramp (void) +{ + return get_tls_tramp; +} + +static guint8* +emit_aotconst (MonoCompile *cfg, guint8 *code, int dreg, int patch_type, gpointer data) +{ + /* OP_AOTCONST */ + mono_add_patch_info (cfg, code - cfg->native_code, patch_type, data); + ARM_LDR_IMM (code, dreg, ARMREG_PC, 0); + ARM_B (code, 0); + *(gpointer*)code = NULL; + code += 4; + /* Load the value from the GOT */ + ARM_LDR_REG_REG (code, dreg, ARMREG_PC, dreg); + return code; +} diff --git a/mono/mini/mini-arm.h b/mono/mini/mini-arm.h index cb31a6e8b24..694f6b87e0e 100644 --- a/mono/mini/mini-arm.h +++ b/mono/mini/mini-arm.h @@ -350,6 +350,7 @@ typedef struct MonoCompileArch { #define MONO_ARCH_HAVE_SDB_TRAMPOLINES 1 #define MONO_ARCH_HAVE_PATCH_CODE_NEW 1 #define MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT 1 +#define MONO_ARCH_HAVE_GET_TLS_TRAMP 1 #define MONO_ARCH_HAVE_TLS_GET (mono_arm_have_tls_get ()) #define MONO_ARCH_HAVE_TLS_GET_REG 1 diff --git a/mono/mini/mini-codegen.c b/mono/mini/mini-codegen.c index 57a7a38deef..a8bf46b2886 100644 --- a/mono/mini/mini-codegen.c +++ b/mono/mini/mini-codegen.c @@ -4,6 +4,8 @@ * (C) 2003 Ximian, Inc. */ +#include "config.h" + #include #include #ifdef HAVE_UNISTD_H @@ -21,6 +23,8 @@ #include "trace.h" #include "mini-arch.h" +#ifndef DISABLE_JIT + #ifndef MONO_MAX_XREGS #define MONO_MAX_XREGS 0 @@ -28,7 +32,6 @@ #define MONO_ARCH_CALLEE_XREGS 0 #endif - #define MONO_ARCH_BANK_MIRRORED -2 @@ -411,47 +414,7 @@ typedef struct { regmask_t preferred_mask; /* the hreg where the register should be allocated, or 0 */ } RegTrack; -#if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT) - -static const char* const patch_info_str[] = { -#define PATCH_INFO(a,b) "" #a, -#include "patch-info.h" -#undef PATCH_INFO -}; - -const char* -mono_ji_type_to_string (MonoJumpInfoType type) -{ - return patch_info_str [type]; -} - -void -mono_print_ji (const MonoJumpInfo *ji) -{ - switch (ji->type) { - case MONO_PATCH_INFO_RGCTX_FETCH: { - MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry; - - printf ("[RGCTX_FETCH "); - mono_print_ji (entry->data); - printf (" - %s]", mono_rgctx_info_type_to_str (entry->info_type)); - break; - } - case MONO_PATCH_INFO_METHODCONST: { - char *s = mono_method_full_name (ji->data.method, TRUE); - printf ("[METHODCONST - %s]", s); - g_free (s); - break; - } - case MONO_PATCH_INFO_INTERNAL_METHOD: { - printf ("[INTERNAL_METHOD - %s]", ji->data.name); - break; - } - default: - printf ("[%s]", patch_info_str [ji->type]); - break; - } -} +#if !defined(DISABLE_LOGGING) void mono_print_ins_index (int i, MonoInst *ins) @@ -785,22 +748,11 @@ print_regtrack (RegTrack *t, int num) } #else -const char* -mono_ji_type_to_string (MonoJumpInfoType type) -{ - return ""; -} - -void -mono_print_ji (const MonoJumpInfo *ji) -{ -} - void mono_print_ins_index (int i, MonoInst *ins) { } -#endif /* !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT) */ +#endif /* !defined(DISABLE_LOGGING) */ void mono_print_ins (MonoInst *ins) @@ -1151,8 +1103,6 @@ get_callee_mask (const char spec) static gint8 desc_to_fixed_reg [256]; static gboolean desc_to_fixed_reg_inited = FALSE; -#ifndef DISABLE_JIT - /* * Local register allocation. * We first scan the list of instructions and we save the liveness info of @@ -2554,47 +2504,6 @@ mono_opcode_to_type (int opcode, int cmp_opcode) } } -#endif /* DISABLE_JIT */ - -gboolean -mono_is_regsize_var (MonoType *t) -{ - t = mini_get_underlying_type (t); - switch (t->type) { - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_PTR: - case MONO_TYPE_FNPTR: -#if SIZEOF_REGISTER == 8 - case MONO_TYPE_I8: - case MONO_TYPE_U8: -#endif - return TRUE; - case MONO_TYPE_OBJECT: - case MONO_TYPE_STRING: - case MONO_TYPE_CLASS: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_ARRAY: - return TRUE; - case MONO_TYPE_GENERICINST: - if (!mono_type_generic_inst_is_valuetype (t)) - return TRUE; - return FALSE; - case MONO_TYPE_VALUETYPE: - return FALSE; - default: - return FALSE; - } -} - -#ifndef DISABLE_JIT - /* * mono_peephole_ins: * @@ -2844,3 +2753,40 @@ mono_regstate_free (MonoRegState *rs) { } #endif /* DISABLE_JIT */ + +gboolean +mono_is_regsize_var (MonoType *t) +{ + t = mini_get_underlying_type (t); + switch (t->type) { + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_PTR: + case MONO_TYPE_FNPTR: +#if SIZEOF_REGISTER == 8 + case MONO_TYPE_I8: + case MONO_TYPE_U8: +#endif + return TRUE; + case MONO_TYPE_OBJECT: + case MONO_TYPE_STRING: + case MONO_TYPE_CLASS: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_ARRAY: + return TRUE; + case MONO_TYPE_GENERICINST: + if (!mono_type_generic_inst_is_valuetype (t)) + return TRUE; + return FALSE; + case MONO_TYPE_VALUETYPE: + return FALSE; + default: + return FALSE; + } +} diff --git a/mono/mini/mini-darwin.c b/mono/mini/mini-darwin.c index a52f5eb80d0..4e632071ce2 100644 --- a/mono/mini/mini-darwin.c +++ b/mono/mini/mini-darwin.c @@ -166,8 +166,8 @@ gboolean mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoThreadInfo *info) { kern_return_t ret; - mach_msg_type_number_t num_state; - thread_state_t state; + mach_msg_type_number_t num_state, num_fpstate; + thread_state_t state, fpstate; ucontext_t ctx; mcontext_t mctx; MonoJitTlsData *jit_tls; @@ -183,15 +183,16 @@ mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoThreadInfo tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = NULL; state = (thread_state_t) alloca (mono_mach_arch_get_thread_state_size ()); + fpstate = (thread_state_t) alloca (mono_mach_arch_get_thread_fpstate_size ()); mctx = (mcontext_t) alloca (mono_mach_arch_get_mcontext_size ()); do { - ret = mono_mach_arch_get_thread_state (info->native_handle, state, &num_state); + ret = mono_mach_arch_get_thread_states (info->native_handle, state, &num_state, fpstate, &num_fpstate); } while (ret == KERN_ABORTED); if (ret != KERN_SUCCESS) return FALSE; - mono_mach_arch_thread_state_to_mcontext (state, mctx); + mono_mach_arch_thread_states_to_mcontext (state, fpstate, mctx); ctx.uc_mcontext = mctx; mono_sigctx_to_monoctx (&ctx, &tctx->ctx); diff --git a/mono/mini/mini-exceptions.c b/mono/mini/mini-exceptions.c index 5342deb8b3a..400940957fb 100644 --- a/mono/mini/mini-exceptions.c +++ b/mono/mini/mini-exceptions.c @@ -613,23 +613,23 @@ get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info) klass = vtable->klass; } - //g_assert (!method->klass->generic_container); - if (method->klass->generic_class) - method_container_class = method->klass->generic_class->container_class; + //g_assert (!mono_class_is_gtd (method->klass)); + if (mono_class_is_ginst (method->klass)) + method_container_class = mono_class_get_generic_class (method->klass)->container_class; else method_container_class = method->klass; /* class might refer to a subclass of method's class */ - while (!(klass == method->klass || (klass->generic_class && klass->generic_class->container_class == method_container_class))) { + while (!(klass == method->klass || (mono_class_is_ginst (klass) && mono_class_get_generic_class (klass)->container_class == method_container_class))) { klass = klass->parent; g_assert (klass); } - if (klass->generic_class || klass->generic_container) + if (mono_class_is_ginst (klass) || mono_class_is_gtd (klass)) context.class_inst = mini_class_get_context (klass)->class_inst; - if (klass->generic_class) - g_assert (mono_class_has_parent_and_ignore_generics (klass->generic_class->container_class, method_container_class)); + if (mono_class_is_ginst (klass)) + g_assert (mono_class_has_parent_and_ignore_generics (mono_class_get_generic_class (klass)->container_class, method_container_class)); else g_assert (mono_class_has_parent_and_ignore_generics (klass, method_container_class)); @@ -1229,7 +1229,7 @@ wrap_non_exception_throws (MonoMethod *m) klass = mono_class_get_runtime_compat_attr_class (); - attrs = mono_custom_attrs_from_assembly_checked (ass, &error); + attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error); mono_error_cleanup (&error); /* FIXME don't swallow the error */ if (attrs) { for (i = 0; i < attrs->num_attrs; ++i) { diff --git a/mono/mini/mini-generic-sharing.c b/mono/mini/mini-generic-sharing.c index da5b3afc6c2..07174330eb2 100644 --- a/mono/mini/mini-generic-sharing.c +++ b/mono/mini/mini-generic-sharing.c @@ -76,7 +76,7 @@ type_check_context_used (MonoType *type, gboolean recursive) if (recursive) { MonoGenericClass *gclass = type->data.generic_class; - g_assert (gclass->container_class->generic_container); + g_assert (mono_class_is_gtd (gclass->container_class)); return mono_generic_context_check_used (&gclass->context); } else { return 0; @@ -137,10 +137,10 @@ mono_class_check_context_used (MonoClass *klass) context_used |= type_check_context_used (&klass->this_arg, FALSE); context_used |= type_check_context_used (&klass->byval_arg, FALSE); - if (klass->generic_class) - context_used |= mono_generic_context_check_used (&klass->generic_class->context); - else if (klass->generic_container) - context_used |= mono_generic_context_check_used (&klass->generic_container->context); + if (mono_class_is_ginst (klass)) + context_used |= mono_generic_context_check_used (&mono_class_get_generic_class (klass)->context); + else if (mono_class_is_gtd (klass)) + context_used |= mono_generic_context_check_used (&mono_class_get_generic_container (klass)->context); return context_used; } @@ -274,8 +274,8 @@ register_generic_subclass (MonoClass *klass) g_assert (rgctx_template); - if (parent->generic_class) - parent = parent->generic_class->container_class; + if (mono_class_is_ginst (parent)) + parent = mono_class_get_generic_class (parent)->container_class; if (!generic_subclass_hash) generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL); @@ -475,7 +475,7 @@ mono_class_get_method_generic (MonoClass *klass, MonoMethod *method) declaring = method; m = NULL; - if (klass->generic_class) + if (mono_class_is_ginst (klass)) m = mono_class_get_inflated_method (klass, declaring); if (!m) { @@ -734,8 +734,8 @@ class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gbo static MonoClass* class_uninstantiated (MonoClass *klass) { - if (klass->generic_class) - return klass->generic_class->container_class; + if (mono_class_is_ginst (klass)) + return mono_class_get_generic_class (klass)->container_class; return klass; } @@ -835,15 +835,15 @@ class_get_rgctx_template_oti (MonoClass *klass, int type_argc, guint32 slot, gbo DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot)); - if (klass->generic_class && !shared) { + if (mono_class_is_ginst (klass) && !shared) { MonoRuntimeGenericContextInfoTemplate oti; gboolean tmp_do_free; - oti = class_get_rgctx_template_oti (klass->generic_class->container_class, + oti = class_get_rgctx_template_oti (mono_class_get_generic_class (klass)->container_class, type_argc, slot, TRUE, FALSE, &tmp_do_free); if (oti.data) { gpointer info = oti.data; - oti.data = inflate_info (&oti, &klass->generic_class->context, klass, temporary); + oti.data = inflate_info (&oti, &mono_class_get_generic_class (klass)->context, klass, temporary); if (tmp_do_free) free_inflated_info (oti.info_type, info); } @@ -1118,7 +1118,7 @@ get_wrapper_shared_type (MonoType *t) return get_wrapper_shared_type (&mono_defaults.object_class->byval_arg); klass = mono_class_from_mono_type (t); - orig_ctx = &klass->generic_class->context; + orig_ctx = &mono_class_get_generic_class (klass)->context; memset (&ctx, 0, sizeof (MonoGenericContext)); @@ -1136,7 +1136,7 @@ get_wrapper_shared_type (MonoType *t) args [i] = get_wrapper_shared_type (inst->type_argv [i]); ctx.method_inst = mono_metadata_get_generic_inst (inst->type_argc, args); } - klass = mono_class_inflate_generic_class_checked (klass->generic_class->container_class, &ctx, &error); + klass = mono_class_inflate_generic_class_checked (mono_class_get_generic_class (klass)->container_class, &ctx, &error); mono_error_assert_ok (&error); /* FIXME don't swallow the error */ return &klass->byval_arg; } @@ -1183,7 +1183,7 @@ mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig) MonoMethod *res, *cached; WrapperInfo *info; MonoMethodSignature *csig, *gsharedvt_sig; - int i, pindex, retval_var; + int i, pindex, retval_var = 0; static GHashTable *cache; // FIXME: Memory management @@ -1646,7 +1646,7 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti mono_class_setup_vtable (info->klass); // FIXME: Check type load - if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (iface_class)) { ioffset = mono_class_interface_offset (info->klass, iface_class); g_assert (ioffset != -1); } else { @@ -1672,7 +1672,7 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti mono_class_setup_vtable (info->klass); // FIXME: Check type load - if (iface_class->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_is_interface (iface_class)) { ioffset = mono_class_interface_offset (info->klass, iface_class); g_assert (ioffset != -1); } else { @@ -1786,7 +1786,7 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti /* See mono_emit_method_call_full () */ /* The gsharedvt trampoline will recognize this constant */ vcall_offset = MONO_GSHAREDVT_DEL_INVOKE_VT_OFFSET; - } else if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) { + } else if (mono_class_is_interface (method->klass)) { guint32 imt_slot = mono_method_get_imt_slot (method); vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P; } else { @@ -2058,8 +2058,8 @@ register_info (MonoClass *klass, int type_argc, gpointer data, MonoRgctxInfoType MonoRuntimeGenericContextTemplate *parent_template; MonoRuntimeGenericContextInfoTemplate *oti; - if (parent->generic_class) - parent = parent->generic_class->container_class; + if (mono_class_is_ginst (parent)) + parent = mono_class_get_generic_class (parent)->container_class; parent_template = mono_class_get_runtime_generic_context_template (parent); oti = rgctx_template_get_other_slot (parent_template, type_argc, i); @@ -2313,7 +2313,7 @@ fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContex int i, first_slot, size; MonoDomain *domain = class_vtable->domain; MonoClass *klass = class_vtable->klass; - MonoGenericContext *class_context = klass->generic_class ? &klass->generic_class->context : NULL; + MonoGenericContext *class_context = mono_class_is_ginst (klass) ? &mono_class_get_generic_class (klass)->context : NULL; MonoRuntimeGenericContextInfoTemplate oti; MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst }; int rgctx_index; @@ -2483,7 +2483,7 @@ mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst MonoMethodRuntimeGenericContext *mrgctx; MonoMethodRuntimeGenericContext key; - g_assert (!class_vtable->klass->generic_container); + g_assert (!mono_class_is_gtd (class_vtable->klass)); g_assert (!method_inst->is_open); mono_domain_lock (domain); @@ -2634,7 +2634,7 @@ mono_method_is_generic_impl (MonoMethod *method) if not compiled with sharing. */ if (method->wrapper_type != MONO_WRAPPER_NONE) return FALSE; - if (method->klass->generic_container) + if (mono_class_is_gtd (method->klass)) return TRUE; return FALSE; } @@ -2786,18 +2786,18 @@ mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_va } } - if (method->klass->generic_class) { - if (!mono_generic_context_is_sharable_full (&method->klass->generic_class->context, allow_type_vars, allow_partial)) + if (mono_class_is_ginst (method->klass)) { + if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method->klass)->context, allow_type_vars, allow_partial)) return FALSE; - g_assert (method->klass->generic_class->container_class && - method->klass->generic_class->container_class->generic_container); + g_assert (mono_class_get_generic_class (method->klass)->container_class && + mono_class_is_gtd (mono_class_get_generic_class (method->klass)->container_class)); - if (has_constraints (method->klass->generic_class->container_class->generic_container)) + if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method->klass)->container_class))) return FALSE; } - if (method->klass->generic_container && !allow_type_vars) + if (mono_class_is_gtd (method->klass) && !allow_type_vars) return FALSE; /* This does potentially expensive cattr checks, so do it at the end */ @@ -2838,7 +2838,7 @@ mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_v return ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype) && - (method->klass->generic_class || method->klass->generic_container); + (mono_class_is_ginst (method->klass) || mono_class_is_gtd (method->klass)); } static MonoGenericInst* @@ -2867,9 +2867,9 @@ mono_method_construct_object_context (MonoMethod *method) { MonoGenericContext object_context; - g_assert (!method->klass->generic_class); - if (method->klass->generic_container) { - int type_argc = method->klass->generic_container->type_argc; + g_assert (!mono_class_is_ginst (method->klass)); + if (mono_class_is_gtd (method->klass)) { + int type_argc = mono_class_get_generic_container (method->klass)->type_argc; object_context.class_inst = get_object_generic_inst (type_argc); } else { @@ -3003,10 +3003,10 @@ mono_generic_context_equal_deep (MonoGenericContext *context1, MonoGenericContex MonoClass* mini_class_get_container_class (MonoClass *klass) { - if (klass->generic_class) - return klass->generic_class->container_class; + if (mono_class_is_ginst (klass)) + return mono_class_get_generic_class (klass)->container_class; - g_assert (klass->generic_container); + g_assert (mono_class_is_gtd (klass)); return klass; } @@ -3019,11 +3019,11 @@ mini_class_get_container_class (MonoClass *klass) MonoGenericContext* mini_class_get_context (MonoClass *klass) { - if (klass->generic_class) - return &klass->generic_class->context; + if (mono_class_is_ginst (klass)) + return &mono_class_get_generic_class (klass)->context; - g_assert (klass->generic_container); - return &klass->generic_container->context; + g_assert (mono_class_is_gtd (klass)); + return &mono_class_get_generic_container (klass)->context; } /* @@ -3205,10 +3205,10 @@ mini_type_is_vtype (MonoType *t) gboolean mini_class_is_generic_sharable (MonoClass *klass) { - if (klass->generic_class && is_async_state_machine_class (klass)) + if (mono_class_is_ginst (klass) && is_async_state_machine_class (klass)) return FALSE; - return (klass->generic_class && mono_generic_context_is_sharable (&klass->generic_class->context, FALSE)); + return (mono_class_is_ginst (klass) && mono_generic_context_is_sharable (&mono_class_get_generic_class (klass)->context, FALSE)); } gboolean @@ -3351,9 +3351,9 @@ get_shared_type (MonoType *t, MonoType *type) memset (&context, 0, sizeof (context)); if (gclass->context.class_inst) - context.class_inst = get_shared_inst (gclass->context.class_inst, gclass->container_class->generic_container->context.class_inst, NULL, FALSE, FALSE, TRUE); + context.class_inst = get_shared_inst (gclass->context.class_inst, mono_class_get_generic_container (gclass->container_class)->context.class_inst, NULL, FALSE, FALSE, TRUE); if (gclass->context.method_inst) - context.method_inst = get_shared_inst (gclass->context.method_inst, gclass->container_class->generic_container->context.method_inst, NULL, FALSE, FALSE, TRUE); + context.method_inst = get_shared_inst (gclass->context.method_inst, mono_class_get_generic_container (gclass->container_class)->context.method_inst, NULL, FALSE, FALSE, TRUE); k = mono_class_inflate_generic_class_checked (gclass->container_class, &context, &error); mono_error_assert_ok (&error); /* FIXME don't swallow the error */ @@ -3456,7 +3456,7 @@ mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gs } } - if (method->is_generic || (method->klass->generic_container && !method->is_inflated)) { + if (method->is_generic || (mono_class_is_gtd (method->klass) && !method->is_inflated)) { declaring_method = method; } else { declaring_method = mono_method_get_declaring_generic_method (method); @@ -3466,14 +3466,14 @@ mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gs if (declaring_method->is_generic) shared_context = mono_method_get_generic_container (declaring_method)->context; else - shared_context = declaring_method->klass->generic_container->context; + shared_context = mono_class_get_generic_container (declaring_method->klass)->context; if (!is_gsharedvt) partial = mono_method_is_generic_sharable_full (method, FALSE, TRUE, FALSE); gsharedvt = is_gsharedvt || (!partial && mini_is_gsharedvt_sharable_method (method)); - class_container = declaring_method->klass->generic_container; + class_container = mono_class_try_get_generic_container (declaring_method->klass); //FIXME is this a case for a try_get? method_container = mono_method_get_generic_container (declaring_method); /* diff --git a/mono/mini/mini-llvm-cpp.cpp b/mono/mini/mini-llvm-cpp.cpp index 1bf14393db2..a93ee9d9111 100644 --- a/mono/mini/mini-llvm-cpp.cpp +++ b/mono/mini/mini-llvm-cpp.cpp @@ -233,7 +233,7 @@ void mono_llvm_set_call_notail (LLVMValueRef func) { #if LLVM_API_VERSION > 100 - //unwrap(func)->setTailCallKind (CallInst::TailCallKind::TCK_NoTail); + unwrap(func)->setTailCallKind (CallInst::TailCallKind::TCK_NoTail); #endif } diff --git a/mono/mini/mini-llvm.c b/mono/mini/mini-llvm.c index 3ccd8d70565..98802978e85 100644 --- a/mono/mini/mini-llvm.c +++ b/mono/mini/mini-llvm.c @@ -6,7 +6,8 @@ * Licensed under the MIT license. See LICENSE file in the project root for full license information. */ -#include "mini.h" +#include "config.h" + #include #include #include @@ -33,6 +34,8 @@ #include "aot-compiler.h" #include "mini-llvm.h" +#ifndef DISABLE_JIT + #ifdef __MINGW32__ #include @@ -3487,6 +3490,9 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, lcall = emit_call (ctx, bb, &builder, callee, args, LLVMCountParamTypes (llvm_sig)); + if (ins->opcode != OP_TAILCALL && LLVMGetInstructionOpcode (lcall) == LLVMCall) + mono_llvm_set_call_notail (lcall); + /* * Modify cconv and parameter attributes to pass rgctx/imt correctly. */ @@ -9197,3 +9203,27 @@ default_mono_llvm_unhandled_exception (void) * code. * - use pointer types to help optimizations. */ + +#else /* DISABLE_JIT */ + +void +mono_llvm_cleanup (void) +{ +} + +void +mono_llvm_free_domain_info (MonoDomain *domain) +{ +} + +void +mono_llvm_init (void) +{ +} + +void +default_mono_llvm_unhandled_exception (void) +{ +} + +#endif /* DISABLE_JIT */ diff --git a/mono/mini/mini-runtime.c b/mono/mini/mini-runtime.c index 92eb960a822..572048ff5ff 100644 --- a/mono/mini/mini-runtime.c +++ b/mono/mini/mini-runtime.c @@ -65,7 +65,7 @@ #include #include #include -#include +#include #include #include "mini.h" @@ -1094,6 +1094,63 @@ mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, return ji; } +#if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT) + +static const char* const patch_info_str[] = { +#define PATCH_INFO(a,b) "" #a, +#include "patch-info.h" +#undef PATCH_INFO +}; + +const char* +mono_ji_type_to_string (MonoJumpInfoType type) +{ + return patch_info_str [type]; +} + +void +mono_print_ji (const MonoJumpInfo *ji) +{ + switch (ji->type) { + case MONO_PATCH_INFO_RGCTX_FETCH: { + MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry; + + printf ("[RGCTX_FETCH "); + mono_print_ji (entry->data); + printf (" - %s]", mono_rgctx_info_type_to_str (entry->info_type)); + break; + } + case MONO_PATCH_INFO_METHODCONST: { + char *s = mono_method_full_name (ji->data.method, TRUE); + printf ("[METHODCONST - %s]", s); + g_free (s); + break; + } + case MONO_PATCH_INFO_INTERNAL_METHOD: { + printf ("[INTERNAL_METHOD - %s]", ji->data.name); + break; + } + default: + printf ("[%s]", patch_info_str [ji->type]); + break; + } +} + +#else + +const char* +mono_ji_type_to_string (MonoJumpInfoType type) +{ + return ""; +} + +void +mono_print_ji (const MonoJumpInfo *ji) +{ +} + +#endif + /** * mono_patch_info_dup_mp: * @@ -1222,6 +1279,7 @@ mono_patch_info_hash (gconstpointer data) case MONO_PATCH_INFO_GOT_OFFSET: case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG: case MONO_PATCH_INFO_AOT_MODULE: + case MONO_PATCH_INFO_GET_TLS_TRAMP: return (ji->type << 8); case MONO_PATCH_INFO_CASTCLASS_CACHE: return (ji->type << 8) | (ji->data.index); @@ -1441,11 +1499,11 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, break; case MONO_PATCH_INFO_IID: mono_class_init (patch_info->data.klass); - target = GINT_TO_POINTER ((int)patch_info->data.klass->interface_id); + target = GUINT_TO_POINTER (patch_info->data.klass->interface_id); break; case MONO_PATCH_INFO_ADJUSTED_IID: mono_class_init (patch_info->data.klass); - target = GINT_TO_POINTER ((int)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P))); + target = GUINT_TO_POINTER ((guint32)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P))); break; case MONO_PATCH_INFO_VTABLE: target = mono_class_vtable (domain, patch_info->data.klass); @@ -1475,7 +1533,7 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, } g_assert (vtable); - if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && (method && mono_class_needs_cctor_run (vtable->klass, method))) + if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (method && mono_class_needs_cctor_run (vtable->klass, method))) /* Done by the generated code */ ; else { @@ -1661,6 +1719,13 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER: target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE); break; + case MONO_PATCH_INFO_GET_TLS_TRAMP: +#ifdef MONO_ARCH_HAVE_GET_TLS_TRAMP + target = mono_arch_get_get_tls_tramp (); +#else + target = NULL; +#endif + break; default: g_assert_not_reached (); } @@ -1879,6 +1944,15 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoError *er if ((code = mono_aot_get_method_checked (domain, method, error))) { MonoVTable *vtable; + if (mono_runtime_is_critical_method (method) || mono_gc_is_critical_method (method)) { + /* + * The suspend code needs to be able to lookup these methods by ip in async context, + * so preload their jit info. + */ + MonoJitInfo *ji = mono_jit_info_table_find (domain, code); + g_assert (ji); + } + /* * In llvm-only mode, method might be a shared method, so we can't initialize its class. * This is not a problem, since it will be initialized when the method is first @@ -3086,7 +3160,7 @@ mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *met return NULL; is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic; - is_interface = method->klass->flags & TYPE_ATTRIBUTE_INTERFACE ? TRUE : FALSE; + is_interface = mono_class_is_interface (method->klass); load_imt_reg = is_virtual_generic || is_interface; if (is_interface) @@ -4201,7 +4275,7 @@ mono_precompile_assembly (MonoAssembly *ass, void *user_data) } if (method->flags & METHOD_ATTRIBUTE_ABSTRACT) continue; - if (method->is_generic || method->klass->generic_container) + if (method->is_generic || mono_class_is_gtd (method->klass)) continue; count++; diff --git a/mono/mini/mini-s390x.c b/mono/mini/mini-s390x.c index 420a7b1a3bf..c3f763ac5d0 100644 --- a/mono/mini/mini-s390x.c +++ b/mono/mini/mini-s390x.c @@ -1292,6 +1292,7 @@ handle_enum: ip = ((gint64) __builtin_extract_return_addr (__builtin_return_address (0))); printf (" ip: %p\n", (gpointer) ip); + va_end (ap); } /*========================= End of Function ========================*/ diff --git a/mono/mini/mini-trampolines.c b/mono/mini/mini-trampolines.c index 122334e6ea6..7f37b4d8595 100644 --- a/mono/mini/mini-trampolines.c +++ b/mono/mini/mini-trampolines.c @@ -198,8 +198,8 @@ mini_resolve_imt_method (MonoVTable *vt, gpointer *vtable_slot, MonoMethod *imt_ /* imt_method->slot might not be set */ impl = mono_class_get_vtable_entry (vt->klass, interface_offset + mono_method_get_declaring_generic_method (imt_method)->slot); - if (impl->klass->generic_class) - context.class_inst = impl->klass->generic_class->context.class_inst; + if (mono_class_is_ginst (impl->klass)) + context.class_inst = mono_class_get_generic_class (impl->klass)->context.class_inst; context.method_inst = ((MonoMethodInflated*)imt_method)->context.method_inst; impl = mono_class_inflate_generic_method_checked (impl, &context, error); mono_error_assert_ok (error); @@ -591,10 +591,10 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTable * else declaring = m; - if (m->klass->generic_class) - context.class_inst = m->klass->generic_class->context.class_inst; + if (mono_class_is_ginst (m->klass)) + context.class_inst = mono_class_get_generic_class (m->klass)->context.class_inst; else - g_assert (!m->klass->generic_container); + g_assert (!mono_class_is_gtd (m->klass)); generic_virtual = mono_arch_find_imt_method (regs, code); g_assert (generic_virtual); @@ -662,10 +662,10 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTable * else declaring = m; - if (klass->generic_class) - context.class_inst = klass->generic_class->context.class_inst; - else if (klass->generic_container) - context.class_inst = klass->generic_container->context.class_inst; + if (mono_class_is_ginst (klass)) + context.class_inst = mono_class_get_generic_class (klass)->context.class_inst; + else if (mono_class_is_gtd (klass)) + context.class_inst = mono_class_get_generic_container (klass)->context.class_inst; context.method_inst = method_inst; actual_method = mono_class_inflate_generic_method_checked (declaring, &context, error); @@ -850,7 +850,7 @@ mono_vcall_trampoline (mgreg_t *regs, guint8 *code, int slot, guint8 *tramp) gpointer *vtable_slot; MonoMethod *m; MonoError error; - gpointer addr, res; + gpointer addr, res = NULL; trampoline_calls ++; @@ -935,10 +935,10 @@ mono_generic_virtual_remoting_trampoline (mgreg_t *regs, guint8 *code, MonoMetho else declaring = m; - if (m->klass->generic_class) - context.class_inst = m->klass->generic_class->context.class_inst; + if (mono_class_is_ginst (m->klass)) + context.class_inst = mono_class_get_generic_class (m->klass)->context.class_inst; else - g_assert (!m->klass->generic_container); + g_assert (!mono_class_is_gtd (m->klass)); imt_method = mono_arch_find_imt_method (regs, code); if (imt_method->is_inflated) @@ -1188,7 +1188,7 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tr * If the call doesn't return a valuetype, then the vcall uses the same calling * convention as a normal call. */ - if (((method->klass->flags & TYPE_ATTRIBUTE_SEALED) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)) && !MONO_TYPE_ISSTRUCT (sig->ret)) { + if ((mono_class_is_sealed (method->klass) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)) && !MONO_TYPE_ISSTRUCT (sig->ret)) { callvirt = FALSE; enable_caching = FALSE; } @@ -1197,7 +1197,7 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tr if (delegate->target && method->flags & METHOD_ATTRIBUTE_VIRTUAL && method->flags & METHOD_ATTRIBUTE_ABSTRACT && - method->klass->flags & TYPE_ATTRIBUTE_ABSTRACT) { + mono_class_is_abstract (method->klass)) { method = mono_object_get_virtual_method (delegate->target, method); enable_caching = FALSE; } diff --git a/mono/mini/mini.c b/mono/mini/mini.c index 815c59042eb..e94e9fc18c0 100644 --- a/mono/mini/mini.c +++ b/mono/mini/mini.c @@ -2422,7 +2422,7 @@ mono_codegen (MonoCompile *cfg) gboolean is_generic = FALSE; if (cfg->method->is_inflated || mono_method_get_generic_container (cfg->method) || - cfg->method->klass->generic_container || cfg->method->klass->generic_class) { + mono_class_is_gtd (cfg->method->klass) || mono_class_is_ginst (cfg->method->klass)) { is_generic = TRUE; } @@ -3335,7 +3335,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl cfg->seq_points = g_ptr_array_new (); mono_error_init (&cfg->error); - if (cfg->compile_aot && !try_generic_shared && (method->is_generic || method->klass->generic_container || method_is_gshared)) { + if (cfg->compile_aot && !try_generic_shared && (method->is_generic || mono_class_is_gtd (method->klass) || method_is_gshared)) { cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED; return cfg; } diff --git a/mono/mini/mini.h b/mono/mini/mini.h index 03ef9f89f19..1d4184ee09c 100644 --- a/mono/mini/mini.h +++ b/mono/mini/mini.h @@ -509,7 +509,7 @@ enum { #define MONO_INS_IS_PCONST_NULL(ins) ((ins)->opcode == OP_PCONST && (ins)->inst_p0 == 0) -#define MONO_METHOD_IS_FINAL(m) (((m)->flags & METHOD_ATTRIBUTE_FINAL) || ((m)->klass && ((m)->klass->flags & TYPE_ATTRIBUTE_SEALED))) +#define MONO_METHOD_IS_FINAL(m) (((m)->flags & METHOD_ATTRIBUTE_FINAL) || ((m)->klass && (mono_class_get_flags ((m)->klass) & TYPE_ATTRIBUTE_SEALED))) #ifdef MONO_ARCH_SIMD_INTRINSICS @@ -2679,6 +2679,7 @@ guint8* mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo * gpointer mono_arch_create_monitor_enter_trampoline (MonoTrampInfo **info, gboolean is_v4, gboolean aot); gpointer mono_arch_create_monitor_exit_trampoline (MonoTrampInfo **info, gboolean aot); guint8 *mono_arch_create_llvm_native_thunk (MonoDomain *domain, guint8* addr) MONO_LLVM_INTERNAL; +gpointer mono_arch_get_get_tls_tramp (void); GList *mono_arch_get_allocatable_int_vars (MonoCompile *cfg); GList *mono_arch_get_global_int_regs (MonoCompile *cfg); GList *mono_arch_get_global_fp_regs (MonoCompile *cfg); diff --git a/mono/mini/patch-info.h b/mono/mini/patch-info.h index e6635a4b49c..a5570035572 100644 --- a/mono/mini/patch-info.h +++ b/mono/mini/patch-info.h @@ -57,3 +57,4 @@ PATCH_INFO(AOT_JIT_INFO, "aot_jit_info") PATCH_INFO(GC_NURSERY_BITS, "gc_nursery_bits") PATCH_INFO(GSHAREDVT_IN_WRAPPER, "gsharedvt_in_wrapper") PATCH_INFO(ICALL_ADDR_CALL, "icall_addr_call") +PATCH_INFO(GET_TLS_TRAMP, "get_tls_tramp") diff --git a/mono/mini/trace.c b/mono/mini/trace.c index 98f89d63500..90f0af81b5a 100644 --- a/mono/mini/trace.c +++ b/mono/mini/trace.c @@ -101,17 +101,21 @@ mono_trace_eval (MonoMethod *method) switch (op->op){ case MONO_TRACEOP_ALL: - inc = 1; break; + inc = 1; + break; case MONO_TRACEOP_PROGRAM: if (trace_spec.assembly && (method->klass->image == mono_assembly_get_image (trace_spec.assembly))) - inc = 1; break; + inc = 1; + break; case MONO_TRACEOP_WRAPPER: if ((method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) || (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)) - inc = 1; break; + inc = 1; + break; case MONO_TRACEOP_METHOD: if (mono_method_desc_full_match ((MonoMethodDesc *) op->data, method)) - inc = 1; break; + inc = 1; + break; case MONO_TRACEOP_CLASS: if (strcmp (method->klass->name_space, op->data) == 0) if (strcmp (method->klass->name, op->data2) == 0) @@ -119,18 +123,21 @@ mono_trace_eval (MonoMethod *method) break; case MONO_TRACEOP_ASSEMBLY: if (strcmp (mono_image_get_name (method->klass->image), op->data) == 0) - inc = 1; break; + inc = 1; + break; case MONO_TRACEOP_NAMESPACE: if (strcmp (method->klass->name_space, op->data) == 0) inc = 1; + break; case MONO_TRACEOP_EXCEPTION: break; } - if (op->exclude){ + if (op->exclude) { if (inc) include = 0; - } else if (inc) + } else if (inc) { include = 1; + } } return include; } diff --git a/mono/mini/tramp-amd64.c b/mono/mini/tramp-amd64.c index 7d7cc41aa61..03e2af6fd39 100644 --- a/mono/mini/tramp-amd64.c +++ b/mono/mini/tramp-amd64.c @@ -881,7 +881,7 @@ mono_arch_get_plt_info_offset (guint8 *plt_entry, mgreg_t *regs, guint8 *code) guint8* mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gboolean aot) { - int tramp_size = 256; + int tramp_size = 512; int i, framesize, ctx_offset, cfa_offset, gregs_offset; guint8 *code, *buf; GSList *unwind_ops = NULL; diff --git a/mono/sgen/sgen-gc.h b/mono/sgen/sgen-gc.h index aefb07f23c5..e99244aecf1 100644 --- a/mono/sgen/sgen-gc.h +++ b/mono/sgen/sgen-gc.h @@ -182,7 +182,7 @@ sgen_aligned_addr_hash (gconstpointer ptr) return GPOINTER_TO_UINT (ptr) >> 3; } -#define SGEN_PTR_IN_NURSERY(p,bits,start,end) (((mword)(p) & ~((1 << (bits)) - 1)) == (mword)(start)) +#define SGEN_PTR_IN_NURSERY(p,bits,start,end) (((mword)(p) & ~(((mword)1 << (bits)) - 1)) == (mword)(start)) #ifdef USER_CONFIG diff --git a/mono/tests/Makefile.am b/mono/tests/Makefile.am index 511e581b66e..92276ab63b2 100644 --- a/mono/tests/Makefile.am +++ b/mono/tests/Makefile.am @@ -85,63 +85,64 @@ STRESS_TESTS_SRC= \ assembly-load-stress.cs BASE_TEST_MOBILE_STATIC_NOT_SUPPORTED= \ - remoting4.cs # Needs remoting support \ - remoting1.cs # Needs remoting support \ - remoting2.cs # Needs remoting support \ - remoting3.cs # Needs remoting support \ - remoting5.cs # Needs remoting support \ - appdomain.cs # Needs appdomain support \ - appdomain-client.cs # Needs appdomain support \ - appdomain-unload.cs # Needs appdomain support \ - appdomain-async-invoke.cs # Needs appdomain support \ - appdomain-thread-abort.cs # Needs appdomain support \ - appdomain1.cs # Needs appdomain support \ - appdomain2.cs # Needs appdomain support \ - appdomain-exit.cs # Needs appdomain support \ - assemblyresolve_event2.2.cs # Needs appdomain support \ - appdomain-unload-callback.cs # Needs appdomain support \ - appdomain-unload-doesnot-raise-pending-events.cs # Needs appdomain support \ - unload-appdomain-on-shutdown.cs # Needs appdomain support \ - bug-47295.cs # Needs SRE \ - loader.cs # Needs SRE \ - pinvoke2.cs # Needs SRE \ - generic-type-builder.2.cs # Needs SRE \ - dynamic-generic-size.cs # Needs SRE \ - cominterop.cs # Needs COM \ - dynamic-method-access.2.cs # Need SRE \ - dynamic-method-finalize.2.cs # Need SRE \ - dynamic-method-stack-traces.cs # Need SRE\ - generic_type_definition.2.cs # Need SRE \ - bug-333798-tb.2.cs # Need SRE \ - bug-335131.2.cs # Need SRE \ - bug-322722_patch_bx.2.cs # Need SRE\ - bug-322722_dyn_method_throw.2.cs # Need SRE \ - bug-389886-2.cs # Need SRE \ - bug-349190.2.cs # Need SRE \ - bug-389886-sre-generic-interface-instances.cs # Need SRE \ - bug-462592.cs # Need SRE \ - bug-575941.cs # Need SRE \ - bug-389886-3.cs # Need SRE \ - constant-division.cs # Need SRE \ - dynamic-method-resurrection.cs # Need SRE \ - bug-80307.cs # Need System.Web \ - assembly_append_ordering.cs # Need SRE \ - bug-544446.cs # Needs AppDomains / TranparentProxy \ - bug-36848.cs # Needs AppDomains / TranparentProxy \ - generic-marshalbyref.2.cs # Needs AppDomains \ - stackframes-async.2.cs # Needs AppDomains \ - transparentproxy.cs # Needs AppDomains / TranparentProxy \ - bug-48015.cs # Needs AppDomains / TranparentProxy \ - delegate9.cs # Needs AppDomains \ - marshal-valuetypes.cs # Needs AppDomains \ - xdomain-threads.cs # Needs AppDomains \ - monitor.cs # Needs AppDomains \ - generic-xdomain.2.cs # Needs AppDomains \ - threadpool-exceptions7.cs # Needs AppDomains \ - cross-domain.cs # Needs AppDomains \ - generic-unloading.2.cs # Needs AppDomains \ - namedmutex-destroy-race.cs # needs named Mutex \ - thread6.cs # On MOBILE, ThreadAbortException doesn't have necessary field for this test + remoting4.cs \ + remoting1.cs \ + remoting2.cs \ + remoting3.cs \ + remoting5.cs \ + appdomain.cs \ + appdomain-client.cs \ + appdomain-unload.cs \ + appdomain-async-invoke.cs \ + appdomain-thread-abort.cs \ + appdomain1.cs \ + appdomain2.cs \ + appdomain-exit.cs \ + assemblyresolve_event2.2.cs \ + appdomain-unload-callback.cs \ + appdomain-unload-doesnot-raise-pending-events.cs \ + unload-appdomain-on-shutdown.cs \ + bug-47295.cs \ + loader.cs \ + pinvoke2.cs \ + generic-type-builder.2.cs \ + dynamic-generic-size.cs \ + cominterop.cs \ + dynamic-method-access.2.cs \ + dynamic-method-finalize.2.cs \ + dynamic-method-stack-traces.cs \ + generic_type_definition.2.cs \ + bug-333798-tb.2.cs \ + bug-335131.2.cs \ + bug-322722_patch_bx.2.cs \ + bug-322722_dyn_method_throw.2.cs \ + bug-389886-2.cs \ + bug-349190.2.cs \ + bug-389886-sre-generic-interface-instances.cs \ + bug-462592.cs \ + bug-575941.cs \ + bug-389886-3.cs \ + constant-division.cs \ + dynamic-method-resurrection.cs \ + bug-80307.cs \ + assembly_append_ordering.cs \ + bug-544446.cs \ + bug-36848.cs \ + generic-marshalbyref.2.cs \ + stackframes-async.2.cs \ + transparentproxy.cs \ + bug-48015.cs \ + delegate9.cs \ + marshal-valuetypes.cs \ + xdomain-threads.cs \ + monitor.cs \ + generic-xdomain.2.cs \ + threadpool-exceptions7.cs \ + cross-domain.cs \ + generic-unloading.2.cs \ + namedmutex-destroy-race.cs \ + thread6.cs \ + appdomain-threadpool-unload.cs # Disabled until ?mcs is fixed # bug-331958.cs @@ -470,7 +471,9 @@ BASE_TEST_CS_SRC_UNIVERSAL= \ bug-29585.cs \ priority.cs \ abort-cctor.cs \ - thread-native-exit.cs + thread-native-exit.cs \ + reference-loader.cs \ + thread-suspend-suspended.cs if INSTALL_MOBILE_STATIC BASE_TEST_CS_SRC= \ @@ -692,7 +695,6 @@ DISABLED_TESTS= \ bug-459094.exe \ delegate-invoke.exe \ bug-Xamarin-5278.exe \ - reference-loader.cs \ $(PLATFORM_DISABLED_TESTS) \ $(EXTRA_DISABLED_TESTS) \ $(COOP_DISABLED_TESTS) \ @@ -881,7 +883,9 @@ bug-324535-il.dll$(PLATFORM_AOT_SUFFIX) \ bug-36848-a.dll$(PLATFORM_AOT_SUFFIX) \ bug-81691-b.dll$(PLATFORM_AOT_SUFFIX) \ bug-327438.2.exe$(PLATFORM_AOT_SUFFIX) \ -bug-81466-lib.dll$(PLATFORM_AOT_SUFFIX) +bug-81466-lib.dll$(PLATFORM_AOT_SUFFIX) \ +TestingReferenceAssembly.dll$(PLATFORM_AOT_SUFFIX) \ +TestingReferenceReferenceAssembly.dll$(PLATFORM_AOT_SUFFIX) if INSTALL_MOBILE_STATIC prereqs: $(PREREQSI_IL_AOT) $(PREREQSI_CS_AOT) $(AOT_EXTRA_LIBS) @@ -1112,7 +1116,7 @@ debug-casts: @$(MCS) -r:TestDriver.dll $(srcdir)/debug-casts.cs @$(RUNTIME) --debug=casts debug-casts.exe -EXTRA_DIST += sgen-bridge.cs sgen-descriptors.cs sgen-gshared-vtype.cs sgen-bridge-major-fragmentation.cs sgen-domain-unload.cs sgen-weakref-stress.cs sgen-cementing-stress.cs sgen-case-23400.cs finalizer-wait.cs critical-finalizers.cs sgen-domain-unload-2.cs sgen-suspend.cs sgen-new-threads-dont-join-stw.cs sgen-new-threads-dont-join-stw-2.cs sgen-bridge-xref.cs bug-17590.cs sgen-toggleref.cs sgen-bridge-gchandle.cs +EXTRA_DIST += sgen-bridge.cs sgen-descriptors.cs sgen-gshared-vtype.cs sgen-bridge-major-fragmentation.cs sgen-domain-unload.cs sgen-weakref-stress.cs sgen-cementing-stress.cs sgen-case-23400.cs finalizer-wait.cs critical-finalizers.cs sgen-domain-unload-2.cs sgen-suspend.cs sgen-new-threads-dont-join-stw.cs sgen-new-threads-dont-join-stw-2.cs sgen-new-threads-collect.cs sgen-bridge-xref.cs bug-17590.cs sgen-toggleref.cs sgen-bridge-gchandle.cs sgen-tests: @@ -1137,6 +1141,7 @@ SGEN_REGULAR_TESTS_UNIVERSAL = \ sgen-case-23400.exe \ sgen-new-threads-dont-join-stw.exe \ sgen-new-threads-dont-join-stw-2.exe \ + sgen-new-threads-collect.exe \ gc-graystack-stress.exe \ bug-17590.exe diff --git a/mono/tests/appdomain-threadpool-unload.cs b/mono/tests/appdomain-threadpool-unload.cs new file mode 100644 index 00000000000..d8a7049af77 --- /dev/null +++ b/mono/tests/appdomain-threadpool-unload.cs @@ -0,0 +1,52 @@ + +using System; +using System.Linq; +using System.Threading; + +class Driver +{ + class ThreadPoolLauncherObject + { + public volatile int i = 0; + + public ThreadPoolLauncherObject () + { + ThreadPool.QueueUserWorkItem (_ => { for (int i = 0; i < 10 * 1000 * 1000; ++i); }, null); + } + } + + public static void Main () + { + int count = 0; + object o = new object (); + + foreach (var i in + Enumerable.Range (0, 100) + .AsParallel ().WithDegreeOfParallelism (Environment.ProcessorCount) + .Select (i => { + AppDomain ad; + + ad = AppDomain.CreateDomain ("testdomain" + i); + ad.CreateInstance (typeof (ThreadPoolLauncherObject).Assembly.FullName, typeof (ThreadPoolLauncherObject).FullName); + + Thread.Sleep (10); + + AppDomain.Unload (ad); + + return i; + }) + .Select (i => { + lock (o) { + count += 1; + + Console.Write ("."); + if (count % 25 == 0) + Console.WriteLine (); + } + + return i; + }) + ) { + } + } +} diff --git a/mono/tests/custom-attr-errors.cs b/mono/tests/custom-attr-errors.cs index 83f3ff71c29..7d0c812357d 100644 --- a/mono/tests/custom-attr-errors.cs +++ b/mono/tests/custom-attr-errors.cs @@ -1,6 +1,9 @@ using System; using System.Reflection; +// this for test_0_missing_attr_on_assembly +[assembly: MissingAttribute] + public sealed class MyAttribute : Attribute { public Type Type { get; set; } @@ -45,6 +48,15 @@ public class Bar {} class Tests { + public static int test_0_missing_attr_on_assembly () { + try { + Assembly.GetExecutingAssembly().GetCustomAttributes (false); + return 1; + } catch (TypeLoadException exn) { + return 0; + } + } + [My3 (new object[] { DisappearingEnum.V0 })] public static int test_0_missing_enum_arg_alt3 () { try { diff --git a/mono/tests/sgen-new-threads-collect.cs b/mono/tests/sgen-new-threads-collect.cs new file mode 100644 index 00000000000..5deee6bc2c3 --- /dev/null +++ b/mono/tests/sgen-new-threads-collect.cs @@ -0,0 +1,51 @@ + +using System; +using System.Collections.Concurrent; +using System.Threading; + +class Driver +{ + public static void Main () + { + BlockingCollection threads = new BlockingCollection (new ConcurrentQueue (), 128); + + bool finished = false; + + Thread gcThread = new Thread (() => { + while (!finished) { + GC.Collect (); + Thread.Yield (); + } + }); + + Thread joinThread = new Thread (() => { + for (int i = 0; ; ++i) { + Thread t = threads.Take (); + if (t == null) + break; + t.Join (); + if ((i + 1) % (50) == 0) + Console.Write ("."); + if ((i + 1) % (50 * 50) == 0) + Console.WriteLine (); + } + }); + + gcThread.Start (); + joinThread.Start (); + + for (int i = 0; i < 10 * 1000; ++i) { + Thread t = new Thread (() => { Thread.Yield (); }); + t.Start (); + + threads.Add (t); + } + + threads.Add (null); + + joinThread.Join (); + + finished = true; + gcThread.Join (); + } +} \ No newline at end of file diff --git a/mono/tests/thread-suspend-suspended.cs b/mono/tests/thread-suspend-suspended.cs new file mode 100644 index 00000000000..994042b2287 --- /dev/null +++ b/mono/tests/thread-suspend-suspended.cs @@ -0,0 +1,43 @@ + +using System; +using System.Runtime.CompilerServices; +using System.Threading; + +class Driver +{ + public static void Main () + { + bool finished = false; + + Thread t1 = new Thread (() => { + while (!finished) {} + }); + + Thread t2 = new Thread (() => { + while (!finished) { + GC.Collect (); + Thread.Yield (); + } + }); + + t1.Start (); + t2.Start (); + + Thread.Sleep (10); + + for (int i = 0; i < 50 * 40 * 20; ++i) { + t1.Suspend (); + Thread.Yield (); + t1.Resume (); + if ((i + 1) % (50) == 0) + Console.Write ("."); + if ((i + 1) % (50 * 40) == 0) + Console.WriteLine (); + } + + finished = true; + + t1.Join (); + t2.Join (); + } +} diff --git a/mono/unit-tests/test-conc-hashtable.c b/mono/unit-tests/test-conc-hashtable.c index abb24d9825f..712e2efa381 100644 --- a/mono/unit-tests/test-conc-hashtable.c +++ b/mono/unit-tests/test-conc-hashtable.c @@ -11,7 +11,7 @@ #include "utils/mono-threads.h" #include "utils/mono-conc-hashtable.h" #include "utils/checked-build.h" -#include "utils/w32handle.h" +#include "metadata/w32handle.h" #include #include diff --git a/mono/utils/Makefile.am b/mono/utils/Makefile.am index add4c6a85fe..ab301d1700b 100644 --- a/mono/utils/Makefile.am +++ b/mono/utils/Makefile.am @@ -173,8 +173,6 @@ monoutils_sources = \ parse.h \ checked-build.c \ checked-build.h \ - w32handle.c \ - w32handle.h \ os-event.h arch_sources = diff --git a/mono/utils/mach-support-amd64.c b/mono/utils/mach-support-amd64.c index 1802ff79f53..179a4f7ed74 100644 --- a/mono/utils/mach-support-amd64.c +++ b/mono/utils/mach-support-amd64.c @@ -59,27 +59,30 @@ mono_mach_arch_get_mcontext_size () } void -mono_mach_arch_thread_state_to_mcontext (thread_state_t state, void *context) +mono_mach_arch_thread_states_to_mcontext (thread_state_t state, thread_state_t fpstate, void *context) { x86_thread_state64_t *arch_state = (x86_thread_state64_t *) state; + x86_float_state64_t *arch_fpstate = (x86_float_state64_t *) fpstate; struct __darwin_mcontext64 *ctx = (struct __darwin_mcontext64 *) context; - ctx->__ss = *arch_state; + ctx->__fs = *arch_fpstate; } void -mono_mach_arch_mcontext_to_thread_state (void *context, thread_state_t state) +mono_mach_arch_mcontext_to_thread_states (void *context, thread_state_t state, thread_state_t fpstate) { x86_thread_state64_t *arch_state = (x86_thread_state64_t *) state; + x86_float_state64_t *arch_fpstate = (x86_float_state64_t *) fpstate; struct __darwin_mcontext64 *ctx = (struct __darwin_mcontext64 *) context; - *arch_state = ctx->__ss; + *arch_fpstate = ctx->__fs; } void -mono_mach_arch_thread_state_to_mono_context (thread_state_t state, MonoContext *context) +mono_mach_arch_thread_states_to_mono_context (thread_state_t state, thread_state_t fpstate, MonoContext *context) { x86_thread_state64_t *arch_state = (x86_thread_state64_t *) state; + x86_float_state64_t *arch_fpstate = (x86_float_state64_t *) fpstate; context->gregs [AMD64_RAX] = arch_state->__rax; context->gregs [AMD64_RBX] = arch_state->__rbx; context->gregs [AMD64_RCX] = arch_state->__rcx; @@ -96,6 +99,22 @@ mono_mach_arch_thread_state_to_mono_context (thread_state_t state, MonoContext * context->gregs [AMD64_R14] = arch_state->__r14; context->gregs [AMD64_R15] = arch_state->__r15; context->gregs [AMD64_RIP] = arch_state->__rip; + context->fregs [AMD64_XMM0] = arch_fpstate->__fpu_xmm0; + context->fregs [AMD64_XMM1] = arch_fpstate->__fpu_xmm1; + context->fregs [AMD64_XMM2] = arch_fpstate->__fpu_xmm2; + context->fregs [AMD64_XMM3] = arch_fpstate->__fpu_xmm3; + context->fregs [AMD64_XMM4] = arch_fpstate->__fpu_xmm4; + context->fregs [AMD64_XMM5] = arch_fpstate->__fpu_xmm5; + context->fregs [AMD64_XMM6] = arch_fpstate->__fpu_xmm6; + context->fregs [AMD64_XMM7] = arch_fpstate->__fpu_xmm7; + context->fregs [AMD64_XMM8] = arch_fpstate->__fpu_xmm8; + context->fregs [AMD64_XMM9] = arch_fpstate->__fpu_xmm9; + context->fregs [AMD64_XMM10] = arch_fpstate->__fpu_xmm10; + context->fregs [AMD64_XMM11] = arch_fpstate->__fpu_xmm11; + context->fregs [AMD64_XMM12] = arch_fpstate->__fpu_xmm12; + context->fregs [AMD64_XMM13] = arch_fpstate->__fpu_xmm13; + context->fregs [AMD64_XMM14] = arch_fpstate->__fpu_xmm14; + context->fregs [AMD64_XMM15] = arch_fpstate->__fpu_xmm15; } int @@ -104,23 +123,39 @@ mono_mach_arch_get_thread_state_size () return sizeof (x86_thread_state64_t); } +int +mono_mach_arch_get_thread_fpstate_size () +{ + return sizeof (x86_float_state64_t); +} + kern_return_t -mono_mach_arch_get_thread_state (thread_port_t thread, thread_state_t state, mach_msg_type_number_t *count) +mono_mach_arch_get_thread_states (thread_port_t thread, thread_state_t state, mach_msg_type_number_t *count, thread_state_t fpstate, mach_msg_type_number_t *fpcount) { - x86_thread_state64_t *arch_state = (x86_thread_state64_t *) state; + x86_thread_state64_t *arch_state = (x86_thread_state64_t *)state; + x86_float_state64_t *arch_fpstate = (x86_float_state64_t *)fpstate; kern_return_t ret; *count = x86_THREAD_STATE64_COUNT; + *fpcount = x86_FLOAT_STATE64_COUNT; - ret = thread_get_state (thread, x86_THREAD_STATE64, (thread_state_t) arch_state, count); + ret = thread_get_state (thread, x86_THREAD_STATE64, (thread_state_t)arch_state, count); + if (ret != KERN_SUCCESS) + return ret; + ret = thread_get_state (thread, x86_FLOAT_STATE64, (thread_state_t)arch_fpstate, fpcount); return ret; } kern_return_t -mono_mach_arch_set_thread_state (thread_port_t thread, thread_state_t state, mach_msg_type_number_t count) +mono_mach_arch_set_thread_states (thread_port_t thread, thread_state_t state, mach_msg_type_number_t count, thread_state_t fpstate, mach_msg_type_number_t fpcount) { - return thread_set_state (thread, x86_THREAD_STATE64, state, count); + kern_return_t ret; + ret = thread_set_state (thread, x86_THREAD_STATE64, state, count); + if (ret != KERN_SUCCESS) + return ret; + ret = thread_set_state (thread, x86_FLOAT_STATE64, fpstate, fpcount); + return ret; } void * diff --git a/mono/utils/mach-support-arm.c b/mono/utils/mach-support-arm.c index d535fbc18dd..a7fd9836d18 100644 --- a/mono/utils/mach-support-arm.c +++ b/mono/utils/mach-support-arm.c @@ -66,7 +66,7 @@ mono_mach_arch_get_mcontext_size () } void -mono_mach_arch_thread_state_to_mcontext (thread_state_t state, void *context) +mono_mach_arch_thread_states_to_mcontext (thread_state_t state, thread_state_t fpstate, void *context) { arm_thread_state_t *arch_state = (arm_thread_state_t *) state; struct __darwin_mcontext *ctx = (struct __darwin_mcontext *) context; @@ -75,7 +75,7 @@ mono_mach_arch_thread_state_to_mcontext (thread_state_t state, void *context) } void -mono_mach_arch_mcontext_to_thread_state (void *context, thread_state_t state) +mono_mach_arch_mcontext_to_thread_states (void *context, thread_state_t state, thread_state_t fpstate) { arm_thread_state_t *arch_state = (arm_thread_state_t *) state; struct __darwin_mcontext *ctx = (struct __darwin_mcontext *) context; @@ -84,7 +84,7 @@ mono_mach_arch_mcontext_to_thread_state (void *context, thread_state_t state) } void -mono_mach_arch_thread_state_to_mono_context (thread_state_t state, MonoContext *context) +mono_mach_arch_thread_states_to_mono_context (thread_state_t state, thread_state_t fpstate, MonoContext *context) { int i; arm_thread_state_t *arch_state = (arm_thread_state_t *) state; @@ -103,8 +103,14 @@ mono_mach_arch_get_thread_state_size () return sizeof (arm_thread_state_t); } +int +mono_mach_arch_get_thread_fpstate_size () +{ + g_assert_not_reached (); +} + kern_return_t -mono_mach_arch_get_thread_state (thread_port_t thread, thread_state_t state, mach_msg_type_number_t *count) +mono_mach_arch_get_thread_states (thread_port_t thread, thread_state_t state, mach_msg_type_number_t *count, thread_state_t fpstate, mach_msg_type_number_t *fpcount) { #if defined(HOST_WATCHOS) g_error ("thread_get_state() is not supported by this platform"); @@ -120,7 +126,7 @@ mono_mach_arch_get_thread_state (thread_port_t thread, thread_state_t state, mac } kern_return_t -mono_mach_arch_set_thread_state (thread_port_t thread, thread_state_t state, mach_msg_type_number_t count) +mono_mach_arch_set_thread_states (thread_port_t thread, thread_state_t state, mach_msg_type_number_t count, thread_state_t fpstate, mach_msg_type_number_t fpcount) { #if defined(HOST_WATCHOS) g_error ("thread_set_state() is not supported by this platform"); diff --git a/mono/utils/mach-support-arm64.c b/mono/utils/mach-support-arm64.c index 6483238d456..2035f485b14 100644 --- a/mono/utils/mach-support-arm64.c +++ b/mono/utils/mach-support-arm64.c @@ -66,7 +66,7 @@ mono_mach_arch_get_mcontext_size () } void -mono_mach_arch_thread_state_to_mcontext (thread_state_t state, void *context) +mono_mach_arch_thread_states_to_mcontext (thread_state_t state, thread_state_t fpstate, void *context) { arm_unified_thread_state_t *arch_state = (arm_unified_thread_state_t *) state; struct __darwin_mcontext64 *ctx = (struct __darwin_mcontext64 *) context; @@ -75,7 +75,7 @@ mono_mach_arch_thread_state_to_mcontext (thread_state_t state, void *context) } void -mono_mach_arch_mcontext_to_thread_state (void *context, thread_state_t state) +mono_mach_arch_mcontext_to_thread_states (void *context, thread_state_t state, thread_state_t fpstate) { arm_unified_thread_state_t *arch_state = (arm_unified_thread_state_t *) state; struct __darwin_mcontext64 *ctx = (struct __darwin_mcontext64 *) context; @@ -84,7 +84,7 @@ mono_mach_arch_mcontext_to_thread_state (void *context, thread_state_t state) } void -mono_mach_arch_thread_state_to_mono_context (thread_state_t state, MonoContext *context) +mono_mach_arch_thread_states_to_mono_context (thread_state_t state, thread_state_t fpstate, MonoContext *context) { int i; arm_unified_thread_state_t *arch_state = (arm_unified_thread_state_t *) state; @@ -103,8 +103,14 @@ mono_mach_arch_get_thread_state_size () return sizeof (arm_unified_thread_state_t); } +int +mono_mach_arch_get_thread_fpstate_size () +{ + g_assert_not_reached (); +} + kern_return_t -mono_mach_arch_get_thread_state (thread_port_t thread, thread_state_t state, mach_msg_type_number_t *count) +mono_mach_arch_get_thread_states (thread_port_t thread, thread_state_t state, mach_msg_type_number_t *count, thread_state_t fpstate, mach_msg_type_number_t *fpcount) { arm_unified_thread_state_t *arch_state = (arm_unified_thread_state_t *) state; kern_return_t ret; @@ -116,7 +122,7 @@ mono_mach_arch_get_thread_state (thread_port_t thread, thread_state_t state, mac } kern_return_t -mono_mach_arch_set_thread_state (thread_port_t thread, thread_state_t state, mach_msg_type_number_t count) +mono_mach_arch_set_thread_states (thread_port_t thread, thread_state_t state, mach_msg_type_number_t count, thread_state_t fpstate, mach_msg_type_number_t fpcount) { return thread_set_state (thread, ARM_UNIFIED_THREAD_STATE, state, count); } diff --git a/mono/utils/mach-support-unknown.c b/mono/utils/mach-support-unknown.c index 20012550114..88eb187da44 100644 --- a/mono/utils/mach-support-unknown.c +++ b/mono/utils/mach-support-unknown.c @@ -35,19 +35,19 @@ mono_mach_arch_get_mcontext_size () } void -mono_mach_arch_thread_state_to_mcontext (thread_state_t state, void *context) +mono_mach_arch_thread_states_to_mcontext (thread_state_t state, thread_state_t fpstate, void *context) { g_assert_not_reached (); } void -mono_mach_arch_mcontext_to_thread_state (void *context, thread_state_t state) +mono_mach_arch_mcontext_to_thread_states (void *context, thread_state_t state, thread_state_t fpstate) { g_assert_not_reached (); } void -mono_mach_arch_thread_state_to_mono_context (thread_state_t state, MonoContext *context) +mono_mach_arch_thread_states_to_mono_context (thread_state_t state, thread_state_t fpstate, MonoContext *context) { g_assert_not_reached (); } @@ -58,14 +58,20 @@ mono_mach_arch_get_thread_state_size () g_assert_not_reached (); } +int +mono_mach_arch_get_thread_fpstate_size () +{ + g_assert_not_reached (); +} + kern_return_t -mono_mach_arch_get_thread_state (thread_port_t thread, thread_state_t state, mach_msg_type_number_t *count) +mono_mach_arch_get_thread_states (thread_port_t thread, thread_state_t state, mach_msg_type_number_t *count, thread_state_t fpstate, mach_msg_type_number_t *fpcount) { g_assert_not_reached (); } kern_return_t -mono_mach_arch_set_thread_state (thread_port_t thread, thread_state_t state, mach_msg_type_number_t count) +mono_mach_arch_set_thread_states (thread_port_t thread, thread_state_t state, mach_msg_type_number_t count, thread_state_t fpstate, mach_msg_type_number_t fpcount) { g_assert_not_reached (); } diff --git a/mono/utils/mach-support-x86.c b/mono/utils/mach-support-x86.c index 3e8b166eaf2..a296254cd2c 100644 --- a/mono/utils/mach-support-x86.c +++ b/mono/utils/mach-support-x86.c @@ -16,6 +16,9 @@ #include "utils/mono-sigcontext.h" #include "mach-support.h" +// For reg numbers +#include + /* Known offsets used for TLS storage*/ /* All OSX versions up to 10.8 */ @@ -55,27 +58,30 @@ mono_mach_arch_get_mcontext_size () } void -mono_mach_arch_thread_state_to_mcontext (thread_state_t state, void *context) +mono_mach_arch_thread_states_to_mcontext (thread_state_t state, thread_state_t fpstate, void *context) { x86_thread_state32_t *arch_state = (x86_thread_state32_t *) state; + x86_float_state32_t *arch_fpstate = (x86_float_state32_t *) fpstate; struct __darwin_mcontext32 *ctx = (struct __darwin_mcontext32 *) context; - ctx->__ss = *arch_state; + ctx->__fs = *arch_fpstate; } void -mono_mach_arch_mcontext_to_thread_state (void *context, thread_state_t state) +mono_mach_arch_mcontext_to_thread_states (void *context, thread_state_t state, thread_state_t fpstate) { x86_thread_state32_t *arch_state = (x86_thread_state32_t *) state; + x86_float_state32_t *arch_fpstate = (x86_float_state32_t *) fpstate; struct __darwin_mcontext32 *ctx = (struct __darwin_mcontext32 *) context; - *arch_state = ctx->__ss; + *arch_fpstate = ctx->__fs; } void -mono_mach_arch_thread_state_to_mono_context (thread_state_t state, MonoContext *context) +mono_mach_arch_thread_states_to_mono_context (thread_state_t state, thread_state_t fpstate, MonoContext *context) { x86_thread_state32_t *arch_state = (x86_thread_state32_t *) state; + x86_float_state32_t *arch_fpstate = (x86_float_state32_t *) state; context->eax = arch_state->__eax; context->ebx = arch_state->__ebx; context->ecx = arch_state->__ecx; @@ -85,38 +91,62 @@ mono_mach_arch_thread_state_to_mono_context (thread_state_t state, MonoContext * context->esi = arch_state->__edi; context->edi = arch_state->__esi; context->eip = arch_state->__eip; + context->fregs [X86_XMM0] = arch_fpstate->__fpu_xmm0; + context->fregs [X86_XMM1] = arch_fpstate->__fpu_xmm1; + context->fregs [X86_XMM2] = arch_fpstate->__fpu_xmm2; + context->fregs [X86_XMM3] = arch_fpstate->__fpu_xmm3; + context->fregs [X86_XMM4] = arch_fpstate->__fpu_xmm4; + context->fregs [X86_XMM5] = arch_fpstate->__fpu_xmm5; + context->fregs [X86_XMM6] = arch_fpstate->__fpu_xmm6; + context->fregs [X86_XMM7] = arch_fpstate->__fpu_xmm7; } - int mono_mach_arch_get_thread_state_size () { return sizeof (x86_thread_state32_t); } +int +mono_mach_arch_get_thread_fpstate_size () +{ + return sizeof (x86_float_state32_t); +} + kern_return_t -mono_mach_arch_get_thread_state (thread_port_t thread, thread_state_t state, mach_msg_type_number_t *count) +mono_mach_arch_get_thread_states (thread_port_t thread, thread_state_t state, mach_msg_type_number_t *count, thread_state_t fpstate, mach_msg_type_number_t *fpcount) { #if defined(HOST_WATCHOS) g_error ("thread_get_state() is not supported by this platform"); #else x86_thread_state32_t *arch_state = (x86_thread_state32_t *) state; + x86_float_state32_t *arch_fpstate = (x86_float_state32_t *) fpstate; kern_return_t ret; *count = x86_THREAD_STATE32_COUNT; - ret = thread_get_state (thread, x86_THREAD_STATE32, (thread_state_t) arch_state, count); + *fpcount = x86_FLOAT_STATE32_COUNT; + + ret = thread_get_state (thread, x86_THREAD_STATE32, (thread_state_t)arch_state, count); + if (ret != KERN_SUCCESS) + return ret; + ret = thread_get_state (thread, x86_FLOAT_STATE32, (thread_state_t)arch_fpstate, fpcount); return ret; #endif } kern_return_t -mono_mach_arch_set_thread_state (thread_port_t thread, thread_state_t state, mach_msg_type_number_t count) +mono_mach_arch_set_thread_states (thread_port_t thread, thread_state_t state, mach_msg_type_number_t count, thread_state_t fpstate, mach_msg_type_number_t fpcount) { #if defined(HOST_WATCHOS) g_error ("thread_set_state() is not supported by this platform"); #else - return thread_set_state (thread, x86_THREAD_STATE32, state, count); + kern_return_t ret; + ret = thread_set_state (thread, x86_THREAD_STATE32, state, count); + if (ret != KERN_SUCCESS) + return ret; + ret = thread_set_state (thread, x86_FLOAT_STATE32, fpstate, fpcount); + return ret; #endif } diff --git a/mono/utils/mach-support.h b/mono/utils/mach-support.h index abc135bd4eb..9ac334c7171 100644 --- a/mono/utils/mach-support.h +++ b/mono/utils/mach-support.h @@ -29,15 +29,17 @@ void *mono_mach_arch_get_sp (thread_state_t state); void mono_mach_init (pthread_key_t key); int mono_mach_arch_get_mcontext_size (void); -void mono_mach_arch_thread_state_to_mcontext (thread_state_t state, void *context); -void mono_mach_arch_mcontext_to_thread_state (void *context, thread_state_t state); -void mono_mach_arch_thread_state_to_mono_context (thread_state_t state, MonoContext *context); +void mono_mach_arch_thread_states_to_mcontext (thread_state_t state, thread_state_t fpstate, void *context); +void mono_mach_arch_mcontext_to_thread_states (void *context, thread_state_t state, thread_state_t fpstate); +void mono_mach_arch_thread_states_to_mono_context (thread_state_t state, thread_state_t fpstate, MonoContext *context); +/* FIXME: Should return size_t, not int. */ int mono_mach_arch_get_thread_state_size (void); +int mono_mach_arch_get_thread_fpstate_size (void); kern_return_t mono_mach_get_threads (thread_act_array_t *threads, guint32 *count); kern_return_t mono_mach_free_threads (thread_act_array_t threads, guint32 count); -kern_return_t mono_mach_arch_get_thread_state (thread_port_t thread, thread_state_t state, mach_msg_type_number_t *count); -kern_return_t mono_mach_arch_set_thread_state (thread_port_t thread, thread_state_t state, mach_msg_type_number_t count); +kern_return_t mono_mach_arch_get_thread_states (thread_port_t thread, thread_state_t state, mach_msg_type_number_t *count, thread_state_t fpstate, mach_msg_type_number_t *fpcount); +kern_return_t mono_mach_arch_set_thread_states (thread_port_t thread, thread_state_t state, mach_msg_type_number_t count, thread_state_t fpstate, mach_msg_type_number_t fpcount); void *mono_mach_arch_get_tls_value_from_thread (pthread_t thread, guint32 key); void *mono_mach_get_tls_address_from_thread (pthread_t thread, pthread_key_t key); diff --git a/mono/utils/mono-codeman.c b/mono/utils/mono-codeman.c index 56948bdd901..f29a67ca096 100644 --- a/mono/utils/mono-codeman.c +++ b/mono/utils/mono-codeman.c @@ -329,7 +329,7 @@ new_codechunk (CodeChunk *last, int dynamic, int size) { int minsize, flags = CODE_FLAG_MMAP; int chunk_size, bsize = 0; - int pagesize; + int pagesize, valloc_granule; CodeChunk *chunk; void *ptr; @@ -338,12 +338,13 @@ new_codechunk (CodeChunk *last, int dynamic, int size) #endif pagesize = mono_pagesize (); + valloc_granule = mono_valloc_granule (); if (dynamic) { chunk_size = size; flags = CODE_FLAG_MALLOC; } else { - minsize = pagesize * MIN_PAGES; + minsize = MAX (pagesize * MIN_PAGES, valloc_granule); if (size < minsize) chunk_size = minsize; else { @@ -353,8 +354,8 @@ new_codechunk (CodeChunk *last, int dynamic, int size) size += MIN_ALIGN - 1; size &= ~(MIN_ALIGN - 1); chunk_size = size; - chunk_size += pagesize - 1; - chunk_size &= ~ (pagesize - 1); + chunk_size += valloc_granule - 1; + chunk_size &= ~ (valloc_granule - 1); } } #ifdef BIND_ROOM @@ -370,8 +371,8 @@ new_codechunk (CodeChunk *last, int dynamic, int size) if (chunk_size - size < bsize) { chunk_size = size + bsize; if (!dynamic) { - chunk_size += pagesize - 1; - chunk_size &= ~ (pagesize - 1); + chunk_size += valloc_granule - 1; + chunk_size &= ~ (valloc_granule - 1); } } #endif diff --git a/mono/utils/mono-context.c b/mono/utils/mono-context.c index 632513d874f..3056c3afd3a 100644 --- a/mono/utils/mono-context.c +++ b/mono/utils/mono-context.c @@ -170,6 +170,26 @@ mono_sigctx_to_monoctx (void *sigctx, MonoContext *mctx) mctx->gregs [AMD64_R14] = UCONTEXT_REG_R14 (ctx); mctx->gregs [AMD64_R15] = UCONTEXT_REG_R15 (ctx); mctx->gregs [AMD64_RIP] = UCONTEXT_REG_RIP (ctx); + +#ifdef UCONTEXT_REG_XMM + mctx->fregs [0] = UCONTEXT_REG_XMM0 (ctx); + mctx->fregs [1] = UCONTEXT_REG_XMM1 (ctx); + mctx->fregs [2] = UCONTEXT_REG_XMM2 (ctx); + mctx->fregs [3] = UCONTEXT_REG_XMM3 (ctx); + mctx->fregs [4] = UCONTEXT_REG_XMM4 (ctx); + mctx->fregs [5] = UCONTEXT_REG_XMM5 (ctx); + mctx->fregs [6] = UCONTEXT_REG_XMM6 (ctx); + mctx->fregs [7] = UCONTEXT_REG_XMM7 (ctx); + mctx->fregs [8] = UCONTEXT_REG_XMM8 (ctx); + mctx->fregs [9] = UCONTEXT_REG_XMM9 (ctx); + mctx->fregs [10] = UCONTEXT_REG_XMM10 (ctx); + mctx->fregs [11] = UCONTEXT_REG_XMM11 (ctx); + mctx->fregs [12] = UCONTEXT_REG_XMM12 (ctx); + mctx->fregs [13] = UCONTEXT_REG_XMM13 (ctx); + mctx->fregs [14] = UCONTEXT_REG_XMM14 (ctx); + mctx->fregs [15] = UCONTEXT_REG_XMM15 (ctx); +#endif + #elif defined(HOST_WIN32) CONTEXT *context = (CONTEXT*)sigctx; @@ -224,6 +244,26 @@ mono_monoctx_to_sigctx (MonoContext *mctx, void *sigctx) UCONTEXT_REG_R14 (ctx) = mctx->gregs [AMD64_R14]; UCONTEXT_REG_R15 (ctx) = mctx->gregs [AMD64_R15]; UCONTEXT_REG_RIP (ctx) = mctx->gregs [AMD64_RIP]; + +#ifdef UCONTEXT_REG_XMM + UCONTEXT_REG_XMM0 (ctx) = mctx->fregs [0]; + UCONTEXT_REG_XMM1 (ctx) = mctx->fregs [1]; + UCONTEXT_REG_XMM2 (ctx) = mctx->fregs [2]; + UCONTEXT_REG_XMM3 (ctx) = mctx->fregs [3]; + UCONTEXT_REG_XMM4 (ctx) = mctx->fregs [4]; + UCONTEXT_REG_XMM5 (ctx) = mctx->fregs [5]; + UCONTEXT_REG_XMM6 (ctx) = mctx->fregs [6]; + UCONTEXT_REG_XMM7 (ctx) = mctx->fregs [7]; + UCONTEXT_REG_XMM8 (ctx) = mctx->fregs [8]; + UCONTEXT_REG_XMM9 (ctx) = mctx->fregs [9]; + UCONTEXT_REG_XMM10 (ctx) = mctx->fregs [10]; + UCONTEXT_REG_XMM11 (ctx) = mctx->fregs [11]; + UCONTEXT_REG_XMM12 (ctx) = mctx->fregs [12]; + UCONTEXT_REG_XMM13 (ctx) = mctx->fregs [13]; + UCONTEXT_REG_XMM14 (ctx) = mctx->fregs [14]; + UCONTEXT_REG_XMM15 (ctx) = mctx->fregs [15]; +#endif + #elif defined(HOST_WIN32) CONTEXT *context = (CONTEXT*)sigctx; diff --git a/mono/utils/mono-context.h b/mono/utils/mono-context.h index 0a1bd524cfd..e8d52d23a28 100644 --- a/mono/utils/mono-context.h +++ b/mono/utils/mono-context.h @@ -18,6 +18,13 @@ #include #endif +#define MONO_CONTEXT_OFFSET(field, index, field_type) \ + "i" (offsetof (MonoContext, field) + (index) * sizeof (field_type)) + +#if defined(__APPLE__) +typedef struct __darwin_xmm_reg MonoContextSimdReg; +#endif + /* * General notes about mono-context. * Each arch defines a MonoContext struct with all GPR regs + IP/PC. @@ -87,6 +94,8 @@ struct sigcontext { # define SC_ESI esi #endif +#include + typedef struct { mgreg_t eax; mgreg_t ebx; @@ -97,6 +106,9 @@ typedef struct { mgreg_t esi; mgreg_t edi; mgreg_t eip; +#ifdef __APPLE__ + MonoContextSimdReg fregs [X86_XMM_NREG]; +#endif } MonoContext; #define MONO_CONTEXT_SET_IP(ctx,ip) do { (ctx)->eip = (mgreg_t)(ip); } while (0); @@ -129,18 +141,26 @@ typedef struct { #else #define MONO_CONTEXT_GET_CURRENT(ctx) \ __asm__ __volatile__( \ - "movl $0x0, 0x00(%0)\n" \ - "mov %%ebx, 0x04(%0)\n" \ - "mov %%ecx, 0x08(%0)\n" \ - "mov %%edx, 0x0c(%0)\n" \ - "mov %%ebp, 0x10(%0)\n" \ - "mov %%esp, 0x14(%0)\n" \ - "mov %%esi, 0x18(%0)\n" \ - "mov %%edi, 0x1c(%0)\n" \ + "movl $0x0, %c[eax](%0)\n" \ + "mov %%ebx, %c[ebx](%0)\n" \ + "mov %%ecx, %c[ecx](%0)\n" \ + "mov %%edx, %c[edx](%0)\n" \ + "mov %%ebp, %c[ebp](%0)\n" \ + "mov %%esp, %c[esp](%0)\n" \ + "mov %%esi, %c[esi](%0)\n" \ + "mov %%edi, %c[edi](%0)\n" \ "call 1f\n" \ "1: pop 0x20(%0)\n" \ : \ - : "a" (&(ctx)) \ + : "a" (&(ctx)), \ + [eax] MONO_CONTEXT_OFFSET (eax, 0, mgreg_t), \ + [ebx] MONO_CONTEXT_OFFSET (ebx, 0, mgreg_t), \ + [ecx] MONO_CONTEXT_OFFSET (ecx, 0, mgreg_t), \ + [edx] MONO_CONTEXT_OFFSET (edx, 0, mgreg_t), \ + [ebp] MONO_CONTEXT_OFFSET (ebp, 0, mgreg_t), \ + [esp] MONO_CONTEXT_OFFSET (esp, 0, mgreg_t), \ + [esi] MONO_CONTEXT_OFFSET (esi, 0, mgreg_t), \ + [edi] MONO_CONTEXT_OFFSET (edi, 0, mgreg_t) \ : "memory") #endif @@ -160,7 +180,11 @@ typedef struct { typedef struct { mgreg_t gregs [AMD64_NREG]; +#ifdef __APPLE__ + MonoContextSimdReg fregs [AMD64_XMM_NREG]; +#else double fregs [AMD64_XMM_NREG]; +#endif } MonoContext; #define MONO_CONTEXT_SET_IP(ctx,ip) do { (ctx)->gregs [AMD64_RIP] = (mgreg_t)(ip); } while (0); @@ -202,30 +226,98 @@ extern void mono_context_get_current (void *); : "rdx", "memory") #else -#define MONO_CONTEXT_GET_CURRENT(ctx) \ - __asm__ __volatile__( \ - "movq $0x0, 0x00(%0)\n" \ - "movq %%rcx, 0x08(%0)\n" \ - "movq %%rdx, 0x10(%0)\n" \ - "movq %%rbx, 0x18(%0)\n" \ - "movq %%rsp, 0x20(%0)\n" \ - "movq %%rbp, 0x28(%0)\n" \ - "movq %%rsi, 0x30(%0)\n" \ - "movq %%rdi, 0x38(%0)\n" \ - "movq %%r8, 0x40(%0)\n" \ - "movq %%r9, 0x48(%0)\n" \ - "movq %%r10, 0x50(%0)\n" \ - "movq %%r11, 0x58(%0)\n" \ - "movq %%r12, 0x60(%0)\n" \ - "movq %%r13, 0x68(%0)\n" \ - "movq %%r14, 0x70(%0)\n" \ - "movq %%r15, 0x78(%0)\n" \ - /* "leaq (%%rip), %%rdx\n" is not understood by icc */ \ - ".byte 0x48, 0x8d, 0x15, 0x00, 0x00, 0x00, 0x00\n" \ - "movq %%rdx, 0x80(%0)\n" \ - : \ - : "a" (&(ctx)) \ - : "rdx", "memory") +#define MONO_CONTEXT_GET_CURRENT_GREGS(ctx) \ + do { \ + __asm__ __volatile__( \ + "movq $0x0, %c[rax](%0)\n" \ + "movq %%rcx, %c[rcx](%0)\n" \ + "movq %%rdx, %c[rdx](%0)\n" \ + "movq %%rbx, %c[rbx](%0)\n" \ + "movq %%rsp, %c[rsp](%0)\n" \ + "movq %%rbp, %c[rbp](%0)\n" \ + "movq %%rsi, %c[rsi](%0)\n" \ + "movq %%rdi, %c[rdi](%0)\n" \ + "movq %%r8, %c[r8](%0)\n" \ + "movq %%r9, %c[r9](%0)\n" \ + "movq %%r10, %c[r10](%0)\n" \ + "movq %%r11, %c[r11](%0)\n" \ + "movq %%r12, %c[r12](%0)\n" \ + "movq %%r13, %c[r13](%0)\n" \ + "movq %%r14, %c[r14](%0)\n" \ + "movq %%r15, %c[r15](%0)\n" \ + /* "leaq (%%rip), %%rdx\n" is not understood by icc */ \ + ".byte 0x48, 0x8d, 0x15, 0x00, 0x00, 0x00, 0x00\n" \ + "movq %%rdx, %c[rip](%0)\n" \ + : \ + : "a" (&(ctx)), \ + [rax] MONO_CONTEXT_OFFSET (gregs, AMD64_RAX, mgreg_t), \ + [rcx] MONO_CONTEXT_OFFSET (gregs, AMD64_RCX, mgreg_t), \ + [rdx] MONO_CONTEXT_OFFSET (gregs, AMD64_RDX, mgreg_t), \ + [rbx] MONO_CONTEXT_OFFSET (gregs, AMD64_RBX, mgreg_t), \ + [rsp] MONO_CONTEXT_OFFSET (gregs, AMD64_RSP, mgreg_t), \ + [rbp] MONO_CONTEXT_OFFSET (gregs, AMD64_RBP, mgreg_t), \ + [rsi] MONO_CONTEXT_OFFSET (gregs, AMD64_RSI, mgreg_t), \ + [rdi] MONO_CONTEXT_OFFSET (gregs, AMD64_RDI, mgreg_t), \ + [r8] MONO_CONTEXT_OFFSET (gregs, AMD64_R8, mgreg_t), \ + [r9] MONO_CONTEXT_OFFSET (gregs, AMD64_R9, mgreg_t), \ + [r10] MONO_CONTEXT_OFFSET (gregs, AMD64_R10, mgreg_t), \ + [r11] MONO_CONTEXT_OFFSET (gregs, AMD64_R11, mgreg_t), \ + [r12] MONO_CONTEXT_OFFSET (gregs, AMD64_R12, mgreg_t), \ + [r13] MONO_CONTEXT_OFFSET (gregs, AMD64_R13, mgreg_t), \ + [r14] MONO_CONTEXT_OFFSET (gregs, AMD64_R14, mgreg_t), \ + [r15] MONO_CONTEXT_OFFSET (gregs, AMD64_R15, mgreg_t), \ + [rip] MONO_CONTEXT_OFFSET (gregs, AMD64_RIP, mgreg_t) \ + : "rdx", "memory"); \ + } while (0) + +#ifdef UCONTEXT_REG_XMM +#define MONO_CONTEXT_GET_CURRENT_FREGS(ctx) \ + do { \ + __asm__ __volatile__ ( \ + "movups %%xmm0, %c[xmm0](%0)\n" \ + "movups %%xmm1, %c[xmm1](%0)\n" \ + "movups %%xmm2, %c[xmm2](%0)\n" \ + "movups %%xmm3, %c[xmm3](%0)\n" \ + "movups %%xmm4, %c[xmm4](%0)\n" \ + "movups %%xmm5, %c[xmm5](%0)\n" \ + "movups %%xmm6, %c[xmm6](%0)\n" \ + "movups %%xmm7, %c[xmm7](%0)\n" \ + "movups %%xmm8, %c[xmm8](%0)\n" \ + "movups %%xmm9, %c[xmm9](%0)\n" \ + "movups %%xmm10, %c[xmm10](%0)\n" \ + "movups %%xmm11, %c[xmm11](%0)\n" \ + "movups %%xmm12, %c[xmm12](%0)\n" \ + "movups %%xmm12, %c[xmm12](%0)\n" \ + "movups %%xmm14, %c[xmm14](%0)\n" \ + "movups %%xmm15, %c[xmm15](%0)\n" \ + : \ + : "a" (&(ctx)), \ + [xmm0] MONO_CONTEXT_OFFSET (fregs, AMD64_XMM0, MonoContextSimdReg), \ + [xmm1] MONO_CONTEXT_OFFSET (fregs, AMD64_XMM1, MonoContextSimdReg), \ + [xmm2] MONO_CONTEXT_OFFSET (fregs, AMD64_XMM2, MonoContextSimdReg), \ + [xmm3] MONO_CONTEXT_OFFSET (fregs, AMD64_XMM3, MonoContextSimdReg), \ + [xmm4] MONO_CONTEXT_OFFSET (fregs, AMD64_XMM4, MonoContextSimdReg), \ + [xmm5] MONO_CONTEXT_OFFSET (fregs, AMD64_XMM5, MonoContextSimdReg), \ + [xmm6] MONO_CONTEXT_OFFSET (fregs, AMD64_XMM6, MonoContextSimdReg), \ + [xmm7] MONO_CONTEXT_OFFSET (fregs, AMD64_XMM7, MonoContextSimdReg), \ + [xmm8] MONO_CONTEXT_OFFSET (fregs, AMD64_XMM8, MonoContextSimdReg), \ + [xmm9] MONO_CONTEXT_OFFSET (fregs, AMD64_XMM9, MonoContextSimdReg), \ + [xmm10] MONO_CONTEXT_OFFSET (fregs, AMD64_XMM10, MonoContextSimdReg), \ + [xmm11] MONO_CONTEXT_OFFSET (fregs, AMD64_XMM11, MonoContextSimdReg), \ + [xmm12] MONO_CONTEXT_OFFSET (fregs, AMD64_XMM12, MonoContextSimdReg), \ + [xmm13] MONO_CONTEXT_OFFSET (fregs, AMD64_XMM13, MonoContextSimdReg), \ + [xmm14] MONO_CONTEXT_OFFSET (fregs, AMD64_XMM14, MonoContextSimdReg), \ + [xmm15] MONO_CONTEXT_OFFSET (fregs, AMD64_XMM15, MonoContextSimdReg)); \ + } while (0) +#else +#define MONO_CONTEXT_GET_CURRENT_FREGS(ctx) +#endif + +#define MONO_CONTEXT_GET_CURRENT(ctx) \ + do { \ + MONO_CONTEXT_GET_CURRENT_GREGS(ctx); \ + MONO_CONTEXT_GET_CURRENT_FREGS(ctx); \ + } while (0) #endif #define MONO_ARCH_HAS_MONO_CONTEXT 1 @@ -264,15 +356,15 @@ typedef struct { "push {r0}\n" \ "push {r1}\n" \ "mov r0, %0\n" \ - "ldr r1, [sp, #4]\n" \ - "str r1, [r0]!\n" \ - "ldr r1, [sp, #0]\n" \ - "str r1, [r0]!\n" \ + "ldr r1, [sp, #4]\n" \ + "str r1, [r0], #4\n" \ + "ldr r1, [sp, #0]\n" \ + "str r1, [r0], #4\n" \ "stmia r0!, {r2-r12}\n" \ - "str sp, [r0]!\n" \ - "str lr, [r0]!\n" \ + "str sp, [r0], #4\n" \ + "str lr, [r0], #4\n" \ "mov r1, pc\n" \ - "str r1, [r0]!\n" \ + "str r1, [r0], #4\n" \ "pop {r1}\n" \ "pop {r0}\n" \ : \ @@ -294,6 +386,11 @@ typedef struct { mgreg_t regs [32]; double fregs [32]; mgreg_t pc; + /* + * fregs might not be initialized if this context was created from a + * ucontext. + */ + mgreg_t has_fregs; } MonoContext; #define MONO_CONTEXT_SET_IP(ctx,ip) do { (ctx)->pc = (mgreg_t)ip; } while (0) @@ -313,7 +410,7 @@ typedef struct { thread_port_t self = mach_thread_self (); \ kern_return_t ret = thread_get_state (self, state_flavor, (thread_state_t) &thread_state, &state_count); \ g_assert (ret == 0); \ - mono_mach_arch_thread_state_to_mono_context ((thread_state_t)&thread_state, &ctx); \ + mono_mach_arch_thread_states_to_mono_context ((thread_state_t)&thread_state, (thread_state_t)NULL, &ctx); \ mach_port_deallocate (current_task (), self); \ } while (0); diff --git a/mono/utils/mono-mmap-windows.c b/mono/utils/mono-mmap-windows.c index 2c161c6c4ab..d0b6072bece 100644 --- a/mono/utils/mono-mmap-windows.c +++ b/mono/utils/mono-mmap-windows.c @@ -27,10 +27,22 @@ mono_pagesize (void) if (saved_pagesize) return saved_pagesize; GetSystemInfo (&info); - saved_pagesize = info.dwAllocationGranularity; + saved_pagesize = info.dwPageSize; return saved_pagesize; } +int +mono_valloc_granule (void) +{ + SYSTEM_INFO info; + static int saved_valloc_granule = 0; + if (saved_valloc_granule) + return saved_valloc_granule; + GetSystemInfo (&info); + saved_valloc_granule = info.dwAllocationGranularity; + return saved_valloc_granule; +} + int mono_mmap_win_prot_from_flags (int flags) { diff --git a/mono/utils/mono-mmap.c b/mono/utils/mono-mmap.c index 91fe5a12def..10a190ff9b0 100644 --- a/mono/utils/mono-mmap.c +++ b/mono/utils/mono-mmap.c @@ -155,6 +155,12 @@ mono_pagesize (void) return saved_pagesize; } +int +mono_valloc_granule (void) +{ + return mono_pagesize (); +} + static int prot_from_flags (int flags) { @@ -364,6 +370,12 @@ mono_pagesize (void) return 4096; } +int +mono_valloc_granule (void) +{ + return mono_pagesize (); +} + void* mono_valloc (void *addr, size_t length, int flags, MonoMemAccountType type) { diff --git a/mono/utils/mono-mmap.h b/mono/utils/mono-mmap.h index d441751c802..1b3b1d63af9 100644 --- a/mono/utils/mono-mmap.h +++ b/mono/utils/mono-mmap.h @@ -49,6 +49,7 @@ MONO_API int mono_file_map_fd (MonoFileMap *fmap); MONO_API int mono_file_map_close (MonoFileMap *fmap); MONO_API int mono_pagesize (void); +MONO_API int mono_valloc_granule (void); MONO_API void* mono_valloc (void *addr, size_t length, int flags, MonoMemAccountType type); MONO_API void* mono_valloc_aligned (size_t length, size_t alignment, int flags, MonoMemAccountType type); MONO_API int mono_vfree (void *addr, size_t length, MonoMemAccountType type); diff --git a/mono/utils/mono-sigcontext.h b/mono/utils/mono-sigcontext.h index 3c2f79b58c3..643bb4d7709 100644 --- a/mono/utils/mono-sigcontext.h +++ b/mono/utils/mono-sigcontext.h @@ -173,6 +173,23 @@ typedef struct ucontext { #define UCONTEXT_REG_R13(ctx) (((ucontext_t*)(ctx))->uc_mcontext->__ss.__r13) #define UCONTEXT_REG_R14(ctx) (((ucontext_t*)(ctx))->uc_mcontext->__ss.__r14) #define UCONTEXT_REG_R15(ctx) (((ucontext_t*)(ctx))->uc_mcontext->__ss.__r15) + #define UCONTEXT_REG_XMM + #define UCONTEXT_REG_XMM0(ctx) (((ucontext_t*)(ctx))->uc_mcontext->__fs.__fpu_xmm0) + #define UCONTEXT_REG_XMM1(ctx) (((ucontext_t*)(ctx))->uc_mcontext->__fs.__fpu_xmm1) + #define UCONTEXT_REG_XMM2(ctx) (((ucontext_t*)(ctx))->uc_mcontext->__fs.__fpu_xmm2) + #define UCONTEXT_REG_XMM3(ctx) (((ucontext_t*)(ctx))->uc_mcontext->__fs.__fpu_xmm3) + #define UCONTEXT_REG_XMM4(ctx) (((ucontext_t*)(ctx))->uc_mcontext->__fs.__fpu_xmm4) + #define UCONTEXT_REG_XMM5(ctx) (((ucontext_t*)(ctx))->uc_mcontext->__fs.__fpu_xmm5) + #define UCONTEXT_REG_XMM6(ctx) (((ucontext_t*)(ctx))->uc_mcontext->__fs.__fpu_xmm6) + #define UCONTEXT_REG_XMM7(ctx) (((ucontext_t*)(ctx))->uc_mcontext->__fs.__fpu_xmm7) + #define UCONTEXT_REG_XMM8(ctx) (((ucontext_t*)(ctx))->uc_mcontext->__fs.__fpu_xmm8) + #define UCONTEXT_REG_XMM9(ctx) (((ucontext_t*)(ctx))->uc_mcontext->__fs.__fpu_xmm9) + #define UCONTEXT_REG_XMM10(ctx) (((ucontext_t*)(ctx))->uc_mcontext->__fs.__fpu_xmm10) + #define UCONTEXT_REG_XMM11(ctx) (((ucontext_t*)(ctx))->uc_mcontext->__fs.__fpu_xmm11) + #define UCONTEXT_REG_XMM12(ctx) (((ucontext_t*)(ctx))->uc_mcontext->__fs.__fpu_xmm12) + #define UCONTEXT_REG_XMM13(ctx) (((ucontext_t*)(ctx))->uc_mcontext->__fs.__fpu_xmm13) + #define UCONTEXT_REG_XMM14(ctx) (((ucontext_t*)(ctx))->uc_mcontext->__fs.__fpu_xmm14) + #define UCONTEXT_REG_XMM15(ctx) (((ucontext_t*)(ctx))->uc_mcontext->__fs.__fpu_xmm15) #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #define UCONTEXT_REG_RAX(ctx) (((ucontext_t*)(ctx))->uc_mcontext.mc_rax) #define UCONTEXT_REG_RBX(ctx) (((ucontext_t*)(ctx))->uc_mcontext.mc_rbx) @@ -229,7 +246,7 @@ typedef struct ucontext { #define UCONTEXT_REG_R14(ctx) (((ucontext_t*)(ctx))->sc_r14) #define UCONTEXT_REG_R15(ctx) (((ucontext_t*)(ctx))->sc_r15) #elif !defined(HOST_WIN32) -#define UCONTEXT_GREGS(ctx) ((guint64*)&(((ucontext_t*)(ctx))->uc_mcontext.gregs)) + #define UCONTEXT_GREGS(ctx) ((guint64*)&(((ucontext_t*)(ctx))->uc_mcontext.gregs)) #endif #ifdef UCONTEXT_GREGS diff --git a/mono/utils/mono-threads-coop.c b/mono/utils/mono-threads-coop.c index 22b232ad4d5..7f274853683 100644 --- a/mono/utils/mono-threads-coop.c +++ b/mono/utils/mono-threads-coop.c @@ -135,7 +135,7 @@ mono_threads_state_poll_with_info (MonoThreadInfo *info) /* commit the saved state and notify others if needed */ switch (mono_threads_transition_state_poll (info)) { case SelfSuspendResumed: - return; + break; case SelfSuspendWait: mono_thread_info_wait_for_resume (info); break; @@ -144,6 +144,12 @@ mono_threads_state_poll_with_info (MonoThreadInfo *info) mono_thread_info_wait_for_resume (info); break; } + + if (info->async_target) { + info->async_target (info->user_data); + info->async_target = NULL; + info->user_data = NULL; + } } static volatile gpointer* dummy_global; diff --git a/mono/utils/mono-threads-mach.c b/mono/utils/mono-threads-mach.c index b696064decd..fdf18bb1891 100644 --- a/mono/utils/mono-threads-mach.c +++ b/mono/utils/mono-threads-mach.c @@ -117,8 +117,8 @@ mono_threads_suspend_begin_async_resume (MonoThreadInfo *info) if (info->async_target) { MonoContext tmp = info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx; - mach_msg_type_number_t num_state; - thread_state_t state; + mach_msg_type_number_t num_state, num_fpstate; + thread_state_t state, fpstate; ucontext_t uctx; mcontext_t mctx; @@ -127,23 +127,24 @@ mono_threads_suspend_begin_async_resume (MonoThreadInfo *info) info->async_target = (void (*)(void *)) info->user_data; state = (thread_state_t) alloca (mono_mach_arch_get_thread_state_size ()); + fpstate = (thread_state_t) alloca (mono_mach_arch_get_thread_fpstate_size ()); mctx = (mcontext_t) alloca (mono_mach_arch_get_mcontext_size ()); do { - ret = mono_mach_arch_get_thread_state (info->native_handle, state, &num_state); + ret = mono_mach_arch_get_thread_states (info->native_handle, state, &num_state, fpstate, &num_fpstate); } while (ret == KERN_ABORTED); if (ret != KERN_SUCCESS) return FALSE; - mono_mach_arch_thread_state_to_mcontext (state, mctx); + mono_mach_arch_thread_states_to_mcontext (state, fpstate, mctx); uctx.uc_mcontext = mctx; mono_monoctx_to_sigctx (&tmp, &uctx); - mono_mach_arch_mcontext_to_thread_state (mctx, state); + mono_mach_arch_mcontext_to_thread_states (mctx, state, fpstate); do { - ret = mono_mach_arch_set_thread_state (info->native_handle, state, num_state); + ret = mono_mach_arch_set_thread_states (info->native_handle, state, num_state, fpstate, num_fpstate); } while (ret == KERN_ABORTED); if (ret != KERN_SUCCESS) diff --git a/mono/utils/mono-threads-posix.c b/mono/utils/mono-threads-posix.c index be440711fb3..5447a8fe93f 100644 --- a/mono/utils/mono-threads-posix.c +++ b/mono/utils/mono-threads-posix.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -36,23 +35,6 @@ extern int tkill (pid_t tid, int signal); #include -#if defined(__native_client__) -void nacl_shutdown_gc_thread(void); -#endif - -void -mono_threads_platform_register (MonoThreadInfo *info) -{ - gpointer thread_handle; - - thread_handle = mono_w32handle_new (MONO_W32HANDLE_THREAD, NULL); - if (thread_handle == INVALID_HANDLE_VALUE) - g_error ("%s: failed to create handle", __func__); - - g_assert (!info->handle); - info->handle = thread_handle; -} - int mono_threads_platform_create_thread (MonoThreadStart thread_fn, gpointer thread_data, gsize* const stack_size, MonoNativeThreadId *out_tid) { @@ -158,25 +140,9 @@ mono_threads_platform_yield (void) } void -mono_threads_platform_exit (int exit_code) +mono_threads_platform_exit (gsize exit_code) { -#if defined(__native_client__) - nacl_shutdown_gc_thread(); -#endif - - mono_thread_info_detach (); - - pthread_exit (NULL); -} - -void -mono_threads_platform_unregister (MonoThreadInfo *info) -{ - g_assert (info->handle); - - /* The thread is no longer active, so unref it */ - mono_w32handle_unref (info->handle); - info->handle = NULL; + pthread_exit ((gpointer) exit_code); } int @@ -193,28 +159,6 @@ mono_threads_get_max_stack_size (void) return (int)lim.rlim_max; } -gpointer -mono_threads_platform_duplicate_handle (MonoThreadInfo *info) -{ - g_assert (info->handle); - mono_w32handle_ref (info->handle); - return info->handle; -} - -HANDLE -mono_threads_platform_open_thread_handle (HANDLE handle, MonoNativeThreadId tid) -{ - mono_w32handle_ref (handle); - - return handle; -} - -void -mono_threads_platform_close_thread_handle (HANDLE handle) -{ - mono_w32handle_unref (handle); -} - int mono_threads_pthread_kill (MonoThreadInfo *info, int signum) { @@ -311,56 +255,6 @@ mono_native_thread_join (MonoNativeThreadId tid) return !pthread_join (tid, &res); } -void -mono_threads_platform_set_exited (gpointer handle) -{ - int thr_ret; - - g_assert (handle); - if (mono_w32handle_issignalled (handle)) - g_error ("%s: handle %p thread %p has already exited, it's handle is signalled", __func__, handle, mono_native_thread_id_get ()); - if (mono_w32handle_get_type (handle) == MONO_W32HANDLE_UNUSED) - g_error ("%s: handle %p thread %p has already exited, it's handle type is 'unused'", __func__, handle, mono_native_thread_id_get ()); - - thr_ret = mono_w32handle_lock_handle (handle); - g_assert (thr_ret == 0); - - mono_w32handle_set_signal_state (handle, TRUE, TRUE); - - thr_ret = mono_w32handle_unlock_handle (handle); - g_assert (thr_ret == 0); -} - -static const gchar* thread_typename (void) -{ - return "Thread"; -} - -static gsize thread_typesize (void) -{ - return 0; -} - -static MonoW32HandleOps thread_ops = { - NULL, /* close */ - NULL, /* signal */ - NULL, /* own */ - NULL, /* is_owned */ - NULL, /* special_wait */ - NULL, /* prewait */ - NULL, /* details */ - thread_typename, /* typename */ - thread_typesize, /* typesize */ -}; - -void -mono_threads_platform_init (void) -{ - mono_w32handle_register_ops (MONO_W32HANDLE_THREAD, &thread_ops); - - mono_w32handle_register_capabilities (MONO_W32HANDLE_THREAD, MONO_W32HANDLE_CAP_WAIT); -} - #endif /* defined(_POSIX_VERSION) || defined(__native_client__) */ #if defined(USE_POSIX_BACKEND) @@ -392,8 +286,13 @@ This begins async resume. This function must do the following: gboolean mono_threads_suspend_begin_async_resume (MonoThreadInfo *info) { - mono_threads_add_to_pending_operation_set (info); - return mono_threads_pthread_kill (info, mono_threads_suspend_get_restart_signal ()) == 0; + int sig = mono_threads_suspend_get_restart_signal (); + + if (!mono_threads_pthread_kill (info, sig)) { + mono_threads_add_to_pending_operation_set (info); + return TRUE; + } + return FALSE; } void diff --git a/mono/utils/mono-threads-windows.c b/mono/utils/mono-threads-windows.c index 9a8a93b9694..f3f160b30c9 100644 --- a/mono/utils/mono-threads-windows.c +++ b/mono/utils/mono-threads-windows.c @@ -189,22 +189,6 @@ mono_threads_suspend_get_abort_signal (void) #if defined (HOST_WIN32) -void -mono_threads_platform_register (MonoThreadInfo *info) -{ - HANDLE thread_handle; - - thread_handle = GetCurrentThread (); - g_assert (thread_handle); - - /* The handle returned by GetCurrentThread () is a pseudo handle, so it can't - * be used to refer to the thread from other threads for things like aborting. */ - DuplicateHandle (GetCurrentProcess (), thread_handle, GetCurrentProcess (), &thread_handle, THREAD_ALL_ACCESS, TRUE, 0); - - g_assert (!info->handle); - info->handle = thread_handle; -} - int mono_threads_platform_create_thread (MonoThreadStart thread_fn, gpointer thread_data, gsize* const stack_size, MonoNativeThreadId *out_tid) { @@ -312,21 +296,11 @@ mono_threads_platform_yield (void) } void -mono_threads_platform_exit (int exit_code) +mono_threads_platform_exit (gsize exit_code) { - mono_thread_info_detach (); ExitThread (exit_code); } -void -mono_threads_platform_unregister (MonoThreadInfo *info) -{ - g_assert (info->handle); - - CloseHandle (info->handle); - info->handle = NULL; -} - int mono_threads_get_max_stack_size (void) { @@ -334,29 +308,6 @@ mono_threads_get_max_stack_size (void) return INT_MAX; } -gpointer -mono_threads_platform_duplicate_handle (MonoThreadInfo *info) -{ - HANDLE thread_handle; - - g_assert (info->handle); - DuplicateHandle (GetCurrentProcess (), info->handle, GetCurrentProcess (), &thread_handle, THREAD_ALL_ACCESS, TRUE, 0); - - return thread_handle; -} - -HANDLE -mono_threads_platform_open_thread_handle (HANDLE handle, MonoNativeThreadId tid) -{ - return OpenThread (THREAD_ALL_ACCESS, TRUE, tid); -} - -void -mono_threads_platform_close_thread_handle (HANDLE handle) -{ - CloseHandle (handle); -} - #if defined(_MSC_VER) const DWORD MS_VC_EXCEPTION=0x406D1388; #pragma pack(push,8) @@ -389,14 +340,4 @@ mono_native_thread_set_name (MonoNativeThreadId tid, const char *name) #endif } -void -mono_threads_platform_set_exited (gpointer handle) -{ -} - -void -mono_threads_platform_init (void) -{ -} - #endif diff --git a/mono/utils/mono-threads.c b/mono/utils/mono-threads.c index 49031c860e5..d97797e8b68 100644 --- a/mono/utils/mono-threads.c +++ b/mono/utils/mono-threads.c @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -347,6 +348,10 @@ register_thread (MonoThreadInfo *info, gpointer baseptr) mono_thread_info_set_tid (info, mono_native_thread_id_get ()); info->small_id = small_id; + info->handle = g_new0 (MonoThreadHandle, 1); + info->handle->ref = 1; + mono_os_event_init (&info->handle->event, TRUE, FALSE); + mono_os_sem_init (&info->resume_semaphore, 0); /*set TLS early so SMR works */ @@ -371,7 +376,6 @@ register_thread (MonoThreadInfo *info, gpointer baseptr) info->stackdata = g_byte_array_new (); - mono_threads_platform_register (info); mono_threads_suspend_register (info); /* @@ -392,6 +396,9 @@ register_thread (MonoThreadInfo *info, gpointer baseptr) static void mono_thread_info_suspend_lock_with_info (MonoThreadInfo *info); +static void +mono_threads_signal_thread_handle (MonoThreadHandle* thread_handle); + static void unregister_thread (void *arg) { @@ -426,7 +433,7 @@ unregister_thread (void *arg) /* we need to duplicate it, as the info->handle is going * to be closed when unregistering from the platform */ - handle = mono_threads_platform_duplicate_handle (info); + handle = mono_threads_open_thread_handle (info->handle); /* First perform the callback that requires no locks. @@ -447,7 +454,10 @@ unregister_thread (void *arg) if (threads_callbacks.thread_unregister) threads_callbacks.thread_unregister (info); - mono_threads_platform_unregister (info); + /* The thread is no longer active, so unref its handle */ + mono_threads_close_thread_handle (info->handle); + info->handle = NULL; + result = mono_thread_info_remove (info); g_assert (result); mono_threads_transition_detach (info); @@ -463,12 +473,9 @@ unregister_thread (void *arg) mono_thread_small_id_free (small_id); - /* Signal the w32handle. It can be done as late as here - * because w32handle does not access the current MonoThreadInfo, - * neither does it switch state to BLOCKING. */ - mono_threads_platform_set_exited (handle); + mono_threads_signal_thread_handle (handle); - mono_threads_platform_close_thread_handle (handle); + mono_threads_close_thread_handle (handle); } static void @@ -689,7 +696,6 @@ mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size) mono_lls_init (&thread_list, NULL); mono_thread_smr_init (); - mono_threads_platform_init (); mono_threads_suspend_init (); mono_threads_suspend_init_signals (); mono_threads_coop_init (); @@ -723,6 +729,8 @@ To finish suspending, call mono_suspend_check. void mono_thread_info_begin_self_suspend (void) { + g_assert (!mono_threads_is_coop_enabled ()); + MonoThreadInfo *info = mono_thread_info_current_unchecked (); if (!info) return; @@ -736,6 +744,8 @@ mono_thread_info_end_self_suspend (void) { MonoThreadInfo *info; + g_assert (!mono_threads_is_coop_enabled ()); + info = mono_thread_info_current (); if (!info) return; @@ -869,6 +879,9 @@ is_thread_in_critical_region (MonoThreadInfo *info) if (stack_start < info->stack_start_limit || stack_start >= info->stack_end) return TRUE; + if (threads_callbacks.ip_in_critical_region) + return threads_callbacks.ip_in_critical_region ((MonoDomain *) state->unwind_data [MONO_UNWIND_DATA_DOMAIN], (char *) MONO_CONTEXT_GET_IP (&state->ctx)); + ji = mono_jit_info_table_find ( (MonoDomain *) state->unwind_data [MONO_UNWIND_DATA_DOMAIN], (char *) MONO_CONTEXT_GET_IP (&state->ctx)); @@ -912,7 +925,7 @@ suspend_sync (MonoNativeThreadId tid, gboolean interrupt_kernel) } break; case AsyncSuspendBlocking: - if (interrupt_kernel) + if (interrupt_kernel && mono_threads_suspend_needs_abort_syscall ()) mono_threads_suspend_abort_syscall (info); break; @@ -992,6 +1005,7 @@ mono_thread_info_safe_suspend_and_run (MonoNativeThreadId id, gboolean interrupt mono_threads_wait_pending_operations (); break; case KeepSuspended: + g_assert (!mono_threads_is_coop_enabled ()); break; default: g_error ("Invalid suspend_and_run callback return value %d", result); @@ -1128,7 +1142,7 @@ typedef struct { gpointer start_routine_arg; gint32 priority; MonoCoopSem registered; - gpointer handle; + MonoThreadHandle *handle; } CreateThreadData; static gsize WINAPI @@ -1138,7 +1152,7 @@ inner_start_thread (gpointer data) MonoThreadInfo *info; MonoThreadStart start_routine; gpointer start_routine_arg; - guint32 start_routine_res; + gsize start_routine_res; gsize dummy; thread_data = (CreateThreadData*) data; @@ -1150,7 +1164,7 @@ inner_start_thread (gpointer data) info = mono_thread_info_attach (&dummy); info->runtime_thread = TRUE; - thread_data->handle = mono_thread_info_duplicate_handle (info); + thread_data->handle = mono_threads_open_thread_handle (info->handle); mono_coop_sem_post (&thread_data->registered); @@ -1165,7 +1179,7 @@ inner_start_thread (gpointer data) /* Run the actual main function of the thread */ start_routine_res = start_routine (start_routine_arg); - mono_threads_platform_exit (start_routine_res); + mono_thread_info_exit (start_routine_res); g_assert_not_reached (); } @@ -1176,12 +1190,12 @@ inner_start_thread (gpointer data) * Create a new thread executing START with argument ARG. Store its id into OUT_TID. * Returns: a windows or io-layer handle for the thread. */ -HANDLE +MonoThreadHandle* mono_threads_create_thread (MonoThreadStart start, gpointer arg, gsize * const stack_size, MonoNativeThreadId *out_tid) { CreateThreadData *thread_data; gint res; - gpointer ret; + MonoThreadHandle *ret; thread_data = g_new0 (CreateThreadData, 1); thread_data->ref = 2; @@ -1401,6 +1415,10 @@ mono_thread_info_tls_set (THREAD_INFO_TYPE *info, MonoTlsKey key, gpointer value ((MonoThreadInfo*)info)->tls [key] = value; } +#if defined(__native_client__) +void nacl_shutdown_gc_thread(void); +#endif + /* * mono_thread_info_exit: * @@ -1408,28 +1426,66 @@ mono_thread_info_tls_set (THREAD_INFO_TYPE *info, MonoTlsKey key, gpointer value * This function doesn't return. */ void -mono_thread_info_exit (void) +mono_thread_info_exit (gsize exit_code) { +#if defined(__native_client__) + nacl_shutdown_gc_thread(); +#endif + + mono_thread_info_detach (); + mono_threads_platform_exit (0); } /* * mono_threads_open_thread_handle: * - * Return a io-layer/win32 handle for the thread identified by HANDLE/TID. - * The handle need to be closed by calling CloseHandle () when it is no - * longer needed. + * Duplicate the handle. The handle needs to be closed by calling + * mono_threads_close_thread_handle () when it is no longer needed. */ -HANDLE -mono_threads_open_thread_handle (HANDLE handle, MonoNativeThreadId tid) +MonoThreadHandle* +mono_threads_open_thread_handle (MonoThreadHandle *thread_handle) { - return mono_threads_platform_open_thread_handle (handle, tid); + guint32 oldref, newref; + + g_assert (thread_handle); + + do { + oldref = thread_handle->ref; + if (!(oldref >= 1)) + g_error ("%s: thread_handle %p has ref %u, it should be >= 1", __func__, thread_handle, oldref); + + newref = oldref + 1; + } while (InterlockedCompareExchange ((gint32*) &thread_handle->ref, newref, oldref) != oldref); + + return thread_handle; } void -mono_threads_close_thread_handle (HANDLE handle) +mono_threads_close_thread_handle (MonoThreadHandle *thread_handle) +{ + guint32 oldref, newref; + + g_assert (thread_handle); + + do { + oldref = thread_handle->ref; + if (!(oldref >= 1)) + g_error ("%s: thread_handle %p has ref %u, it should be >= 1", __func__, thread_handle, oldref); + + newref = oldref - 1; + } while (InterlockedCompareExchange ((gint32*) &thread_handle->ref, newref, oldref) != oldref); + + if (newref == 0) { + mono_os_event_destroy (&thread_handle->event); + g_free (thread_handle); + } +} + +static void +mono_threads_signal_thread_handle (MonoThreadHandle* thread_handle) { - return mono_threads_platform_close_thread_handle (handle); + mono_os_event_set (&thread_handle->event); } #define INTERRUPT_STATE ((MonoThreadInfoInterruptToken*) (size_t) -1) @@ -1638,18 +1694,46 @@ mono_thread_info_is_current (MonoThreadInfo *info) return mono_thread_info_get_tid (info) == mono_native_thread_id_get (); } -void -mono_thread_info_set_exited (THREAD_INFO_TYPE *info) +MonoThreadInfoWaitRet +mono_thread_info_wait_one_handle (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable) { - g_assert (mono_thread_info_is_current (info)); + MonoOSEventWaitRet res; - g_assert (info->handle); - mono_threads_platform_set_exited (info->handle); + res = mono_os_event_wait_one (&thread_handle->event, timeout); + if (res == MONO_OS_EVENT_WAIT_RET_SUCCESS_0) + return MONO_THREAD_INFO_WAIT_RET_SUCCESS_0; + else if (res == MONO_OS_EVENT_WAIT_RET_ALERTED) + return MONO_THREAD_INFO_WAIT_RET_ALERTED; + else if (res == MONO_OS_EVENT_WAIT_RET_TIMEOUT) + return MONO_THREAD_INFO_WAIT_RET_TIMEOUT; + else + g_error ("%s: unknown res value %d", __func__, res); } -gpointer -mono_thread_info_duplicate_handle (MonoThreadInfo *info) +MonoThreadInfoWaitRet +mono_thread_info_wait_multiple_handle (MonoThreadHandle **thread_handles, gsize nhandles, MonoOSEvent *background_change_event, gboolean waitall, guint32 timeout, gboolean alertable) { - g_assert (mono_thread_info_is_current (info)); - return mono_threads_platform_duplicate_handle (info); + MonoOSEventWaitRet res; + MonoOSEvent *thread_events [MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS]; + gint i; + + g_assert (nhandles <= MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS); + if (background_change_event) + g_assert (nhandles <= MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS - 1); + + for (i = 0; i < nhandles; ++i) + thread_events [i] = &thread_handles [i]->event; + + if (background_change_event) + thread_events [nhandles ++] = background_change_event; + + res = mono_os_event_wait_multiple (thread_events, nhandles, waitall, timeout); + if (res >= MONO_OS_EVENT_WAIT_RET_SUCCESS_0 && res <= MONO_OS_EVENT_WAIT_RET_SUCCESS_0 + nhandles - 1) + return MONO_THREAD_INFO_WAIT_RET_SUCCESS_0 + (res - MONO_OS_EVENT_WAIT_RET_SUCCESS_0); + else if (res == MONO_OS_EVENT_WAIT_RET_ALERTED) + return MONO_THREAD_INFO_WAIT_RET_ALERTED; + else if (res == MONO_OS_EVENT_WAIT_RET_TIMEOUT) + return MONO_THREAD_INFO_WAIT_RET_TIMEOUT; + else + g_error ("%s: unknown res value %d", __func__, res); } diff --git a/mono/utils/mono-threads.h b/mono/utils/mono-threads.h index 90c44c8b74d..a9776c32dbf 100644 --- a/mono/utils/mono-threads.h +++ b/mono/utils/mono-threads.h @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -62,6 +63,11 @@ typedef gsize (*MonoThreadStart)(gpointer); #endif /* #ifdef HOST_WIN32 */ +typedef struct { + guint32 ref; + MonoOSEvent event; +} MonoThreadHandle; + /* THREAD_INFO_TYPE is a way to make the mono-threads module parametric - or sort of. The GC using mono-threads might extend the MonoThreadInfo struct to add its own @@ -192,7 +198,7 @@ typedef struct { /* IO layer handle for this thread */ /* Set when the thread is started, or in _wapi_thread_duplicate () */ - HANDLE handle; + MonoThreadHandle *handle; void *jit_data; @@ -223,6 +229,7 @@ typedef struct { void (*thread_detach)(THREAD_INFO_TYPE *info); void (*thread_attach)(THREAD_INFO_TYPE *info); gboolean (*mono_method_is_critical) (void *method); + gboolean (*ip_in_critical_region) (MonoDomain *domain, gpointer ip); gboolean (*mono_thread_in_critical_region) (THREAD_INFO_TYPE *info); } MonoThreadInfoCallbacks; @@ -369,10 +376,7 @@ void mono_thread_info_tls_set (THREAD_INFO_TYPE *info, MonoTlsKey key, gpointer value); void -mono_thread_info_exit (void); - -void -mono_thread_info_set_exited (THREAD_INFO_TYPE *info); +mono_thread_info_exit (gsize exit_code); void mono_thread_info_install_interrupt (void (*callback) (gpointer data), gpointer data, gboolean *interrupted); @@ -401,17 +405,17 @@ mono_thread_info_describe_interrupt_token (THREAD_INFO_TYPE *info, GString *text gboolean mono_thread_info_is_live (THREAD_INFO_TYPE *info); -HANDLE +MonoThreadHandle* mono_threads_create_thread (MonoThreadStart start, gpointer arg, gsize * const stack_size, MonoNativeThreadId *out_tid); int mono_threads_get_max_stack_size (void); -HANDLE -mono_threads_open_thread_handle (HANDLE handle, MonoNativeThreadId tid); +MonoThreadHandle* +mono_threads_open_thread_handle (MonoThreadHandle *handle); void -mono_threads_close_thread_handle (HANDLE handle); +mono_threads_close_thread_handle (MonoThreadHandle *handle); MONO_API void mono_threads_attach_tools_thread (void); @@ -436,8 +440,6 @@ void mono_threads_suspend_init (void); //ok void mono_threads_suspend_init_signals (void); -void mono_threads_platform_init (void); - void mono_threads_coop_init (void); /* @@ -477,16 +479,10 @@ gint mono_threads_suspend_get_suspend_signal (void); gint mono_threads_suspend_get_restart_signal (void); gint mono_threads_suspend_get_abort_signal (void); -void mono_threads_platform_register (THREAD_INFO_TYPE *info); -void mono_threads_platform_unregister (THREAD_INFO_TYPE *info); int mono_threads_platform_create_thread (MonoThreadStart thread_fn, gpointer thread_data, gsize* const stack_size, MonoNativeThreadId *out_tid); void mono_threads_platform_get_stack_bounds (guint8 **staddr, size_t *stsize); gboolean mono_threads_platform_yield (void); -void mono_threads_platform_exit (int exit_code); -HANDLE mono_threads_platform_open_thread_handle (HANDLE handle, MonoNativeThreadId tid); -void mono_threads_platform_close_thread_handle (HANDLE handle); -void mono_threads_platform_set_exited (gpointer handle); -gpointer mono_threads_platform_duplicate_handle (THREAD_INFO_TYPE *info); +void mono_threads_platform_exit (gsize exit_code); void mono_threads_coop_begin_global_suspend (void); void mono_threads_coop_end_global_suspend (void); @@ -604,7 +600,17 @@ void mono_threads_end_global_suspend (void); gboolean mono_thread_info_is_current (THREAD_INFO_TYPE *info); -gpointer -mono_thread_info_duplicate_handle (THREAD_INFO_TYPE *info); +typedef enum { + MONO_THREAD_INFO_WAIT_RET_SUCCESS_0 = 0, + MONO_THREAD_INFO_WAIT_RET_ALERTED = -1, + MONO_THREAD_INFO_WAIT_RET_TIMEOUT = -2, + MONO_THREAD_INFO_WAIT_RET_FAILED = -3, +} MonoThreadInfoWaitRet; + +MonoThreadInfoWaitRet +mono_thread_info_wait_one_handle (MonoThreadHandle *handle, guint32 timeout, gboolean alertable); + +MonoThreadInfoWaitRet +mono_thread_info_wait_multiple_handle (MonoThreadHandle **thread_handles, gsize nhandles, MonoOSEvent *background_change_event, gboolean waitall, guint32 timeout, gboolean alertable); #endif /* __MONO_THREADS_H__ */ diff --git a/mono/utils/os-event-unix.c b/mono/utils/os-event-unix.c index 12ef05c2697..a2678b4f949 100644 --- a/mono/utils/os-event-unix.c +++ b/mono/utils/os-event-unix.c @@ -80,10 +80,10 @@ mono_os_event_set (MonoOSEvent *event) mono_os_mutex_lock (&event->mutex); if (event->manual) { - mono_os_event_signal (event, FALSE); + mono_os_event_signal (event, TRUE); } else { event->set_count = 1; - mono_os_event_signal (event, TRUE); + mono_os_event_signal (event, FALSE); } mono_os_mutex_unlock (&event->mutex); diff --git a/mono/utils/w32handle.c b/mono/utils/w32handle.c deleted file mode 100644 index bd82fb5578d..00000000000 --- a/mono/utils/w32handle.c +++ /dev/null @@ -1,1546 +0,0 @@ -/* - * w32handle.c: Generic and internal operations on handles - * - * Author: - * Dick Porter (dick@ximian.com) - * Ludovic Henry (luhenry@microsoft.com) - * - * (C) 2002-2011 Novell, Inc. - * Copyright 2011 Xamarin Inc - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -#include - -#if !defined(HOST_WIN32) - -#include -#include -#include -#include -#ifdef HAVE_SIGNAL_H -#include -#endif -#include -#include -#ifdef HAVE_SYS_SOCKET_H -# include -#endif -#ifdef HAVE_SYS_UN_H -# include -#endif -#ifdef HAVE_SYS_MMAN_H -# include -#endif -#ifdef HAVE_DIRENT_H -# include -#endif -#include -#ifdef HAVE_SYS_RESOURCE_H -# include -#endif - -#include "w32handle.h" - -#include "atomic.h" -#include "mono-logger-internals.h" -#include "mono-os-mutex.h" -#include "mono-proclib.h" -#include "mono-threads.h" -#include "mono-time.h" - -#undef DEBUG_REFS - -#define SLOT_MAX (1024 * 16) - -/* must be a power of 2 */ -#define HANDLE_PER_SLOT (256) - -#define INFINITE 0xFFFFFFFF - -typedef struct { - MonoW32HandleType type; - guint ref; - gboolean signalled; - mono_mutex_t signal_mutex; - mono_cond_t signal_cond; - gpointer specific; -} MonoW32HandleBase; - -static MonoW32HandleCapability handle_caps [MONO_W32HANDLE_COUNT]; -static MonoW32HandleOps *handle_ops [MONO_W32HANDLE_COUNT]; - -/* - * We can hold SLOT_MAX * HANDLE_PER_SLOT handles. - * If 4M handles are not enough... Oh, well... we will crash. - */ -#define SLOT_INDEX(x) (x / HANDLE_PER_SLOT) -#define SLOT_OFFSET(x) (x % HANDLE_PER_SLOT) - -static MonoW32HandleBase *private_handles [SLOT_MAX]; -static guint32 private_handles_count = 0; -static guint32 private_handles_slots_count = 0; - -guint32 mono_w32handle_fd_reserve; - -/* - * This is an internal handle which is used for handling waiting for multiple handles. - * Threads which wait for multiple handles wait on this one handle, and when a handle - * is signalled, this handle is signalled too. - */ -static mono_mutex_t global_signal_mutex; -static mono_cond_t global_signal_cond; - -static mono_mutex_t scan_mutex; - -static gboolean shutting_down = FALSE; - -static gboolean -type_is_fd (MonoW32HandleType type) -{ - switch (type) { - case MONO_W32HANDLE_FILE: - case MONO_W32HANDLE_CONSOLE: - case MONO_W32HANDLE_SOCKET: - case MONO_W32HANDLE_PIPE: - return TRUE; - default: - return FALSE; - } -} - -static gboolean -mono_w32handle_lookup_data (gpointer handle, MonoW32HandleBase **handle_data) -{ - gsize index, offset; - - g_assert (handle_data); - - index = SLOT_INDEX ((gsize) handle); - if (index >= SLOT_MAX) - return FALSE; - if (!private_handles [index]) - return FALSE; - - offset = SLOT_OFFSET ((gsize) handle); - if (private_handles [index][offset].type == MONO_W32HANDLE_UNUSED) - return FALSE; - - *handle_data = &private_handles [index][offset]; - return TRUE; -} - -MonoW32HandleType -mono_w32handle_get_type (gpointer handle) -{ - MonoW32HandleBase *handle_data; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) - return MONO_W32HANDLE_UNUSED; /* An impossible type */ - - return handle_data->type; -} - -void -mono_w32handle_set_signal_state (gpointer handle, gboolean state, gboolean broadcast) -{ - MonoW32HandleBase *handle_data; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return; - } - -#ifdef DEBUG - g_message ("%s: setting state of %p to %s (broadcast %s)", __func__, - handle, state?"TRUE":"FALSE", broadcast?"TRUE":"FALSE"); -#endif - - if (state == TRUE) { - /* Tell everyone blocking on a single handle */ - - /* The condition the global signal cond is waiting on is the signalling of - * _any_ handle. So lock it before setting the signalled state. - */ - mono_os_mutex_lock (&global_signal_mutex); - - /* This function _must_ be called with - * handle->signal_mutex locked - */ - handle_data->signalled=state; - - if (broadcast == TRUE) { - mono_os_cond_broadcast (&handle_data->signal_cond); - } else { - mono_os_cond_signal (&handle_data->signal_cond); - } - - /* Tell everyone blocking on multiple handles that something - * was signalled - */ - mono_os_cond_broadcast (&global_signal_cond); - - mono_os_mutex_unlock (&global_signal_mutex); - } else { - handle_data->signalled=state; - } -} - -gboolean -mono_w32handle_issignalled (gpointer handle) -{ - MonoW32HandleBase *handle_data; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return(FALSE); - } - - return handle_data->signalled; -} - -static int -mono_w32handle_lock_signal_mutex (void) -{ -#ifdef DEBUG - g_message ("%s: lock global signal mutex", __func__); -#endif - - mono_os_mutex_lock (&global_signal_mutex); - - return 0; -} - -static int -mono_w32handle_unlock_signal_mutex (void) -{ -#ifdef DEBUG - g_message ("%s: unlock global signal mutex", __func__); -#endif - - mono_os_mutex_unlock (&global_signal_mutex); - - return 0; -} - -int -mono_w32handle_lock_handle (gpointer handle) -{ - MonoW32HandleBase *handle_data; - -#ifdef DEBUG - g_message ("%s: locking handle %p", __func__, handle); -#endif - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return(0); - } - - mono_w32handle_ref (handle); - - mono_os_mutex_lock (&handle_data->signal_mutex); - - return 0; -} - -int -mono_w32handle_trylock_handle (gpointer handle) -{ - MonoW32HandleBase *handle_data; - int ret; - -#ifdef DEBUG - g_message ("%s: locking handle %p", __func__, handle); -#endif - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return(0); - } - - mono_w32handle_ref (handle); - - ret = mono_os_mutex_trylock (&handle_data->signal_mutex); - if (ret != 0) { - mono_w32handle_unref (handle); - } - - return(ret); -} - -int -mono_w32handle_unlock_handle (gpointer handle) -{ - MonoW32HandleBase *handle_data; - -#ifdef DEBUG - g_message ("%s: unlocking handle %p", __func__, handle); -#endif - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return(0); - } - - mono_os_mutex_unlock (&handle_data->signal_mutex); - - mono_w32handle_unref (handle); - - return 0; -} - -/* - * wapi_init: - * - * Initialize the io-layer. - */ -void -mono_w32handle_init (void) -{ - static gboolean initialized = FALSE; - - if (initialized) - return; - - g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0])) - == MONO_W32HANDLE_COUNT); - - /* This is needed by the code in mono_w32handle_new_internal */ - mono_w32handle_fd_reserve = (eg_getdtablesize () + (HANDLE_PER_SLOT - 1)) & ~(HANDLE_PER_SLOT - 1); - - do { - /* - * The entries in private_handles reserved for fds are allocated lazily to - * save memory. - */ - - private_handles_count += HANDLE_PER_SLOT; - private_handles_slots_count ++; - } while(mono_w32handle_fd_reserve > private_handles_count); - - mono_os_mutex_init (&scan_mutex); - - mono_os_cond_init (&global_signal_cond); - mono_os_mutex_init (&global_signal_mutex); - - initialized = TRUE; -} - -void -mono_w32handle_cleanup (void) -{ - int i, j, k; - - g_assert (!shutting_down); - shutting_down = TRUE; - - /* Every shared handle we were using ought really to be closed - * by now, but to make sure just blow them all away. The - * exiting finalizer thread in particular races us to the - * program exit and doesn't always win, so it can be left - * cluttering up the shared file. Anything else left over is - * really a bug. - */ - for(i = SLOT_INDEX (0); private_handles[i] != NULL; i++) { - for(j = SLOT_OFFSET (0); j < HANDLE_PER_SLOT; j++) { - MonoW32HandleBase *handle_data = &private_handles[i][j]; - gpointer handle = GINT_TO_POINTER (i*HANDLE_PER_SLOT+j); - - for(k = handle_data->ref; k > 0; k--) { - mono_w32handle_unref (handle); - } - } - } - - for (i = 0; i < SLOT_MAX; ++i) - g_free (private_handles [i]); -} - -static void mono_w32handle_init_handle (MonoW32HandleBase *handle, - MonoW32HandleType type, gpointer handle_specific) -{ - g_assert (handle->ref == 0); - - handle->type = type; - handle->signalled = FALSE; - handle->ref = 1; - - mono_os_cond_init (&handle->signal_cond); - mono_os_mutex_init (&handle->signal_mutex); - - if (handle_specific) - handle->specific = g_memdup (handle_specific, mono_w32handle_ops_typesize (type)); -} - -/* - * mono_w32handle_new_internal: - * @type: Init handle to this type - * - * Search for a free handle and initialize it. Return the handle on - * success and 0 on failure. This is only called from - * mono_w32handle_new, and scan_mutex must be held. - */ -static guint32 mono_w32handle_new_internal (MonoW32HandleType type, - gpointer handle_specific) -{ - guint32 i, k, count; - static guint32 last = 0; - gboolean retry = FALSE; - - /* A linear scan should be fast enough. Start from the last - * allocation, assuming that handles are allocated more often - * than they're freed. Leave the space reserved for file - * descriptors - */ - - if (last < mono_w32handle_fd_reserve) { - last = mono_w32handle_fd_reserve; - } else { - retry = TRUE; - } - -again: - count = last; - for(i = SLOT_INDEX (count); i < private_handles_slots_count; i++) { - if (private_handles [i]) { - for (k = SLOT_OFFSET (count); k < HANDLE_PER_SLOT; k++) { - MonoW32HandleBase *handle = &private_handles [i][k]; - - if(handle->type == MONO_W32HANDLE_UNUSED) { - last = count + 1; - - mono_w32handle_init_handle (handle, type, handle_specific); - return (count); - } - count++; - } - } - } - - if(retry && last > mono_w32handle_fd_reserve) { - /* Try again from the beginning */ - last = mono_w32handle_fd_reserve; - goto again; - } - - /* Will need to expand the array. The caller will sort it out */ - - return(0); -} - -gpointer -mono_w32handle_new (MonoW32HandleType type, gpointer handle_specific) -{ - guint32 handle_idx = 0; - gpointer handle; - - g_assert (!shutting_down); - - g_assert(!type_is_fd(type)); - - mono_os_mutex_lock (&scan_mutex); - - while ((handle_idx = mono_w32handle_new_internal (type, handle_specific)) == 0) { - /* Try and expand the array, and have another go */ - int idx = SLOT_INDEX (private_handles_count); - if (idx >= SLOT_MAX) { - break; - } - - private_handles [idx] = g_new0 (MonoW32HandleBase, HANDLE_PER_SLOT); - - private_handles_count += HANDLE_PER_SLOT; - private_handles_slots_count ++; - } - - mono_os_mutex_unlock (&scan_mutex); - - if (handle_idx == 0) { - /* We ran out of slots */ - handle = INVALID_HANDLE_VALUE; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to create %s handle", __func__, mono_w32handle_ops_typename (type)); - goto done; - } - - /* Make sure we left the space for fd mappings */ - g_assert (handle_idx >= mono_w32handle_fd_reserve); - - handle = GUINT_TO_POINTER (handle_idx); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: create %s handle %p", __func__, mono_w32handle_ops_typename (type), handle); - -done: - return(handle); -} - -gpointer mono_w32handle_new_fd (MonoW32HandleType type, int fd, - gpointer handle_specific) -{ - MonoW32HandleBase *handle_data; - int fd_index, fd_offset; - - g_assert (!shutting_down); - - g_assert(type_is_fd(type)); - - if (fd >= mono_w32handle_fd_reserve) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to create %s handle, fd is too big", __func__, mono_w32handle_ops_typename (type)); - - return(GUINT_TO_POINTER (INVALID_HANDLE_VALUE)); - } - - fd_index = SLOT_INDEX (fd); - fd_offset = SLOT_OFFSET (fd); - - /* Initialize the array entries on demand */ - if (!private_handles [fd_index]) { - mono_os_mutex_lock (&scan_mutex); - - if (!private_handles [fd_index]) - private_handles [fd_index] = g_new0 (MonoW32HandleBase, HANDLE_PER_SLOT); - - mono_os_mutex_unlock (&scan_mutex); - } - - handle_data = &private_handles [fd_index][fd_offset]; - - if (handle_data->type != MONO_W32HANDLE_UNUSED) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to create %s handle, fd is already in use", __func__, mono_w32handle_ops_typename (type)); - /* FIXME: clean up this handle? We can't do anything - * with the fd, cos thats the new one - */ - return(GUINT_TO_POINTER (INVALID_HANDLE_VALUE)); - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: create %s handle %p", __func__, mono_w32handle_ops_typename (type), GUINT_TO_POINTER(fd)); - - mono_w32handle_init_handle (handle_data, type, handle_specific); - - return(GUINT_TO_POINTER(fd)); -} - -gboolean -mono_w32handle_lookup (gpointer handle, MonoW32HandleType type, - gpointer *handle_specific) -{ - MonoW32HandleBase *handle_data; - - g_assert (handle_specific); - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return(FALSE); - } - - if (handle_data->type != type) { - return(FALSE); - } - - *handle_specific = handle_data->specific; - - return(TRUE); -} - -static gboolean -mono_w32handle_ref_core (gpointer handle, MonoW32HandleBase *handle_data); - -static gboolean -mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data, guint minimum); - -void -mono_w32handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpointer user_data), gpointer user_data) -{ - guint32 i, k; - - mono_os_mutex_lock (&scan_mutex); - - for (i = SLOT_INDEX (0); i < private_handles_slots_count; i++) { - if (!private_handles [i]) - continue; - for (k = SLOT_OFFSET (0); k < HANDLE_PER_SLOT; k++) { - MonoW32HandleBase *handle_data = NULL; - gpointer handle; - gboolean destroy, finished; - - handle_data = &private_handles [i][k]; - if (handle_data->type == MONO_W32HANDLE_UNUSED) - continue; - - handle = GUINT_TO_POINTER (i * HANDLE_PER_SLOT + k); - - if (!mono_w32handle_ref_core (handle, handle_data)) { - /* we are racing with mono_w32handle_unref: - * the handle ref has been decremented, but it - * hasn't yet been destroyed. */ - continue; - } - - finished = on_each (handle, handle_data->specific, user_data); - - /* we do not want to have to destroy the handle here, - * as it would means the ref/unref are unbalanced */ - destroy = mono_w32handle_unref_core (handle, handle_data, 2); - g_assert (!destroy); - - if (finished) - goto done; - } - } - -done: - mono_os_mutex_unlock (&scan_mutex); -} - -typedef struct { - MonoW32HandleType type; - gboolean (*search_user_callback)(gpointer handle, gpointer data); - gpointer search_user_data; - gpointer handle; - gpointer handle_specific; -} SearchData; - -static gboolean -search_callback (gpointer handle, gpointer handle_specific, gpointer user_data) -{ - SearchData *search_data = (SearchData*) user_data; - - if (search_data->type != mono_w32handle_get_type (handle)) - return FALSE; - - if (!search_data->search_user_callback (handle, search_data->search_user_data)) - return FALSE; - - mono_w32handle_ref (handle); - search_data->handle = handle; - search_data->handle_specific = handle_specific; - return TRUE; -} - -/* This might list some shared handles twice if they are already - * opened by this process, and the check function returns FALSE the - * first time. Shared handles that are created during the search are - * unreffed if the check function returns FALSE, so callers must not - * rely on the handle persisting (unless the check function returns - * TRUE) - * The caller owns the returned handle. - */ -gpointer mono_w32handle_search (MonoW32HandleType type, - gboolean (*check)(gpointer test, gpointer user), - gpointer user_data, - gpointer *handle_specific, - gboolean search_shared) -{ - SearchData search_data; - - memset (&search_data, 0, sizeof (search_data)); - search_data.type = type; - search_data.search_user_callback = check; - search_data.search_user_data = user_data; - mono_w32handle_foreach (search_callback, &search_data); - if (handle_specific) - *handle_specific = search_data.handle_specific; - return search_data.handle; -} - -static gboolean -mono_w32handle_ref_core (gpointer handle, MonoW32HandleBase *handle_data) -{ - guint old, new; - - do { - old = handle_data->ref; - if (old == 0) - return FALSE; - - new = old + 1; - } while (InterlockedCompareExchange ((gint32*) &handle_data->ref, new, old) != old); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: ref %s handle %p, ref: %d -> %d", - __func__, mono_w32handle_ops_typename (handle_data->type), handle, old, new); - - return TRUE; -} - -static gboolean -mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data, guint minimum) -{ - MonoW32HandleType type; - guint old, new; - - type = handle_data->type; - - do { - old = handle_data->ref; - if (!(old >= minimum)) - g_error ("%s: handle %p has ref %d, it should be >= %d", __func__, handle, old, minimum); - - new = old - 1; - } while (InterlockedCompareExchange ((gint32*) &handle_data->ref, new, old) != old); - - /* handle_data might contain invalid data from now on, if - * another thread is unref'ing this handle at the same time */ - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: unref %s handle %p, ref: %d -> %d destroy: %s", - __func__, mono_w32handle_ops_typename (type), handle, old, new, new == 0 ? "true" : "false"); - - return new == 0; -} - -void mono_w32handle_ref (gpointer handle) -{ - MonoW32HandleBase *handle_data; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to ref handle %p, unknown handle", __func__, handle); - return; - } - - if (!mono_w32handle_ref_core (handle, handle_data)) - g_error ("%s: failed to ref handle %p", __func__, handle); -} - -static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer, gpointer); - -/* The handle must not be locked on entry to this function */ -void -mono_w32handle_unref (gpointer handle) -{ - MonoW32HandleBase *handle_data; - gboolean destroy; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to unref handle %p, unknown handle", - __func__, handle); - return; - } - - destroy = mono_w32handle_unref_core (handle, handle_data, 1); - - if (destroy) { - /* Need to copy the handle info, reset the slot in the - * array, and _only then_ call the close function to - * avoid race conditions (eg file descriptors being - * closed, and another file being opened getting the - * same fd racing the memset()) - */ - MonoW32HandleType type; - gpointer handle_specific; - void (*close_func)(gpointer, gpointer); - - type = handle_data->type; - handle_specific = handle_data->specific; - - mono_os_mutex_lock (&scan_mutex); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: destroy %s handle %p", __func__, mono_w32handle_ops_typename (type), handle); - - mono_os_mutex_destroy (&handle_data->signal_mutex); - mono_os_cond_destroy (&handle_data->signal_cond); - - memset (handle_data, 0, sizeof (MonoW32HandleBase)); - - mono_os_mutex_unlock (&scan_mutex); - - close_func = _wapi_handle_ops_get_close_func (type); - if (close_func != NULL) { - close_func (handle, handle_specific); - } - - g_free (handle_specific); - } -} - -void -mono_w32handle_register_ops (MonoW32HandleType type, MonoW32HandleOps *ops) -{ - handle_ops [type] = ops; -} - -void mono_w32handle_register_capabilities (MonoW32HandleType type, - MonoW32HandleCapability caps) -{ - handle_caps[type] = caps; -} - -gboolean mono_w32handle_test_capabilities (gpointer handle, - MonoW32HandleCapability caps) -{ - MonoW32HandleBase *handle_data; - MonoW32HandleType type; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return(FALSE); - } - - type = handle_data->type; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: testing 0x%x against 0x%x (%d)", __func__, - handle_caps[type], caps, handle_caps[type] & caps); - - return((handle_caps[type] & caps) != 0); -} - -static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer, gpointer) -{ - if (handle_ops[type] != NULL && - handle_ops[type]->close != NULL) { - return (handle_ops[type]->close); - } - - return (NULL); -} - -void mono_w32handle_ops_close (gpointer handle, gpointer data) -{ - MonoW32HandleBase *handle_data; - MonoW32HandleType type; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return; - } - - type = handle_data->type; - - if (handle_ops[type] != NULL && - handle_ops[type]->close != NULL) { - handle_ops[type]->close (handle, data); - } -} - -void mono_w32handle_ops_details (MonoW32HandleType type, gpointer data) -{ - if (handle_ops[type] != NULL && - handle_ops[type]->details != NULL) { - handle_ops[type]->details (data); - } -} - -const gchar* mono_w32handle_ops_typename (MonoW32HandleType type) -{ - g_assert (handle_ops [type]); - g_assert (handle_ops [type]->typename); - return handle_ops [type]->typename (); -} - -gsize mono_w32handle_ops_typesize (MonoW32HandleType type) -{ - g_assert (handle_ops [type]); - g_assert (handle_ops [type]->typesize); - return handle_ops [type]->typesize (); -} - -void mono_w32handle_ops_signal (gpointer handle) -{ - MonoW32HandleBase *handle_data; - MonoW32HandleType type; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return; - } - - type = handle_data->type; - - if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) { - handle_ops[type]->signal (handle); - } -} - -gboolean mono_w32handle_ops_own (gpointer handle, guint32 *statuscode) -{ - MonoW32HandleBase *handle_data; - MonoW32HandleType type; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return(FALSE); - } - - type = handle_data->type; - - if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) { - return(handle_ops[type]->own_handle (handle, statuscode)); - } else { - return(FALSE); - } -} - -gboolean mono_w32handle_ops_isowned (gpointer handle) -{ - MonoW32HandleBase *handle_data; - MonoW32HandleType type; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return(FALSE); - } - - type = handle_data->type; - - if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) { - return(handle_ops[type]->is_owned (handle)); - } else { - return(FALSE); - } -} - -guint32 mono_w32handle_ops_specialwait (gpointer handle, guint32 timeout, gboolean *alerted) -{ - MonoW32HandleBase *handle_data; - MonoW32HandleType type; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return(WAIT_FAILED); - } - - type = handle_data->type; - - if (handle_ops[type] != NULL && - handle_ops[type]->special_wait != NULL) { - return(handle_ops[type]->special_wait (handle, timeout, alerted)); - } else { - return(WAIT_FAILED); - } -} - -void mono_w32handle_ops_prewait (gpointer handle) -{ - MonoW32HandleBase *handle_data; - MonoW32HandleType type; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return; - } - - type = handle_data->type; - - if (handle_ops[type] != NULL && - handle_ops[type]->prewait != NULL) { - handle_ops[type]->prewait (handle); - } -} - -static void -spin (guint32 ms) -{ - struct timespec sleepytime; - - g_assert (ms < 1000); - - sleepytime.tv_sec = 0; - sleepytime.tv_nsec = ms * 1000000; - nanosleep (&sleepytime, NULL); -} - -static void -mono_w32handle_lock_handles (gpointer *handles, gsize numhandles) -{ - guint32 i, iter=0; - int thr_ret; - - /* Lock all the handles, with backoff */ -again: - for(i=0; isignal_cond; - mutex = &handle_data->signal_mutex; - - mono_os_mutex_lock (mutex); - mono_os_cond_broadcast (cond); - mono_os_mutex_unlock (mutex); - - mono_w32handle_unref (handle); -} - -static int -mono_w32handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboolean poll, gboolean *alerted) -{ - MonoW32HandleBase *handle_data; - int res; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) - g_error ("cannot wait on unknown handle %p", handle); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: waiting for %p (type %s)", __func__, handle, - mono_w32handle_ops_typename (mono_w32handle_get_type (handle))); - - if (alerted) - *alerted = FALSE; - - if (alerted) { - mono_thread_info_install_interrupt (signal_handle_and_unref, handle, alerted); - if (*alerted) - return 0; - mono_w32handle_ref (handle); - } - - res = mono_w32handle_timedwait_signal_naked (&handle_data->signal_cond, &handle_data->signal_mutex, timeout, poll, alerted); - - if (alerted) { - mono_thread_info_uninstall_interrupt (alerted); - if (!*alerted) { - /* if it is alerted, then the handle is unref in the interrupt callback */ - mono_w32handle_unref (handle); - } - } - - return res; -} - -static gboolean -dump_callback (gpointer handle, gpointer handle_specific, gpointer user_data) -{ - MonoW32HandleBase *handle_data; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) - g_error ("cannot dump unknown handle %p", handle); - - g_print ("%p [%7s] signalled: %5s ref: %3d ", - handle, mono_w32handle_ops_typename (handle_data->type), handle_data->signalled ? "true" : "false", handle_data->ref); - mono_w32handle_ops_details (handle_data->type, handle_data->specific); - g_print ("\n"); - - return FALSE; -} - -void mono_w32handle_dump (void) -{ - mono_w32handle_foreach (dump_callback, NULL); -} - -static gboolean -own_if_signalled (gpointer handle, guint32 *statuscode) -{ - if (!mono_w32handle_issignalled (handle)) - return FALSE; - - *statuscode = WAIT_OBJECT_0; - mono_w32handle_ops_own (handle, statuscode); - return TRUE; -} - -static gboolean -own_if_owned( gpointer handle, guint32 *statuscode) -{ - if (!mono_w32handle_ops_isowned (handle)) - return FALSE; - - *statuscode = WAIT_OBJECT_0; - mono_w32handle_ops_own (handle, statuscode); - return TRUE; -} - -MonoW32HandleWaitRet -mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable) -{ - MonoW32HandleWaitRet ret; - gboolean alerted; - gint64 start; - gint thr_ret; - guint32 statuscode = 0; - - alerted = FALSE; - - if (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_SPECIAL_WAIT)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p has special wait", - __func__, handle); - - switch (mono_w32handle_ops_specialwait (handle, timeout, alertable ? &alerted : NULL)) { - case WAIT_OBJECT_0: - ret = MONO_W32HANDLE_WAIT_RET_SUCCESS_0; - break; - case WAIT_ABANDONED_0: - ret = MONO_W32HANDLE_WAIT_RET_ABANDONED_0; - break; - case WAIT_IO_COMPLETION: - ret = MONO_W32HANDLE_WAIT_RET_ALERTED; - break; - case WAIT_TIMEOUT: - ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; - break; - case WAIT_FAILED: - ret = MONO_W32HANDLE_WAIT_RET_FAILED; - break; - default: - g_assert_not_reached (); - } - - if (alerted) - ret = MONO_W32HANDLE_WAIT_RET_ALERTED; - - return ret; - } - - if (!mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_WAIT)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p can't be waited for", - __func__, handle); - - return MONO_W32HANDLE_WAIT_RET_FAILED; - } - - thr_ret = mono_w32handle_lock_handle (handle); - g_assert (thr_ret == 0); - - if (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_OWN)) { - if (own_if_owned (handle, &statuscode)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p already owned", - __func__, handle); - - ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; - goto done; - } - } - - if (timeout != INFINITE) - start = mono_msec_ticks (); - - for (;;) { - gint waited; - - if (own_if_signalled (handle, &statuscode)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p signalled", - __func__, handle); - - ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; - goto done; - } - - mono_w32handle_ops_prewait (handle); - - if (timeout == INFINITE) { - waited = mono_w32handle_timedwait_signal_handle (handle, INFINITE, FALSE, alertable ? &alerted : NULL); - } else { - gint64 elapsed; - - elapsed = mono_msec_ticks () - start; - if (elapsed > timeout) { - ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; - goto done; - } - - waited = mono_w32handle_timedwait_signal_handle (handle, timeout - elapsed, FALSE, alertable ? &alerted : NULL); - } - - if (alerted) { - ret = MONO_W32HANDLE_WAIT_RET_ALERTED; - goto done; - } - - if (waited != 0) { - ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; - goto done; - } - } - -done: - thr_ret = mono_w32handle_unlock_handle (handle); - g_assert (thr_ret == 0); - - return ret; -} - -MonoW32HandleWaitRet -mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waitall, guint32 timeout, gboolean alertable) -{ - MonoW32HandleWaitRet ret; - gboolean alerted, poll; - gint i, thr_ret; - gint64 start; - gpointer handles_sorted [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS]; - guint32 statuscodes [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS] = {0}; - - if (nhandles == 0) - return MONO_W32HANDLE_WAIT_RET_FAILED; - - if (nhandles == 1) - return mono_w32handle_wait_one (handles [0], timeout, alertable); - - alerted = FALSE; - - if (nhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: too many handles: %zd", - __func__, nhandles); - - return MONO_W32HANDLE_WAIT_RET_FAILED; - } - - for (i = 0; i < nhandles; ++i) { - if (!mono_w32handle_test_capabilities (handles[i], MONO_W32HANDLE_CAP_WAIT) - && !mono_w32handle_test_capabilities (handles[i], MONO_W32HANDLE_CAP_SPECIAL_WAIT)) - { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p can't be waited for", - __func__, handles [i]); - - return MONO_W32HANDLE_WAIT_RET_FAILED; - } - - handles_sorted [i] = handles [i]; - } - - qsort (handles_sorted, nhandles, sizeof (gpointer), g_direct_equal); - for (i = 1; i < nhandles; ++i) { - if (handles_sorted [i - 1] == handles_sorted [i]) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p is duplicated", - __func__, handles_sorted [i]); - - return MONO_W32HANDLE_WAIT_RET_FAILED; - } - } - - poll = FALSE; - for (i = 0; i < nhandles; ++i) { - if (mono_w32handle_get_type (handles [i]) == MONO_W32HANDLE_PROCESS) { - /* Can't wait for a process handle + another handle without polling */ - poll = TRUE; - } - } - - if (timeout != INFINITE) - start = mono_msec_ticks (); - - for (i = 0; i < nhandles; ++i) { - /* Add a reference, as we need to ensure the handle wont - * disappear from under us while we're waiting in the loop - * (not lock, as we don't want exclusive access here) */ - mono_w32handle_ref (handles [i]); - } - - for (;;) { - gsize count, lowest; - gboolean signalled; - gint waited; - - count = 0; - lowest = nhandles; - - mono_w32handle_lock_handles (handles, nhandles); - - for (i = 0; i < nhandles; i++) { - if ((mono_w32handle_test_capabilities (handles [i], MONO_W32HANDLE_CAP_OWN) && mono_w32handle_ops_isowned (handles [i])) - || mono_w32handle_issignalled (handles [i])) - { - count ++; - - if (i < lowest) - lowest = i; - } - } - - signalled = (waitall && count == nhandles) || (!waitall && count > 0); - - if (signalled) { - for (i = 0; i < nhandles; i++) - own_if_signalled (handles [i], &statuscodes [i]); - } - - mono_w32handle_unlock_handles (handles, nhandles); - - if (signalled) { - ret = MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + lowest; - for (i = lowest; i < nhandles; i++) { - if (statuscodes [i] == WAIT_ABANDONED_0) { - ret = MONO_W32HANDLE_WAIT_RET_ABANDONED_0 + lowest; - break; - } - } - goto done; - } - - for (i = 0; i < nhandles; i++) { - mono_w32handle_ops_prewait (handles[i]); - - if (mono_w32handle_test_capabilities (handles [i], MONO_W32HANDLE_CAP_SPECIAL_WAIT) - && !mono_w32handle_issignalled (handles [i])) - { - mono_w32handle_ops_specialwait (handles [i], 0, alertable ? &alerted : NULL); - } - } - - thr_ret = mono_w32handle_lock_signal_mutex (); - g_assert (thr_ret == 0); - - if (waitall) { - signalled = TRUE; - for (i = 0; i < nhandles; ++i) { - if (!mono_w32handle_issignalled (handles [i])) { - signalled = FALSE; - break; - } - } - } else { - signalled = FALSE; - for (i = 0; i < nhandles; ++i) { - if (mono_w32handle_issignalled (handles [i])) { - signalled = TRUE; - break; - } - } - } - - waited = 0; - - if (!signalled) { - if (timeout == INFINITE) { - waited = mono_w32handle_timedwait_signal (INFINITE, poll, alertable ? &alerted : NULL); - } else { - gint64 elapsed; - - elapsed = mono_msec_ticks () - start; - if (elapsed > timeout) { - ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; - - thr_ret = mono_w32handle_unlock_signal_mutex (); - g_assert (thr_ret == 0); - - goto done; - } - - waited = mono_w32handle_timedwait_signal (timeout - elapsed, poll, alertable ? &alerted : NULL); - } - } - - thr_ret = mono_w32handle_unlock_signal_mutex (); - g_assert (thr_ret == 0); - - if (alerted) { - ret = MONO_W32HANDLE_WAIT_RET_ALERTED; - goto done; - } - - if (waited != 0) { - ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; - goto done; - } - } - -done: - for (i = 0; i < nhandles; i++) { - /* Unref everything we reffed above */ - mono_w32handle_unref (handles [i]); - } - - return ret; -} - -MonoW32HandleWaitRet -mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, guint32 timeout, gboolean alertable) -{ - MonoW32HandleWaitRet ret; - gint64 start; - gboolean alerted; - gint thr_ret; - guint32 statuscode = 0; - - alerted = FALSE; - - if (!mono_w32handle_test_capabilities (signal_handle, MONO_W32HANDLE_CAP_SIGNAL)) - return MONO_W32HANDLE_WAIT_RET_FAILED; - if (!mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_WAIT)) - return MONO_W32HANDLE_WAIT_RET_FAILED; - - if (mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_SPECIAL_WAIT)) { - g_warning ("%s: handle %p has special wait, implement me!!", __func__, wait_handle); - return MONO_W32HANDLE_WAIT_RET_FAILED; - } - - thr_ret = mono_w32handle_lock_handle (wait_handle); - g_assert (thr_ret == 0); - - mono_w32handle_ops_signal (signal_handle); - - if (mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_OWN)) { - if (own_if_owned (wait_handle, &statuscode)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p already owned", - __func__, wait_handle); - - ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; - goto done; - } - } - - if (timeout != INFINITE) - start = mono_msec_ticks (); - - for (;;) { - gint waited; - - if (own_if_signalled (wait_handle, &statuscode)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p signalled", - __func__, wait_handle); - - ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; - goto done; - } - - mono_w32handle_ops_prewait (wait_handle); - - if (timeout == INFINITE) { - waited = mono_w32handle_timedwait_signal_handle (wait_handle, INFINITE, FALSE, alertable ? &alerted : NULL); - } else { - gint64 elapsed; - - elapsed = mono_msec_ticks () - start; - if (elapsed > timeout) { - ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; - goto done; - } - - waited = mono_w32handle_timedwait_signal_handle (wait_handle, timeout - elapsed, FALSE, alertable ? &alerted : NULL); - } - - if (alerted) { - ret = MONO_W32HANDLE_WAIT_RET_ALERTED; - goto done; - } - - if (waited != 0) { - ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; - goto done; - } - } - -done: - thr_ret = mono_w32handle_unlock_handle (wait_handle); - g_assert (thr_ret == 0); - - return ret; -} - -#endif /* !defined(HOST_WIN32) */ diff --git a/mono/utils/w32handle.h b/mono/utils/w32handle.h deleted file mode 100644 index de65da19e9f..00000000000 --- a/mono/utils/w32handle.h +++ /dev/null @@ -1,186 +0,0 @@ - -#ifndef _MONO_UTILS_W32HANDLE_H_ -#define _MONO_UTILS_W32HANDLE_H_ - -#include -#include - -#ifndef INVALID_HANDLE_VALUE -#define INVALID_HANDLE_VALUE (gpointer)-1 -#endif - -#define MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS 64 - -typedef enum { - MONO_W32HANDLE_UNUSED = 0, - MONO_W32HANDLE_FILE, - MONO_W32HANDLE_CONSOLE, - MONO_W32HANDLE_THREAD, - MONO_W32HANDLE_SEM, - MONO_W32HANDLE_MUTEX, - MONO_W32HANDLE_EVENT, - MONO_W32HANDLE_SOCKET, - MONO_W32HANDLE_FIND, - MONO_W32HANDLE_PROCESS, - MONO_W32HANDLE_PIPE, - MONO_W32HANDLE_NAMEDMUTEX, - MONO_W32HANDLE_NAMEDSEM, - MONO_W32HANDLE_NAMEDEVENT, - MONO_W32HANDLE_COUNT -} MonoW32HandleType; - -typedef struct -{ - void (*close)(gpointer handle, gpointer data); - - /* SignalObjectAndWait */ - void (*signal)(gpointer signal); - - /* Called by WaitForSingleObject and WaitForMultipleObjects, - * with the handle locked (shared handles aren't locked.) - * Returns TRUE if ownership was established, false otherwise. - * If TRUE, *statuscode contains a status code such as - * WAIT_OBJECT_0 or WAIT_ABANDONED_0. - */ - gboolean (*own_handle)(gpointer handle, guint32 *statuscode); - - /* Called by WaitForSingleObject and WaitForMultipleObjects, if the - * handle in question is "ownable" (ie mutexes), to see if the current - * thread already owns this handle - */ - gboolean (*is_owned)(gpointer handle); - - /* Called by WaitForSingleObject and WaitForMultipleObjects, - * if the handle in question needs a special wait function - * instead of using the normal handle signal mechanism. - * Returns the WaitForSingleObject return code. - */ - guint32 (*special_wait)(gpointer handle, guint32 timeout, gboolean *alerted); - - /* Called by WaitForSingleObject and WaitForMultipleObjects, - * if the handle in question needs some preprocessing before the - * signal wait. - */ - void (*prewait)(gpointer handle); - - /* Called when dumping the handles */ - void (*details)(gpointer data); - - /* Called to get the name of the handle type */ - const gchar* (*typename) (void); - - /* Called to get the size of the handle type */ - gsize (*typesize) (void); -} MonoW32HandleOps; - -typedef enum { - MONO_W32HANDLE_CAP_WAIT = 0x01, - MONO_W32HANDLE_CAP_SIGNAL = 0x02, - MONO_W32HANDLE_CAP_OWN = 0x04, - MONO_W32HANDLE_CAP_SPECIAL_WAIT = 0x08, -} MonoW32HandleCapability; - -extern guint32 mono_w32handle_fd_reserve; - -void -mono_w32handle_init (void); - -void -mono_w32handle_cleanup (void); - -void -mono_w32handle_register_ops (MonoW32HandleType type, MonoW32HandleOps *ops); - -gpointer -mono_w32handle_new (MonoW32HandleType type, gpointer handle_specific); - -gpointer -mono_w32handle_new_fd (MonoW32HandleType type, int fd, gpointer handle_specific); - -MonoW32HandleType -mono_w32handle_get_type (gpointer handle); - -gboolean -mono_w32handle_lookup (gpointer handle, MonoW32HandleType type, gpointer *handle_specific); - -gpointer -mono_w32handle_search (MonoW32HandleType type, gboolean (*check)(gpointer, gpointer), gpointer user_data, gpointer *handle_specific, gboolean search_shared); - -void -mono_w32handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpointer user_data), gpointer user_data); - -void -mono_w32handle_dump (void); - -void -mono_w32handle_ref (gpointer handle); - -void -mono_w32handle_unref (gpointer handle); - -void -mono_w32handle_register_capabilities (MonoW32HandleType type, MonoW32HandleCapability caps); - -gboolean -mono_w32handle_test_capabilities (gpointer handle, MonoW32HandleCapability caps); - -void -mono_w32handle_ops_close (gpointer handle, gpointer data); - -void -mono_w32handle_ops_signal (gpointer handle); - -gboolean -mono_w32handle_ops_own (gpointer handle, guint32 *statuscode); - -gboolean -mono_w32handle_ops_isowned (gpointer handle); - -guint32 -mono_w32handle_ops_specialwait (gpointer handle, guint32 timeout, gboolean *alerted); - -void -mono_w32handle_ops_prewait (gpointer handle); - -void -mono_w32handle_ops_details (MonoW32HandleType type, gpointer data); - -const gchar* -mono_w32handle_ops_typename (MonoW32HandleType type); - -gsize -mono_w32handle_ops_typesize (MonoW32HandleType type); - -void -mono_w32handle_set_signal_state (gpointer handle, gboolean state, gboolean broadcast); - -gboolean -mono_w32handle_issignalled (gpointer handle); - -int -mono_w32handle_lock_handle (gpointer handle); - -int -mono_w32handle_trylock_handle (gpointer handle); - -int -mono_w32handle_unlock_handle (gpointer handle); - -typedef enum { - MONO_W32HANDLE_WAIT_RET_SUCCESS_0 = 0, - MONO_W32HANDLE_WAIT_RET_ABANDONED_0 = MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS, - MONO_W32HANDLE_WAIT_RET_ALERTED = -1, - MONO_W32HANDLE_WAIT_RET_TIMEOUT = -2, - MONO_W32HANDLE_WAIT_RET_FAILED = -3, -} MonoW32HandleWaitRet; - -MonoW32HandleWaitRet -mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable); - -MonoW32HandleWaitRet -mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waitall, guint32 timeout, gboolean alertable); - -MonoW32HandleWaitRet -mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, guint32 timeout, gboolean alertable); - -#endif /* _MONO_UTILS_W32HANDLE_H_ */ diff --git a/msvc/libmonoruntime.vcxproj b/msvc/libmonoruntime.vcxproj index c51ed6b6c19..54361b9ef2d 100644 --- a/msvc/libmonoruntime.vcxproj +++ b/msvc/libmonoruntime.vcxproj @@ -23,6 +23,7 @@ + @@ -31,10 +32,11 @@ - + + @@ -78,7 +80,6 @@ - @@ -141,8 +142,9 @@ - - + + + @@ -179,7 +181,6 @@ - diff --git a/msvc/libmonoruntime.vcxproj.filters b/msvc/libmonoruntime.vcxproj.filters index e0257f56ee4..c412bbe885d 100644 --- a/msvc/libmonoruntime.vcxproj.filters +++ b/msvc/libmonoruntime.vcxproj.filters @@ -127,7 +127,10 @@ Source Files - + + Source Files + + Source Files @@ -242,7 +245,7 @@ Source Files - Source Files + Source Files Source Files @@ -256,7 +259,7 @@ Source Files - + Source Files @@ -408,7 +411,13 @@ Header Files - + + Header Files + + + Header Files + + Header Files @@ -537,12 +546,6 @@ Header Files - - Header Files - - - Header Files - diff --git a/msvc/pedump.vcxproj b/msvc/pedump.vcxproj index 36dc0ecaab7..ad0d476fd93 100644 --- a/msvc/pedump.vcxproj +++ b/msvc/pedump.vcxproj @@ -226,10 +226,10 @@ - - + + diff --git a/msvc/pedump.vcxproj.filters b/msvc/pedump.vcxproj.filters index d05fff4fa96..72a54e16255 100644 --- a/msvc/pedump.vcxproj.filters +++ b/msvc/pedump.vcxproj.filters @@ -61,7 +61,10 @@ Source Files - + + Source Files + + Source Files @@ -91,9 +94,6 @@ Source Files - - Source Files - Source Files diff --git a/msvc/scripts/order.xml b/msvc/scripts/order.xml index e5849b15aec..348bedb9c11 100644 --- a/msvc/scripts/order.xml +++ b/msvc/scripts/order.xml @@ -4809,7 +4809,7 @@ - /codepage:65001 -d:NET_4_0 -d:NET_4_5 -d:NET_4_6 -d:MONO -nowarn:1699 -nostdlib -r:./../../class/lib/net_4_x/mscorlib.dll -debug -optimize /noconfig -r:Mono.Cecil -r:System.Xml -r:System.Core -r:System -r:System.Xml.Linq + /codepage:65001 -d:NET_4_0 -d:NET_4_5 -d:NET_4_6 -d:MONO -nowarn:1699 -nostdlib -r:./../../class/lib/net_4_x/mscorlib.dll -debug -optimize /noconfig -r:System.Xml -r:System.Core -r:System -r:System.Xml.Linq mono-api-html.exe ./../../class/lib/net_4_x/mono-api-html.exe @@ -7425,6 +7425,17 @@ System.Security.Cryptography.Cng.dll.sources + + false + /codepage:65001 -d:NET_1_1 -d:NET_2_0 -d:NET_2_1 -d:NET_3_5 -d:NET_4_0 -d:NET_4_5 -d:MONO -d:MOBILE,MOBILE_LEGACY -d:MOBILE_DYNAMIC -d:MONODROID -d:ANDROID -d:NETSTANDARD -nowarn:1699 -nostdlib -r:./../../class/lib/monodroid/mscorlib.dll -debug -optimize /noconfig -unsafe -nowarn:1030 -keyfile:../mono.pub -delaysign -d:SECURITY_DEP -r:./../../class/lib/monodroid/System.dll -r:./../../class/lib/monodroid/Mono.Security.dll + Mono.Btls.Interface.dll + + ./../../class/lib/monodroid/Mono.Btls.Interface.dll + 2.1 + monodroid + + Mono.Btls.Interface.dll.sources + true /codepage:65001 -unsafe -nostdlib -nowarn:612,618,1635 -d:INSIDE_CORLIB,MONO_CULTURE_DATA -d:LIBC -d:FEATURE_PAL,GENERICS_WORK,FEATURE_LIST_PREDICATES,FEATURE_SERIALIZATION,FEATURE_ASCII,FEATURE_LATIN1,FEATURE_UTF7,FEATURE_UTF32,MONO_HYBRID_ENCODING_SUPPORT,FEATURE_ASYNC_IO,NEW_EXPERIMENTAL_ASYNC_IO,FEATURE_UTF32,FEATURE_EXCEPTIONDISPATCHINFO,FEATURE_CORRUPTING_EXCEPTIONS,FEATURE_EXCEPTION_NOTIFICATIONS,FEATURE_STRONGNAME_MIGRATION,FEATURE_USE_LCID,FEATURE_FUSION,FEATURE_CRYPTO,FEATURE_X509_SECURESTRINGS,FEATURE_SYNCHRONIZATIONCONTEXT,FEATURE_SYNCHRONIZATIONCONTEXT_WAIT,HAS_CORLIB_CONTRACTS -d:MONO_FEATURE_THREAD_ABORT -d:MONO_FEATURE_THREAD_SUSPEND_RESUME -d:MONO_FEATURE_MULTIPLE_APPDOMAINS -d:NET_1_1 -d:NET_2_0 -d:NET_2_1 -d:NET_3_5 -d:NET_4_0 -d:NET_4_5 -d:MOBILE,MOBILE_LEGACY -d:MONO -d:MONOTOUCH -d:DISABLE_REMOTING -d:DISABLE_COM -d:FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK -d:NETSTANDARD -nowarn:1699 -nostdlib -debug -d:FULL_AOT_RUNTIME -optimize /noconfig -d:FEATURE_PAL,GENERICS_WORK,FEATURE_LIST_PREDICATES,FEATURE_SERIALIZATION,FEATURE_ASCII,FEATURE_LATIN1,FEATURE_UTF7,FEATURE_UTF32,MONO_HYBRID_ENCODING_SUPPORT,FEATURE_ASYNC_IO,NEW_EXPERIMENTAL_ASYNC_IO,FEATURE_UTF32,FEATURE_EXCEPTIONDISPATCHINFO,FEATURE_CORRUPTING_EXCEPTIONS,FEATURE_EXCEPTION_NOTIFICATIONS,FEATURE_STRONGNAME_MIGRATION,FEATURE_USE_LCID,FEATURE_FUSION,FEATURE_CRYPTO,FEATURE_X509_SECURESTRINGS,FEATURE_SYNCHRONIZATIONCONTEXT,FEATURE_SYNCHRONIZATIONCONTEXT_WAIT,HAS_CORLIB_CONTRACTS -d:MONO_FEATURE_THREAD_ABORT -d:MONO_FEATURE_THREAD_SUSPEND_RESUME -d:MONO_FEATURE_MULTIPLE_APPDOMAINS -resource:resources/charinfo.nlp -resource:resources/collation.core.bin -resource:resources/collation.tailoring.bin -resource:resources/collation.cjkCHS.bin -resource:resources/collation.cjkCHT.bin -resource:resources/collation.cjkJA.bin -resource:resources/collation.cjkKO.bin -resource:resources/collation.cjkKOlv2.bin --runtime:v4 @@ -15050,7 +15061,7 @@ false - /codepage:65001 -d:NET_1_1 -d:NET_2_0 -d:NET_2_1 -d:NET_3_5 -d:NET_4_0 -d:NET_4_5 -d:MONO -d:MOBILE -d:MOBILE_DYNAMIC -d:XAMMAC -d:FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK -d:XAMARIN_MODERN -d:NETSTANDARD -nowarn:1699 -nostdlib -r:./../../class/lib/xammac/mscorlib.dll -debug -optimize /noconfig -d:CONFIGURATION_2_0 -d:FEATURE_PAL,SYSTEM_NAMESPACE,MONO,PLATFORM_UNIX -d:MONO_FEATURE_PROCESS_START -d:MONO_FEATURE_THREAD_ABORT -d:MONO_FEATURE_THREAD_SUSPEND_RESUME -d:MONO_FEATURE_MULTIPLE_APPDOMAINS -unsafe -d:MONO_FEATURE_BTLS -d:INSIDE_SYSTEM -d:SECURITY_DEP -nowarn:618,1635 -d:SECURITY_DEP -d:XML_DEP -r:./../../class/lib/xammac/System.Xml.dll -r:MonoSecurity=./../../class/lib/xammac/Mono.Security.dll + /codepage:65001 -d:NET_1_1 -d:NET_2_0 -d:NET_2_1 -d:NET_3_5 -d:NET_4_0 -d:NET_4_5 -d:MONO -d:MOBILE -d:MOBILE_DYNAMIC -d:XAMMAC -d:FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK -d:XAMARIN_MODERN -d:NETSTANDARD -nowarn:1699 -nostdlib -r:./../../class/lib/xammac/mscorlib.dll -debug -optimize /noconfig -d:CONFIGURATION_2_0 -d:FEATURE_PAL,SYSTEM_NAMESPACE,MONO,PLATFORM_UNIX -d:MONO_FEATURE_PROCESS_START -d:MONO_FEATURE_THREAD_ABORT -d:MONO_FEATURE_THREAD_SUSPEND_RESUME -d:MONO_FEATURE_MULTIPLE_APPDOMAINS -unsafe -d:INSIDE_SYSTEM -d:SECURITY_DEP -nowarn:618,1635 -d:SECURITY_DEP -d:XML_DEP -r:./../../class/lib/xammac/System.Xml.dll -r:MonoSecurity=./../../class/lib/xammac/Mono.Security.dll System.dll ./../../class/lib/xammac/System.dll @@ -15061,7 +15072,7 @@ false - /codepage:65001 -d:NET_1_1 -d:NET_2_0 -d:NET_2_1 -d:NET_3_5 -d:NET_4_0 -d:NET_4_5 -d:MONO -d:MOBILE -d:MOBILE_DYNAMIC -d:XAMMAC -d:FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK -d:XAMARIN_MODERN -d:NETSTANDARD -nowarn:1699 -nostdlib -r:./../../class/lib/xammac/mscorlib.dll -debug -optimize /noconfig -d:CONFIGURATION_2_0 -d:FEATURE_PAL,SYSTEM_NAMESPACE,MONO,PLATFORM_UNIX -d:MONO_FEATURE_PROCESS_START -d:MONO_FEATURE_THREAD_ABORT -d:MONO_FEATURE_THREAD_SUSPEND_RESUME -d:MONO_FEATURE_MULTIPLE_APPDOMAINS -unsafe -d:MONO_FEATURE_BTLS -d:INSIDE_SYSTEM -d:SECURITY_DEP -nowarn:618,1635 + /codepage:65001 -d:NET_1_1 -d:NET_2_0 -d:NET_2_1 -d:NET_3_5 -d:NET_4_0 -d:NET_4_5 -d:MONO -d:MOBILE -d:MOBILE_DYNAMIC -d:XAMMAC -d:FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK -d:XAMARIN_MODERN -d:NETSTANDARD -nowarn:1699 -nostdlib -r:./../../class/lib/xammac/mscorlib.dll -debug -optimize /noconfig -d:CONFIGURATION_2_0 -d:FEATURE_PAL,SYSTEM_NAMESPACE,MONO,PLATFORM_UNIX -d:MONO_FEATURE_PROCESS_START -d:MONO_FEATURE_THREAD_ABORT -d:MONO_FEATURE_THREAD_SUSPEND_RESUME -d:MONO_FEATURE_MULTIPLE_APPDOMAINS -unsafe -d:INSIDE_SYSTEM -d:SECURITY_DEP -nowarn:618,1635 System.dll ./../../class/lib/xammac/bare/System.dll @@ -15072,7 +15083,7 @@ false - /codepage:65001 -d:NET_1_1 -d:NET_2_0 -d:NET_2_1 -d:NET_3_5 -d:NET_4_0 -d:NET_4_5 -d:MONO -d:MOBILE -d:MOBILE_DYNAMIC -d:XAMMAC -d:FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK -d:XAMARIN_MODERN -d:NETSTANDARD -nowarn:1699 -nostdlib -r:./../../class/lib/xammac/mscorlib.dll -debug -optimize /noconfig -d:CONFIGURATION_2_0 -d:FEATURE_PAL,SYSTEM_NAMESPACE,MONO,PLATFORM_UNIX -d:MONO_FEATURE_PROCESS_START -d:MONO_FEATURE_THREAD_ABORT -d:MONO_FEATURE_THREAD_SUSPEND_RESUME -d:MONO_FEATURE_MULTIPLE_APPDOMAINS -unsafe -d:MONO_FEATURE_BTLS -d:INSIDE_SYSTEM -d:SECURITY_DEP -nowarn:618,1635 -d:SECURITY_DEP -d:XML_DEP -r:./../../class/lib/xammac/bare/System.Xml.dll -r:MonoSecurity=./../../class/lib/xammac/Mono.Security.dll + /codepage:65001 -d:NET_1_1 -d:NET_2_0 -d:NET_2_1 -d:NET_3_5 -d:NET_4_0 -d:NET_4_5 -d:MONO -d:MOBILE -d:MOBILE_DYNAMIC -d:XAMMAC -d:FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK -d:XAMARIN_MODERN -d:NETSTANDARD -nowarn:1699 -nostdlib -r:./../../class/lib/xammac/mscorlib.dll -debug -optimize /noconfig -d:CONFIGURATION_2_0 -d:FEATURE_PAL,SYSTEM_NAMESPACE,MONO,PLATFORM_UNIX -d:MONO_FEATURE_PROCESS_START -d:MONO_FEATURE_THREAD_ABORT -d:MONO_FEATURE_THREAD_SUSPEND_RESUME -d:MONO_FEATURE_MULTIPLE_APPDOMAINS -unsafe -d:INSIDE_SYSTEM -d:SECURITY_DEP -nowarn:618,1635 -d:SECURITY_DEP -d:XML_DEP -r:./../../class/lib/xammac/bare/System.Xml.dll -r:MonoSecurity=./../../class/lib/xammac/Mono.Security.dll System.dll ./../../class/lib/xammac/secxml/System.dll @@ -17030,7 +17041,7 @@ false - /codepage:65001 -d:NET_4_0 -d:NET_4_5 -d:NET_4_6 -d:MONO -nowarn:1699 -nostdlib -r:./../../class/lib/xammac_net_4_5/mscorlib.dll -debug -d:FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK -d:NO_SYSTEM_DRAWING_DEPENDENCY -d:NO_WINFORMS_DEPENDENCY -d:NO_SYSTEM_WEB_DEPENDENCY -d:XAMMAC_4_5 -d:XAMARIN_MODERN -optimize /noconfig -d:CONFIGURATION_2_0 -d:FEATURE_PAL,SYSTEM_NAMESPACE,MONO,PLATFORM_UNIX -d:MONO_FEATURE_PROCESS_START -d:MONO_FEATURE_THREAD_ABORT -d:MONO_FEATURE_THREAD_SUSPEND_RESUME -d:MONO_FEATURE_MULTIPLE_APPDOMAINS -unsafe -resource:resources/Asterisk.wav -resource:resources/Beep.wav -resource:resources/Exclamation.wav -resource:resources/Hand.wav -resource:resources/Question.wav -d:MONO_FEATURE_BTLS -d:SECURITY_DEP -d:XML_DEP -d:MONO_SECURITY_ALIAS -d:CONFIGURATION_DEP -r:./../../class/lib/xammac_net_4_5/System.Xml.dll -r:./../../class/lib/xammac_net_4_5/System.Configuration.dll -r:MonoSecurity=./../../class/lib/xammac_net_4_5/Mono.Security.dll + /codepage:65001 -d:NET_4_0 -d:NET_4_5 -d:NET_4_6 -d:MONO -nowarn:1699 -nostdlib -r:./../../class/lib/xammac_net_4_5/mscorlib.dll -debug -d:FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK -d:NO_SYSTEM_DRAWING_DEPENDENCY -d:NO_WINFORMS_DEPENDENCY -d:NO_SYSTEM_WEB_DEPENDENCY -d:XAMMAC_4_5 -d:XAMARIN_MODERN -optimize /noconfig -d:CONFIGURATION_2_0 -d:FEATURE_PAL,SYSTEM_NAMESPACE,MONO,PLATFORM_UNIX -d:MONO_FEATURE_PROCESS_START -d:MONO_FEATURE_THREAD_ABORT -d:MONO_FEATURE_THREAD_SUSPEND_RESUME -d:MONO_FEATURE_MULTIPLE_APPDOMAINS -unsafe -resource:resources/Asterisk.wav -resource:resources/Beep.wav -resource:resources/Exclamation.wav -resource:resources/Hand.wav -resource:resources/Question.wav -d:SECURITY_DEP -d:XML_DEP -d:MONO_SECURITY_ALIAS -d:CONFIGURATION_DEP -r:./../../class/lib/xammac_net_4_5/System.Xml.dll -r:./../../class/lib/xammac_net_4_5/System.Configuration.dll -r:MonoSecurity=./../../class/lib/xammac_net_4_5/Mono.Security.dll System.dll ./../../class/lib/xammac_net_4_5/System.dll @@ -17052,7 +17063,7 @@ false - /codepage:65001 -d:NET_4_0 -d:NET_4_5 -d:NET_4_6 -d:MONO -nowarn:1699 -nostdlib -r:./../../class/lib/xammac_net_4_5/mscorlib.dll -debug -d:FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK -d:NO_SYSTEM_DRAWING_DEPENDENCY -d:NO_WINFORMS_DEPENDENCY -d:NO_SYSTEM_WEB_DEPENDENCY -d:XAMMAC_4_5 -d:XAMARIN_MODERN -optimize /noconfig -d:CONFIGURATION_2_0 -d:FEATURE_PAL,SYSTEM_NAMESPACE,MONO,PLATFORM_UNIX -d:MONO_FEATURE_PROCESS_START -d:MONO_FEATURE_THREAD_ABORT -d:MONO_FEATURE_THREAD_SUSPEND_RESUME -d:MONO_FEATURE_MULTIPLE_APPDOMAINS -unsafe -resource:resources/Asterisk.wav -resource:resources/Beep.wav -resource:resources/Exclamation.wav -resource:resources/Hand.wav -resource:resources/Question.wav -d:MONO_FEATURE_BTLS + /codepage:65001 -d:NET_4_0 -d:NET_4_5 -d:NET_4_6 -d:MONO -nowarn:1699 -nostdlib -r:./../../class/lib/xammac_net_4_5/mscorlib.dll -debug -d:FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK -d:NO_SYSTEM_DRAWING_DEPENDENCY -d:NO_WINFORMS_DEPENDENCY -d:NO_SYSTEM_WEB_DEPENDENCY -d:XAMMAC_4_5 -d:XAMARIN_MODERN -optimize /noconfig -d:CONFIGURATION_2_0 -d:FEATURE_PAL,SYSTEM_NAMESPACE,MONO,PLATFORM_UNIX -d:MONO_FEATURE_PROCESS_START -d:MONO_FEATURE_THREAD_ABORT -d:MONO_FEATURE_THREAD_SUSPEND_RESUME -d:MONO_FEATURE_MULTIPLE_APPDOMAINS -unsafe -resource:resources/Asterisk.wav -resource:resources/Beep.wav -resource:resources/Exclamation.wav -resource:resources/Hand.wav -resource:resources/Question.wav System.dll ./../../class/lib/xammac_net_4_5/bare/System.dll @@ -17074,7 +17085,7 @@ false - /codepage:65001 -d:NET_4_0 -d:NET_4_5 -d:NET_4_6 -d:MONO -nowarn:1699 -nostdlib -r:./../../class/lib/xammac_net_4_5/mscorlib.dll -debug -d:FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK -d:NO_SYSTEM_DRAWING_DEPENDENCY -d:NO_WINFORMS_DEPENDENCY -d:NO_SYSTEM_WEB_DEPENDENCY -d:XAMMAC_4_5 -d:XAMARIN_MODERN -optimize /noconfig -d:CONFIGURATION_2_0 -d:FEATURE_PAL,SYSTEM_NAMESPACE,MONO,PLATFORM_UNIX -d:MONO_FEATURE_PROCESS_START -d:MONO_FEATURE_THREAD_ABORT -d:MONO_FEATURE_THREAD_SUSPEND_RESUME -d:MONO_FEATURE_MULTIPLE_APPDOMAINS -unsafe -resource:resources/Asterisk.wav -resource:resources/Beep.wav -resource:resources/Exclamation.wav -resource:resources/Hand.wav -resource:resources/Question.wav -d:MONO_FEATURE_BTLS -d:SECURITY_DEP -d:XML_DEP -d:MONO_SECURITY_ALIAS -r:./../../class/lib/xammac_net_4_5/bare/System.Xml.dll -r:MonoSecurity=./../../class/lib/xammac_net_4_5/Mono.Security.dll + /codepage:65001 -d:NET_4_0 -d:NET_4_5 -d:NET_4_6 -d:MONO -nowarn:1699 -nostdlib -r:./../../class/lib/xammac_net_4_5/mscorlib.dll -debug -d:FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK -d:NO_SYSTEM_DRAWING_DEPENDENCY -d:NO_WINFORMS_DEPENDENCY -d:NO_SYSTEM_WEB_DEPENDENCY -d:XAMMAC_4_5 -d:XAMARIN_MODERN -optimize /noconfig -d:CONFIGURATION_2_0 -d:FEATURE_PAL,SYSTEM_NAMESPACE,MONO,PLATFORM_UNIX -d:MONO_FEATURE_PROCESS_START -d:MONO_FEATURE_THREAD_ABORT -d:MONO_FEATURE_THREAD_SUSPEND_RESUME -d:MONO_FEATURE_MULTIPLE_APPDOMAINS -unsafe -resource:resources/Asterisk.wav -resource:resources/Beep.wav -resource:resources/Exclamation.wav -resource:resources/Hand.wav -resource:resources/Question.wav -d:SECURITY_DEP -d:XML_DEP -d:MONO_SECURITY_ALIAS -r:./../../class/lib/xammac_net_4_5/bare/System.Xml.dll -r:MonoSecurity=./../../class/lib/xammac_net_4_5/Mono.Security.dll System.dll ./../../class/lib/xammac_net_4_5/secxml/System.dll @@ -17963,17 +17974,6 @@ System.Net.Http.WebRequest.dll.sources - - false - /codepage:65001 -d:NET_4_0 -d:NET_4_5 -d:NET_4_6 -d:MONO -nowarn:1699 -nostdlib -r:./../../class/lib/xammac_net_4_5/mscorlib.dll -debug -d:FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK -d:NO_SYSTEM_DRAWING_DEPENDENCY -d:NO_WINFORMS_DEPENDENCY -d:NO_SYSTEM_WEB_DEPENDENCY -d:XAMMAC_4_5 -d:XAMARIN_MODERN -optimize /noconfig -unsafe -nowarn:1030 -keyfile:../mono.pub -delaysign -d:SECURITY_DEP -r:./../../class/lib/xammac_net_4_5/System.dll -r:./../../class/lib/xammac_net_4_5/Mono.Security.dll - Mono.Btls.Interface.dll - - ./../../class/lib/xammac_net_4_5/Mono.Btls.Interface.dll - 4.5 - xammac_net_4_5 - - Mono.Btls.Interface.dll.sources - false /codepage:65001 -d:NET_4_0 -d:NET_4_5 -d:NET_4_6 -d:MONO -nowarn:1699 -nostdlib -r:./../../class/lib/xammac_net_4_5/mscorlib.dll -debug -d:FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK -d:NO_SYSTEM_DRAWING_DEPENDENCY -d:NO_WINFORMS_DEPENDENCY -d:NO_SYSTEM_WEB_DEPENDENCY -d:XAMMAC_4_5 -d:XAMARIN_MODERN -optimize /noconfig -r:./../../class/lib/xammac_net_4_5/System.dll diff --git a/scripts/ci/run-test-default.sh b/scripts/ci/run-test-default.sh index fa96ad7cef2..91c9b11c9c5 100755 --- a/scripts/ci/run-test-default.sh +++ b/scripts/ci/run-test-default.sh @@ -25,7 +25,7 @@ fi ${TESTCMD} --label=System.Data --timeout=5m make -w -C mcs/class/System.Data run-test ${TESTCMD} --label=System.Data.OracleClient --timeout=5m make -w -C mcs/class/System.Data.OracleClient run-test; ${TESTCMD} --label=System.Design --timeout=5m make -w -C mcs/class/System.Design run-test; -if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=Mono.Posix --skip; else ${TESTCMD} --label=Mono.Posix --timeout=5m make -w -C mcs/class/Mono.Posix run-test; fi +${TESTCMD} --label=Mono.Posix --timeout=5m make -w -C mcs/class/Mono.Posix run-test ${TESTCMD} --label=System.Web --timeout=30m make -w -C mcs/class/System.Web run-test ${TESTCMD} --label=System.Web.Services --timeout=5m make -w -C mcs/class/System.Web.Services run-test ${TESTCMD} --label=System.Runtime.SFS --timeout=5m make -w -C mcs/class/System.Runtime.Serialization.Formatters.Soap run-test; diff --git a/support/zlib-helper.c b/support/zlib-helper.c index f364a66095f..9dcebc7e967 100644 --- a/support/zlib-helper.c +++ b/support/zlib-helper.c @@ -194,21 +194,22 @@ ReadZStream (ZStream *stream, guchar *buffer, gint length) while (zs->avail_out > 0) { if (zs->avail_in == 0) { n = stream->func (stream->buffer, BUFFER_SIZE, stream->gchandle); + n = n < 0 ? 0 : n; stream->total_in += n; - if (n <= 0) { - stream->eof = TRUE; - } zs->next_in = stream->buffer; - zs->avail_in = n < 0 ? 0 : n; + zs->avail_in = n; } - if (zs->avail_in == 0 && (zs->total_in == 0 || stream->total_in == zs->total_in)) - return Z_STREAM_END; + if (zs->avail_in == 0 && zs->total_in == 0) + return 0; status = inflate (stream->stream, Z_SYNC_FLUSH); if (status == Z_STREAM_END) { stream->eof = TRUE; break; + } else if (status == Z_BUF_ERROR && stream->total_in == zs->total_in) { + stream->eof = TRUE; + break; } else if (status != Z_OK) { return status; } diff --git a/tools/monograph/monograph.c b/tools/monograph/monograph.c index 27f1a5f3cf9..4d3cb837069 100644 --- a/tools/monograph/monograph.c +++ b/tools/monograph/monograph.c @@ -260,9 +260,9 @@ method_stats (MonoMethod *method) { if (i == MONO_CEE_CASTCLASS || i == MONO_CEE_ISINST) { guint32 token = read32 (ip + 1); MonoClass *k = mono_class_get (method->klass->image, token); - if (k && k->flags & TYPE_ATTRIBUTE_SEALED) + if (k && mono_class_get_flags (k) & TYPE_ATTRIBUTE_SEALED) cast_sealed++; - if (k && k->flags & TYPE_ATTRIBUTE_INTERFACE) + if (k && mono_class_get_flags (k) & TYPE_ATTRIBUTE_INTERFACE) cast_iface++; total_cast++; } @@ -364,7 +364,7 @@ method_stats (MonoMethod *method) { MonoMethod *cm = mono_get_method (method->klass->image, read32 (ip + 1), NULL); if (cm && !(cm->flags & METHOD_ATTRIBUTE_VIRTUAL)) nonvirt_callvirt++; - if (cm && (cm->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) + if (cm && (mono_class_get_flags (cm->klass) & TYPE_ATTRIBUTE_INTERFACE)) iface_callvirt++; total_callvirt++; } @@ -430,7 +430,7 @@ type_stats (MonoClass *klass) { MonoClass *parent; int depth = 1; - if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) { + if (mono_class_get_flags (klass) & TYPE_ATTRIBUTE_INTERFACE) { num_ifaces++; return; }