diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 5a423ee75b3788..cdf6a3b27b8747 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -15,7 +15,7 @@ ] }, "microsoft.dotnet.xharness.cli": { - "version": "1.0.0-prerelease.22411.1", + "version": "7.0.0-prerelease.23253.3", "commands": [ "xharness" ] diff --git a/.github/PULL_REQUEST_TEMPLATE/servicing_pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/servicing_pull_request_template.md index 8932380eb8e13e..9a748a085a20f1 100644 --- a/.github/PULL_REQUEST_TEMPLATE/servicing_pull_request_template.md +++ b/.github/PULL_REQUEST_TEMPLATE/servicing_pull_request_template.md @@ -24,5 +24,4 @@ main PR # Package authoring signed off? - -IMPORTANT: If this change touches code that ships in a NuGet package, please make certain that you have added any necessary [package authoring](https://github.com/dotnet/runtime/blob/main/docs/project/library-servicing.md) and gotten it explicitly reviewed. +IMPORTANT: If this change touches code that ships in a NuGet package, please make certain that you have added any necessary [package authoring](../../docs/project/library-servicing.md) and gotten it explicitly reviewed. diff --git a/.github/workflows/check-service-labels.yml b/.github/workflows/check-service-labels.yml index efbbcdf9925fd7..5261cc165ee128 100644 --- a/.github/workflows/check-service-labels.yml +++ b/.github/workflows/check-service-labels.yml @@ -13,10 +13,12 @@ jobs: check-labels: runs-on: ubuntu-latest steps: - - name: Check servicing labels + - name: Check 'Servicing-approved' label run: | + echo "Merging permission is enabled for servicing PRs when the `Servicing-approved` label is applied." if [ "${{ contains(github.event.pull_request.labels.*.name, 'Servicing-approved') }}" = "true" ]; then exit 0 else + echo "::error:: 'Servicing-approved' label not applied to the PR yet. More information: https://github.com/dotnet/runtime/blob/main/docs/project/library-servicing.md#approval-process" exit 1 fi diff --git a/docs/project/library-servicing.md b/docs/project/library-servicing.md index 3429c62085a3b2..f95587849d9268 100644 --- a/docs/project/library-servicing.md +++ b/docs/project/library-servicing.md @@ -1,6 +1,6 @@ # How to service a library -This document provides the steps necessary after modifying a library in a servicing branch. +This document provides the steps that need to be followed after modifying a library in a servicing branch. Servicing branches represent shipped versions of .NET, and their name is in the format `release/X.0-staging`. Examples: @@ -41,5 +41,15 @@ All the servicing change must go through an approval process. You have two ways For both cases, you must: - Fill out the template of the PR description. -- Add the `servicing-consider` label. -- Bring it to the attention of the engineering lead responsible for the area, so they consider the fix for servicing. \ No newline at end of file +- Bring it to the attention of the [engineering lead responsible for the area](~/docs/area-owners.md). +- If the fix is a product change, the area owner will: + - Add the `Servicing-consider` label. + - Ask the area owner to champion your PR in the .NET Tactics meeting to request merge approval. + - If the change is approved, they will replace the `Servicing-consider` label by `Servicing-approved` and sign-off the PR. +- If the fix is a test-only or infra-only change, the area owner will: + - Review the PR and sign-off if they approve it. + - Add the `Servicing-approved` label. + +The area owner can then merge the PR once the CI looks good (it's either green or the failures are investigated and determined to be unrelated to the PR). + +**Note**: Applying the `Servicing-approved` label ensures the `check-service-labels` CI job passes, which is a mandatory requirement for merging a PR in a servicing branch. diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 20d53bb84d674f..d529b4f685a386 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -58,77 +58,77 @@ - + https://github.com/dotnet/arcade - 7c5e5a782c67460b123c8e41d484ebcca8002c93 + df8799988af6503cbcd9544713d30732328c8c57 - + https://github.com/dotnet/arcade - 7c5e5a782c67460b123c8e41d484ebcca8002c93 + df8799988af6503cbcd9544713d30732328c8c57 - + https://github.com/dotnet/arcade - 7c5e5a782c67460b123c8e41d484ebcca8002c93 + df8799988af6503cbcd9544713d30732328c8c57 - + https://github.com/dotnet/arcade - 7c5e5a782c67460b123c8e41d484ebcca8002c93 + df8799988af6503cbcd9544713d30732328c8c57 - + https://github.com/dotnet/arcade - 7c5e5a782c67460b123c8e41d484ebcca8002c93 + df8799988af6503cbcd9544713d30732328c8c57 - + https://github.com/dotnet/arcade - 7c5e5a782c67460b123c8e41d484ebcca8002c93 + df8799988af6503cbcd9544713d30732328c8c57 - + https://github.com/dotnet/arcade - 7c5e5a782c67460b123c8e41d484ebcca8002c93 + df8799988af6503cbcd9544713d30732328c8c57 - + https://github.com/dotnet/arcade - 7c5e5a782c67460b123c8e41d484ebcca8002c93 + df8799988af6503cbcd9544713d30732328c8c57 - + https://github.com/dotnet/arcade - 7c5e5a782c67460b123c8e41d484ebcca8002c93 + df8799988af6503cbcd9544713d30732328c8c57 - + https://github.com/dotnet/arcade - 7c5e5a782c67460b123c8e41d484ebcca8002c93 + df8799988af6503cbcd9544713d30732328c8c57 - + https://github.com/dotnet/arcade - 7c5e5a782c67460b123c8e41d484ebcca8002c93 + df8799988af6503cbcd9544713d30732328c8c57 - + https://github.com/dotnet/arcade - 7c5e5a782c67460b123c8e41d484ebcca8002c93 + df8799988af6503cbcd9544713d30732328c8c57 - + https://github.com/dotnet/arcade - 7c5e5a782c67460b123c8e41d484ebcca8002c93 + df8799988af6503cbcd9544713d30732328c8c57 - + https://github.com/dotnet/arcade - 7c5e5a782c67460b123c8e41d484ebcca8002c93 + df8799988af6503cbcd9544713d30732328c8c57 - + https://github.com/dotnet/arcade - 7c5e5a782c67460b123c8e41d484ebcca8002c93 + df8799988af6503cbcd9544713d30732328c8c57 - + https://github.com/dotnet/arcade - 7c5e5a782c67460b123c8e41d484ebcca8002c93 + df8799988af6503cbcd9544713d30732328c8c57 - + https://github.com/dotnet/arcade - 7c5e5a782c67460b123c8e41d484ebcca8002c93 + df8799988af6503cbcd9544713d30732328c8c57 - + https://github.com/dotnet/arcade - 7c5e5a782c67460b123c8e41d484ebcca8002c93 + df8799988af6503cbcd9544713d30732328c8c57 https://github.com/dotnet/runtime-assets @@ -242,25 +242,25 @@ https://github.com/dotnet/runtime e680411c22e33f45821f4ae64365a2970b2430a6 - + https://github.com/dotnet/linker - 08a09f27f664fb84368aa4b9eb862b13bf808579 + 9d4b3f3e0c100fe5ac4dc7f40d14d792178dbd0c - + https://github.com/dotnet/xharness - 5ebf69650b9f7b4ecab485be840b3022420f7812 + 2105520c1f824406b7738d715ad132bbd42a6d6b - + https://github.com/dotnet/xharness - 5ebf69650b9f7b4ecab485be840b3022420f7812 + 2105520c1f824406b7738d715ad132bbd42a6d6b - + https://github.com/dotnet/xharness - 5ebf69650b9f7b4ecab485be840b3022420f7812 + 2105520c1f824406b7738d715ad132bbd42a6d6b - + https://github.com/dotnet/arcade - 7c5e5a782c67460b123c8e41d484ebcca8002c93 + df8799988af6503cbcd9544713d30732328c8c57 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -278,9 +278,9 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-optimization 5e0b0da43f660de5798186f4fd3bc900fc90576c - + https://github.com/dotnet/hotreload-utils - 14a4f4c6e6478b84cac9037935f823b40ddad01d + d4a9c1673071b9ef797eefc18a7586c92fcd34a1 https://github.com/dotnet/runtime-assets diff --git a/eng/Versions.props b/eng/Versions.props index fd307f2d6241a7..58c5f33ed4b557 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -53,22 +53,22 @@ 7.0.100-rc.1.22402.1 - 7.0.0-beta.23211.2 - 7.0.0-beta.23211.2 - 7.0.0-beta.23211.2 - 7.0.0-beta.23211.2 - 7.0.0-beta.23211.2 - 7.0.0-beta.23211.2 - 2.5.1-beta.23211.2 - 7.0.0-beta.23211.2 - 7.0.0-beta.23211.2 - 7.0.0-beta.23211.2 - 7.0.0-beta.23211.2 - 7.0.0-beta.23211.2 - 7.0.0-beta.23211.2 - 7.0.0-beta.23211.2 - 7.0.0-beta.23211.2 - 7.0.0-beta.23211.2 + 7.0.0-beta.23228.7 + 7.0.0-beta.23228.7 + 7.0.0-beta.23228.7 + 7.0.0-beta.23228.7 + 7.0.0-beta.23228.7 + 7.0.0-beta.23228.7 + 2.5.1-beta.23228.7 + 7.0.0-beta.23228.7 + 7.0.0-beta.23228.7 + 7.0.0-beta.23228.7 + 7.0.0-beta.23228.7 + 7.0.0-beta.23228.7 + 7.0.0-beta.23228.7 + 7.0.0-beta.23228.7 + 7.0.0-beta.23228.7 + 7.0.0-beta.23228.7 6.0.0-preview.1.102 @@ -154,10 +154,10 @@ 1.1.0 17.4.0-preview-20220707-01 - 1.0.0-prerelease.22411.1 - 1.0.0-prerelease.22411.1 - 1.0.0-prerelease.22411.1 - 1.1.0-alpha.0.22470.1 + 7.0.0-prerelease.23253.3 + 7.0.0-prerelease.23253.3 + 7.0.0-prerelease.23253.3 + 7.0.0-alpha.0.23226.5 2.4.2 1.0.0 2.4.5 @@ -174,7 +174,7 @@ 7.0.0-preview-20221010.1 - 7.0.100-1.23207.1 + 7.0.100-1.23211.1 $(MicrosoftNETILLinkTasksVersion) 7.0.0-rtm.23218.4 diff --git a/eng/common/loc/P22DotNetHtmlLocalization.lss b/eng/common/loc/P22DotNetHtmlLocalization.lss index 6661fed566e49b..858a0b237c62ce 100644 Binary files a/eng/common/loc/P22DotNetHtmlLocalization.lss and b/eng/common/loc/P22DotNetHtmlLocalization.lss differ diff --git a/eng/common/templates/job/job.yml b/eng/common/templates/job/job.yml index e3ba9398016be8..3cb5145eabf743 100644 --- a/eng/common/templates/job/job.yml +++ b/eng/common/templates/job/job.yml @@ -24,7 +24,7 @@ parameters: enablePublishBuildAssets: false enablePublishTestResults: false enablePublishUsingPipelines: false - disableComponentGovernance: false + disableComponentGovernance: '' mergeTestResults: false testRunTitle: '' testResultsFormat: '' @@ -142,9 +142,13 @@ jobs: richNavLogOutputDirectory: $(Build.SourcesDirectory)/artifacts/bin continueOnError: true - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), ne(parameters.disableComponentGovernance, 'true')) }}: - - task: ComponentGovernanceComponentDetection@0 - continueOnError: true + - template: /eng/common/templates/steps/component-governance.yml + parameters: + ${{ if eq(parameters.disableComponentGovernance, '') }}: + ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), eq(parameters.runAsPublic, 'false'), or(contains(variables['Build.SourceBranch'], 'internal/release'), eq(variables['Build.SourceBranch'], 'main'))) }}: + disableComponentGovernance: false + ${{ else }}: + disableComponentGovernance: true - ${{ if eq(parameters.enableMicrobuild, 'true') }}: - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: diff --git a/eng/common/templates/steps/component-governance.yml b/eng/common/templates/steps/component-governance.yml new file mode 100644 index 00000000000000..babc2757d8d123 --- /dev/null +++ b/eng/common/templates/steps/component-governance.yml @@ -0,0 +1,10 @@ +parameters: + disableComponentGovernance: false + +steps: +- ${{ if eq(parameters.disableComponentGovernance, 'true') }}: + - script: "echo ##vso[task.setvariable variable=skipComponentGovernanceDetection]true" + displayName: Set skipComponentGovernanceDetection variable +- ${{ if ne(parameters.disableComponentGovernance, 'true') }}: + - task: ComponentGovernanceComponentDetection@0 + continueOnError: true \ No newline at end of file diff --git a/eng/native/configurecompiler.cmake b/eng/native/configurecompiler.cmake index 9090289f50e347..0c9138ba029050 100644 --- a/eng/native/configurecompiler.cmake +++ b/eng/native/configurecompiler.cmake @@ -69,12 +69,14 @@ if (MSVC) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /PDBCOMPRESS") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DEBUG") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DEBUGTYPE:CV,FIXUP") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /IGNORE:4197,4013,4254,4070,4221") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SUBSYSTEM:WINDOWS,${WINDOWS_SUBSYSTEM_VERSION}") set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /IGNORE:4221") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DEBUG") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DEBUGTYPE:CV,FIXUP") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /PDBCOMPRESS") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:1572864") @@ -447,6 +449,15 @@ if (CLR_CMAKE_HOST_UNIX) add_compile_options(-Wno-incompatible-ms-struct) add_compile_options(-Wno-reserved-identifier) + + # clang 16.0 introduced buffer hardening https://discourse.llvm.org/t/rfc-c-buffer-hardening/65734 + # which we are not conforming to yet. + add_compile_options(-Wno-unsafe-buffer-usage) + + # other clang 16.0 suppressions + add_compile_options(-Wno-single-bit-bitfield-constant-conversion) + add_compile_options(-Wno-cast-function-type-strict) + add_compile_options(-Wno-incompatible-function-pointer-types-strict) else() add_compile_options(-Wno-uninitialized) add_compile_options(-Wno-strict-aliasing) diff --git a/eng/pipelines/coreclr/perf-non-wasm-jobs.yml b/eng/pipelines/coreclr/perf-non-wasm-jobs.yml index 69479200e24c0c..39a8b0527b1e78 100644 --- a/eng/pipelines/coreclr/perf-non-wasm-jobs.yml +++ b/eng/pipelines/coreclr/perf-non-wasm-jobs.yml @@ -111,7 +111,7 @@ jobs: platforms: - Linux_x64 - # run mono and maui android scenarios + # run android scenarios - template: /eng/pipelines/common/platform-matrix.yml parameters: jobTemplate: /eng/pipelines/coreclr/templates/perf-job.yml @@ -119,9 +119,6 @@ jobs: runtimeFlavor: mono platforms: - Windows_x64 - variables: - - name: mauiVersion - value: $[ dependencies.Build_iOS_arm64_release_MACiOSAndroidMauiNet7.outputs['getMauiVersion.mauiVersion'] ] jobParameters: testGroup: perf runtimeType: AndroidMono @@ -129,9 +126,8 @@ jobs: runKind: android_scenarios runJobTemplate: /eng/pipelines/coreclr/templates/run-scenarios-job.yml logicalmachine: 'perfpixel4a' - additionalSetupParameters: "-MauiVersion $env:mauiVersion" - # run mono iOS scenarios and maui iOS scenarios + # run mono iOS scenarios scenarios - template: /eng/pipelines/common/platform-matrix.yml parameters: jobTemplate: /eng/pipelines/coreclr/templates/perf-job.yml @@ -139,9 +135,6 @@ jobs: runtimeFlavor: mono platforms: - OSX_x64 - variables: - - name: mauiVersion - value: $[ dependencies.Build_iOS_arm64_release_MACiOSAndroidMauiNet7.outputs['getMauiVersion.mauiVersion'] ] jobParameters: testGroup: perf runtimeType: iOSMono @@ -150,7 +143,6 @@ jobs: runJobTemplate: /eng/pipelines/coreclr/templates/run-scenarios-job.yml logicalmachine: 'perfiphone12mini' iOSLlvmBuild: False - additionalSetupParameters: "--mauiversion $(mauiVersion)" - template: /eng/pipelines/common/platform-matrix.yml parameters: @@ -159,9 +151,6 @@ jobs: runtimeFlavor: mono platforms: - OSX_x64 - variables: - - name: mauiVersion - value: $[ dependencies.Build_iOS_arm64_release_MACiOSAndroidMauiNet7.outputs['getMauiVersion.mauiVersion'] ] jobParameters: testGroup: perf runtimeType: iOSMono @@ -170,48 +159,6 @@ jobs: runJobTemplate: /eng/pipelines/coreclr/templates/run-scenarios-job.yml logicalmachine: 'perfiphone12mini' iOSLlvmBuild: True - additionalSetupParameters: "--mauiversion $(mauiVersion)" - - # run maui android scenarios for net6 - - template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/coreclr/templates/perf-job.yml - buildConfig: release - runtimeFlavor: mono - platforms: - - Windows_x64 - variables: - - name: mauiVersion - value: $[ dependencies.Build_iOS_arm64_release_MACiOSAndroidMauiNet6.outputs['getMauiVersion.mauiVersion'] ] - jobParameters: - testGroup: perf - runtimeType: AndroidMobileNet6 - projectFile: android_scenarios_net6.proj - runKind: android_scenarios_net6 - runJobTemplate: /eng/pipelines/coreclr/templates/run-scenarios-job.yml - logicalmachine: 'perfpixel4a' - additionalSetupParameters: "-MauiVersion $env:mauiVersion" - - # run maui iOS scenarios for net6 (Maui doesn't need Llmv true build (for net6)) - - template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/coreclr/templates/perf-job.yml - buildConfig: release - runtimeFlavor: mono - platforms: - - OSX_x64 - variables: - - name: mauiVersion - value: $[ dependencies.Build_iOS_arm64_release_MACiOSAndroidMauiNet6.outputs['getMauiVersion.mauiVersion'] ] - jobParameters: - testGroup: perf - runtimeType: iOSMobileNet6 - projectFile: ios_scenarios_net6.proj - runKind: ios_scenarios_net6 - runJobTemplate: /eng/pipelines/coreclr/templates/run-scenarios-job.yml - logicalmachine: 'perfiphone12mini' - iOSLlvmBuild: False - additionalSetupParameters: "--mauiversion $(mauiVersion)" # run mono microbenchmarks perf job - template: /eng/pipelines/common/platform-matrix.yml @@ -368,85 +315,3 @@ jobs: runKind: crossgen_scenarios runJobTemplate: /eng/pipelines/coreclr/templates/run-scenarios-job.yml logicalmachine: 'perftiger' - - # Uncomment to reenable package replacement - ## build maui runtime packs - #- template: /eng/pipelines/common/platform-matrix.yml - # parameters: - # jobTemplate: /eng/pipelines/common/global-build-job.yml - # buildConfig: release - # runtimeFlavor: mono - # platforms: - # - Android_x86 - # - Android_x64 - # - Android_arm - # - Android_arm64 - # - MacCatalyst_x64 - # - iOSSimulator_x64 - # - iOS_arm64 - # - iOS_arm - # jobParameters: - # buildArgs: -s mono+libs+host+packs -c $(_BuildConfig) - # nameSuffix: Maui_Packs_Mono - # isOfficialBuild: false - # extraStepsTemplate: /eng/pipelines/common/upload-intermediate-artifacts-step.yml - # extraStepsParameters: - # name: MonoRuntimePacks - - # build maui app net7.0 - - template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - buildConfig: release - runtimeFlavor: mono - platforms: - - iOS_arm64 - jobParameters: - # Uncomment to reenable package replacement for main - #dependsOn: - # - Build_Android_arm_release_Maui_Packs_Mono - # - Build_Android_arm64_release_Maui_Packs_Mono - # - Build_Android_x86_release_Maui_Packs_Mono - # - Build_Android_x64_release_Maui_Packs_Mono - # - Build_MacCatalyst_x64_release_Maui_Packs_Mono - # - Build_iOSSimulator_x64_release_Maui_Packs_Mono - # - Build_iOS_arm_release_Maui_Packs_Mono - # - Build_iOS_arm64_release_Maui_Packs_Mono - buildArgs: -s mono -c $(_BuildConfig) - nameSuffix: MACiOSAndroidMauiNet7 - isOfficialBuild: false - pool: - vmImage: 'macos-12' - extraStepsTemplate: /eng/pipelines/coreclr/templates/build-perf-maui-apps-net7.yml - extraStepsParameters: - rootFolder: '$(Build.SourcesDirectory)/artifacts/' - includeRootFolder: true - displayName: MAC, iOS, and Android Maui Artifacts Net7 - artifactName: MACiOSAndroidMauiArmNet7 - archiveExtension: '.tar.gz' - archiveType: tar - tarCompression: gz - - # build maui app net6.0 - - template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - buildConfig: release - runtimeFlavor: mono - platforms: - - iOS_arm64 - jobParameters: - buildArgs: -s mono -c $(_BuildConfig) - nameSuffix: MACiOSAndroidMauiNet6 - isOfficialBuild: false - pool: - vmImage: 'macos-12' - extraStepsTemplate: /eng/pipelines/coreclr/templates/build-perf-maui-apps-net6.yml - extraStepsParameters: - rootFolder: '$(Build.SourcesDirectory)/artifacts/' - includeRootFolder: true - displayName: MAC, iOS, and Android Maui Artifacts Net6 - artifactName: MACiOSAndroidMauiArmNet6 - archiveExtension: '.tar.gz' - archiveType: tar - tarCompression: gz diff --git a/eng/pipelines/coreclr/templates/build-perf-maui-apps-net6.yml b/eng/pipelines/coreclr/templates/build-perf-maui-apps-net6.yml deleted file mode 100644 index 305541577632a7..00000000000000 --- a/eng/pipelines/coreclr/templates/build-perf-maui-apps-net6.yml +++ /dev/null @@ -1,366 +0,0 @@ -parameters: - osGroup: '' - osSubgroup: '' - archType: '' - buildConfig: '' - runtimeFlavor: '' - helixQueues: '' - targetRid: '' - nameSuffix: '' - platform: '' - shouldContinueOnError: '' - rootFolder: '' - includeRootFolder: '' - displayName: '' - artifactName: '' - archiveExtension: '' - archiveType: '' - tarCompression: '' - - -steps: - # There is a global.json in the runtime repo, but it sets the version to 7.xxx preview. This creates a local global.json to allow the running of 6.0 version. - - script: | - echo '{}' > ./global.json - displayName: Create global.json - workingDirectory: $(Build.SourcesDirectory) - - # Get the current maui nuget config so all things can be found and darc based package sources are kept up to date. - - script: | - curl -o NuGet.config 'https://raw.githubusercontent.com/dotnet/maui/net6.0/NuGet.config' - curl -o dotnet-install.sh 'https://dotnet.microsoft.com/download/dotnet/scripts/v1/dotnet-install.sh' - chmod -R a+rx . - ./dotnet-install.sh --channel 6.0 --quality daily --install-dir . - ./dotnet --info - ./dotnet workload install maui --from-rollback-file https://aka.ms/dotnet/maui/net6.0.json --configfile NuGet.config - displayName: Install MAUI workload - workingDirectory: $(Build.SourcesDirectory) - - - script: $(Build.SourcesDirectory)/eng/testing/performance/create-provisioning-profile.sh - displayName: Create iOS code signing and provisioning profile - - - script: | - ./dotnet new maui -n MauiTesting - cd MauiTesting - cp $(Build.SourcesDirectory)/src/tests/Common/maui/MauiScenario.props.net6 ./Directory.Build.props - cp $(Build.SourcesDirectory)/src/tests/Common/maui/MauiScenario.targets.net6 ./Directory.Build.targets - cp $(Build.SourcesDirectory)/NuGet.config ./NuGet.config - displayName: Setup MAUI Project - workingDirectory: $(Build.SourcesDirectory) - - - script: | - chmod -R a+r . - # Restore is split out because of https://github.com/dotnet/sdk/issues/21877, can be removed with --no-restore once fixed - ../dotnet restore - ../dotnet publish -bl:MauiAndroid.binlog -f net6.0-android -c Release -r android-arm64 --no-restore --self-contained - mv ./bin/Release/net6.0-android/android-arm64/com.companyname.mauitesting-Signed.apk ./MauiAndroidDefault.apk - displayName: Build MAUI Android - workingDirectory: $(Build.SourcesDirectory)/MauiTesting - - - script: | - set -x - pwd - git clone https://github.com/microsoft/dotnet-podcasts.git -b maui/perf --single-branch - cd dotnet-podcasts - cp $(Build.SourcesDirectory)/src/tests/Common/maui/MauiScenario.props.net6 ./Directory.Build.props - cp $(Build.SourcesDirectory)/src/tests/Common/maui/MauiScenario.targets.net6 ./Directory.Build.targets - displayName: Clone podcast app - workingDirectory: $(Build.SourcesDirectory) - - - script: | - set -x - pwd - chmod -R a+r . - ../../../dotnet restore Microsoft.NetConf2021.Maui.csproj - ../../../dotnet publish Microsoft.NetConf2021.Maui.csproj -bl:MauiPodcastAndroid.binlog -r android-arm64 --self-contained --no-restore -f net6.0-android -c Release - mv ./bin/Release/net6.0-android/android-arm64/com.Microsoft.NetConf2021.Maui-Signed.apk $(Build.SourcesDirectory)/MauiTesting/MauiAndroidPodcast.apk - displayName: Build MAUI Podcast Android - workingDirectory: $(Build.SourcesDirectory)/dotnet-podcasts/src/Mobile - - # This step pulls the product version from the used Microsoft.Maui.dll file properties and saves it for upload with the maui test counter. - # We pull from this file as we did not find another place to reliably get the version information pre or post build. - - powershell: | - $RetrievedMauiVersion = Get-ChildItem .\obj\Release\net6.0-android\android-arm64\linked\Microsoft.Maui.dll | Select-Object -ExpandProperty VersionInfo | Select-Object ProductVersion | Select-Object -ExpandProperty ProductVersion - $RetrievedMauiVersion - Write-Host "##vso[task.setvariable variable=mauiVersion;isOutput=true]$RetrievedMauiVersion" - name: getMauiVersion - displayName: Get and Save MAUI Version - workingDirectory: $(Build.SourcesDirectory)/MauiTesting - - - script: | - chmod -R a+r . - # remove net6.0-maccatalyst to work around https://github.com/dotnet/sdk/issues/21877 - cp MauiTesting.csproj MauiTesting.csproj.bak - sed -i'' -e 's/net6.0-ios;net6.0-maccatalyst/net6.0-ios/g' MauiTesting.csproj - - ../dotnet publish -bl:MauiiOS.binlog -f net6.0-ios --self-contained -r ios-arm64 -c Release /p:_RequireCodeSigning=false /p:ApplicationId=net.dot.mauitesting - mv ./bin/Release/net6.0-ios/ios-arm64/publish/MauiTesting.ipa ./MauiiOSDefault.ipa - - cp MauiTesting.csproj.bak MauiTesting.csproj - displayName: Build MAUI Default iOS - workingDirectory: $(Build.SourcesDirectory)/MauiTesting - - - script: | - chmod -R a+r . - # remove net6.0-maccatalyst to work around https://github.com/dotnet/sdk/issues/21877 - cp Microsoft.NetConf2021.Maui.csproj Microsoft.NetConf2021.Maui.csproj.bak - sed -i'' -e 's/net6.0-ios;net6.0-maccatalyst/net6.0-ios/g' Microsoft.NetConf2021.Maui.csproj - - ../../../dotnet build ../Web/Components/Podcast.Components.Maui.csproj - ../../../dotnet publish Microsoft.NetConf2021.Maui.csproj -bl:MauiiOSPodcast.binlog -f net6.0-ios --self-contained -r ios-arm64 -c Release /p:_RequireCodeSigning=false /p:ApplicationId=net.dot.netconf2021.maui - mv ./bin/Release/net6.0-ios/ios-arm64/publish/Microsoft.NetConf2021.Maui.ipa ./MauiiOSPodcast.ipa - - cp Microsoft.NetConf2021.Maui.csproj.bak Microsoft.NetConf2021.Maui.csproj - displayName: Build MAUI Podcast iOS - workingDirectory: $(Build.SourcesDirectory)/dotnet-podcasts/src/Mobile - - - script: | - chmod -R a+r . - ../dotnet publish -bl:MauiMacCatalyst.binlog -f net6.0-maccatalyst -c Release - mv ./bin/Release/net6.0-maccatalyst/maccatalyst-x64/MauiTesting.app ./MauiMacCatalystDefault.app - displayName: Build MAUI MacCatalyst - workingDirectory: $(Build.SourcesDirectory)/MauiTesting - - - script: | - ./dotnet new maui-blazor -n MauiBlazorTesting - cd MauiBlazorTesting - cp $(Build.SourcesDirectory)/src/tests/Common/maui/MauiScenario.props.net6 ./Directory.Build.props - cp $(Build.SourcesDirectory)/src/tests/Common/maui/MauiScenario.targets.net6 ./Directory.Build.targets - cp $(Build.SourcesDirectory)/NuGet.config ./NuGet.config - - echo -e "using Microsoft.AspNetCore.Components; - #if ANDROID - using Android.App; - #endif - - namespace MauiBlazorTesting.Pages - { - public partial class Index - { - protected override void OnAfterRender(bool firstRender) - { - if (firstRender) - { - #if ANDROID - var activity = MainActivity.Context as Activity; - activity.ReportFullyDrawn(); - #else - System.Console.WriteLine(\"__MAUI_Blazor_WebView_OnAfterRender__\"); - #endif - } - } - } - }" > Pages/Index.razor.cs - - sed -i'' -e "s/{/{\npublic static Android.Content.Context Context { get; private set; }\npublic MainActivity() { Context = this; }/g" Platforms/Android/MainActivity.cs - displayName: Setup MAUI Blazor Hybrid Project - workingDirectory: $(Build.SourcesDirectory) - - - script: | - chmod -R a+r . - # Restore is split out because of https://github.com/dotnet/sdk/issues/21877, can be removed with --no-restore once fixed - ../dotnet restore - ../dotnet publish -bl:MauiBlazorAndroid.binlog -f net6.0-android -c Release -r android-arm64 --no-restore --self-contained - mv ./bin/Release/net6.0-android/android-arm64/com.companyname.mauiblazortesting-Signed.apk ./MauiBlazorAndroidDefault.apk - displayName: Build MAUI Blazor Android - workingDirectory: $(Build.SourcesDirectory)/MauiBlazorTesting - - - script: | - chmod -R a+r . - # remove net6.0-maccatalyst to work around https://github.com/dotnet/sdk/issues/21877 - cp MauiBlazorTesting.csproj MauiBlazorTesting.csproj.bak - sed -i'' -e 's/net6.0-ios;net6.0-maccatalyst/net6.0-ios/g' MauiBlazorTesting.csproj - - # NuGet.config file cannot be in the build directory currently due to https://github.com/dotnet/aspnetcore/issues/41397 - rm NuGet.config - - ../dotnet publish -bl:MauiBlazoriOS.binlog -f net6.0-ios --self-contained -r ios-arm64 -c Release /p:_RequireCodeSigning=false /p:ApplicationId=net.dot.mauiblazortesting - mv ./bin/Release/net6.0-ios/ios-arm64/publish/MauiBlazorTesting.ipa ./MauiBlazoriOSDefault.ipa - - # Restore NuGet.config - cp $(Build.SourcesDirectory)/NuGet.config ./NuGet.config - - cp MauiBlazorTesting.csproj.bak MauiBlazorTesting.csproj - displayName: Build MAUI Blazor iOS - workingDirectory: $(Build.SourcesDirectory)/MauiBlazorTesting - - - script: | - chmod -R a+r . - - # NuGet.config file cannot be in the build directory currently due to https://github.com/dotnet/aspnetcore/issues/41397 - rm NuGet.config - - ../dotnet publish -bl:MauiBlazorMacCatalyst.binlog -f net6.0-maccatalyst -c Release - - # Restore NuGet.config - cp $(Build.SourcesDirectory)/NuGet.config ./NuGet.config - - mv ./bin/Release/net6.0-maccatalyst/maccatalyst-x64/MauiBlazorTesting.app ./MauiBlazorMacCatalystDefault.app - displayName: Build MAUI Blazor MacCatalyst - workingDirectory: $(Build.SourcesDirectory)/MauiBlazorTesting - - - task: PublishBuildArtifacts@1 - displayName: 'Publish MauiAndroid binlog' - condition: always() - inputs: - pathtoPublish: $(Build.SourcesDirectory)/MauiTesting/MauiAndroid.binlog - artifactName: ${{ parameters.artifactName }} - - - task: PublishBuildArtifacts@1 - displayName: 'Publish MauiBlazorAndroid binlog' - condition: always() - inputs: - pathtoPublish: $(Build.SourcesDirectory)/MauiBlazorTesting/MauiBlazorAndroid.binlog - artifactName: ${{ parameters.artifactName }} - - - task: PublishBuildArtifacts@1 - displayName: 'Publish MauiiOS binlog' - condition: always() - inputs: - pathtoPublish: $(Build.SourcesDirectory)/MauiTesting/MauiiOS.binlog - artifactName: ${{ parameters.artifactName }} - - - task: PublishBuildArtifacts@1 - displayName: 'Publish MauiMacCatalyst binlog' - condition: always() - inputs: - pathtoPublish: $(Build.SourcesDirectory)/MauiTesting/MauiMacCatalyst.binlog - artifactName: ${{ parameters.artifactName }} - - - task: PublishBuildArtifacts@1 - displayName: 'Publish MauiBlazorAndroid binlog' - condition: always() - inputs: - pathtoPublish: $(Build.SourcesDirectory)/MauiBlazorTesting/MauiBlazorAndroid.binlog - artifactName: ${{ parameters.artifactName }} - - - task: PublishBuildArtifacts@1 - displayName: 'Publish MauiBlazoriOS binlog' - condition: always() - inputs: - pathtoPublish: $(Build.SourcesDirectory)/MauiBlazorTesting/MauiBlazoriOS.binlog - artifactName: ${{ parameters.artifactName }} - - - task: PublishBuildArtifacts@1 - displayName: 'Publish MauiBlazorMacCatalyst binlog' - condition: always() - inputs: - pathtoPublish: $(Build.SourcesDirectory)/MauiBlazorTesting/MauiBlazorMacCatalyst.binlog - artifactName: ${{ parameters.artifactName }} - - - task: PublishBuildArtifacts@1 - displayName: 'Publish MauiiOSPodcast binlog' - condition: always() - inputs: - pathtoPublish: $(Build.SourcesDirectory)/dotnet-podcasts/src/Mobile/MauiiOSPodcast.binlog - artifactName: ${{ parameters.artifactName }} - - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - rootFolder: $(Build.SourcesDirectory)/MauiTesting/MauiAndroidDefault.apk - includeRootFolder: true - displayName: Maui Android App - artifactName: MauiAndroidAppNet6 - archiveExtension: '.tar.gz' - archiveType: tar - tarCompression: gz - - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - rootFolder: $(Build.SourcesDirectory)/MauiBlazorTesting/MauiBlazorAndroidDefault.apk - includeRootFolder: true - displayName: Maui Blazor Android App - artifactName: MauiBlazorAndroidAppNet6 - archiveExtension: '.tar.gz' - archiveType: tar - tarCompression: gz - - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - rootFolder: $(Build.SourcesDirectory)/MauiTesting/MauiAndroidPodcast.apk - includeRootFolder: true - displayName: Maui Android Podcast - artifactName: MauiAndroidPodcastNet6 - archiveExtension: '.tar.gz' - archiveType: tar - tarCompression: gz - - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - rootFolder: $(Build.SourcesDirectory)/MauiTesting/MauiiOSDefault.ipa - includeRootFolder: true - displayName: Maui iOS IPA - artifactName: MauiiOSDefaultIPANet6 - archiveExtension: '.tar.gz' - archiveType: tar - tarCompression: gz - - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - rootFolder: $(Build.SourcesDirectory)/MauiBlazorTesting/MauiBlazoriOSDefault.ipa - includeRootFolder: true - displayName: Maui Blazor iOS IPA - artifactName: MauiBlazoriOSDefaultIPANet6 - archiveExtension: '.tar.gz' - archiveType: tar - tarCompression: gz - - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - rootFolder: $(Build.SourcesDirectory)/dotnet-podcasts/src/Mobile/MauiiOSPodcast.ipa - includeRootFolder: true - displayName: Maui iOS Podcast IPA - artifactName: MauiiOSPodcastIPANet6 - archiveExtension: '.tar.gz' - archiveType: tar - tarCompression: gz - - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - rootFolder: $(Build.SourcesDirectory)/MauiTesting/MauiMacCatalystDefault.app - includeRootFolder: true - displayName: Maui MacCatalyst App - artifactName: MauiMacCatalystDefaultNet6 - archiveExtension: '.tar.gz' - archiveType: tar - tarCompression: gz - - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - rootFolder: $(Build.SourcesDirectory)/MauiBlazorTesting/MauiBlazorMacCatalystDefault.app - includeRootFolder: true - displayName: Maui Blazor MacCatalyst App - artifactName: MauiBlazorMacCatalystDefaultNet6 - archiveExtension: '.tar.gz' - archiveType: tar - tarCompression: gz - - - script: rm -r -f ./bin - workingDirectory: $(Build.SourcesDirectory)/MauiTesting - displayName: Clean MauiTesting bin directory - condition: succeededOrFailed() - - - script: rm -r -f ./bin - workingDirectory: $(Build.SourcesDirectory)/MauiBlazorTesting - displayName: Clean MauiBlazorTesting bin directory - condition: succeededOrFailed() - - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - osGroup: ${{ parameters.osGroup }} - osSubgroup: ${{ parameters.osSubgroup }} - archType: ${{ parameters.archType }} - buildConfig: ${{ parameters.buildConfig }} - runtimeFlavor: ${{ parameters.runtimeFlavor }} - helixQueues: ${{ parameters.helixQueues }} - targetRid: ${{ parameters.targetRid }} - nameSuffix: ${{ parameters.nameSuffix }} - platform: ${{ parameters.platform }} - shouldContinueOnError: ${{ parameters.shouldContinueOnError }} - rootFolder: ${{ parameters.rootFolder }} - includeRootFolder: ${{ parameters.includeRootFolder }} - displayName: ${{ parameters.displayName }} - artifactName: ${{ parameters.artifactName }} - archiveExtension: ${{ parameters.archiveExtension }} - archiveType: ${{ parameters.archiveType }} - tarCompression: ${{ parameters.tarCompression }} diff --git a/eng/pipelines/coreclr/templates/build-perf-maui-apps-net7.yml b/eng/pipelines/coreclr/templates/build-perf-maui-apps-net7.yml deleted file mode 100644 index 61cf711967f703..00000000000000 --- a/eng/pipelines/coreclr/templates/build-perf-maui-apps-net7.yml +++ /dev/null @@ -1,457 +0,0 @@ -parameters: - osGroup: '' - osSubgroup: '' - archType: '' - buildConfig: '' - runtimeFlavor: '' - helixQueues: '' - targetRid: '' - nameSuffix: '' - platform: '' - shouldContinueOnError: '' - rootFolder: '' - includeRootFolder: '' - displayName: '' - artifactName: '' - archiveExtension: '' - archiveType: '' - tarCompression: '' - - -steps: - # Uncomment to reenable package replacement - #- task: DownloadPipelineArtifact@2 - # displayName: Download runtime packages - # inputs: - # artifact: 'IntermediateArtifacts' - # path: $(Build.SourcesDirectory)/MauiTesting/ArtifactPacks - # patterns: | - # IntermediateArtifacts/MonoRuntimePacks/Shipping/Microsoft.NETCore.App.Runtime.Mono.android-!(*.symbols).nupkg - # IntermediateArtifacts/MonoRuntimePacks/Shipping/Microsoft.NETCore.App.Runtime.Mono.ios-!(*.symbols).nupkg - # IntermediateArtifacts/MonoRuntimePacks/Shipping/Microsoft.NETCore.App.Runtime.Mono.iossimulator-!(*.symbols).nupkg - # IntermediateArtifacts/MonoRuntimePacks/Shipping/Microsoft.NETCore.App.Runtime.Mono.maccatalyst-!(*.symbols).nupkg - - # # Other artifacts to include once they are being built - # # EX. IntermediateArtifacts/MonoRuntimePacks/Shipping/Microsoft.NETCore.App.Runtime.Mono.maccatalyst-*.nupkg - - #- task: CopyFiles@2 - # displayName: Flatten packages - # inputs: - # sourceFolder: $(Build.SourcesDirectory)/MauiTesting/ArtifactPacks - # contents: '*/Shipping/*.nupkg' - # cleanTargetFolder: false - # targetFolder: $(Build.SourcesDirectory)/MauiTesting/ArtifactPacks - # flattenFolders: true - - #- script: | - # for file in *.nupkg - # do - # mv -v "$file" "${file%.nupkg}.zip" - # done - # displayName: Change nupkgs to zips - # workingDirectory: $(Build.SourcesDirectory)/MauiTesting/ArtifactPacks - - - ##Unzip the nuget packages to make the actual runtimes accessible - #- task: ExtractFiles@1 - # displayName: Extract android-arm runtime - # inputs: - # archiveFilePatterns: $(Build.SourcesDirectory)/MauiTesting/ArtifactPacks/Microsoft.NETCore.App.Runtime.Mono.android-arm.*.zip - # destinationFolder: $(Build.SourcesDirectory)/MauiTesting/ArtifactPacks/Microsoft.NETCore.App.Runtime.Mono.android-arm - # overwriteExistingFiles: true - # cleanDestinationFolder: false - #- task: ExtractFiles@1 - # displayName: Extract android-arm64 runtime - # inputs: - # archiveFilePatterns: $(Build.SourcesDirectory)/MauiTesting/ArtifactPacks/Microsoft.NETCore.App.Runtime.Mono.android-arm64.*.zip - # destinationFolder: $(Build.SourcesDirectory)/MauiTesting/ArtifactPacks/Microsoft.NETCore.App.Runtime.Mono.android-arm64 - # overwriteExistingFiles: true - # cleanDestinationFolder: false - #- task: ExtractFiles@1 - # displayName: Extract android-x86 runtime - # inputs: - # archiveFilePatterns: $(Build.SourcesDirectory)/MauiTesting/ArtifactPacks/Microsoft.NETCore.App.Runtime.Mono.android-x86.*.zip - # destinationFolder: $(Build.SourcesDirectory)/MauiTesting/ArtifactPacks/Microsoft.NETCore.App.Runtime.Mono.android-x86 - # overwriteExistingFiles: true - # cleanDestinationFolder: false - #- task: ExtractFiles@1 - # displayName: Extract android-x64 runtime - # inputs: - # archiveFilePatterns: $(Build.SourcesDirectory)/MauiTesting/ArtifactPacks/Microsoft.NETCore.App.Runtime.Mono.android-x64.*.zip - # destinationFolder: $(Build.SourcesDirectory)/MauiTesting/ArtifactPacks/Microsoft.NETCore.App.Runtime.Mono.android-x64 - # overwriteExistingFiles: true - # cleanDestinationFolder: false - #- task: ExtractFiles@1 - # displayName: Extract ios-arm runtime - # inputs: - # archiveFilePatterns: $(Build.SourcesDirectory)/MauiTesting/ArtifactPacks/Microsoft.NETCore.App.Runtime.Mono.ios-arm.*.zip - # destinationFolder: $(Build.SourcesDirectory)/MauiTesting/ArtifactPacks/Microsoft.NETCore.App.Runtime.Mono.ios-arm - # overwriteExistingFiles: true - # cleanDestinationFolder: false - #- task: ExtractFiles@1 - # displayName: Extract ios-arm64 runtime - # inputs: - # archiveFilePatterns: $(Build.SourcesDirectory)/MauiTesting/ArtifactPacks/Microsoft.NETCore.App.Runtime.Mono.ios-arm64.*.zip - # destinationFolder: $(Build.SourcesDirectory)/MauiTesting/ArtifactPacks/Microsoft.NETCore.App.Runtime.Mono.ios-arm64 - # overwriteExistingFiles: true - # cleanDestinationFolder: false - #- task: ExtractFiles@1 - # displayName: Extract maccatalyst-x64 runtime - # inputs: - # archiveFilePatterns: $(Build.SourcesDirectory)/MauiTesting/ArtifactPacks/Microsoft.NETCore.App.Runtime.Mono.maccatalyst-x64.*.zip - # destinationFolder: $(Build.SourcesDirectory)/MauiTesting/ArtifactPacks/Microsoft.NETCore.App.Runtime.Mono.maccatalyst-x64 - # overwriteExistingFiles: true - # cleanDestinationFolder: false - #- task: ExtractFiles@1 - # displayName: Extract iossimulator-x64 runtime - # inputs: - # archiveFilePatterns: $(Build.SourcesDirectory)/MauiTesting/ArtifactPacks/Microsoft.NETCore.App.Runtime.Mono.iossimulator-x64.*.zip - # destinationFolder: $(Build.SourcesDirectory)/MauiTesting/ArtifactPacks/Microsoft.NETCore.App.Runtime.Mono.iossimulator-x64 - # overwriteExistingFiles: true - # cleanDestinationFolder: false - - # Get the current maui nuget config so all things can be found and darc based package sources are kept up to date. - - script: | - echo '{}' > ./global.json - displayName: Create global.json - workingDirectory: $(Build.SourcesDirectory) - - - script: | - curl -o NuGet.config 'https://raw.githubusercontent.com/dotnet/maui/main/NuGet.config' - curl -o dotnet-install.sh 'https://dotnet.microsoft.com/download/dotnet/scripts/v1/dotnet-install.sh' - chmod -R a+rx . - cp $(Build.SourcesDirectory)/src/tests/Common/maui/rollbackfile-net7.json ./rollbackfile-net7.json - ./dotnet-install.sh --version 7.0.100-preview.7.22376.5 --install-dir . - ./dotnet --info - ./dotnet workload install maui --from-rollback-file rollbackfile-net7.json --configfile NuGet.config - displayName: Install MAUI workload - workingDirectory: $(Build.SourcesDirectory) - - - script: $(Build.SourcesDirectory)/eng/testing/performance/create-provisioning-profile.sh - displayName: Create iOS code signing and provisioning profile - - - script: | - ./dotnet new maui -n MauiTesting - cd MauiTesting - cp $(Build.SourcesDirectory)/src/tests/Common/maui/MauiScenario.props ./Directory.Build.props - cp $(Build.SourcesDirectory)/src/tests/Common/maui/MauiScenario.targets ./Directory.Build.targets - cp $(Build.SourcesDirectory)/NuGet.config ./NuGet.config - displayName: Setup MAUI Project - workingDirectory: $(Build.SourcesDirectory) - - - script: | - chmod -R a+r . - # Restore is split out because of https://github.com/dotnet/sdk/issues/21877, can be removed with --no-restore once fixed - ../dotnet restore - ../dotnet publish -bl:MauiAndroid.binlog -f net7.0-android -c Release -r android-arm64 --no-restore --self-contained - mv ./bin/Release/net7.0-android/android-arm64/com.companyname.mauitesting-Signed.apk ./MauiAndroidDefault.apk - displayName: Build MAUI Android - workingDirectory: $(Build.SourcesDirectory)/MauiTesting - - - script: | - set -x - pwd - git clone https://github.com/microsoft/dotnet-podcasts.git -b net7.0 --single-branch - cd dotnet-podcasts - cp $(Build.SourcesDirectory)/src/tests/Common/maui/MauiScenario.props ./Directory.Build.props - cp $(Build.SourcesDirectory)/src/tests/Common/maui/MauiScenario.targets ./Directory.Build.targets - displayName: Clone podcast app - workingDirectory: $(Build.SourcesDirectory) - - - script: | - set -x - pwd - chmod -R a+r . - ../../../dotnet restore Microsoft.NetConf2021.Maui.csproj - ../../../dotnet publish Microsoft.NetConf2021.Maui.csproj -bl:MauiPodcastAndroid.binlog -r android-arm64 --self-contained --no-restore -f net7.0-android -c Release - mv ./bin/Release/net7.0-android/android-arm64/com.Microsoft.NetConf2021.Maui-Signed.apk $(Build.SourcesDirectory)/MauiTesting/MauiAndroidPodcast.apk - displayName: Build MAUI Podcast Android - workingDirectory: $(Build.SourcesDirectory)/dotnet-podcasts/src/Mobile - - # This step pulls the product version from the used Microsoft.Maui.dll file properties and saves it for upload with the maui test counter. - # We pull from this file as we did not find another place to reliably get the version information pre or post build. - - powershell: | - $RetrievedMauiVersion = Get-ChildItem .\obj\Release\net7.0-android\android-arm64\linked\Microsoft.Maui.dll | Select-Object -ExpandProperty VersionInfo | Select-Object ProductVersion | Select-Object -ExpandProperty ProductVersion - $RetrievedMauiVersion - Write-Host "##vso[task.setvariable variable=mauiVersion;isOutput=true]$RetrievedMauiVersion" - name: getMauiVersion - displayName: Get and Save MAUI Version - workingDirectory: $(Build.SourcesDirectory)/MauiTesting - - - script: | - chmod -R a+r . - # remove net7.0-maccatalyst to work around https://github.com/dotnet/sdk/issues/21877 - cp MauiTesting.csproj MauiTesting.csproj.bak - sed -i'' -e 's/net7.0-ios;net7.0-maccatalyst/net7.0-ios/g' MauiTesting.csproj - - ../dotnet publish -bl:MauiiOS.binlog -f net7.0-ios --self-contained -r ios-arm64 -c Release /p:_RequireCodeSigning=false /p:ApplicationId=net.dot.mauitesting - mv ./bin/Release/net7.0-ios/ios-arm64/publish/MauiTesting.ipa ./MauiiOSDefault.ipa - - cp MauiTesting.csproj.bak MauiTesting.csproj - displayName: Build MAUI Default iOS - workingDirectory: $(Build.SourcesDirectory)/MauiTesting - - - script: | - chmod -R a+r . - # remove net7.0-maccatalyst to work around https://github.com/dotnet/sdk/issues/21877 - cp Microsoft.NetConf2021.Maui.csproj Microsoft.NetConf2021.Maui.csproj.bak - sed -i'' -e 's/net7.0-ios;net7.0-maccatalyst/net7.0-ios/g' Microsoft.NetConf2021.Maui.csproj - - ../../../dotnet build ../Web/Components/Podcast.Components.Maui.csproj - ../../../dotnet publish Microsoft.NetConf2021.Maui.csproj -bl:MauiiOSPodcast.binlog -f net7.0-ios --self-contained -r ios-arm64 -c Release /p:_RequireCodeSigning=false /p:ApplicationId=net.dot.netconf2021.maui - mv ./bin/Release/net7.0-ios/ios-arm64/publish/Microsoft.NetConf2021.Maui.ipa ./MauiiOSPodcast.ipa - - cp Microsoft.NetConf2021.Maui.csproj.bak Microsoft.NetConf2021.Maui.csproj - displayName: Build MAUI Podcast iOS - workingDirectory: $(Build.SourcesDirectory)/dotnet-podcasts/src/Mobile - - - script: | - chmod -R a+r . - ../dotnet publish -bl:MauiMacCatalyst.binlog -f net7.0-maccatalyst -c Release - mv ./bin/Release/net7.0-maccatalyst/maccatalyst-x64/MauiTesting.app ./MauiMacCatalystDefault.app - displayName: Build MAUI MacCatalyst - workingDirectory: $(Build.SourcesDirectory)/MauiTesting - - - script: | - ./dotnet new maui-blazor -n MauiBlazorTesting - cd MauiBlazorTesting - cp $(Build.SourcesDirectory)/src/tests/Common/maui/MauiScenario.props ./Directory.Build.props - cp $(Build.SourcesDirectory)/src/tests/Common/maui/MauiScenario.targets ./Directory.Build.targets - cp $(Build.SourcesDirectory)/NuGet.config ./NuGet.config - - echo -e "using Microsoft.AspNetCore.Components; - #if ANDROID - using Android.App; - #endif - - namespace MauiBlazorTesting.Pages - { - public partial class Index - { - protected override void OnAfterRender(bool firstRender) - { - if (firstRender) - { - #if ANDROID - var activity = MainActivity.Context as Activity; - activity.ReportFullyDrawn(); - #else - System.Console.WriteLine(\"__MAUI_Blazor_WebView_OnAfterRender__\"); - #endif - } - } - } - }" > Pages/Index.razor.cs - - sed -i'' -e "s/{/{\npublic static Android.Content.Context Context { get; private set; }\npublic MainActivity() { Context = this; }/g" Platforms/Android/MainActivity.cs - displayName: Setup MAUI Blazor Hybrid Project - workingDirectory: $(Build.SourcesDirectory) - - - script: | - chmod -R a+r . - # Restore is split out because of https://github.com/dotnet/sdk/issues/21877, can be removed with --no-restore once fixed - ../dotnet restore - ../dotnet publish -bl:MauiBlazorAndroid.binlog -f net7.0-android -c Release -r android-arm64 --no-restore --self-contained - mv ./bin/Release/net7.0-android/android-arm64/com.companyname.mauiblazortesting-Signed.apk ./MauiBlazorAndroidDefault.apk - displayName: Build MAUI Blazor Android - workingDirectory: $(Build.SourcesDirectory)/MauiBlazorTesting - - - script: | - chmod -R a+r . - # remove net7.0-maccatalyst to work around https://github.com/dotnet/sdk/issues/21877 - cp MauiBlazorTesting.csproj MauiBlazorTesting.csproj.bak - sed -i'' -e 's/net7.0-ios;net7.0-maccatalyst/net7.0-ios/g' MauiBlazorTesting.csproj - - # NuGet.config file cannot be in the build directory currently due to https://github.com/dotnet/aspnetcore/issues/41397 - rm NuGet.config - - ../dotnet publish -bl:MauiBlazoriOS.binlog -f net7.0-ios --self-contained -r ios-arm64 -c Release /p:_RequireCodeSigning=false /p:ApplicationId=net.dot.mauiblazortesting - mv ./bin/Release/net7.0-ios/ios-arm64/publish/MauiBlazorTesting.ipa ./MauiBlazoriOSDefault.ipa - - # Restore NuGet.config - cp $(Build.SourcesDirectory)/NuGet.config ./NuGet.config - - cp MauiBlazorTesting.csproj.bak MauiBlazorTesting.csproj - displayName: Build MAUI Blazor iOS - workingDirectory: $(Build.SourcesDirectory)/MauiBlazorTesting - - - script: | - chmod -R a+r . - - # NuGet.config file cannot be in the build directory currently due to https://github.com/dotnet/aspnetcore/issues/41397 - rm NuGet.config - - ../dotnet publish -bl:MauiBlazorMacCatalyst.binlog -f net7.0-maccatalyst -c Release - - # Restore NuGet.config - cp $(Build.SourcesDirectory)/NuGet.config ./NuGet.config - - mv ./bin/Release/net7.0-maccatalyst/maccatalyst-x64/MauiBlazorTesting.app ./MauiBlazorMacCatalystDefault.app - displayName: Build MAUI Blazor MacCatalyst - workingDirectory: $(Build.SourcesDirectory)/MauiBlazorTesting - - - task: PublishBuildArtifacts@1 - displayName: 'Publish MauiAndroid binlog' - condition: always() - inputs: - pathtoPublish: $(Build.SourcesDirectory)/MauiTesting/MauiAndroid.binlog - artifactName: ${{ parameters.artifactName }} - - - task: PublishBuildArtifacts@1 - displayName: 'Publish MauiBlazorAndroid binlog' - condition: always() - inputs: - pathtoPublish: $(Build.SourcesDirectory)/MauiBlazorTesting/MauiBlazorAndroid.binlog - artifactName: ${{ parameters.artifactName }} - - - task: PublishBuildArtifacts@1 - displayName: 'Publish MauiiOS binlog' - condition: always() - inputs: - pathtoPublish: $(Build.SourcesDirectory)/MauiTesting/MauiiOS.binlog - artifactName: ${{ parameters.artifactName }} - - - task: PublishBuildArtifacts@1 - displayName: 'Publish MauiMacCatalyst binlog' - condition: always() - inputs: - pathtoPublish: $(Build.SourcesDirectory)/MauiTesting/MauiMacCatalyst.binlog - artifactName: ${{ parameters.artifactName }} - - - task: PublishBuildArtifacts@1 - displayName: 'Publish MauiBlazorAndroid binlog' - condition: always() - inputs: - pathtoPublish: $(Build.SourcesDirectory)/MauiBlazorTesting/MauiBlazorAndroid.binlog - artifactName: ${{ parameters.artifactName }} - - - task: PublishBuildArtifacts@1 - displayName: 'Publish MauiBlazoriOS binlog' - condition: always() - inputs: - pathtoPublish: $(Build.SourcesDirectory)/MauiBlazorTesting/MauiBlazoriOS.binlog - artifactName: ${{ parameters.artifactName }} - - - task: PublishBuildArtifacts@1 - displayName: 'Publish MauiBlazorMacCatalyst binlog' - condition: always() - inputs: - pathtoPublish: $(Build.SourcesDirectory)/MauiBlazorTesting/MauiBlazorMacCatalyst.binlog - artifactName: ${{ parameters.artifactName }} - - - task: PublishBuildArtifacts@1 - displayName: 'Publish MauiiOSPodcast binlog' - condition: always() - inputs: - pathtoPublish: $(Build.SourcesDirectory)/dotnet-podcasts/src/Mobile/MauiiOSPodcast.binlog - artifactName: ${{ parameters.artifactName }} - - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - rootFolder: $(Build.SourcesDirectory)/MauiTesting/MauiAndroidDefault.apk - includeRootFolder: true - displayName: Maui Android App - artifactName: MauiAndroidApp - archiveExtension: '.tar.gz' - archiveType: tar - tarCompression: gz - - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - rootFolder: $(Build.SourcesDirectory)/MauiBlazorTesting/MauiBlazorAndroidDefault.apk - includeRootFolder: true - displayName: Maui Blazor Android App - artifactName: MauiBlazorAndroidApp - archiveExtension: '.tar.gz' - archiveType: tar - tarCompression: gz - - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - rootFolder: $(Build.SourcesDirectory)/MauiTesting/MauiAndroidPodcast.apk - includeRootFolder: true - displayName: Maui Android Podcast - artifactName: MauiAndroidPodcast - archiveExtension: '.tar.gz' - archiveType: tar - tarCompression: gz - - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - rootFolder: $(Build.SourcesDirectory)/MauiTesting/MauiiOSDefault.ipa - includeRootFolder: true - displayName: Maui iOS IPA - artifactName: MauiiOSDefaultIPA - archiveExtension: '.tar.gz' - archiveType: tar - tarCompression: gz - - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - rootFolder: $(Build.SourcesDirectory)/MauiBlazorTesting/MauiBlazoriOSDefault.ipa - includeRootFolder: true - displayName: Maui Blazor iOS IPA - artifactName: MauiBlazoriOSDefaultIPA - archiveExtension: '.tar.gz' - archiveType: tar - tarCompression: gz - - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - rootFolder: $(Build.SourcesDirectory)/dotnet-podcasts/src/Mobile/MauiiOSPodcast.ipa - includeRootFolder: true - displayName: Maui iOS Podcast IPA - artifactName: MauiiOSPodcastIPA - archiveExtension: '.tar.gz' - archiveType: tar - tarCompression: gz - - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - rootFolder: $(Build.SourcesDirectory)/MauiTesting/MauiMacCatalystDefault.app - includeRootFolder: true - displayName: Maui MacCatalyst App - artifactName: MauiMacCatalystDefault - archiveExtension: '.tar.gz' - archiveType: tar - tarCompression: gz - - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - rootFolder: $(Build.SourcesDirectory)/MauiBlazorTesting/MauiBlazorMacCatalystDefault.app - includeRootFolder: true - displayName: Maui Blazor MacCatalyst App - artifactName: MauiBlazorMacCatalystDefault - archiveExtension: '.tar.gz' - archiveType: tar - tarCompression: gz - - - script: rm -r -f ./bin - workingDirectory: $(Build.SourcesDirectory)/MauiTesting - displayName: Clean MauiTesting bin directory - condition: succeededOrFailed() - - - script: rm -r -f ./bin - workingDirectory: $(Build.SourcesDirectory)/MauiBlazorTesting - displayName: Clean MauiBlazorTesting bin directory - condition: succeededOrFailed() - - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - osGroup: ${{ parameters.osGroup }} - osSubgroup: ${{ parameters.osSubgroup }} - archType: ${{ parameters.archType }} - buildConfig: ${{ parameters.buildConfig }} - runtimeFlavor: ${{ parameters.runtimeFlavor }} - helixQueues: ${{ parameters.helixQueues }} - targetRid: ${{ parameters.targetRid }} - nameSuffix: ${{ parameters.nameSuffix }} - platform: ${{ parameters.platform }} - shouldContinueOnError: ${{ parameters.shouldContinueOnError }} - rootFolder: ${{ parameters.rootFolder }} - includeRootFolder: ${{ parameters.includeRootFolder }} - displayName: ${{ parameters.displayName }} - artifactName: ${{ parameters.artifactName }} - archiveExtension: ${{ parameters.archiveExtension }} - archiveType: ${{ parameters.archiveType }} - tarCompression: ${{ parameters.tarCompression }} diff --git a/eng/pipelines/coreclr/templates/perf-job.yml b/eng/pipelines/coreclr/templates/perf-job.yml index 55111153f86094..0c8fce9101541a 100644 --- a/eng/pipelines/coreclr/templates/perf-job.yml +++ b/eng/pipelines/coreclr/templates/perf-job.yml @@ -67,7 +67,7 @@ jobs: # Test job depends on the corresponding build job ${{ if eq(parameters.downloadSpecificBuild.buildId, '') }}: dependsOn: - - ${{ if not(in(parameters.runtimeType, 'AndroidMono', 'iOSMono', 'AndroidMobileNet6', 'iOSMobileNet6', 'wasm')) }}: + - ${{ if not(in(parameters.runtimeType, 'AndroidMono', 'iOSMono', 'wasm')) }}: - ${{ format('coreclr_{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} - ${{ if and(ne(parameters.liveLibrariesBuildConfig, ''), eq(parameters.skipLiveLibrariesDownload, 'false')) }}: - ${{ format('libraries_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveLibrariesBuildConfig) }} @@ -79,21 +79,15 @@ jobs: - ${{ format('build_{0}{1}_{2}_{3}_{4}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig, parameters.codeGenType) }} - ${{ if eq(parameters.runtimeType, 'AndroidMono')}}: - ${{ 'build_Android_arm64_release_AndroidMono' }} - - ${{ 'Build_iOS_arm64_release_MACiOSAndroidMauiNet7' }} - - ${{ if eq(parameters.runtimeType, 'AndroidMobileNet6')}}: - - ${{ 'Build_iOS_arm64_release_MACiOSAndroidMauiNet6' }} - ${{ if eq(parameters.runtimeType, 'iOSMono')}}: - ${{ 'build_iOS_arm64_release_iOSMono' }} - - ${{ 'Build_iOS_arm64_release_MACiOSAndroidMauiNet7' }} - - ${{ if eq(parameters.runtimeType, 'iOSMobileNet6')}}: - - ${{ 'Build_iOS_arm64_release_MACiOSAndroidMauiNet6' }} - ${{ if and(eq(parameters.osGroup, 'windows'), not(in(parameters.runtimeType, 'AndroidMono', 'iOSMono', 'AndroidMobileNet6', 'iOSMobileNet6'))) }}: + ${{ if and(eq(parameters.osGroup, 'windows'), not(in(parameters.runtimeType, 'AndroidMono', 'iOSMono'))) }}: ${{ if eq(parameters.runtimeType, 'mono') }}: extraSetupParameters: -Architecture ${{ parameters.archType }} -MonoDotnet $(Build.SourcesDirectory)\.dotnet-mono ${{ if eq(parameters.runtimeType, 'coreclr') }}: extraSetupParameters: -CoreRootDirectory $(Build.SourcesDirectory)\artifacts\tests\coreclr\${{ parameters.osGroup }}.${{ parameters.archType }}.Release\Tests\Core_Root -Architecture ${{ parameters.archType }} - ${{ if and(ne(parameters.osGroup, 'windows'), not(in(parameters.runtimeType, 'AndroidMono', 'iOSMono', 'AndroidMobileNet6', 'iOSMobileNet6'))) }}: + ${{ if and(ne(parameters.osGroup, 'windows'), not(in(parameters.runtimeType, 'AndroidMono', 'iOSMono'))) }}: ${{ if and(eq(parameters.runtimeType, 'mono'), ne(parameters.codeGenType, 'AOT')) }}: extraSetupParameters: --architecture ${{ parameters.archType }} --monodotnet $(Build.SourcesDirectory)/.dotnet-mono ${{ if and(eq(parameters.runtimeType, 'wasm'), ne(parameters.codeGenType, 'AOT')) }}: @@ -106,9 +100,9 @@ jobs: extraSetupParameters: --corerootdirectory $(Build.SourcesDirectory)/artifacts/tests/coreclr/${{ parameters.osGroup }}.${{ parameters.archType }}.Release/Tests/Core_Root --architecture ${{ parameters.archType }} ${{ if and(eq(parameters.runtimeType, 'coreclr'), eq(parameters.osSubGroup, '_musl')) }}: extraSetupParameters: --corerootdirectory $(Build.SourcesDirectory)/artifacts/tests/coreclr/${{ parameters.osGroup }}.${{ parameters.archType }}.Release/Tests/Core_Root --architecture ${{ parameters.archType }} --alpine - ${{ if in(parameters.runtimeType, 'AndroidMono', 'AndroidMobileNet6') }}: + ${{ if in(parameters.runtimeType, 'AndroidMono') }}: extraSetupParameters: -Architecture ${{ parameters.archType }} -AndroidMono - ${{ if in(parameters.runtimeType, 'iosMono', 'iOSMobileNet6') }}: + ${{ if in(parameters.runtimeType, 'iosMono') }}: extraSetupParameters: --architecture ${{ parameters.archType }} --iosmono --iosllvmbuild ${{ parameters.iOSLlvmBuild }} variables: @@ -148,7 +142,7 @@ jobs: displayName: 'live-built libraries' # Download coreclr - - ${{ if not(in(parameters.runtimeType, 'AndroidMono', 'iOSMono', 'AndroidMobileNet6', 'iOSMobileNet6', 'wasm')) }}: + - ${{ if not(in(parameters.runtimeType, 'AndroidMono', 'iOSMono', 'wasm')) }}: - template: /eng/pipelines/common/download-artifact-step.yml parameters: unpackFolder: $(buildProductRootFolderPath) @@ -205,7 +199,7 @@ jobs: - script: "mkdir -p $(librariesDownloadDir)/bin/aot/sgen;mkdir -p $(librariesDownloadDir)/bin/aot/pack;cp -r $(librariesDownloadDir)/LinuxMonoAOT/artifacts/obj/mono/Linux.${{ parameters.archType }}.Release/mono/* $(librariesDownloadDir)/bin/aot/sgen;cp -r $(librariesDownloadDir)/LinuxMonoAOT/artifacts/bin/microsoft.netcore.app.runtime.linux-${{ parameters.archType }}/Release/* $(librariesDownloadDir)/bin/aot/pack" displayName: "Create aot directory (Linux)" - # Download AndroidMono and MauiAndroid + # Download artifacts for Android Testing - ${{ if eq(parameters.runtimeType, 'AndroidMono')}}: - template: /eng/pipelines/common/download-artifact-step.yml parameters: @@ -214,53 +208,8 @@ jobs: artifactFileName: 'AndroidMonoarm64.tar.gz' artifactName: 'AndroidMonoarm64' displayName: 'Mono Android HelloWorld' - - template: /eng/pipelines/common/download-artifact-step.yml - parameters: - unpackFolder: $(Build.SourcesDirectory) - cleanUnpackFolder: false - artifactFileName: 'MauiAndroidApp.tar.gz' - artifactName: 'MauiAndroidApp' - displayName: 'Maui Android App' - - template: /eng/pipelines/common/download-artifact-step.yml - parameters: - unpackFolder: $(Build.SourcesDirectory) - cleanUnpackFolder: false - artifactFileName: 'MauiAndroidPodcast.tar.gz' - artifactName: 'MauiAndroidPodcast' - displayName: 'Maui Android Podcast' - - template: /eng/pipelines/common/download-artifact-step.yml - parameters: - unpackFolder: $(Build.SourcesDirectory) - cleanUnpackFolder: false - artifactFileName: 'MauiBlazorAndroidApp.tar.gz' - artifactName: 'MauiBlazorAndroidApp' - displayName: 'Maui Blazor Android App' - - # Download Maui Android net6 stuff - - ${{ if eq(parameters.runtimeType, 'AndroidMobileNet6')}}: - - template: /eng/pipelines/common/download-artifact-step.yml - parameters: - unpackFolder: $(Build.SourcesDirectory) - cleanUnpackFolder: false - artifactFileName: 'MauiAndroidAppNet6.tar.gz' - artifactName: 'MauiAndroidAppNet6' - displayName: 'Maui Android App Net6' - - template: /eng/pipelines/common/download-artifact-step.yml - parameters: - unpackFolder: $(Build.SourcesDirectory) - cleanUnpackFolder: false - artifactFileName: 'MauiAndroidPodcastNet6.tar.gz' - artifactName: 'MauiAndroidPodcastNet6' - displayName: 'Maui Android Podcast Net6' - - template: /eng/pipelines/common/download-artifact-step.yml - parameters: - unpackFolder: $(Build.SourcesDirectory) - cleanUnpackFolder: false - artifactFileName: 'MauiBlazorAndroidAppNet6.tar.gz' - artifactName: 'MauiBlazorAndroidAppNet6' - displayName: 'Maui Blazor Android App Net6' - - # Download iOSMono tests and MauiiOS/MacCatalyst + + # Download iOSMono tests - ${{ if eq(parameters.runtimeType, 'iOSMono') }}: - template: /eng/pipelines/common/download-artifact-step.yml parameters: @@ -294,80 +243,6 @@ jobs: downloadPath: '$(Build.SourcesDirectory)/iosHelloWorldZip/llvmzip' artifactName: 'iOSSampleAppLLVM' checkDownloadedFiles: true - - template: /eng/pipelines/common/download-artifact-step.yml - parameters: - unpackFolder: $(Build.SourcesDirectory)/MauiiOSDefaultIPA - cleanUnpackFolder: false - artifactFileName: 'MauiiOSDefaultIPA.tar.gz' - artifactName: 'MauiiOSDefaultIPA' - displayName: 'Maui iOS IPA' - - template: /eng/pipelines/common/download-artifact-step.yml - parameters: - unpackFolder: $(Build.SourcesDirectory)/MauiMacCatalystDefault - cleanUnpackFolder: false - artifactFileName: 'MauiMacCatalystDefault.tar.gz' - artifactName: 'MauiMacCatalystDefault' - displayName: 'Maui MacCatalyst App' - - template: /eng/pipelines/common/download-artifact-step.yml - parameters: - unpackFolder: $(Build.SourcesDirectory)/MauiiOSPodcastIPA - cleanUnpackFolder: false - artifactFileName: 'MauiiOSPodcastIPA.tar.gz' - artifactName: 'MauiiOSPodcastIPA' - displayName: 'Maui iOS Podcast IPA' - - template: /eng/pipelines/common/download-artifact-step.yml - parameters: - unpackFolder: $(Build.SourcesDirectory)/MauiBlazoriOSDefaultIPA - cleanUnpackFolder: false - artifactFileName: 'MauiBlazoriOSDefaultIPA.tar.gz' - artifactName: 'MauiBlazoriOSDefaultIPA' - displayName: 'Maui Blazor iOS IPA' - - template: /eng/pipelines/common/download-artifact-step.yml - parameters: - unpackFolder: $(Build.SourcesDirectory)/MauiBlazorMacCatalystDefault - cleanUnpackFolder: false - artifactFileName: 'MauiBlazorMacCatalystDefault.tar.gz' - artifactName: 'MauiBlazorMacCatalystDefault' - displayName: 'Maui Blazor MacCatalyst App' - - - # Download Maui iOS net6 stuff - - ${{ if eq(parameters.runtimeType, 'iOSMobileNet6') }}: - - template: /eng/pipelines/common/download-artifact-step.yml - parameters: - unpackFolder: $(Build.SourcesDirectory)/MauiiOSDefaultIPA - cleanUnpackFolder: false - artifactFileName: 'MauiiOSDefaultIPANet6.tar.gz' - artifactName: 'MauiiOSDefaultIPANet6' - displayName: 'Maui iOS IPA Net6' - - template: /eng/pipelines/common/download-artifact-step.yml - parameters: - unpackFolder: $(Build.SourcesDirectory)/MauiMacCatalystDefault - cleanUnpackFolder: false - artifactFileName: 'MauiMacCatalystDefaultNet6.tar.gz' - artifactName: 'MauiMacCatalystDefaultNet6' - displayName: 'Maui MacCatalyst App Net6' - - template: /eng/pipelines/common/download-artifact-step.yml - parameters: - unpackFolder: $(Build.SourcesDirectory)/MauiiOSPodcastIPA - cleanUnpackFolder: false - artifactFileName: 'MauiiOSPodcastIPANet6.tar.gz' - artifactName: 'MauiiOSPodcastIPANet6' - displayName: 'Maui iOS Podcast IPA Net6' - - template: /eng/pipelines/common/download-artifact-step.yml - parameters: - unpackFolder: $(Build.SourcesDirectory)/MauiBlazoriOSDefaultIPA - cleanUnpackFolder: false - artifactFileName: 'MauiBlazoriOSDefaultIPANet6.tar.gz' - artifactName: 'MauiBlazoriOSDefaultIPANet6' - displayName: 'Maui Blazor iOS IPA Net6' - - template: /eng/pipelines/common/download-artifact-step.yml - parameters: - unpackFolder: $(Build.SourcesDirectory)/MauiBlazorMacCatalystDefault - cleanUnpackFolder: false - artifactFileName: 'MauiBlazorMacCatalystDefaultNet6.tar.gz' - artifactName: 'MauiBlazorMacCatalystDefaultNet6' - displayName: 'Maui Blazor MacCatalyst App Net6' # Create Core_Root - script: $(Build.SourcesDirectory)/src/tests/build$(scriptExt) $(buildConfig) $(archType) generatelayoutonly $(librariesOverrideArg) @@ -377,8 +252,8 @@ jobs: # Copy the runtime directory into the testhost folder to include OOBs. - script: "build.cmd -subset libs.pretest -configuration release -ci -arch $(archType) -testscope innerloop /p:RuntimeArtifactsPath=$(librariesDownloadDir)\\bin\\mono\\$(osGroup).$(archType).$(buildConfigUpper) /p:RuntimeFlavor=mono;xcopy $(Build.SourcesDirectory)\\artifacts\\bin\\runtime\\$(_Framework)-$(osGroup)-$(buildConfigUpper)-$(archType)\\* $(Build.SourcesDirectory)\\artifacts\\bin\\testhost\\$(_Framework)-$(osGroup)-$(buildConfigUpper)-$(archType)\\shared\\Microsoft.NETCore.App\\$(productVersion) /E /I /Y;xcopy $(Build.SourcesDirectory)\\artifacts\\bin\\testhost\\$(_Framework)-$(osGroup)-$(buildConfigUpper)-$(archType)\\* $(Build.SourcesDirectory)\\.dotnet-mono /E /I /Y;copy $(Build.SourcesDirectory)\\artifacts\\bin\\coreclr\\$(osGroup).$(archType).$(buildConfigUpper)\\corerun.exe $(Build.SourcesDirectory)\\.dotnet-mono\\shared\\Microsoft.NETCore.App\\$(productVersion)\\corerun.exe" displayName: "Create mono dotnet (Windows)" - condition: and(and(succeeded(), eq(variables.runtimeFlavorName, 'Mono')), eq(variables.osGroup, 'windows'), not(in('${{ parameters.runtimeType }}', 'AndroidMono', 'iOSMono', 'AndroidMobileNet6', 'iOSMobileNet6'))) + condition: and(and(succeeded(), eq(variables.runtimeFlavorName, 'Mono')), eq(variables.osGroup, 'windows'), not(in('${{ parameters.runtimeType }}', 'AndroidMono', 'iOSMono'))) - script: "mkdir $(Build.SourcesDirectory)/.dotnet-mono;./build.sh -subset libs.pretest -configuration release -ci -arch $(archType) -testscope innerloop /p:RuntimeArtifactsPath=$(librariesDownloadDir)/bin/mono/$(osGroup).$(archType).$(buildConfigUpper) /p:RuntimeFlavor=mono;cp $(Build.SourcesDirectory)/artifacts/bin/runtime/$(_Framework)-$(osGroup)-$(buildConfigUpper)-$(archType)/* $(Build.SourcesDirectory)/artifacts/bin/testhost/$(_Framework)-$(osGroup)-$(buildConfigUpper)-$(archType)/shared/Microsoft.NETCore.App/$(productVersion) -rf;cp $(Build.SourcesDirectory)/artifacts/bin/testhost/$(_Framework)-$(osGroup)-$(buildConfigUpper)-$(archType)/* $(Build.SourcesDirectory)/.dotnet-mono -r;cp $(Build.SourcesDirectory)/artifacts/bin/coreclr/$(osGroup).$(archType).$(buildConfigUpper)/corerun $(Build.SourcesDirectory)/.dotnet-mono/shared/Microsoft.NETCore.App/$(productVersion)/corerun" displayName: "Create mono dotnet (Linux)" - condition: and(and(succeeded(), eq(variables.runtimeFlavorName, 'Mono')), ne(variables.osGroup, 'windows'), not(in('${{ parameters.runtimeType }}', 'AndroidMono', 'iOSMono', 'AndroidMobileNet6', 'iOSMobileNet6'))) + condition: and(and(succeeded(), eq(variables.runtimeFlavorName, 'Mono')), ne(variables.osGroup, 'windows'), not(in('${{ parameters.runtimeType }}', 'AndroidMono', 'iOSMono'))) diff --git a/eng/testing/performance/android_scenarios.proj b/eng/testing/performance/android_scenarios.proj index f01d7c17c26438..5d22af65c6cc67 100644 --- a/eng/testing/performance/android_scenarios.proj +++ b/eng/testing/performance/android_scenarios.proj @@ -35,42 +35,6 @@ $(Python) test.py sod --scenario-name "%(Identity)" $(Python) post.py - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiAndroidDefault.apk .; $(Python) pre.py --apk-name MauiAndroidDefault.apk - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiblazorandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiBlazorAndroidDefault.apk .; $(Python) pre.py --apk-name MauiBlazorAndroidDefault.apk - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiAndroidPodcast.apk .; $(Python) pre.py --apk-name MauiAndroidPodcast.apk - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiAndroidDefault.apk .; $(Python) pre.py --unzip --apk-name MauiAndroidDefault.apk - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiblazorandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiBlazorAndroidDefault.apk .; $(Python) pre.py --unzip --apk-name MauiBlazorAndroidDefault.apk - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiAndroidPodcast.apk .; $(Python) pre.py --unzip --apk-name MauiAndroidPodcast.apk - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - $(WorkItemDirectory) echo on;set XHARNESSPATH=$(XharnessPath);cd $(ScenarioDirectory)helloandroid;copy %HELIX_CORRELATION_PAYLOAD%\HelloAndroid.apk .;$(Python) pre.py --apk-name HelloAndroid.apk @@ -83,41 +47,5 @@ $(Python) test.py devicestartup --device-type android --package-path pub\HelloAndroid.apk --package-name net.dot.HelloAndroid --scenario-name "%(Identity)" --disable-animations $(Python) post.py - - $(WorkItemDirectory) - echo on;set XHARNESSPATH=$(XharnessPath);cd $(ScenarioDirectory)mauiandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiAndroidDefault.apk .;$(Python) pre.py --apk-name MauiAndroidDefault.apk - $(Python) test.py devicestartup --device-type android --package-path pub\MauiAndroidDefault.apk --package-name com.companyname.mauitesting --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - echo on;set XHARNESSPATH=$(XharnessPath);cd $(ScenarioDirectory)mauiblazorandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiBlazorAndroidDefault.apk .;$(Python) pre.py --apk-name MauiBlazorAndroidDefault.apk - $(Python) test.py devicestartup --device-type android --package-path pub\MauiBlazorAndroidDefault.apk --package-name com.companyname.mauiblazortesting --scenario-name "%(Identity)" --use-fully-drawn-time --fully-drawn-extra-delay 6 - $(Python) post.py - - - $(WorkItemDirectory) - echo on;set XHARNESSPATH=$(XharnessPath);cd $(ScenarioDirectory)mauiandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiAndroidPodcast.apk .;$(Python) pre.py --apk-name MauiAndroidPodcast.apk - $(Python) test.py devicestartup --device-type android --package-path pub\MauiAndroidPodcast.apk --package-name com.Microsoft.NetConf2021.Maui --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - echo on;set XHARNESSPATH=$(XharnessPath);cd $(ScenarioDirectory)mauiandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiAndroidDefault.apk .;$(Python) pre.py --apk-name MauiAndroidDefault.apk - $(Python) test.py devicestartup --device-type android --package-path pub\MauiAndroidDefault.apk --package-name com.companyname.mauitesting --scenario-name "%(Identity)" --disable-animations - $(Python) post.py - - - $(WorkItemDirectory) - echo on;set XHARNESSPATH=$(XharnessPath);cd $(ScenarioDirectory)mauiblazorandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiBlazorAndroidDefault.apk .;$(Python) pre.py --apk-name MauiBlazorAndroidDefault.apk - $(Python) test.py devicestartup --device-type android --package-path pub\MauiBlazorAndroidDefault.apk --package-name com.companyname.mauiblazortesting --scenario-name "%(Identity)" --use-fully-drawn-time --fully-drawn-extra-delay 6 --disable-animations - $(Python) post.py - - - $(WorkItemDirectory) - echo on;set XHARNESSPATH=$(XharnessPath);cd $(ScenarioDirectory)mauiandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiAndroidPodcast.apk .;$(Python) pre.py --apk-name MauiAndroidPodcast.apk - $(Python) test.py devicestartup --device-type android --package-path pub\MauiAndroidPodcast.apk --package-name com.Microsoft.NetConf2021.Maui --scenario-name "%(Identity)" --disable-animations - $(Python) post.py - diff --git a/eng/testing/performance/android_scenarios_net6.proj b/eng/testing/performance/android_scenarios_net6.proj deleted file mode 100644 index edd493db6481a8..00000000000000 --- a/eng/testing/performance/android_scenarios_net6.proj +++ /dev/null @@ -1,99 +0,0 @@ - - - true - 1.0.0-prerelease.21566.2 - %HELIX_CORRELATION_PAYLOAD%\microsoft.dotnet.xharness.cli\$(MicrosoftDotNetXHarnessCLIVersion)\tools\net6.0\any\Microsoft.DotNet.XHarness.CLI.dll - - - python3 - $(HelixPreCommands);chmod +x $HELIX_WORKITEM_PAYLOAD/SOD/SizeOnDisk - - - - - %(Identity) - - - - - %HELIX_CORRELATION_PAYLOAD%\performance\src\scenarios\ - - - $HELIX_CORRELATION_PAYLOAD/performance/src/scenarios/ - - - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiAndroidDefault.apk .; $(Python) pre.py --apk-name MauiAndroidDefault.apk - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiblazorandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiBlazorAndroidDefault.apk .; $(Python) pre.py --apk-name MauiBlazorAndroidDefault.apk - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiAndroidPodcast.apk .; $(Python) pre.py --apk-name MauiAndroidPodcast.apk - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiAndroidDefault.apk .; $(Python) pre.py --unzip --apk-name MauiAndroidDefault.apk - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiblazorandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiBlazorAndroidDefault.apk .; $(Python) pre.py --unzip --apk-name MauiBlazorAndroidDefault.apk - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiAndroidPodcast.apk .; $(Python) pre.py --unzip --apk-name MauiAndroidPodcast.apk - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - echo on;set XHARNESSPATH=$(XharnessPath);cd $(ScenarioDirectory)mauiandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiAndroidDefault.apk .;$(Python) pre.py --apk-name MauiAndroidDefault.apk - $(Python) test.py devicestartup --device-type android --package-path pub\MauiAndroidDefault.apk --package-name com.companyname.mauitesting --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - echo on;set XHARNESSPATH=$(XharnessPath);cd $(ScenarioDirectory)mauiblazorandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiBlazorAndroidDefault.apk .;$(Python) pre.py --apk-name MauiBlazorAndroidDefault.apk - $(Python) test.py devicestartup --device-type android --package-path pub\MauiBlazorAndroidDefault.apk --package-name com.companyname.mauiblazortesting --scenario-name "%(Identity)" --use-fully-drawn-time --fully-drawn-extra-delay 6 - $(Python) post.py - - - $(WorkItemDirectory) - echo on;set XHARNESSPATH=$(XharnessPath);cd $(ScenarioDirectory)mauiandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiAndroidPodcast.apk .;$(Python) pre.py --apk-name MauiAndroidPodcast.apk - $(Python) test.py devicestartup --device-type android --package-path pub\MauiAndroidPodcast.apk --package-name com.Microsoft.NetConf2021.Maui --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - echo on;set XHARNESSPATH=$(XharnessPath);cd $(ScenarioDirectory)mauiandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiAndroidDefault.apk .;$(Python) pre.py --apk-name MauiAndroidDefault.apk - $(Python) test.py devicestartup --device-type android --package-path pub\MauiAndroidDefault.apk --package-name com.companyname.mauitesting --scenario-name "%(Identity)" --disable-animations - $(Python) post.py - - - $(WorkItemDirectory) - echo on;set XHARNESSPATH=$(XharnessPath);cd $(ScenarioDirectory)mauiblazorandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiBlazorAndroidDefault.apk .;$(Python) pre.py --apk-name MauiBlazorAndroidDefault.apk - $(Python) test.py devicestartup --device-type android --package-path pub\MauiBlazorAndroidDefault.apk --package-name com.companyname.mauiblazortesting --scenario-name "%(Identity)" --use-fully-drawn-time --fully-drawn-extra-delay 6 --disable-animations - $(Python) post.py - - - $(WorkItemDirectory) - echo on;set XHARNESSPATH=$(XharnessPath);cd $(ScenarioDirectory)mauiandroid;copy %HELIX_CORRELATION_PAYLOAD%\MauiAndroidPodcast.apk .;$(Python) pre.py --apk-name MauiAndroidPodcast.apk - $(Python) test.py devicestartup --device-type android --package-path pub\MauiAndroidPodcast.apk --package-name com.Microsoft.NetConf2021.Maui --scenario-name "%(Identity)" --disable-animations - $(Python) post.py - - - diff --git a/eng/testing/performance/ios_scenarios.proj b/eng/testing/performance/ios_scenarios.proj index 40dee2324c31d5..6b30417fdff479 100644 --- a/eng/testing/performance/ios_scenarios.proj +++ b/eng/testing/performance/ios_scenarios.proj @@ -60,132 +60,6 @@ $(Python) test.py devicestartup --device-type ios --package-path HelloiOS.app --package-name net.dot.HelloiOS --scenario-name "%(Identity)" ((result=$?)) - # Post commands - $(Python) post.py - exit $result - ]]> - - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiios;cp -rf $HELIX_CORRELATION_PAYLOAD/MauiMacCatalystDefault ./app;$(Python) pre.py --name app - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiios;cp $HELIX_CORRELATION_PAYLOAD/MauiiOSDefault.ipa .;$(Python) pre.py --name MauiiOSDefault.ipa - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiios;cp $HELIX_CORRELATION_PAYLOAD/MauiiOSDefault.ipa .;$(Python) pre.py --unzip --name MauiiOSDefault.ipa - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiblazorios;cp $HELIX_CORRELATION_PAYLOAD/MauiBlazoriOSDefault.ipa .;$(Python) pre.py --name MauiBlazoriOSDefault.ipa - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiblazorios;cp $HELIX_CORRELATION_PAYLOAD/MauiBlazoriOSDefault.ipa .;$(Python) pre.py --unzip --name MauiBlazoriOSDefault.ipa - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiblazorios;cp -rf $HELIX_CORRELATION_PAYLOAD/MauiBlazorMacCatalystDefault ./app;$(Python) pre.py --name app - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiios;cp $HELIX_CORRELATION_PAYLOAD/MauiiOSPodcast.ipa .;$(Python) pre.py --name MauiiOSPodcast.ipa - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiios;cp $HELIX_CORRELATION_PAYLOAD/MauiiOSPodcast.ipa .;$(Python) pre.py --unzip --name MauiiOSPodcast.ipa - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory).zip - 00:15:00 - ios-device - - - - - - $(WorkItemDirectory).zip - 00:15:00 - ios-device - - - - - - $(WorkItemDirectory).zip - 00:15:00 - ios-device - - - - - - export PYTHONPATH=$ORIGPYPATH;$(HelixPostCommands) - - diff --git a/eng/testing/performance/ios_scenarios_net6.proj b/eng/testing/performance/ios_scenarios_net6.proj deleted file mode 100644 index 36c8cabc5560d1..00000000000000 --- a/eng/testing/performance/ios_scenarios_net6.proj +++ /dev/null @@ -1,168 +0,0 @@ - - - true - - - python3 - $(HelixPreCommands);chmod +x $HELIX_WORKITEM_PAYLOAD/SOD/SizeOnDisk - $(HelixPreCommands);chmod +x $HELIX_WORKITEM_PAYLOAD/startup/Startup - - - - - %(Identity) - - - - - nollvm - llvm - - - - %HELIX_CORRELATION_PAYLOAD%\performance\src\scenarios\ - - - - $HELIX_CORRELATION_PAYLOAD/performance/src/scenarios/ - - - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiios;cp -rf $HELIX_CORRELATION_PAYLOAD/MauiMacCatalystDefault ./app;$(Python) pre.py --name app - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiios;cp $HELIX_CORRELATION_PAYLOAD/MauiiOSDefault.ipa .;$(Python) pre.py --name MauiiOSDefault.ipa - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiios;cp $HELIX_CORRELATION_PAYLOAD/MauiiOSDefault.ipa .;$(Python) pre.py --unzip --name MauiiOSDefault.ipa - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiblazorios;cp $HELIX_CORRELATION_PAYLOAD/MauiBlazoriOSDefault.ipa .;$(Python) pre.py --name MauiBlazoriOSDefault.ipa - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiblazorios;cp $HELIX_CORRELATION_PAYLOAD/MauiBlazoriOSDefault.ipa .;$(Python) pre.py --unzip --name MauiBlazoriOSDefault.ipa - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiblazorios;cp -rf $HELIX_CORRELATION_PAYLOAD/MauiBlazorMacCatalystDefault ./app;$(Python) pre.py --name app - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiios;cp $HELIX_CORRELATION_PAYLOAD/MauiiOSPodcast.ipa .;$(Python) pre.py --name MauiiOSPodcast.ipa - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory) - cd $(ScenarioDirectory)mauiios;cp $HELIX_CORRELATION_PAYLOAD/MauiiOSPodcast.ipa .;$(Python) pre.py --unzip --name MauiiOSPodcast.ipa - $(Python) test.py sod --scenario-name "%(Identity)" - $(Python) post.py - - - $(WorkItemDirectory).zip - 00:15:00 - ios-device - - - - - - $(WorkItemDirectory).zip - 00:15:00 - ios-device - - - - - - $(WorkItemDirectory).zip - 00:15:00 - ios-device - - - - - - - - - export PYTHONPATH=$ORIGPYPATH;$(HelixPostCommands) - - - diff --git a/eng/testing/performance/performance-setup.ps1 b/eng/testing/performance/performance-setup.ps1 index 183f84f9fc8392..1590b5f1e36d09 100644 --- a/eng/testing/performance/performance-setup.ps1 +++ b/eng/testing/performance/performance-setup.ps1 @@ -162,14 +162,7 @@ if ($AndroidMono) { { mkdir $WorkItemDirectory } - if($Kind -ne "android_scenarios_net6") - { - Copy-Item -path "$SourceDirectory\androidHelloWorld\HelloAndroid.apk" $PayloadDirectory -Verbose - } - Copy-Item -path "$SourceDirectory\MauiAndroidDefault.apk" $PayloadDirectory -Verbose - Copy-Item -path "$SourceDirectory\MauiBlazorAndroidDefault.apk" $PayloadDirectory -Verbose - Copy-Item -path "$SourceDirectory\MauiAndroidPodcast.apk" $PayloadDirectory -Verbose - + Copy-Item -path "$SourceDirectory\androidHelloWorld\HelloAndroid.apk" $PayloadDirectory -Verbose $SetupArguments = $SetupArguments -replace $Architecture, 'arm64' } diff --git a/eng/testing/performance/performance-setup.sh b/eng/testing/performance/performance-setup.sh index 0ab69f8a3cde53..5af80ba888d62c 100755 --- a/eng/testing/performance/performance-setup.sh +++ b/eng/testing/performance/performance-setup.sh @@ -385,37 +385,13 @@ fi if [[ "$iosmono" == "true" ]]; then if [[ "$iosllvmbuild" == "True" ]]; then - if [[ "$kind" != "ios_scenarios_net6" ]]; then - # LLVM Mono .app - mkdir -p $payload_directory/iosHelloWorld && cp -rv $source_directory/iosHelloWorld/llvm $payload_directory/iosHelloWorld - mkdir -p $payload_directory/iosHelloWorldZip/llvmzip && cp -rv $source_directory/iosHelloWorldZip/llvmzip $payload_directory/iosHelloWorldZip - fi + # LLVM Mono .app + mkdir -p $payload_directory/iosHelloWorld && cp -rv $source_directory/iosHelloWorld/llvm $payload_directory/iosHelloWorld + mkdir -p $payload_directory/iosHelloWorldZip/llvmzip && cp -rv $source_directory/iosHelloWorldZip/llvmzip $payload_directory/iosHelloWorldZip else - # NoLLVM Mono .app, Maui iOS IPA, Maui Maccatalyst, Maui iOS Podcast IPA - if [[ "$kind" != "ios_scenarios_net6" ]]; then - mkdir -p $payload_directory/iosHelloWorld && cp -rv $source_directory/iosHelloWorld/nollvm $payload_directory/iosHelloWorld - mkdir -p $payload_directory/iosHelloWorldZip/nollvmzip && cp -rv $source_directory/iosHelloWorldZip/nollvmzip $payload_directory/iosHelloWorldZip - fi - mkdir -p $payload_directory/MauiMacCatalystDefault && cp -rv $source_directory/MauiMacCatalystDefault/MauiMacCatalystDefault.app $payload_directory/MauiMacCatalystDefault - mkdir -p $payload_directory/MauiBlazorMacCatalystDefault && cp -rv $source_directory/MauiBlazorMacCatalystDefault/MauiBlazorMacCatalystDefault.app $payload_directory/MauiBlazorMacCatalystDefault - cp -v $source_directory/MauiiOSDefaultIPA/MauiiOSDefault.ipa $payload_directory/MauiiOSDefault.ipa - cp -v $source_directory/MauiBlazoriOSDefaultIPA/MauiBlazoriOSDefault.ipa $payload_directory/MauiBlazoriOSDefault.ipa - cp -v $source_directory/MauiiOSPodcastIPA/MauiiOSPodcast.ipa $payload_directory/MauiiOSPodcast.ipa - - # Get the .app so we can resign in the xharness item - cp -v $source_directory/MauiiOSDefaultIPA/MauiiOSDefault.ipa $source_directory/MauiiOSDefaultIPA/MauiiOSDefault.zip - unzip -d $source_directory/MauiiOSDefaultIPA $source_directory/MauiiOSDefaultIPA/MauiiOSDefault.zip - mv $source_directory/MauiiOSDefaultIPA/Payload/MauiTesting.app $payload_directory/ - - # Get the .app so we can resign in the xharness item for Maui Blazor - cp -v $source_directory/MauiBlazoriOSDefaultIPA/MauiBlazoriOSDefault.ipa $source_directory/MauiBlazoriOSDefaultIPA/MauiBlazoriOSDefault.zip - unzip -d $source_directory/MauiBlazoriOSDefaultIPA $source_directory/MauiBlazoriOSDefaultIPA/MauiBlazoriOSDefault.zip - mv $source_directory/MauiBlazoriOSDefaultIPA/Payload/MauiBlazorTesting.app $payload_directory/ - - # Get the .app so we can resign in the xharness item for podcast - cp -v $source_directory/MauiiOSPodcastIPA/MauiiOSPodcast.ipa $source_directory/MauiiOSPodcastIPA/MauiiOSPodcast.zip - unzip -d $source_directory/MauiiOSPodcastIPA $source_directory/MauiiOSPodcastIPA/MauiiOSPodcast.zip - mv $source_directory/MauiiOSPodcastIPA/Payload/Microsoft.NetConf2021.Maui.app $payload_directory/ + # NoLLVM Mono .app + mkdir -p $payload_directory/iosHelloWorld && cp -rv $source_directory/iosHelloWorld/nollvm $payload_directory/iosHelloWorld + mkdir -p $payload_directory/iosHelloWorldZip/nollvmzip && cp -rv $source_directory/iosHelloWorldZip/nollvmzip $payload_directory/iosHelloWorldZip fi fi diff --git a/eng/testing/xunit/xunit.targets b/eng/testing/xunit/xunit.targets index 6b048e6f6a9a4e..e72ebd444ad835 100644 --- a/eng/testing/xunit/xunit.targets +++ b/eng/testing/xunit/xunit.targets @@ -6,6 +6,11 @@ Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'" /> + + true + true + + $(OutDir) diff --git a/global.json b/global.json index b9d7d81f1f2ad2..8a868c539e9603 100644 --- a/global.json +++ b/global.json @@ -8,9 +8,9 @@ "dotnet": "7.0.105" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.23211.2", - "Microsoft.DotNet.Helix.Sdk": "7.0.0-beta.23211.2", - "Microsoft.DotNet.SharedFramework.Sdk": "7.0.0-beta.23211.2", + "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.23228.7", + "Microsoft.DotNet.Helix.Sdk": "7.0.0-beta.23228.7", + "Microsoft.DotNet.SharedFramework.Sdk": "7.0.0-beta.23228.7", "Microsoft.Build.NoTargets": "3.5.0", "Microsoft.Build.Traversal": "3.1.6", "Microsoft.NET.Sdk.IL": "7.0.0-rc.1.22414.6" diff --git a/src/coreclr/debug/createdump/createdump.h b/src/coreclr/debug/createdump/createdump.h index 7203300af089cf..51ffca9c520269 100644 --- a/src/coreclr/debug/createdump/createdump.h +++ b/src/coreclr/debug/createdump/createdump.h @@ -100,7 +100,7 @@ typedef struct int Pid; int CrashThread; int Signal; -#if defined(HOST_UNIX) && !defined(HOST_OSX) +#if defined(HOST_UNIX) int SignalCode; int SignalErrno; void* SignalAddress; diff --git a/src/coreclr/debug/createdump/main.cpp b/src/coreclr/debug/createdump/main.cpp index b54cab825025e9..75a616dc2e47b4 100644 --- a/src/coreclr/debug/createdump/main.cpp +++ b/src/coreclr/debug/createdump/main.cpp @@ -70,7 +70,7 @@ int __cdecl main(const int argc, const char* argv[]) options.Signal = 0; options.CrashThread = 0; options.Pid = 0; -#if defined(HOST_UNIX) && !defined(HOST_OSX) +#if defined(HOST_UNIX) options.SignalCode = 0; options.SignalErrno = 0; options.SignalAddress = nullptr; @@ -161,7 +161,6 @@ int __cdecl main(const int argc, const char* argv[]) { g_checkForSingleFile = true; } -#ifndef HOST_OSX else if (strcmp(*argv, "--code") == 0) { options.SignalCode = atoi(*++argv); @@ -174,7 +173,6 @@ int __cdecl main(const int argc, const char* argv[]) { options.SignalAddress = (void*)atoll(*++argv); } -#endif #endif else if ((strcmp(*argv, "-d") == 0) || (strcmp(*argv, "--diag") == 0)) { diff --git a/src/coreclr/dlls/mscordbi/CMakeLists.txt b/src/coreclr/dlls/mscordbi/CMakeLists.txt index c24a90cf70409c..c577651141e5c5 100644 --- a/src/coreclr/dlls/mscordbi/CMakeLists.txt +++ b/src/coreclr/dlls/mscordbi/CMakeLists.txt @@ -100,6 +100,17 @@ elseif(CLR_CMAKE_HOST_UNIX) mscordaccore ) + # Before llvm 16, lld was setting `--undefined-version` by default. The default was + # flipped to `--no-undefined-version` in lld 16, so we will explicitly set it to + # `--undefined-version` for our use-case. + include(CheckLinkerFlag OPTIONAL) + if(COMMAND check_linker_flag) + check_linker_flag(CXX -Wl,--undefined-version LINKER_SUPPORTS_UNDEFINED_VERSION) + if (LINKER_SUPPORTS_UNDEFINED_VERSION) + add_linker_flag(-Wl,--undefined-version) + endif(LINKER_SUPPORTS_UNDEFINED_VERSION) + endif(COMMAND check_linker_flag) + # COREDBI_LIBRARIES is mentioned twice because ld is one pass linker and will not find symbols # if they are defined after they are used. Having all libs twice makes sure that ld will actually # find all symbols. diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index d7e3dd2d71012a..e3122f12da18cc 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -91,6 +91,8 @@ BOOL bgc_heap_walk_for_etw_p = FALSE; #define UOH_ALLOCATION_RETRY_MAX_COUNT 2 +#define MAX_YP_SPIN_COUNT_UNIT 32768 + uint32_t yp_spin_count_unit = 0; uint32_t original_spin_count_unit = 0; size_t loh_size_threshold = LARGE_OBJECT_SIZE; @@ -2287,6 +2289,7 @@ double gc_heap::short_plugs_pad_ratio = 0; int gc_heap::generation_skip_ratio_threshold = 0; int gc_heap::conserve_mem_setting = 0; +bool gc_heap::spin_count_unit_config_p = false; uint64_t gc_heap::suspended_start_time = 0; uint64_t gc_heap::end_gc_time = 0; @@ -2334,9 +2337,6 @@ size_t gc_heap::heap_hard_limit_oh[total_oh_count]; size_t gc_heap::regions_range = 0; -size_t gc_heap::heap_hard_limit_for_heap = 0; -size_t gc_heap::heap_hard_limit_for_bookkeeping = 0; - #endif //USE_REGIONS bool affinity_config_specified_p = false; @@ -6944,10 +6944,6 @@ bool gc_heap::virtual_commit (void* address, size_t size, int bucket, int h_numb if (heap_hard_limit_oh[soh] != 0) { -#ifdef USE_REGIONS - assert (heap_hard_limit_for_heap == 0); - assert (heap_hard_limit_for_bookkeeping == 0); -#endif //USE_REGIONS if ((bucket < total_oh_count) && (committed_by_oh[bucket] + size) > heap_hard_limit_oh[bucket]) { exceeded_p = true; @@ -6955,23 +6951,9 @@ bool gc_heap::virtual_commit (void* address, size_t size, int bucket, int h_numb } else { - size_t base; - size_t limit; -#ifdef USE_REGIONS - if (h_number < 0) - { - base = current_total_committed_bookkeeping; - limit = heap_hard_limit_for_bookkeeping; - } - else - { - base = current_total_committed - current_total_committed_bookkeeping; - limit = heap_hard_limit_for_heap; - } -#else - base = current_total_committed; - limit = heap_hard_limit; -#endif //USE_REGIONS + size_t base = current_total_committed; + size_t limit = heap_hard_limit; + if ((base + size) > limit) { dprintf (1, ("%Id + %Id = %Id > limit %Id ", base, size, (base + size), limit)); @@ -11282,12 +11264,6 @@ void gc_heap::clear_region_info (heap_segment* region) seg_deleted); bgc_verify_mark_array_cleared (region); - - if (dt_high_memory_load_p()) - { - decommit_mark_array_by_seg (region); - region->flags &= ~(heap_segment_flags_ma_committed); - } #endif //BACKGROUND_GC } @@ -13607,26 +13583,6 @@ HRESULT gc_heap::initialize_gc (size_t soh_segment_size, #endif //BACKGROUND_GC #endif //WRITE_WATCH -#ifdef USE_REGIONS - if (gc_heap::heap_hard_limit && gc_heap::heap_hard_limit_oh[soh] == 0) - { - size_t gc_region_size = (size_t)1 << min_segment_size_shr; - size_t sizes[total_bookkeeping_elements]; - size_t bookkeeping_size_per_region = 0; - uint8_t* temp_lowest_address = (uint8_t*)gc_region_size; - gc_heap::get_card_table_element_sizes(temp_lowest_address, temp_lowest_address + gc_region_size, sizes); - for (int i = 0; i < total_bookkeeping_elements; i++) - { - bookkeeping_size_per_region += sizes[i]; - } - size_t total_size_per_region = gc_region_size + bookkeeping_size_per_region; - size_t max_region_count = gc_heap::heap_hard_limit / total_size_per_region; // implictly rounded down - gc_heap::heap_hard_limit_for_heap = max_region_count * gc_region_size; - gc_heap::heap_hard_limit_for_bookkeeping = max_region_count * bookkeeping_size_per_region; - dprintf (REGIONS_LOG, ("bookkeeping_size_per_region = %Id", bookkeeping_size_per_region)); - } -#endif //USE_REGIONS - #ifdef BACKGROUND_GC // leave the first page to contain only segment info // because otherwise we could need to revisit the first page frequently in @@ -13791,6 +13747,14 @@ HRESULT gc_heap::initialize_gc (size_t soh_segment_size, yp_spin_count_unit = 32 * g_num_processors; #endif //MULTIPLE_HEAPS + // Check if the values are valid for the spin count if provided by the user + // and if they are, set them as the yp_spin_count_unit and then ignore any updates made in SetYieldProcessorScalingFactor. + uint32_t spin_count_unit_from_config = (uint32_t)GCConfig::GetGCSpinCountUnit(); + gc_heap::spin_count_unit_config_p = (spin_count_unit_from_config > 0) && (spin_count_unit_from_config <= MAX_YP_SPIN_COUNT_UNIT); + if (gc_heap::spin_count_unit_config_p) + { + yp_spin_count_unit = spin_count_unit_from_config; + } original_spin_count_unit = yp_spin_count_unit; #if defined(__linux__) @@ -14390,6 +14354,8 @@ gc_heap::init_gc_heap (int h_number) #endif //CARD_BUNDLE #ifdef BACKGROUND_GC + background_saved_highest_address = nullptr; + background_saved_lowest_address = nullptr; if (gc_can_use_concurrent) mark_array = translate_mark_array (card_table_mark_array (&g_gc_card_table[card_word (card_of (g_gc_lowest_address))])); else @@ -20310,20 +20276,17 @@ bool gc_heap::try_get_new_free_region() bool gc_heap::init_table_for_region (int gen_number, heap_segment* region) { #ifdef BACKGROUND_GC - if (is_bgc_in_progress()) + dprintf (GC_TABLE_LOG, ("new seg %Ix, mark_array is %Ix", + heap_segment_mem (region), mark_array)); + if (((region->flags & heap_segment_flags_ma_committed) == 0) && + !commit_mark_array_new_seg (__this, region)) { - dprintf (GC_TABLE_LOG, ("new seg %Ix, mark_array is %Ix", - heap_segment_mem (region), mark_array)); - if (((region->flags & heap_segment_flags_ma_committed) == 0) && - !commit_mark_array_new_seg (__this, region)) - { - dprintf (GC_TABLE_LOG, ("failed to commit mark array for the new region %Ix-%Ix", - get_region_start (region), heap_segment_reserved (region))); + dprintf (GC_TABLE_LOG, ("failed to commit mark array for the new region %Ix-%Ix", + get_region_start (region), heap_segment_reserved (region))); - // We don't have memory to commit the mark array so we cannot use the new region. - decommit_region (region, gen_to_oh (gen_number), heap_number); - return false; - } + // We don't have memory to commit the mark array so we cannot use the new region. + decommit_region (region, gen_to_oh (gen_number), heap_number); + return false; } if ((region->flags & heap_segment_flags_ma_committed) != 0) { @@ -22594,6 +22557,8 @@ void gc_heap::garbage_collect_pm_full_gc() void gc_heap::garbage_collect (int n) { + gc_pause_mode saved_settings_pause_mode = settings.pause_mode; + //reset the number of alloc contexts alloc_contexts_used = 0; @@ -22999,7 +22964,7 @@ void gc_heap::garbage_collect (int n) #endif //MULTIPLE_HEAPS done: - if (settings.pause_mode == pause_no_gc) + if (saved_settings_pause_mode == pause_no_gc) allocate_for_no_gc_after_gc(); } @@ -45674,14 +45639,17 @@ size_t GCHeap::GetPromotedBytes(int heap_index) void GCHeap::SetYieldProcessorScalingFactor (float scalingFactor) { - assert (yp_spin_count_unit != 0); - uint32_t saved_yp_spin_count_unit = yp_spin_count_unit; - yp_spin_count_unit = (uint32_t)((float)original_spin_count_unit * scalingFactor / (float)9); - - // It's very suspicious if it becomes 0 and also, we don't want to spin too much. - if ((yp_spin_count_unit == 0) || (yp_spin_count_unit > 32768)) + if (!gc_heap::spin_count_unit_config_p) { - yp_spin_count_unit = saved_yp_spin_count_unit; + assert (yp_spin_count_unit != 0); + uint32_t saved_yp_spin_count_unit = yp_spin_count_unit; + yp_spin_count_unit = (uint32_t)((float)original_spin_count_unit * scalingFactor / (float)9); + + // It's very suspicious if it becomes 0 and also, we don't want to spin too much. + if ((yp_spin_count_unit == 0) || (yp_spin_count_unit > MAX_YP_SPIN_COUNT_UNIT)) + { + yp_spin_count_unit = saved_yp_spin_count_unit; + } } } diff --git a/src/coreclr/gc/gcconfig.h b/src/coreclr/gc/gcconfig.h index 2b5f87b41f4cc3..c20febbb79dc61 100644 --- a/src/coreclr/gc/gcconfig.h +++ b/src/coreclr/gc/gcconfig.h @@ -136,7 +136,9 @@ class GCConfigStringHolder INT_CONFIG (GCEnabledInstructionSets, "GCEnabledInstructionSets", NULL, -1, "Specifies whether GC can use AVX2 or AVX512F - 0 for neither, 1 for AVX2, 3 for AVX512F")\ INT_CONFIG (GCConserveMem, "GCConserveMemory", "System.GC.ConserveMemory", 0, "Specifies how hard GC should try to conserve memory - values 0-9") \ INT_CONFIG (GCWriteBarrier, "GCWriteBarrier", NULL, 0, "Specifies whether GC should use more precise but slower write barrier") \ - STRING_CONFIG(GCName, "GCName", "System.GC.Name", "Specifies the path of the standalone GC implementation.") + STRING_CONFIG(GCName, "GCName", "System.GC.Name", "Specifies the path of the standalone GC implementation.") \ + INT_CONFIG (GCSpinCountUnit, "GCSpinCountUnit", NULL, 0, "Specifies the spin count unit used by the GC.") + // This class is responsible for retreiving configuration information // for how the GC should operate. class GCConfig diff --git a/src/coreclr/gc/gcpriv.h b/src/coreclr/gc/gcpriv.h index 995a6f14b586e1..fde1cb3c36f2d7 100644 --- a/src/coreclr/gc/gcpriv.h +++ b/src/coreclr/gc/gcpriv.h @@ -4116,12 +4116,6 @@ class gc_heap PER_HEAP_ISOLATED size_t heap_hard_limit_oh[total_oh_count]; - PER_HEAP_ISOLATED - size_t heap_hard_limit_for_heap; - - PER_HEAP_ISOLATED - size_t heap_hard_limit_for_bookkeeping; - PER_HEAP_ISOLATED CLRCriticalSection check_commit_cs; @@ -4865,6 +4859,9 @@ class gc_heap PER_HEAP_ISOLATED int conserve_mem_setting; + PER_HEAP_ISOLATED + bool spin_count_unit_config_p; + PER_HEAP BOOL gen0_bricks_cleared; PER_HEAP diff --git a/src/coreclr/pal/src/config.h.in b/src/coreclr/pal/src/config.h.in index 75507804d23a00..3f881d2b3ec6ba 100644 --- a/src/coreclr/pal/src/config.h.in +++ b/src/coreclr/pal/src/config.h.in @@ -68,6 +68,7 @@ #cmakedefine01 HAVE_SCHED_SETAFFINITY #cmakedefine HAVE_UNW_GET_SAVE_LOC #cmakedefine HAVE_UNW_GET_ACCESSORS +#cmakedefine HAVE_UNW_AARCH64_X19 #cmakedefine01 HAVE_XSWDEV #cmakedefine01 HAVE_XSW_USAGE #cmakedefine01 HAVE_PUBLIC_XSTATE_STRUCT diff --git a/src/coreclr/pal/src/configure.cmake b/src/coreclr/pal/src/configure.cmake index 4f900a5555ef63..37165783b476e2 100644 --- a/src/coreclr/pal/src/configure.cmake +++ b/src/coreclr/pal/src/configure.cmake @@ -1047,6 +1047,15 @@ int main(int argc, char **argv) check_symbol_exists(unw_get_save_loc libunwind.h HAVE_UNW_GET_SAVE_LOC) check_symbol_exists(unw_get_accessors libunwind.h HAVE_UNW_GET_ACCESSORS) +check_cxx_source_compiles(" +#include + +int main(int argc, char **argv) +{ + int flag = (int)UNW_AARCH64_X19; + return 0; +}" HAVE_UNW_AARCH64_X19) + if(NOT CLR_CMAKE_USE_SYSTEM_LIBUNWIND) list(REMOVE_AT CMAKE_REQUIRED_INCLUDES 0 1) endif() diff --git a/src/coreclr/pal/src/exception/seh-unwind.cpp b/src/coreclr/pal/src/exception/seh-unwind.cpp index f718be6af54c27..fb437c3b5b1fa2 100644 --- a/src/coreclr/pal/src/exception/seh-unwind.cpp +++ b/src/coreclr/pal/src/exception/seh-unwind.cpp @@ -54,7 +54,7 @@ Module Name: #endif // HOST_UNIX -#if defined(TARGET_OSX) && defined(TARGET_ARM64) +#if defined(TARGET_OSX) && defined(TARGET_ARM64) && !defined(HAVE_UNW_AARCH64_X19) // MacOS uses ARM64 instead of AARCH64 to describe these registers // Create aliases to reuse more code enum diff --git a/src/coreclr/vm/perfmap.cpp b/src/coreclr/vm/perfmap.cpp index af4cfcf646c08b..26a8492f89c3cf 100644 --- a/src/coreclr/vm/perfmap.cpp +++ b/src/coreclr/vm/perfmap.cpp @@ -12,6 +12,7 @@ #include "perfinfo.h" #include "pal.h" + // The code addresses are actually native image offsets during crossgen. Print // them as 32-bit numbers for consistent output when cross-targeting and to // make the output more compact. @@ -21,6 +22,15 @@ Volatile PerfMap::s_enabled = false; PerfMap * PerfMap::s_Current = nullptr; bool PerfMap::s_ShowOptimizationTiers = false; +unsigned PerfMap::s_StubsMapped = 0; + +enum +{ + DISABLED, + ALL, + JITDUMP, + PERFMAP +}; // Initialize the map for the process - called from EEStartupHelper. void PerfMap::Initialize() @@ -28,7 +38,7 @@ void PerfMap::Initialize() LIMITED_METHOD_CONTRACT; // Only enable the map if requested. - if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_PerfMapEnabled)) + if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_PerfMapEnabled) == ALL || CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_PerfMapEnabled) == PERFMAP) { // Get the current process id. int currentPid = GetCurrentProcessId(); @@ -49,7 +59,10 @@ void PerfMap::Initialize() } s_enabled = true; + } + if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_PerfMapEnabled) == ALL || CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_PerfMapEnabled) == JITDUMP) + { const char* jitdumpPath; char jitdumpPathBuffer[4096]; @@ -65,6 +78,13 @@ void PerfMap::Initialize() } PAL_PerfJitDump_Start(jitdumpPath); + + if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_PerfMapShowOptimizationTiers) != 0) + { + s_ShowOptimizationTiers = true; + } + + s_enabled = true; } } @@ -89,8 +109,6 @@ PerfMap::PerfMap(int pid) // Initialize with no failures. m_ErrorEncountered = false; - m_StubsMapped = 0; - // Build the path to the map file on disk. WCHAR tempPath[MAX_LONGPATH+1]; if(!GetTempPathW(MAX_LONGPATH, tempPath)) @@ -117,8 +135,6 @@ PerfMap::PerfMap() // Initialize with no failures. m_ErrorEncountered = false; - - m_StubsMapped = 0; } // Clean-up resources. @@ -156,6 +172,11 @@ void PerfMap::WriteLine(SString& line) { STANDARD_VM_CONTRACT; + if (m_FileStream == nullptr || m_ErrorEncountered) + { + return; + } + EX_TRY { // Write the line. @@ -176,50 +197,9 @@ void PerfMap::WriteLine(SString& line) EX_CATCH{} EX_END_CATCH(SwallowAllExceptions); } -// Log a method to the map. -void PerfMap::LogMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize, const char *optimizationTier) -{ - CONTRACTL{ - THROWS; - GC_NOTRIGGER; - MODE_PREEMPTIVE; - PRECONDITION(pMethod != nullptr); - PRECONDITION(pCode != nullptr); - PRECONDITION(codeSize > 0); - } CONTRACTL_END; - - if (m_FileStream == nullptr || m_ErrorEncountered) - { - // A failure occurred, do not log. - return; - } - - // Logging failures should not cause any exceptions to flow upstream. - EX_TRY - { - // Get the full method signature. - SString name; - pMethod->GetFullMethodInfo(name); - - // Build the map file line. - if (optimizationTier != nullptr && s_ShowOptimizationTiers) - { - name.AppendPrintf("[%s]", optimizationTier); - } - SString line; - line.Printf(FMT_CODE_ADDR " %x %s\n", pCode, codeSize, name.GetUTF8()); - - // Write the line. - WriteLine(line); - PAL_PerfJitDump_LogMethod((void*)pCode, codeSize, name.GetUTF8(), nullptr, nullptr); - } - EX_CATCH{} EX_END_CATCH(SwallowAllExceptions); -} - - void PerfMap::LogImageLoad(PEAssembly * pPEAssembly) { - if (s_enabled) + if (s_enabled && s_Current != nullptr) { s_Current->LogImage(pPEAssembly); } @@ -258,6 +238,15 @@ void PerfMap::LogJITCompiledMethod(MethodDesc * pMethod, PCODE pCode, size_t cod { LIMITED_METHOD_CONTRACT; + CONTRACTL{ + THROWS; + GC_NOTRIGGER; + MODE_PREEMPTIVE; + PRECONDITION(pMethod != nullptr); + PRECONDITION(pCode != nullptr); + PRECONDITION(codeSize > 0); + } CONTRACTL_END; + if (!s_enabled) { return; @@ -269,7 +258,31 @@ void PerfMap::LogJITCompiledMethod(MethodDesc * pMethod, PCODE pCode, size_t cod optimizationTier = PrepareCodeConfig::GetJitOptimizationTierStr(pConfig, pMethod); } - s_Current->LogMethod(pMethod, pCode, codeSize, optimizationTier); + // Logging failures should not cause any exceptions to flow upstream. + EX_TRY + { + // Get the full method signature. + SString name; + pMethod->GetFullMethodInfo(name); + + // Build the map file line. + if (optimizationTier != nullptr && s_ShowOptimizationTiers) + { + name.AppendPrintf("[%s]", optimizationTier); + } + + SString line; + line.Printf(FMT_CODE_ADDR " %x %s\n", pCode, codeSize, name.GetUTF8()); + + // Write the line. + if(s_Current != nullptr) + { + s_Current->WriteLine(line); + } + PAL_PerfJitDump_LogMethod((void*)pCode, codeSize, name.GetUTF8(), nullptr, nullptr); + } + EX_CATCH{} EX_END_CATCH(SwallowAllExceptions); + } // Log a pre-compiled method to the perfmap. @@ -326,7 +339,7 @@ void PerfMap::LogStubs(const char* stubType, const char* stubOwner, PCODE pCode, { LIMITED_METHOD_CONTRACT; - if (!s_enabled || s_Current->m_FileStream == nullptr) + if (!s_enabled) { return; } @@ -344,13 +357,15 @@ void PerfMap::LogStubs(const char* stubType, const char* stubOwner, PCODE pCode, } SString name; - // Build the map file line. - name.Printf("stub<%d> %s<%s>", ++(s_Current->m_StubsMapped), stubType, stubOwner); + name.Printf("stub<%d> %s<%s>", ++(s_StubsMapped), stubType, stubOwner); SString line; line.Printf(FMT_CODE_ADDR " %x %s\n", pCode, codeSize, name.GetUTF8()); // Write the line. - s_Current->WriteLine(line); + if(s_Current != nullptr) + { + s_Current->WriteLine(line); + } PAL_PerfJitDump_LogMethod((void*)pCode, codeSize, name.GetUTF8(), nullptr, nullptr); } EX_CATCH{} EX_END_CATCH(SwallowAllExceptions); @@ -407,6 +422,41 @@ NativeImagePerfMap::NativeImagePerfMap(Assembly * pAssembly, BSTR pDestPath) } } +void NativeImagePerfMap::LogMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize, const char *optimizationTier) +{ + CONTRACTL{ + THROWS; + GC_NOTRIGGER; + MODE_PREEMPTIVE; + PRECONDITION(pMethod != nullptr); + PRECONDITION(pCode != nullptr); + PRECONDITION(codeSize > 0); + } CONTRACTL_END; + + // Logging failures should not cause any exceptions to flow upstream. + EX_TRY + { + // Get the full method signature. + SString name; + pMethod->GetFullMethodInfo(name); + + // Build the map file line. + if (optimizationTier != nullptr && s_ShowOptimizationTiers) + { + name.AppendPrintf("[%s]", optimizationTier); + } + SString line; + line.Printf(FMT_CODE_ADDR " %x %s\n", pCode, codeSize, name.GetUTF8()); + + if (s_Current != nullptr) + { + s_Current->WriteLine(line); + } + PAL_PerfJitDump_LogMethod((void*)pCode, codeSize, name.GetUTF8(), nullptr, nullptr); + } + EX_CATCH{} EX_END_CATCH(SwallowAllExceptions); +} + // Log data to the perfmap for the specified module. void NativeImagePerfMap::LogDataForModule(Module * pModule) { diff --git a/src/coreclr/vm/perfmap.h b/src/coreclr/vm/perfmap.h index 587a776e682760..ca240f9eda71b1 100644 --- a/src/coreclr/vm/perfmap.h +++ b/src/coreclr/vm/perfmap.h @@ -18,11 +18,8 @@ class PerfMap private: static Volatile s_enabled; - // The one and only PerfMap for the process. - static PerfMap * s_Current; - - // Indicates whether optimization tiers should be shown for methods in perf maps - static bool s_ShowOptimizationTiers; + // Set to true if an error is encountered when writing to the file. + static unsigned s_StubsMapped; // The file stream to write the map to. CFileStream * m_FileStream; @@ -33,16 +30,16 @@ class PerfMap // Set to true if an error is encountered when writing to the file. bool m_ErrorEncountered; - // Set to true if an error is encountered when writing to the file. - unsigned m_StubsMapped; - // Construct a new map for the specified pid. PerfMap(int pid); - // Write a line to the map file. - void WriteLine(SString & line); - protected: + // Indicates whether optimization tiers should be shown for methods in perf maps + static bool s_ShowOptimizationTiers; + + // The one and only PerfMap for the process. + static PerfMap * s_Current; + // Construct a new map without a specified file name. // Used for offline creation of NGEN map files. PerfMap(); @@ -53,9 +50,6 @@ class PerfMap // Open the perf map file for write. void OpenFile(SString& path); - // Does the actual work to log a method to the map. - void LogMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize, const char *optimizationTier); - // Does the actual work to log an image void LogImage(PEAssembly * pPEAssembly); @@ -63,6 +57,9 @@ class PerfMap static void GetNativeImageSignature(PEAssembly * pPEAssembly, WCHAR * pwszSig, unsigned int nSigSize); public: + // Write a line to the map file. + void WriteLine(SString & line); + // Initialize the map for the current process. static void Initialize(); @@ -91,6 +88,9 @@ class NativeImagePerfMap : PerfMap // Specify the address format since it's now possible for 'perf script' to output file offsets or RVAs. bool m_EmitRVAs; + // Does the actual work to log a method to the map. + void LogMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize, const char *optimizationTier); + // Log a pre-compiled method to the map. void LogPreCompiledMethod(MethodDesc * pMethod, PCODE pCode, PEImageLayout *pLoadedLayout, const char *optimizationTier); diff --git a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.QueryServiceStatusEx.cs b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.QueryServiceStatusEx.cs new file mode 100644 index 00000000000000..8c38dec4df8eb4 --- /dev/null +++ b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.QueryServiceStatusEx.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Win32.SafeHandles; +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Advapi32 + { + [StructLayout(LayoutKind.Sequential)] + internal struct SERVICE_STATUS_PROCESS + { + public int dwServiceType; + public int dwCurrentState; + public int dwControlsAccepted; + public int dwWin32ExitCode; + public int dwServiceSpecificExitCode; + public int dwCheckPoint; + public int dwWaitHint; + public int dwProcessId; + public int dwServiceFlags; + } + + private const int SC_STATUS_PROCESS_INFO = 0; + + [LibraryImport(Libraries.Advapi32, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static unsafe partial bool QueryServiceStatusEx(SafeServiceHandle serviceHandle, int InfoLevel, SERVICE_STATUS_PROCESS* pStatus, int cbBufSize, out int pcbBytesNeeded); + + internal static unsafe bool QueryServiceStatusEx(SafeServiceHandle serviceHandle, SERVICE_STATUS_PROCESS* pStatus) => QueryServiceStatusEx(serviceHandle, SC_STATUS_PROCESS_INFO, pStatus, sizeof(SERVICE_STATUS_PROCESS), out _); + } +} diff --git a/src/libraries/Common/src/Interop/Windows/Interop.Errors.cs b/src/libraries/Common/src/Interop/Windows/Interop.Errors.cs index cde3ae0ac197e8..c810603e6300a9 100644 --- a/src/libraries/Common/src/Interop/Windows/Interop.Errors.cs +++ b/src/libraries/Common/src/Interop/Windows/Interop.Errors.cs @@ -64,6 +64,8 @@ internal static partial class Errors internal const int ERROR_IO_PENDING = 0x3E5; internal const int ERROR_NO_TOKEN = 0x3f0; internal const int ERROR_SERVICE_DOES_NOT_EXIST = 0x424; + internal const int ERROR_EXCEPTION_IN_SERVICE = 0x428; + internal const int ERROR_PROCESS_ABORTED = 0x42B; internal const int ERROR_NO_UNICODE_TRANSLATION = 0x459; internal const int ERROR_DLL_INIT_FAILED = 0x45A; internal const int ERROR_COUNTER_TIMEOUT = 0x461; diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http2/Hpack/HPackDecoder.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http2/Hpack/HPackDecoder.cs index cefb377f40c094..0f1a7e94d75c47 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http2/Hpack/HPackDecoder.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http2/Hpack/HPackDecoder.cs @@ -187,12 +187,11 @@ private void DecodeInternal(ReadOnlySpan data, IHttpStreamHeadersHandler h // will no longer be valid. if (_headerNameRange != null) { - EnsureStringCapacity(ref _headerNameOctets); + EnsureStringCapacity(ref _headerNameOctets, _headerNameLength); _headerName = _headerNameOctets; ReadOnlySpan headerBytes = data.Slice(_headerNameRange.GetValueOrDefault().start, _headerNameRange.GetValueOrDefault().length); headerBytes.CopyTo(_headerName); - _headerNameLength = headerBytes.Length; _headerNameRange = null; } } @@ -427,6 +426,7 @@ private void ParseHeaderName(ReadOnlySpan data, ref int currentIndex, IHtt { // Fast path. Store the range rather than copying. _headerNameRange = (start: currentIndex, count); + _headerNameLength = _stringLength; currentIndex += count; _state = State.HeaderValueLength; @@ -621,11 +621,12 @@ int Decode(ref byte[] dst) _state = nextState; } - private void EnsureStringCapacity(ref byte[] dst) + private void EnsureStringCapacity(ref byte[] dst, int stringLength = -1) { - if (dst.Length < _stringLength) + stringLength = stringLength >= 0 ? stringLength : _stringLength; + if (dst.Length < stringLength) { - dst = new byte[Math.Max(_stringLength, dst.Length * 2)]; + dst = new byte[Math.Max(stringLength, dst.Length * 2)]; } } diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackDecoder.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackDecoder.cs index 394cc1aee72a5f..608a2ae73acfd5 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackDecoder.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackDecoder.cs @@ -243,12 +243,11 @@ private void DecodeInternal(ReadOnlySpan data, IHttpStreamHeadersHandler h // will no longer be valid. if (_headerNameRange != null) { - EnsureStringCapacity(ref _headerNameOctets, _stringLength, existingLength: 0); + EnsureStringCapacity(ref _headerNameOctets, _headerNameLength, existingLength: 0); _headerName = _headerNameOctets; ReadOnlySpan headerBytes = data.Slice(_headerNameRange.GetValueOrDefault().start, _headerNameRange.GetValueOrDefault().length); headerBytes.CopyTo(_headerName); - _headerNameLength = headerBytes.Length; _headerNameRange = null; } } @@ -294,6 +293,7 @@ private void ParseHeaderName(ReadOnlySpan data, ref int currentIndex, IHtt { // Fast path. Store the range rather than copying. _headerNameRange = (start: currentIndex, count); + _headerNameLength = _stringLength; currentIndex += count; _state = State.HeaderValueLength; diff --git a/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http2/HPackDecoderTest.cs b/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http2/HPackDecoderTest.cs index e5f3c3b698e21d..5f4390db033d24 100644 --- a/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http2/HPackDecoderTest.cs +++ b/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http2/HPackDecoderTest.cs @@ -46,8 +46,13 @@ public class HPackDecoderTests private const string _headerNameString = "new-header"; + // On purpose longer than 4096 (DefaultStringOctetsSize from HPackDecoder) to trigger https://github.com/dotnet/runtime/issues/78516 + private static readonly string _literalHeaderNameString = string.Concat(Enumerable.Range(0, 4100).Select(c => (char)('a' + (c % 26)))); + private static readonly byte[] _headerNameBytes = Encoding.ASCII.GetBytes(_headerNameString); + private static readonly byte[] _literalHeaderNameBytes = Encoding.ASCII.GetBytes(_literalHeaderNameString); + // n e w - h e a d e r * // 10101000 10111110 00010110 10011100 10100011 10010000 10110110 01111111 private static readonly byte[] _headerNameHuffmanBytes = new byte[] { 0xa8, 0xbe, 0x16, 0x9c, 0xa3, 0x90, 0xb6, 0x7f }; @@ -64,6 +69,12 @@ public class HPackDecoderTests .Concat(_headerNameBytes) .ToArray(); + // size = 4096 ==> 0x7f, 0x81, 0x1f (7+) prefixed integer + // size = 4100 ==> 0x7f, 0x85, 0x1f (7+) prefixed integer + private static readonly byte[] _literalHeaderName = new byte[] { 0x7f, 0x85, 0x1f } // 4100 + .Concat(_literalHeaderNameBytes) + .ToArray(); + private static readonly byte[] _headerNameHuffman = new byte[] { (byte)(0x80 | _headerNameHuffmanBytes.Length) } .Concat(_headerNameHuffmanBytes) .ToArray(); @@ -392,6 +403,101 @@ public void DecodesLiteralHeaderFieldNeverIndexed_IndexedName_OutOfRange_Error() Assert.Empty(_handler.DecodedHeaders); } + [Fact] + public void DecodesLiteralHeaderFieldNeverIndexed_NewName_SingleBuffer() + { + byte[] encoded = _literalHeaderFieldWithoutIndexingNewName + .Concat(_literalHeaderName) + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(encoded, endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderNameString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderNameString]); + } + + [Fact] + public void DecodesLiteralHeaderFieldNeverIndexed_NewName_NameLengthBrokenIntoSeparateBuffers() + { + byte[] encoded = _literalHeaderFieldWithoutIndexingNewName + .Concat(_literalHeaderName) + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(encoded[..1], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[1..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderNameString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderNameString]); + } + + [Fact] + public void DecodesLiteralHeaderFieldNeverIndexed_NewName_NameBrokenIntoSeparateBuffers() + { + byte[] encoded = _literalHeaderFieldWithoutIndexingNewName + .Concat(_literalHeaderName) + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(encoded[..(_literalHeaderNameString.Length / 2)], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[(_literalHeaderNameString.Length / 2)..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderNameString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderNameString]); + } + + [Fact] + public void DecodesLiteralHeaderFieldNeverIndexed_NewName_NameAndValueBrokenIntoSeparateBuffers() + { + byte[] encoded = _literalHeaderFieldWithoutIndexingNewName + .Concat(_literalHeaderName) + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(encoded[..^_headerValue.Length], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[^_headerValue.Length..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderNameString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderNameString]); + } + + [Fact] + public void DecodesLiteralHeaderFieldNeverIndexed_NewName_ValueLengthBrokenIntoSeparateBuffers() + { + byte[] encoded = _literalHeaderFieldWithoutIndexingNewName + .Concat(_literalHeaderName) + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(encoded[..^(_headerValue.Length - 1)], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[^(_headerValue.Length - 1)..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderNameString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderNameString]); + } + + [Fact] + public void DecodesLiteralHeaderFieldNeverIndexed_NewName_ValueBrokenIntoSeparateBuffers() + { + byte[] encoded = _literalHeaderFieldWithoutIndexingNewName + .Concat(_literalHeaderName) + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(encoded[..^(_headerValueString.Length / 2)], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[^(_headerValueString.Length / 2)..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderNameString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderNameString]); + } + [Fact] public void DecodesDynamicTableSizeUpdate() { diff --git a/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs b/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs index 475fddeab09bdf..8db70d84ee05e1 100644 --- a/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs +++ b/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs @@ -25,11 +25,11 @@ public class QPackDecoderTests // 4.5.4 - Literal Header Field With Name Reference - Static Table - Index 44 (content-type) private static readonly byte[] _literalHeaderFieldWithNameReferenceStatic = new byte[] { 0x5f, 0x1d }; - // 4.5.6 - Literal Field Line With Literal Name - (translate) - private static readonly byte[] _literalFieldLineWithLiteralName = new byte[] { 0x37, 0x02, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x65 }; + // 4.5.6 - Literal Field Line With Literal Name - (literal-header-field) + private static readonly byte[] _literalFieldLineWithLiteralName = new byte[] { 0x37, 0x0d, 0x6c, 0x69, 0x74, 0x65, 0x72, 0x61, 0x6c, 0x2d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2d, 0x66, 0x69, 0x65, 0x6c, 0x64 }; private const string _contentTypeString = "content-type"; - private const string _translateString = "translate"; + private const string _literalHeaderFieldString = "literal-header-field"; // n e w - h e a d e r * // 10101000 10111110 00010110 10011100 10100011 10010000 10110110 01111111 @@ -97,7 +97,7 @@ public void DecodesLiteralFieldLineWithLiteralName_Value() .Concat(_headerValue) .ToArray(); - TestDecodeWithoutIndexing(encoded, _translateString, _headerValueString); + TestDecodeWithoutIndexing(encoded, _literalHeaderFieldString, _headerValueString); } [Fact] @@ -140,7 +140,7 @@ public void DecodesLiteralFieldLineWithLiteralName_HuffmanEncodedValue() .Concat(_headerValueHuffman) .ToArray(); - TestDecodeWithoutIndexing(encoded, _translateString, _headerValueString); + TestDecodeWithoutIndexing(encoded, _literalHeaderFieldString, _headerValueString); } [Fact] @@ -173,6 +173,101 @@ public void DecodesLiteralFieldLineWithLiteralName_LargeValues() }); } + [Fact] + public void LiteralFieldWithoutNameReference_SingleBuffer() + { + byte[] encoded = _literalFieldLineWithLiteralName + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(new byte[] { 0x00, 0x00 }, endHeaders: false, handler: _handler); + _decoder.Decode(encoded, endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderFieldString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); + } + + [Fact] + public void LiteralFieldWithoutNameReference_NameLengthBrokenIntoSeparateBuffers() + { + byte[] encoded = _literalFieldLineWithLiteralName + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(new byte[] { 0x00, 0x00 }, endHeaders: false, handler: _handler); + _decoder.Decode(encoded[..1], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[1..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderFieldString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); + } + + [Fact] + public void LiteralFieldWithoutNameReference_NameBrokenIntoSeparateBuffers() + { + byte[] encoded = _literalFieldLineWithLiteralName + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(new byte[] { 0x00, 0x00 }, endHeaders: false, handler: _handler); + _decoder.Decode(encoded[..(_literalHeaderFieldString.Length / 2)], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[(_literalHeaderFieldString.Length / 2)..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderFieldString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); + } + + [Fact] + public void LiteralFieldWithoutNameReference_NameAndValueBrokenIntoSeparateBuffers() + { + byte[] encoded = _literalFieldLineWithLiteralName + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(new byte[] { 0x00, 0x00 }, endHeaders: false, handler: _handler); + _decoder.Decode(encoded[..^_headerValue.Length], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[^_headerValue.Length..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderFieldString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); + } + + [Fact] + public void LiteralFieldWithoutNameReference_ValueLengthBrokenIntoSeparateBuffers() + { + byte[] encoded = _literalFieldLineWithLiteralName + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(new byte[] { 0x00, 0x00 }, endHeaders: false, handler: _handler); + _decoder.Decode(encoded[..^(_headerValue.Length - 1)], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[^(_headerValue.Length - 1)..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderFieldString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); + } + + [Fact] + public void LiteralFieldWithoutNameReference_ValueBrokenIntoSeparateBuffers() + { + byte[] encoded = _literalFieldLineWithLiteralName + .Concat(_headerValue) + .ToArray(); + + _decoder.Decode(new byte[] { 0x00, 0x00 }, endHeaders: false, handler: _handler); + _decoder.Decode(encoded[..^(_headerValueString.Length / 2)], endHeaders: false, handler: _handler); + _decoder.Decode(encoded[^(_headerValueString.Length / 2)..], endHeaders: true, handler: _handler); + + Assert.Equal(1, _handler.DecodedHeaders.Count); + Assert.True(_handler.DecodedHeaders.ContainsKey(_literalHeaderFieldString)); + Assert.Equal(_headerValueString, _handler.DecodedHeaders[_literalHeaderFieldString]); + } + public static readonly TheoryData _incompleteHeaderBlockData = new TheoryData { // Incomplete header diff --git a/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/Microsoft.Extensions.Hosting.WindowsServices.csproj b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/Microsoft.Extensions.Hosting.WindowsServices.csproj index 86e6da3a39b766..4c8f143107caaa 100644 --- a/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/Microsoft.Extensions.Hosting.WindowsServices.csproj +++ b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/Microsoft.Extensions.Hosting.WindowsServices.csproj @@ -7,6 +7,8 @@ true .NET hosting infrastructure for Windows Services. true + true + 1 @@ -27,6 +29,7 @@ + diff --git a/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/WindowsServiceLifetime.cs b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/WindowsServiceLifetime.cs index 164e60670fb674..642f770591d39d 100644 --- a/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/WindowsServiceLifetime.cs +++ b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/WindowsServiceLifetime.cs @@ -15,8 +15,10 @@ namespace Microsoft.Extensions.Hosting.WindowsServices public class WindowsServiceLifetime : ServiceBase, IHostLifetime { private readonly TaskCompletionSource _delayStart = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + private readonly TaskCompletionSource _serviceDispatcherStopped = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); private readonly ManualResetEventSlim _delayStop = new ManualResetEventSlim(); private readonly HostOptions _hostOptions; + private bool _serviceStopRequested; public WindowsServiceLifetime(IHostEnvironment environment, IHostApplicationLifetime applicationLifetime, ILoggerFactory loggerFactory, IOptions optionsAccessor) : this(environment, applicationLifetime, loggerFactory, optionsAccessor, Options.Options.Create(new WindowsServiceLifetimeOptions())) @@ -69,19 +71,30 @@ private void Run() { Run(this); // This blocks until the service is stopped. _delayStart.TrySetException(new InvalidOperationException("Stopped without starting")); + _serviceDispatcherStopped.TrySetResult(null); } catch (Exception ex) { _delayStart.TrySetException(ex); + _serviceDispatcherStopped.TrySetException(ex); } } - public Task StopAsync(CancellationToken cancellationToken) + /// + /// Called from to stop the service if not already stopped, and wait for the service dispatcher to exit. + /// Once this method returns the service is stopped and the process can be terminated at any time. + /// + public async Task StopAsync(CancellationToken cancellationToken) { - // Avoid deadlock where host waits for StopAsync before firing ApplicationStopped, - // and Stop waits for ApplicationStopped. - Task.Run(Stop, CancellationToken.None); - return Task.CompletedTask; + cancellationToken.ThrowIfCancellationRequested(); + + if (!_serviceStopRequested) + { + await Task.Run(Stop, cancellationToken).ConfigureAwait(false); + } + + // When the underlying service is stopped this will cause the ServiceBase.Run method to complete and return, which completes _serviceDispatcherStopped. + await _serviceDispatcherStopped.Task.ConfigureAwait(false); } // Called by base.Run when the service is ready to start. @@ -91,18 +104,28 @@ protected override void OnStart(string[] args) base.OnStart(args); } - // Called by base.Stop. This may be called multiple times by service Stop, ApplicationStopping, and StopAsync. - // That's OK because StopApplication uses a CancellationTokenSource and prevents any recursion. + /// + /// Executes when a Stop command is sent to the service by the Service Control Manager (SCM). + /// Triggers and waits for . + /// Shortly after this method returns, the Service will be marked as stopped in SCM and the process may exit at any point. + /// protected override void OnStop() { + _serviceStopRequested = true; ApplicationLifetime.StopApplication(); // Wait for the host to shutdown before marking service as stopped. _delayStop.Wait(_hostOptions.ShutdownTimeout); base.OnStop(); } + /// + /// Executes when a Shutdown command is sent to the service by the Service Control Manager (SCM). + /// Triggers and waits for . + /// Shortly after this method returns, the Service will be marked as stopped in SCM and the process may exit at any point. + /// protected override void OnShutdown() { + _serviceStopRequested = true; ApplicationLifetime.StopApplication(); // Wait for the host to shutdown before marking service as stopped. _delayStop.Wait(_hostOptions.ShutdownTimeout); diff --git a/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/tests/Microsoft.Extensions.Hosting.WindowsServices.Tests.csproj b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/tests/Microsoft.Extensions.Hosting.WindowsServices.Tests.csproj index 93be9b87c967b5..ee433d9207d1d2 100644 --- a/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/tests/Microsoft.Extensions.Hosting.WindowsServices.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/tests/Microsoft.Extensions.Hosting.WindowsServices.Tests.csproj @@ -4,12 +4,45 @@ $(NetCoreAppCurrent)-windows;$(NetFrameworkMinimum) true + true + true + true + + + + + + + + + + + + + + + + diff --git a/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/tests/UseWindowsServiceTests.cs b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/tests/UseWindowsServiceTests.cs index 1fb2ade8a94079..4f1657ee2daa35 100644 --- a/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/tests/UseWindowsServiceTests.cs +++ b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/tests/UseWindowsServiceTests.cs @@ -2,9 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.IO; using System.Reflection; using System.ServiceProcess; +using Microsoft.DotNet.RemoteExecutor; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting.Internal; using Microsoft.Extensions.Hosting.WindowsServices; @@ -17,6 +17,8 @@ namespace Microsoft.Extensions.Hosting { public class UseWindowsServiceTests { + private static bool IsRemoteExecutorSupportedAndPrivilegedProcess => RemoteExecutor.IsSupported && AdminHelpers.IsProcessElevated(); + private static MethodInfo? _addWindowsServiceLifetimeMethod = null; [Fact] @@ -30,6 +32,26 @@ public void DefaultsToOffOutsideOfService() Assert.IsType(lifetime); } + [ConditionalFact(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] + public void CanCreateService() + { + using var serviceTester = WindowsServiceTester.Create(() => + { + using IHost host = new HostBuilder() + .UseWindowsService() + .Build(); + host.Run(); + }); + + serviceTester.Start(); + serviceTester.WaitForStatus(ServiceControllerStatus.Running); + serviceTester.Stop(); + serviceTester.WaitForStatus(ServiceControllerStatus.Stopped); + + var status = serviceTester.QueryServiceStatus(); + Assert.Equal(0, status.win32ExitCode); + } + [Fact] public void ServiceCollectionExtensionMethodDefaultsToOffOutsideOfService() { @@ -66,7 +88,7 @@ public void ServiceCollectionExtensionMethodSetsEventLogSourceNameToApplicationN var builder = new HostApplicationBuilder(new HostApplicationBuilderSettings { ApplicationName = appName, - }); + }); // Emulate calling builder.Services.AddWindowsService() from inside a Windows service. AddWindowsServiceLifetime(builder.Services); @@ -82,7 +104,7 @@ public void ServiceCollectionExtensionMethodSetsEventLogSourceNameToApplicationN [Fact] public void ServiceCollectionExtensionMethodCanBeCalledOnDefaultConfiguration() { - var builder = new HostApplicationBuilder(); + var builder = new HostApplicationBuilder(); // Emulate calling builder.Services.AddWindowsService() from inside a Windows service. AddWindowsServiceLifetime(builder.Services); diff --git a/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/tests/WindowsServiceLifetimeTests.cs b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/tests/WindowsServiceLifetimeTests.cs new file mode 100644 index 00000000000000..c060648b818e83 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/tests/WindowsServiceLifetimeTests.cs @@ -0,0 +1,352 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics; +using System.IO; +using System.ServiceProcess; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.DotNet.RemoteExecutor; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting.Internal; +using Microsoft.Extensions.Hosting.WindowsServices; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using Xunit; + +namespace Microsoft.Extensions.Hosting +{ + public class WindowsServiceLifetimeTests + { + private static bool IsRemoteExecutorSupportedAndPrivilegedProcess => RemoteExecutor.IsSupported && AdminHelpers.IsProcessElevated(); + + [ConditionalFact(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] + public void ServiceStops() + { + using var serviceTester = WindowsServiceTester.Create(async () => + { + var applicationLifetime = new ApplicationLifetime(NullLogger.Instance); + using var lifetime = new WindowsServiceLifetime( + new HostingEnvironment(), + applicationLifetime, + NullLoggerFactory.Instance, + new OptionsWrapper(new HostOptions())); + + await lifetime.WaitForStartAsync(CancellationToken.None); + + // would normally occur here, but WindowsServiceLifetime does not depend on it. + // applicationLifetime.NotifyStarted(); + + // will be signaled by WindowsServiceLifetime when SCM stops the service. + applicationLifetime.ApplicationStopping.WaitHandle.WaitOne(); + + // required by WindowsServiceLifetime to identify that app has stopped. + applicationLifetime.NotifyStopped(); + + await lifetime.StopAsync(CancellationToken.None); + }); + + serviceTester.Start(); + serviceTester.WaitForStatus(ServiceControllerStatus.Running); + + var statusEx = serviceTester.QueryServiceStatusEx(); + var serviceProcess = Process.GetProcessById(statusEx.dwProcessId); + + serviceTester.Stop(); + serviceTester.WaitForStatus(ServiceControllerStatus.Stopped); + + serviceProcess.WaitForExit(); + + var status = serviceTester.QueryServiceStatus(); + Assert.Equal(0, status.win32ExitCode); + } + + + [ConditionalFact(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] + [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, ".NET Framework is missing the fix from https://github.com/dotnet/corefx/commit/3e68d791066ad0fdc6e0b81828afbd9df00dd7f8")] + public void ExceptionOnStartIsPropagated() + { + using var serviceTester = WindowsServiceTester.Create(async () => + { + using (var lifetime = ThrowingWindowsServiceLifetime.Create(throwOnStart: new Exception("Should be thrown"))) + { + Assert.Equal(lifetime.ThrowOnStart, + await Assert.ThrowsAsync(async () => + await lifetime.WaitForStartAsync(CancellationToken.None))); + } + }); + + serviceTester.Start(); + + serviceTester.WaitForStatus(ServiceControllerStatus.Stopped); + var status = serviceTester.QueryServiceStatus(); + Assert.Equal(Interop.Errors.ERROR_EXCEPTION_IN_SERVICE, status.win32ExitCode); + } + + [ConditionalFact(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] + public void ExceptionOnStopIsPropagated() + { + using var serviceTester = WindowsServiceTester.Create(async () => + { + using (var lifetime = ThrowingWindowsServiceLifetime.Create(throwOnStop: new Exception("Should be thrown"))) + { + await lifetime.WaitForStartAsync(CancellationToken.None); + lifetime.ApplicationLifetime.NotifyStopped(); + Assert.Equal(lifetime.ThrowOnStop, + await Assert.ThrowsAsync(async () => + await lifetime.StopAsync(CancellationToken.None))); + } + }); + + serviceTester.Start(); + + serviceTester.WaitForStatus(ServiceControllerStatus.Stopped); + var status = serviceTester.QueryServiceStatus(); + Assert.Equal(Interop.Errors.ERROR_PROCESS_ABORTED, status.win32ExitCode); + } + + [ConditionalFact(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] + public void CancelStopAsync() + { + using var serviceTester = WindowsServiceTester.Create(async () => + { + var applicationLifetime = new ApplicationLifetime(NullLogger.Instance); + using var lifetime = new WindowsServiceLifetime( + new HostingEnvironment(), + applicationLifetime, + NullLoggerFactory.Instance, + new OptionsWrapper(new HostOptions())); + await lifetime.WaitForStartAsync(CancellationToken.None); + + await Assert.ThrowsAsync(async () => await lifetime.StopAsync(new CancellationToken(true))); + }); + + serviceTester.Start(); + + serviceTester.WaitForStatus(ServiceControllerStatus.Stopped); + var status = serviceTester.QueryServiceStatus(); + Assert.Equal(Interop.Errors.ERROR_PROCESS_ABORTED, status.win32ExitCode); + } + + + [ConditionalFact(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] + public void ServiceCanStopItself() + { + using (var serviceTester = WindowsServiceTester.Create(async () => + { + FileLogger.InitializeForTestCase(nameof(ServiceCanStopItself)); + using IHost host = new HostBuilder() + .ConfigureServices(services => + { + services.AddHostedService(); + services.AddSingleton(); + }) + .Build(); + + var applicationLifetime = host.Services.GetRequiredService(); + applicationLifetime.ApplicationStarted.Register(() => FileLogger.Log($"lifetime started")); + applicationLifetime.ApplicationStopping.Register(() => FileLogger.Log($"lifetime stopping")); + applicationLifetime.ApplicationStopped.Register(() => FileLogger.Log($"lifetime stopped")); + + FileLogger.Log("host.Start()"); + host.Start(); + + using (ServiceController selfController = new(nameof(ServiceCanStopItself))) + { + selfController.WaitForStatus(ServiceControllerStatus.Running, WindowsServiceTester.WaitForStatusTimeout); + Assert.Equal(ServiceControllerStatus.Running, selfController.Status); + + FileLogger.Log("host.Stop()"); + await host.StopAsync(); + FileLogger.Log("host.Stop() complete"); + + selfController.WaitForStatus(ServiceControllerStatus.Stopped, WindowsServiceTester.WaitForStatusTimeout); + Assert.Equal(ServiceControllerStatus.Stopped, selfController.Status); + } + })) + { + FileLogger.DeleteLog(nameof(ServiceCanStopItself)); + + // service should start cleanly + serviceTester.Start(); + + // service will proceed to stopped without any error + serviceTester.WaitForStatus(ServiceControllerStatus.Stopped); + + var status = serviceTester.QueryServiceStatus(); + Assert.Equal(0, status.win32ExitCode); + + } + + var logText = FileLogger.ReadLog(nameof(ServiceCanStopItself)); + Assert.Equal(""" + host.Start() + WindowsServiceLifetime.OnStart + BackgroundService.StartAsync + lifetime started + host.Stop() + lifetime stopping + BackgroundService.StopAsync + lifetime stopped + WindowsServiceLifetime.OnStop + host.Stop() complete + + """, logText); + } + + [ConditionalFact(nameof(IsRemoteExecutorSupportedAndPrivilegedProcess))] + public void ServiceSequenceIsCorrect() + { + using (var serviceTester = WindowsServiceTester.Create(() => + { + FileLogger.InitializeForTestCase(nameof(ServiceSequenceIsCorrect)); + using IHost host = new HostBuilder() + .ConfigureServices(services => + { + services.AddHostedService(); + services.AddSingleton(); + }) + .Build(); + + var applicationLifetime = host.Services.GetRequiredService(); + applicationLifetime.ApplicationStarted.Register(() => FileLogger.Log($"lifetime started")); + applicationLifetime.ApplicationStopping.Register(() => FileLogger.Log($"lifetime stopping")); + applicationLifetime.ApplicationStopped.Register(() => FileLogger.Log($"lifetime stopped")); + + FileLogger.Log("host.Run()"); + host.Run(); + FileLogger.Log("host.Run() complete"); + })) + { + + FileLogger.DeleteLog(nameof(ServiceSequenceIsCorrect)); + + serviceTester.Start(); + serviceTester.WaitForStatus(ServiceControllerStatus.Running); + + var statusEx = serviceTester.QueryServiceStatusEx(); + var serviceProcess = Process.GetProcessById(statusEx.dwProcessId); + + // Give a chance for all asynchronous "started" events to be raised, these happen after the service status changes to started + Thread.Sleep(1000); + + serviceTester.Stop(); + serviceTester.WaitForStatus(ServiceControllerStatus.Stopped); + + var status = serviceTester.QueryServiceStatus(); + Assert.Equal(0, status.win32ExitCode); + + } + + var logText = FileLogger.ReadLog(nameof(ServiceSequenceIsCorrect)); + Assert.Equal(""" + host.Run() + WindowsServiceLifetime.OnStart + BackgroundService.StartAsync + lifetime started + WindowsServiceLifetime.OnStop + lifetime stopping + BackgroundService.StopAsync + lifetime stopped + host.Run() complete + + """, logText); + + } + + public class LoggingWindowsServiceLifetime : WindowsServiceLifetime + { + public LoggingWindowsServiceLifetime(IHostEnvironment environment, IHostApplicationLifetime applicationLifetime, ILoggerFactory loggerFactory, IOptions optionsAccessor) : + base(environment, applicationLifetime, loggerFactory, optionsAccessor) + { } + + protected override void OnStart(string[] args) + { + FileLogger.Log("WindowsServiceLifetime.OnStart"); + base.OnStart(args); + } + + protected override void OnStop() + { + FileLogger.Log("WindowsServiceLifetime.OnStop"); + base.OnStop(); + } + } + + public class ThrowingWindowsServiceLifetime : WindowsServiceLifetime + { + public static ThrowingWindowsServiceLifetime Create(Exception throwOnStart = null, Exception throwOnStop = null) => + new ThrowingWindowsServiceLifetime( + new HostingEnvironment(), + new ApplicationLifetime(NullLogger.Instance), + NullLoggerFactory.Instance, + new OptionsWrapper(new HostOptions())) + { + ThrowOnStart = throwOnStart, + ThrowOnStop = throwOnStop + }; + + public ThrowingWindowsServiceLifetime(IHostEnvironment environment, ApplicationLifetime applicationLifetime, ILoggerFactory loggerFactory, IOptions optionsAccessor) : + base(environment, applicationLifetime, loggerFactory, optionsAccessor) + { + ApplicationLifetime = applicationLifetime; + } + + public ApplicationLifetime ApplicationLifetime { get; } + + public Exception ThrowOnStart { get; set; } + protected override void OnStart(string[] args) + { + if (ThrowOnStart != null) + { + throw ThrowOnStart; + } + base.OnStart(args); + } + + public Exception ThrowOnStop { get; set; } + protected override void OnStop() + { + if (ThrowOnStop != null) + { + throw ThrowOnStop; + } + base.OnStop(); + } + } + + public class LoggingBackgroundService : BackgroundService + { +#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously + protected override async Task ExecuteAsync(CancellationToken stoppingToken) => FileLogger.Log("BackgroundService.ExecuteAsync"); + public override async Task StartAsync(CancellationToken stoppingToken) => FileLogger.Log("BackgroundService.StartAsync"); + public override async Task StopAsync(CancellationToken stoppingToken) => FileLogger.Log("BackgroundService.StopAsync"); +#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously + } + + static class FileLogger + { + static string _fileName; + + public static void InitializeForTestCase(string testCaseName) + { + Assert.Null(_fileName); + _fileName = GetLogForTestCase(testCaseName); + } + + private static string GetLogForTestCase(string testCaseName) => Path.Combine(AppContext.BaseDirectory, $"{testCaseName}.log"); + public static void DeleteLog(string testCaseName) => File.Delete(GetLogForTestCase(testCaseName)); + public static string ReadLog(string testCaseName) => File.ReadAllText(GetLogForTestCase(testCaseName)); + public static void Log(string message) + { + Assert.NotNull(_fileName); + lock (_fileName) + { + File.AppendAllText(_fileName, message + Environment.NewLine); + } + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/tests/WindowsServiceTester.cs b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/tests/WindowsServiceTester.cs new file mode 100644 index 00000000000000..880fae3e0465a4 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/tests/WindowsServiceTester.cs @@ -0,0 +1,158 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.ServiceProcess; +using System.Threading.Tasks; +using Microsoft.DotNet.RemoteExecutor; +using Microsoft.Win32.SafeHandles; +using Xunit; + +namespace Microsoft.Extensions.Hosting +{ + public class WindowsServiceTester : ServiceController + { + private WindowsServiceTester(SafeServiceHandle serviceHandle, RemoteInvokeHandle remoteInvokeHandle, string serviceName) : base(serviceName) + { + _serviceHandle = serviceHandle; + _remoteInvokeHandle = remoteInvokeHandle; + } + + private SafeServiceHandle _serviceHandle; + private RemoteInvokeHandle _remoteInvokeHandle; + + public new void Start() + { + Start(Array.Empty()); + } + + public new void Start(string[] args) + { + base.Start(args); + + // get the process + _remoteInvokeHandle.Process.Dispose(); + _remoteInvokeHandle.Process = null; + + var statusEx = QueryServiceStatusEx(); + try + { + _remoteInvokeHandle.Process = Process.GetProcessById(statusEx.dwProcessId); + // fetch the process handle so that we can get the exit code later. + var _ = _remoteInvokeHandle.Process.SafeHandle; + } + catch (ArgumentException) + { } + } + + public static TimeSpan WaitForStatusTimeout { get; set; } = TimeSpan.FromSeconds(30); + + public new void WaitForStatus(ServiceControllerStatus desiredStatus) => + WaitForStatus(desiredStatus, WaitForStatusTimeout); + + public new void WaitForStatus(ServiceControllerStatus desiredStatus, TimeSpan timeout) + { + base.WaitForStatus(desiredStatus, timeout); + + Assert.Equal(Status, desiredStatus); + } + + // the following overloads are necessary to ensure the compiler will produce the correct signature from a lambda. + public static WindowsServiceTester Create(Func serviceMain, [CallerMemberName] string serviceName = null) => Create(RemoteExecutor.Invoke(serviceMain, remoteInvokeOptions), serviceName); + + public static WindowsServiceTester Create(Func> serviceMain, [CallerMemberName] string serviceName = null) => Create(RemoteExecutor.Invoke(serviceMain, remoteInvokeOptions), serviceName); + + public static WindowsServiceTester Create(Func serviceMain, [CallerMemberName] string serviceName = null) => Create(RemoteExecutor.Invoke(serviceMain, remoteInvokeOptions), serviceName); + + public static WindowsServiceTester Create(Action serviceMain, [CallerMemberName] string serviceName = null) => Create(RemoteExecutor.Invoke(serviceMain, remoteInvokeOptions), serviceName); + + private static RemoteInvokeOptions remoteInvokeOptions = new RemoteInvokeOptions() { Start = false }; + + private static WindowsServiceTester Create(RemoteInvokeHandle remoteInvokeHandle, string serviceName) + { + // create remote executor commandline arguments + var startInfo = remoteInvokeHandle.Process.StartInfo; + string commandLine = startInfo.FileName + " " + startInfo.Arguments; + + // install the service + using (var serviceManagerHandle = new SafeServiceHandle(Interop.Advapi32.OpenSCManager(null, null, Interop.Advapi32.ServiceControllerOptions.SC_MANAGER_ALL))) + { + if (serviceManagerHandle.IsInvalid) + { + throw new InvalidOperationException(); + } + + // delete existing service if it exists + using (var existingServiceHandle = new SafeServiceHandle(Interop.Advapi32.OpenService(serviceManagerHandle, serviceName, Interop.Advapi32.ServiceAccessOptions.ACCESS_TYPE_ALL))) + { + if (!existingServiceHandle.IsInvalid) + { + Interop.Advapi32.DeleteService(existingServiceHandle); + } + } + + var serviceHandle = new SafeServiceHandle( + Interop.Advapi32.CreateService(serviceManagerHandle, + serviceName, + $"{nameof(WindowsServiceTester)} {serviceName} test service", + Interop.Advapi32.ServiceAccessOptions.ACCESS_TYPE_ALL, + Interop.Advapi32.ServiceTypeOptions.SERVICE_WIN32_OWN_PROCESS, + (int)ServiceStartMode.Manual, + Interop.Advapi32.ServiceStartErrorModes.ERROR_CONTROL_NORMAL, + commandLine, + loadOrderGroup: null, + pTagId: IntPtr.Zero, + dependencies: null, + servicesStartName: null, + password: null)); + + if (serviceHandle.IsInvalid) + { + throw new Win32Exception(); + } + + return new WindowsServiceTester(serviceHandle, remoteInvokeHandle, serviceName); + } + } + + internal unsafe Interop.Advapi32.SERVICE_STATUS QueryServiceStatus() + { + Interop.Advapi32.SERVICE_STATUS status = default; + bool success = Interop.Advapi32.QueryServiceStatus(_serviceHandle, &status); + if (!success) + { + throw new Win32Exception(); + } + return status; + } + + internal unsafe Interop.Advapi32.SERVICE_STATUS_PROCESS QueryServiceStatusEx() + { + Interop.Advapi32.SERVICE_STATUS_PROCESS status = default; + bool success = Interop.Advapi32.QueryServiceStatusEx(_serviceHandle, &status); + if (!success) + { + throw new Win32Exception(); + } + return status; + } + + protected override void Dispose(bool disposing) + { + if (_remoteInvokeHandle != null) + { + _remoteInvokeHandle.Dispose(); + } + + if (!_serviceHandle.IsInvalid) + { + // delete the temporary test service + Interop.Advapi32.DeleteService(_serviceHandle); + _serviceHandle.Close(); + } + } + } +} diff --git a/src/libraries/Microsoft.NETCore.Platforms/src/Microsoft.NETCore.Platforms.csproj b/src/libraries/Microsoft.NETCore.Platforms/src/Microsoft.NETCore.Platforms.csproj index 7bcc94c575a494..67af62b2d7f296 100644 --- a/src/libraries/Microsoft.NETCore.Platforms/src/Microsoft.NETCore.Platforms.csproj +++ b/src/libraries/Microsoft.NETCore.Platforms/src/Microsoft.NETCore.Platforms.csproj @@ -24,8 +24,8 @@ <_generateRuntimeGraphTask>$([MSBuild]::NormalizePath('$(BaseOutputPath)', $(Configuration), '$(_generateRuntimeGraphTargetFramework)', '$(AssemblyName).dll')) $(AdditionalRuntimeIdentifiers);$(OutputRID) - 2 - false + 3 + true diff --git a/src/libraries/Microsoft.NETCore.Platforms/src/RID.cs b/src/libraries/Microsoft.NETCore.Platforms/src/RID.cs index 6457fd29cadf0e..b464d5f0f54e37 100644 --- a/src/libraries/Microsoft.NETCore.Platforms/src/RID.cs +++ b/src/libraries/Microsoft.NETCore.Platforms/src/RID.cs @@ -56,7 +56,7 @@ private enum RIDPart : int Max = Qualifier } - public static RID Parse(string runtimeIdentifier) + public static RID Parse(string runtimeIdentifier, bool noQualifier) { string[] parts = new string[(int)RIDPart.Max + 1]; bool omitVersionDelimiter = true; @@ -90,6 +90,15 @@ public static RID Parse(string runtimeIdentifier) // version might be omitted else if (current == ArchitectureDelimiter) { + // The qualifier delimiter and architecture delimiter are the same. + // When there is no qualifier, there will be one delimiter past the base part + // for the architecture. + // So if we see another delimiter later in the string (for the architecture), + // extend the base part instead of starting the architecture part. + if (noQualifier && runtimeIdentifier.IndexOf(ArchitectureDelimiter, i + 1) != -1) + { + break; + } // ensure there's no version later in the string if (runtimeIdentifier.IndexOf(VersionDelimiter, i) != -1) { diff --git a/src/libraries/Microsoft.NETCore.Platforms/src/RuntimeGroupCollection.cs b/src/libraries/Microsoft.NETCore.Platforms/src/RuntimeGroupCollection.cs index 447aa7239a844f..d233ec4a89c0bb 100644 --- a/src/libraries/Microsoft.NETCore.Platforms/src/RuntimeGroupCollection.cs +++ b/src/libraries/Microsoft.NETCore.Platforms/src/RuntimeGroupCollection.cs @@ -34,7 +34,8 @@ public RuntimeGroupCollection(ICollection runtimeGroups) /// public void AddRuntimeIdentifier(string runtimeIdentifier, string parent) { - RID rid = RID.Parse(runtimeIdentifier); + // don't parse qualifier since we don't use them and they are ambiguous with `-` in base RID + RID rid = RID.Parse(runtimeIdentifier, noQualifier: true); AddRuntimeIdentifier(rid, parent); } diff --git a/src/libraries/Microsoft.NETCore.Platforms/src/runtime.compatibility.json b/src/libraries/Microsoft.NETCore.Platforms/src/runtime.compatibility.json index d6676d4e0f57fc..9d4f4d19cc8702 100644 --- a/src/libraries/Microsoft.NETCore.Platforms/src/runtime.compatibility.json +++ b/src/libraries/Microsoft.NETCore.Platforms/src/runtime.compatibility.json @@ -1847,6 +1847,293 @@ "any", "base" ], + "alpine.3.18": [ + "alpine.3.18", + "alpine.3.17", + "alpine.3.16", + "alpine.3.15", + "alpine.3.14", + "alpine.3.13", + "alpine.3.12", + "alpine.3.11", + "alpine.3.10", + "alpine.3.9", + "alpine.3.8", + "alpine.3.7", + "alpine.3.6", + "alpine", + "linux-musl", + "linux", + "unix", + "any", + "base" + ], + "alpine.3.18-arm": [ + "alpine.3.18-arm", + "alpine.3.18", + "alpine.3.17-arm", + "alpine.3.17", + "alpine.3.16-arm", + "alpine.3.16", + "alpine.3.15-arm", + "alpine.3.15", + "alpine.3.14-arm", + "alpine.3.14", + "alpine.3.13-arm", + "alpine.3.13", + "alpine.3.12-arm", + "alpine.3.12", + "alpine.3.11-arm", + "alpine.3.11", + "alpine.3.10-arm", + "alpine.3.10", + "alpine.3.9-arm", + "alpine.3.9", + "alpine.3.8-arm", + "alpine.3.8", + "alpine.3.7-arm", + "alpine.3.7", + "alpine.3.6-arm", + "alpine.3.6", + "alpine-arm", + "alpine", + "linux-musl-arm", + "linux-musl", + "linux-arm", + "linux", + "unix-arm", + "unix", + "any", + "base" + ], + "alpine.3.18-arm64": [ + "alpine.3.18-arm64", + "alpine.3.18", + "alpine.3.17-arm64", + "alpine.3.17", + "alpine.3.16-arm64", + "alpine.3.16", + "alpine.3.15-arm64", + "alpine.3.15", + "alpine.3.14-arm64", + "alpine.3.14", + "alpine.3.13-arm64", + "alpine.3.13", + "alpine.3.12-arm64", + "alpine.3.12", + "alpine.3.11-arm64", + "alpine.3.11", + "alpine.3.10-arm64", + "alpine.3.10", + "alpine.3.9-arm64", + "alpine.3.9", + "alpine.3.8-arm64", + "alpine.3.8", + "alpine.3.7-arm64", + "alpine.3.7", + "alpine.3.6-arm64", + "alpine.3.6", + "alpine-arm64", + "alpine", + "linux-musl-arm64", + "linux-musl", + "linux-arm64", + "linux", + "unix-arm64", + "unix", + "any", + "base" + ], + "alpine.3.18-armv6": [ + "alpine.3.18-armv6", + "alpine.3.18", + "alpine.3.17-armv6", + "alpine.3.17", + "alpine.3.16-armv6", + "alpine.3.16", + "alpine.3.15-armv6", + "alpine.3.15", + "alpine.3.14-armv6", + "alpine.3.14", + "alpine.3.13-armv6", + "alpine.3.13", + "alpine.3.12-armv6", + "alpine.3.12", + "alpine.3.11-armv6", + "alpine.3.11", + "alpine.3.10-armv6", + "alpine.3.10", + "alpine.3.9-armv6", + "alpine.3.9", + "alpine.3.8-armv6", + "alpine.3.8", + "alpine.3.7-armv6", + "alpine.3.7", + "alpine.3.6-armv6", + "alpine.3.6", + "alpine-armv6", + "alpine", + "linux-musl-armv6", + "linux-musl", + "linux-armv6", + "linux", + "unix-armv6", + "unix", + "any", + "base" + ], + "alpine.3.18-ppc64le": [ + "alpine.3.18-ppc64le", + "alpine.3.18", + "alpine.3.17-ppc64le", + "alpine.3.17", + "alpine.3.16-ppc64le", + "alpine.3.16", + "alpine.3.15-ppc64le", + "alpine.3.15", + "alpine.3.14-ppc64le", + "alpine.3.14", + "alpine.3.13-ppc64le", + "alpine.3.13", + "alpine.3.12-ppc64le", + "alpine.3.12", + "alpine.3.11-ppc64le", + "alpine.3.11", + "alpine.3.10-ppc64le", + "alpine.3.10", + "alpine.3.9-ppc64le", + "alpine.3.9", + "alpine.3.8-ppc64le", + "alpine.3.8", + "alpine.3.7-ppc64le", + "alpine.3.7", + "alpine.3.6-ppc64le", + "alpine.3.6", + "alpine-ppc64le", + "alpine", + "linux-musl-ppc64le", + "linux-musl", + "linux-ppc64le", + "linux", + "unix-ppc64le", + "unix", + "any", + "base" + ], + "alpine.3.18-s390x": [ + "alpine.3.18-s390x", + "alpine.3.18", + "alpine.3.17-s390x", + "alpine.3.17", + "alpine.3.16-s390x", + "alpine.3.16", + "alpine.3.15-s390x", + "alpine.3.15", + "alpine.3.14-s390x", + "alpine.3.14", + "alpine.3.13-s390x", + "alpine.3.13", + "alpine.3.12-s390x", + "alpine.3.12", + "alpine.3.11-s390x", + "alpine.3.11", + "alpine.3.10-s390x", + "alpine.3.10", + "alpine.3.9-s390x", + "alpine.3.9", + "alpine.3.8-s390x", + "alpine.3.8", + "alpine.3.7-s390x", + "alpine.3.7", + "alpine.3.6-s390x", + "alpine.3.6", + "alpine-s390x", + "alpine", + "linux-musl-s390x", + "linux-musl", + "linux-s390x", + "linux", + "unix-s390x", + "unix", + "any", + "base" + ], + "alpine.3.18-x64": [ + "alpine.3.18-x64", + "alpine.3.18", + "alpine.3.17-x64", + "alpine.3.17", + "alpine.3.16-x64", + "alpine.3.16", + "alpine.3.15-x64", + "alpine.3.15", + "alpine.3.14-x64", + "alpine.3.14", + "alpine.3.13-x64", + "alpine.3.13", + "alpine.3.12-x64", + "alpine.3.12", + "alpine.3.11-x64", + "alpine.3.11", + "alpine.3.10-x64", + "alpine.3.10", + "alpine.3.9-x64", + "alpine.3.9", + "alpine.3.8-x64", + "alpine.3.8", + "alpine.3.7-x64", + "alpine.3.7", + "alpine.3.6-x64", + "alpine.3.6", + "alpine-x64", + "alpine", + "linux-musl-x64", + "linux-musl", + "linux-x64", + "linux", + "unix-x64", + "unix", + "any", + "base" + ], + "alpine.3.18-x86": [ + "alpine.3.18-x86", + "alpine.3.18", + "alpine.3.17-x86", + "alpine.3.17", + "alpine.3.16-x86", + "alpine.3.16", + "alpine.3.15-x86", + "alpine.3.15", + "alpine.3.14-x86", + "alpine.3.14", + "alpine.3.13-x86", + "alpine.3.13", + "alpine.3.12-x86", + "alpine.3.12", + "alpine.3.11-x86", + "alpine.3.11", + "alpine.3.10-x86", + "alpine.3.10", + "alpine.3.9-x86", + "alpine.3.9", + "alpine.3.8-x86", + "alpine.3.8", + "alpine.3.7-x86", + "alpine.3.7", + "alpine.3.6-x86", + "alpine.3.6", + "alpine-x86", + "alpine", + "linux-musl-x86", + "linux-musl", + "linux-x86", + "linux", + "unix-x86", + "unix", + "any", + "base" + ], "alpine.3.6": [ "alpine.3.6", "alpine", @@ -10455,6 +10742,71 @@ "any", "base" ], + "ubuntu.22.10": [ + "ubuntu.22.10", + "ubuntu", + "debian", + "linux", + "unix", + "any", + "base" + ], + "ubuntu.22.10-arm": [ + "ubuntu.22.10-arm", + "ubuntu.22.10", + "ubuntu-arm", + "ubuntu", + "debian-arm", + "debian", + "linux-arm", + "linux", + "unix-arm", + "unix", + "any", + "base" + ], + "ubuntu.22.10-arm64": [ + "ubuntu.22.10-arm64", + "ubuntu.22.10", + "ubuntu-arm64", + "ubuntu", + "debian-arm64", + "debian", + "linux-arm64", + "linux", + "unix-arm64", + "unix", + "any", + "base" + ], + "ubuntu.22.10-x64": [ + "ubuntu.22.10-x64", + "ubuntu.22.10", + "ubuntu-x64", + "ubuntu", + "debian-x64", + "debian", + "linux-x64", + "linux", + "unix-x64", + "unix", + "any", + "base" + ], + "ubuntu.22.10-x86": [ + "ubuntu.22.10-x86", + "ubuntu.22.10", + "ubuntu-x86", + "ubuntu", + "debian-x86", + "debian", + "linux-x86", + "linux", + "unix-x86", + "unix", + "any", + "base" + ], "ubuntu.23.04": [ "ubuntu.23.04", "ubuntu", @@ -10520,6 +10872,71 @@ "any", "base" ], + "ubuntu.23.10": [ + "ubuntu.23.10", + "ubuntu", + "debian", + "linux", + "unix", + "any", + "base" + ], + "ubuntu.23.10-arm": [ + "ubuntu.23.10-arm", + "ubuntu.23.10", + "ubuntu-arm", + "ubuntu", + "debian-arm", + "debian", + "linux-arm", + "linux", + "unix-arm", + "unix", + "any", + "base" + ], + "ubuntu.23.10-arm64": [ + "ubuntu.23.10-arm64", + "ubuntu.23.10", + "ubuntu-arm64", + "ubuntu", + "debian-arm64", + "debian", + "linux-arm64", + "linux", + "unix-arm64", + "unix", + "any", + "base" + ], + "ubuntu.23.10-x64": [ + "ubuntu.23.10-x64", + "ubuntu.23.10", + "ubuntu-x64", + "ubuntu", + "debian-x64", + "debian", + "linux-x64", + "linux", + "unix-x64", + "unix", + "any", + "base" + ], + "ubuntu.23.10-x86": [ + "ubuntu.23.10-x86", + "ubuntu.23.10", + "ubuntu-x86", + "ubuntu", + "debian-x86", + "debian", + "linux-x86", + "linux", + "unix-x86", + "unix", + "any", + "base" + ], "unix": [ "unix", "any", diff --git a/src/libraries/Microsoft.NETCore.Platforms/src/runtime.json b/src/libraries/Microsoft.NETCore.Platforms/src/runtime.json index c9dd91cf953fcb..73862a890c233e 100644 --- a/src/libraries/Microsoft.NETCore.Platforms/src/runtime.json +++ b/src/libraries/Microsoft.NETCore.Platforms/src/runtime.json @@ -423,6 +423,53 @@ "alpine.3.16-x86" ] }, + "alpine.3.18": { + "#import": [ + "alpine.3.17" + ] + }, + "alpine.3.18-arm": { + "#import": [ + "alpine.3.18", + "alpine.3.17-arm" + ] + }, + "alpine.3.18-arm64": { + "#import": [ + "alpine.3.18", + "alpine.3.17-arm64" + ] + }, + "alpine.3.18-armv6": { + "#import": [ + "alpine.3.18", + "alpine.3.17-armv6" + ] + }, + "alpine.3.18-ppc64le": { + "#import": [ + "alpine.3.18", + "alpine.3.17-ppc64le" + ] + }, + "alpine.3.18-s390x": { + "#import": [ + "alpine.3.18", + "alpine.3.17-s390x" + ] + }, + "alpine.3.18-x64": { + "#import": [ + "alpine.3.18", + "alpine.3.17-x64" + ] + }, + "alpine.3.18-x86": { + "#import": [ + "alpine.3.18", + "alpine.3.17-x86" + ] + }, "alpine.3.6": { "#import": [ "alpine" @@ -4016,6 +4063,35 @@ "ubuntu-x86" ] }, + "ubuntu.22.10": { + "#import": [ + "ubuntu" + ] + }, + "ubuntu.22.10-arm": { + "#import": [ + "ubuntu.22.10", + "ubuntu-arm" + ] + }, + "ubuntu.22.10-arm64": { + "#import": [ + "ubuntu.22.10", + "ubuntu-arm64" + ] + }, + "ubuntu.22.10-x64": { + "#import": [ + "ubuntu.22.10", + "ubuntu-x64" + ] + }, + "ubuntu.22.10-x86": { + "#import": [ + "ubuntu.22.10", + "ubuntu-x86" + ] + }, "ubuntu.23.04": { "#import": [ "ubuntu" @@ -4045,6 +4121,35 @@ "ubuntu-x86" ] }, + "ubuntu.23.10": { + "#import": [ + "ubuntu" + ] + }, + "ubuntu.23.10-arm": { + "#import": [ + "ubuntu.23.10", + "ubuntu-arm" + ] + }, + "ubuntu.23.10-arm64": { + "#import": [ + "ubuntu.23.10", + "ubuntu-arm64" + ] + }, + "ubuntu.23.10-x64": { + "#import": [ + "ubuntu.23.10", + "ubuntu-x64" + ] + }, + "ubuntu.23.10-x86": { + "#import": [ + "ubuntu.23.10", + "ubuntu-x86" + ] + }, "unix": { "#import": [ "any" diff --git a/src/libraries/Microsoft.NETCore.Platforms/src/runtimeGroups.props b/src/libraries/Microsoft.NETCore.Platforms/src/runtimeGroups.props index fed285b6bb2d03..c0d2977412fd35 100644 --- a/src/libraries/Microsoft.NETCore.Platforms/src/runtimeGroups.props +++ b/src/libraries/Microsoft.NETCore.Platforms/src/runtimeGroups.props @@ -17,7 +17,7 @@ linux-musl x64;x86;arm;armv6;arm64;s390x;ppc64le - 3.6;3.7;3.8;3.9;3.10;3.11;3.12;3.13;3.14;3.15;3.16;3.17 + 3.6;3.7;3.8;3.9;3.10;3.11;3.12;3.13;3.14;3.15;3.16;3.17;3.18 @@ -262,7 +262,7 @@ debian x64;x86;arm;arm64 - 16.04;16.10;17.04;17.10;18.04;18.10;19.04;19.10;20.04;20.10;21.04;21.10;22.04;23.04 + 16.04;16.10;17.04;17.10;18.04;18.10;19.04;19.10;20.04;20.10;21.04;21.10;22.04;22.10;23.04;23.10 false diff --git a/src/libraries/Microsoft.NETCore.Platforms/tests/RidTests.cs b/src/libraries/Microsoft.NETCore.Platforms/tests/RidTests.cs index 227bcbdd10d4db..8dee0ebeda17a4 100644 --- a/src/libraries/Microsoft.NETCore.Platforms/tests/RidTests.cs +++ b/src/libraries/Microsoft.NETCore.Platforms/tests/RidTests.cs @@ -10,35 +10,57 @@ public class RidTests { public static IEnumerable ValidRIDData() { - yield return new object[] { "win10-x64", new RID() { BaseRID = "win", OmitVersionDelimiter = true, Version = new RuntimeVersion("10"), Architecture = "x64" } }; - yield return new object[] { "win10", new RID() { BaseRID = "win", OmitVersionDelimiter = true, Version = new RuntimeVersion("10")} }; - yield return new object[] { "linux", new RID() { BaseRID = "linux" } }; - yield return new object[] { "linux-x64", new RID() { BaseRID = "linux", Architecture = "x64" } }; - yield return new object[] { "linux-x64", new RID() { BaseRID = "linux", Architecture = "x64" } }; - yield return new object[] { "debian.10-x64", new RID() { BaseRID = "debian", Version = new RuntimeVersion("10"), Architecture = "x64" } }; - yield return new object[] { "linuxmint.19.2-x64", new RID() { BaseRID = "linuxmint", Version = new RuntimeVersion("19.2"), Architecture = "x64" } }; - yield return new object[] { "ubuntu.14.04-x64", new RID() { BaseRID = "ubuntu", Version = new RuntimeVersion("14.04"), Architecture = "x64" } }; - yield return new object[] { "foo-bar.42-arm", new RID() { BaseRID = "foo-bar", Version = new RuntimeVersion("42"), Architecture = "arm" } }; - yield return new object[] { "foo-bar-arm", new RID() { BaseRID = "foo", Architecture = "bar", Qualifier = "arm" } }; // demonstrates ambiguity, avoid using `-` in base - yield return new object[] { "linux-musl-x64", new RID() { BaseRID = "linux", Architecture = "musl", Qualifier = "x64" } }; // yes, we already have ambiguous RIDs + yield return new object[] { "win10-x64", new RID() { BaseRID = "win", OmitVersionDelimiter = true, Version = new RuntimeVersion("10"), Architecture = "x64" }, null }; + yield return new object[] { "win10", new RID() { BaseRID = "win", OmitVersionDelimiter = true, Version = new RuntimeVersion("10")}, null }; + yield return new object[] { "linux", new RID() { BaseRID = "linux" }, null }; + yield return new object[] { "linux-x64", new RID() { BaseRID = "linux", Architecture = "x64" }, null }; + yield return new object[] { "linux-x64", new RID() { BaseRID = "linux", Architecture = "x64" }, null }; + yield return new object[] { "debian.10-x64", new RID() { BaseRID = "debian", Version = new RuntimeVersion("10"), Architecture = "x64" }, null }; + yield return new object[] { "linuxmint.19.2-x64", new RID() { BaseRID = "linuxmint", Version = new RuntimeVersion("19.2"), Architecture = "x64" }, null }; + yield return new object[] { "ubuntu.14.04-x64", new RID() { BaseRID = "ubuntu", Version = new RuntimeVersion("14.04"), Architecture = "x64" }, null }; + yield return new object[] { "foo-bar.42-arm", new RID() { BaseRID = "foo-bar", Version = new RuntimeVersion("42"), Architecture = "arm" }, null }; + yield return new object[] { "foo-bar-arm", new RID() { BaseRID = "foo", Architecture = "bar", Qualifier = "arm" }, // demonstrates ambiguity, avoid using `-` in base + new RID() { BaseRID = "foo-bar", Architecture = "arm" } }; + yield return new object[] { "linux-musl-x64", new RID() { BaseRID = "linux", Architecture = "musl", Qualifier = "x64" }, // yes, we already have ambiguous RIDs + new RID() { BaseRID = "linux-musl", Architecture = "x64" } }; } [Theory] [MemberData(nameof(ValidRIDData))] - internal void ParseCorrectly(string input, RID expected) + internal void ParseCorrectly(string input, RID expected, RID? expectedNoQualifier) { - RID actual = RID.Parse(input); + _ = expectedNoQualifier; // unused + + RID actual = RID.Parse(input, noQualifier: false); Assert.Equal(expected, actual); } [Theory] [MemberData(nameof(ValidRIDData))] - internal void ToStringAsExpected(string expected, RID rid) + internal void ParseCorrectlyNoQualifier(string input, RID expected, RID? expectedNoQualifier) + { + expectedNoQualifier ??= expected; + + RID actual = RID.Parse(input, noQualifier: true); + + Assert.Equal(expectedNoQualifier, actual); + } + + [Theory] + [MemberData(nameof(ValidRIDData))] + internal void ToStringAsExpected(string expected, RID rid, RID? expectedNoQualifierRid) { string actual = rid.ToString(); Assert.Equal(expected, actual); + + if (expectedNoQualifierRid is not null) + { + actual = expectedNoQualifierRid.ToString(); + + Assert.Equal(expected, actual); + } } } } diff --git a/src/libraries/Microsoft.Windows.Compatibility/src/Microsoft.Windows.Compatibility.csproj b/src/libraries/Microsoft.Windows.Compatibility/src/Microsoft.Windows.Compatibility.csproj index e314fc30744921..3a4b0455680c8d 100644 --- a/src/libraries/Microsoft.Windows.Compatibility/src/Microsoft.Windows.Compatibility.csproj +++ b/src/libraries/Microsoft.Windows.Compatibility/src/Microsoft.Windows.Compatibility.csproj @@ -6,7 +6,7 @@ false true true - 2 + 3 $(NoWarn);NU5128 This Windows Compatibility Pack provides access to APIs that were previously available only for .NET Framework. It can be used from both .NET as well as .NET Standard. diff --git a/src/libraries/System.Formats.Tar/tests/System.Formats.Tar.Tests.csproj b/src/libraries/System.Formats.Tar/tests/System.Formats.Tar.Tests.csproj index 831da89c1ea91a..ad1e7316f99462 100644 --- a/src/libraries/System.Formats.Tar/tests/System.Formats.Tar.Tests.csproj +++ b/src/libraries/System.Formats.Tar/tests/System.Formats.Tar.Tests.csproj @@ -13,6 +13,7 @@ + diff --git a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.CreateFromDirectoryAsync.File.Roundtrip.cs b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.CreateFromDirectoryAsync.File.Roundtrip.cs new file mode 100644 index 00000000000000..7908d459ced984 --- /dev/null +++ b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.CreateFromDirectoryAsync.File.Roundtrip.cs @@ -0,0 +1,80 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.IO; +using System.Threading.Tasks; +using Xunit; + +namespace System.Formats.Tar.Tests +{ + public class TarFile_CreateFromDirectoryAsync_Roundtrip_Tests : TarTestsBase + { + [ConditionalTheory(typeof(MountHelper), nameof(MountHelper.CanCreateSymbolicLinks))] + [InlineData("./file.txt", "subDirectory")] + [InlineData("../file.txt", "subDirectory")] + [InlineData("../file.txt", "subDirectory1/subDirectory1.1")] + [InlineData("./file.txt", "subDirectory1/subDirectory1.1")] + [InlineData("./file.txt", null)] + public async Task SymlinkRelativeTargets_InsideTheArchive_RoundtripsSuccessfully_Async(string symlinkTargetPath, string subDirectory) + { + using TempDirectory root = new TempDirectory(); + + string destinationArchive = Path.Join(root.Path, "destination.tar"); + + string sourceDirectoryName = Path.Join(root.Path, "baseDirectory"); + Directory.CreateDirectory(sourceDirectoryName); + + string destinationDirectoryName = Path.Join(root.Path, "destinationDirectory"); + Directory.CreateDirectory(destinationDirectoryName); + + string sourceSubDirectory = Path.Join(sourceDirectoryName, subDirectory); + if (subDirectory != null) Directory.CreateDirectory(sourceSubDirectory); + + File.Create(Path.Join(sourceDirectoryName, subDirectory, symlinkTargetPath)).Dispose(); + File.CreateSymbolicLink(Path.Join(sourceSubDirectory, "linkToFile"), symlinkTargetPath); + + await TarFile.CreateFromDirectoryAsync(sourceDirectoryName, destinationArchive, includeBaseDirectory: false); + + await using FileStream archiveStream = File.OpenRead(destinationArchive); + await TarFile.ExtractToDirectoryAsync(archiveStream, destinationDirectoryName, overwriteFiles: true); + + string destinationSubDirectory = Path.Join(destinationDirectoryName, subDirectory); + string symlinkPath = Path.Join(destinationSubDirectory, "linkToFile"); + Assert.True(File.Exists(symlinkPath)); + + FileInfo? fileInfo = new(symlinkPath); + Assert.Equal(symlinkTargetPath, fileInfo.LinkTarget); + + FileSystemInfo? symlinkTarget = File.ResolveLinkTarget(symlinkPath, returnFinalTarget: true); + Assert.True(File.Exists(symlinkTarget.FullName)); + } + + [ConditionalTheory(typeof(MountHelper), nameof(MountHelper.CanCreateSymbolicLinks))] + [InlineData("../file.txt", null)] + [InlineData("../../file.txt", "subDirectory")] + public async Task SymlinkRelativeTargets_OutsideTheArchive_Fails_Async(string symlinkTargetPath, string subDirectory) + { + using TempDirectory root = new TempDirectory(); + + string destinationArchive = Path.Join(root.Path, "destination.tar"); + + string sourceDirectoryName = Path.Join(root.Path, "baseDirectory"); + Directory.CreateDirectory(sourceDirectoryName); + + string destinationDirectoryName = Path.Join(root.Path, "destinationDirectory"); + Directory.CreateDirectory(destinationDirectoryName); + + string sourceSubDirectory = Path.Join(sourceDirectoryName, subDirectory); + if (subDirectory != null) Directory.CreateDirectory(sourceSubDirectory); + + File.CreateSymbolicLink(Path.Join(sourceSubDirectory, "linkToFile"), symlinkTargetPath); + + await TarFile.CreateFromDirectoryAsync(sourceDirectoryName, destinationArchive, includeBaseDirectory: false); + + using FileStream archiveStream = File.OpenRead(destinationArchive); + Exception exception = await Assert.ThrowsAsync(() => TarFile.ExtractToDirectoryAsync(archiveStream, destinationDirectoryName, overwriteFiles: true)); + + Assert.Equal(SR.Format(SR.TarExtractingResultsLinkOutside, symlinkTargetPath, destinationDirectoryName), exception.Message); + } + } +} diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs index 83f4ab8db11660..c5e8ce8860465a 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs @@ -229,7 +229,7 @@ private async Task GetStringAsyncCore(HttpRequestMessage request, Cancel } finally { - FinishSend(cts, disposeCts, telemetryStarted, responseContentTelemetryStarted); + FinishSend(response, cts, disposeCts, telemetryStarted, responseContentTelemetryStarted); } } @@ -308,7 +308,7 @@ private async Task GetByteArrayAsyncCore(HttpRequestMessage request, Can } finally { - FinishSend(cts, disposeCts, telemetryStarted, responseContentTelemetryStarted); + FinishSend(response, cts, disposeCts, telemetryStarted, responseContentTelemetryStarted); } } @@ -354,7 +354,7 @@ private async Task GetStreamAsyncCore(HttpRequestMessage request, Cancel } finally { - FinishSend(cts, disposeCts, telemetryStarted, responseContentTelemetryStarted: false); + FinishSend(response, cts, disposeCts, telemetryStarted, responseContentTelemetryStarted: false); } } @@ -498,7 +498,7 @@ public HttpResponseMessage Send(HttpRequestMessage request, HttpCompletionOption } finally { - FinishSend(cts, disposeCts, telemetryStarted, responseContentTelemetryStarted); + FinishSend(response, cts, disposeCts, telemetryStarted, responseContentTelemetryStarted); } } @@ -553,7 +553,7 @@ async Task Core( } finally { - FinishSend(cts, disposeCts, telemetryStarted, responseContentTelemetryStarted); + FinishSend(response, cts, disposeCts, telemetryStarted, responseContentTelemetryStarted); } } } @@ -585,8 +585,6 @@ private static bool ShouldBufferResponse(HttpCompletionOption completionOption, private void HandleFailure(Exception e, bool telemetryStarted, HttpResponseMessage? response, CancellationTokenSource cts, CancellationToken cancellationToken, CancellationTokenSource pendingRequestsCts) { - LogRequestFailed(telemetryStarted); - response?.Dispose(); Exception? toThrow = null; @@ -625,6 +623,8 @@ private void HandleFailure(Exception e, bool telemetryStarted, HttpResponseMessa e = toThrow = new OperationCanceledException(cancellationToken.IsCancellationRequested ? cancellationToken : cts.Token); } + LogRequestFailed(e, telemetryStarted); + if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(this, e); if (toThrow != null) @@ -644,7 +644,7 @@ private static bool StartSend(HttpRequestMessage request) return false; } - private static void FinishSend(CancellationTokenSource cts, bool disposeCts, bool telemetryStarted, bool responseContentTelemetryStarted) + private static void FinishSend(HttpResponseMessage? response, CancellationTokenSource cts, bool disposeCts, bool telemetryStarted, bool responseContentTelemetryStarted) { // Log completion. if (HttpTelemetry.Log.IsEnabled() && telemetryStarted) @@ -654,7 +654,7 @@ private static void FinishSend(CancellationTokenSource cts, bool disposeCts, boo HttpTelemetry.Log.ResponseContentStop(); } - HttpTelemetry.Log.RequestStop(); + HttpTelemetry.Log.RequestStop(response); } // Dispose of the CancellationTokenSource if it was created specially for this request diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpMessageInvoker.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpMessageInvoker.cs index a06da5b9ed5a27..ceb93c06a2aae2 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpMessageInvoker.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpMessageInvoker.cs @@ -41,18 +41,20 @@ public virtual HttpResponseMessage Send(HttpRequestMessage request, Cancellation { HttpTelemetry.Log.RequestStart(request); + HttpResponseMessage? response = null; try { - return _handler.Send(request, cancellationToken); + response = _handler.Send(request, cancellationToken); + return response; } - catch when (LogRequestFailed(telemetryStarted: true)) + catch (Exception ex) when (LogRequestFailed(ex, telemetryStarted: true)) { // Unreachable as LogRequestFailed will return false throw; } finally { - HttpTelemetry.Log.RequestStop(); + HttpTelemetry.Log.RequestStop(response); } } else @@ -78,18 +80,20 @@ static async Task SendAsyncWithTelemetry(HttpMessageHandler { HttpTelemetry.Log.RequestStart(request); + HttpResponseMessage? response = null; try { - return await handler.SendAsync(request, cancellationToken).ConfigureAwait(false); + response = await handler.SendAsync(request, cancellationToken).ConfigureAwait(false); + return response; } - catch when (LogRequestFailed(telemetryStarted: true)) + catch (Exception ex) when (LogRequestFailed(ex, telemetryStarted: true)) { // Unreachable as LogRequestFailed will return false throw; } finally { - HttpTelemetry.Log.RequestStop(); + HttpTelemetry.Log.RequestStop(response); } } } @@ -100,11 +104,11 @@ private static bool ShouldSendWithTelemetry(HttpRequestMessage request) => request.RequestUri is Uri requestUri && requestUri.IsAbsoluteUri; - internal static bool LogRequestFailed(bool telemetryStarted) + internal static bool LogRequestFailed(Exception exception, bool telemetryStarted) { if (HttpTelemetry.Log.IsEnabled() && telemetryStarted) { - HttpTelemetry.Log.RequestFailed(); + HttpTelemetry.Log.RequestFailed(exception); } return false; } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpTelemetry.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpTelemetry.cs index 131748bddf5a8c..d85862dbfb7825 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpTelemetry.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpTelemetry.cs @@ -50,18 +50,34 @@ public void RequestStart(HttpRequestMessage request) request.VersionPolicy); } - [Event(2, Level = EventLevel.Informational)] - public void RequestStop() + [NonEvent] + public void RequestStop(HttpResponseMessage? response) + { + RequestStop(response is null ? -1 : (int)response.StatusCode); + } + + [Event(2, Level = EventLevel.Informational, Version = 1)] + private void RequestStop(int statusCode) { Interlocked.Increment(ref _stoppedRequests); - WriteEvent(eventId: 2); + WriteEvent(eventId: 2, statusCode); } - [Event(3, Level = EventLevel.Error)] - public void RequestFailed() + [NonEvent] + public void RequestFailed(Exception exception) { Interlocked.Increment(ref _failedRequests); - WriteEvent(eventId: 3); + + if (IsEnabled(EventLevel.Error, EventKeywords.None)) + { + RequestFailed(exceptionMessage: exception.Message); + } + } + + [Event(3, Level = EventLevel.Error, Version = 1)] + private void RequestFailed(string exceptionMessage) + { + WriteEvent(eventId: 3, exceptionMessage); } [Event(4, Level = EventLevel.Informational)] @@ -112,10 +128,10 @@ public void ResponseHeadersStart() WriteEvent(eventId: 11); } - [Event(12, Level = EventLevel.Informational)] - public void ResponseHeadersStop() + [Event(12, Level = EventLevel.Informational, Version = 1)] + public void ResponseHeadersStop(int statusCode) { - WriteEvent(eventId: 12); + WriteEvent(eventId: 12, statusCode); } [Event(13, Level = EventLevel.Informational)] diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs index 7557ece3e264e0..89cacb066ece5b 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs @@ -1024,7 +1024,8 @@ public async Task ReadResponseHeadersAsync(CancellationToken cancellationToken) Debug.Assert(!wait); } - if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.ResponseHeadersStop(); + Debug.Assert(_response is not null); + if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.ResponseHeadersStop((int)_response.StatusCode); } catch { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs index 4d95a94488851d..56fe374b3bef2b 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs @@ -352,7 +352,7 @@ private async Task ReadResponseAsync(CancellationToken cancellationToken) _headerState = HeaderState.TrailingHeaders; - if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.ResponseHeadersStop(); + if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.ResponseHeadersStop((int)_response.StatusCode); } private async Task SendContentAsync(HttpContent content, CancellationToken cancellationToken) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs index d0bef3bc27a23a..95749c4fa950c1 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs @@ -666,7 +666,7 @@ public async Task SendAsyncCore(HttpRequestMessage request, ParseHeaderNameValue(this, line.Span, response, isFromTrailer: false); } - if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.ResponseHeadersStop(); + if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.ResponseHeadersStop((int)response.StatusCode); if (allowExpect100ToContinue != null) { diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/TelemetryTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/TelemetryTest.cs index 38785e38f45591..e3b79bd00d465e 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/TelemetryTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/TelemetryTest.cs @@ -6,7 +6,6 @@ using System.Diagnostics.Tracing; using System.IO; using System.Linq; -using System.Net.Quic; using System.Net.Test.Common; using System.Text; using System.Threading; @@ -412,14 +411,25 @@ private static void ValidateStartFailedStopEvents(ConcurrentQueue<(EventWrittenE Assert.Equal(count, starts.Length); (EventWrittenEventArgs Event, Guid ActivityId)[] stops = events.Where(e => e.Event.EventName == "RequestStop").ToArray(); - Assert.All(stops, stopEvent => Assert.Empty(stopEvent.Event.Payload)); + foreach (EventWrittenEventArgs stopEvent in stops.Select(e => e.Event)) + { + object payload = Assert.Single(stopEvent.Payload); + int statusCode = Assert.IsType(payload); + Assert.Equal(shouldHaveFailures ? -1 : 200, statusCode); + } ValidateSameActivityIds(starts, stops); (EventWrittenEventArgs Event, Guid ActivityId)[] failures = events.Where(e => e.Event.EventName == "RequestFailed").ToArray(); - Assert.All(failures, failedEvent => Assert.Empty(failedEvent.Event.Payload)); if (shouldHaveFailures) { + foreach (EventWrittenEventArgs failedEvent in failures.Select(e => e.Event)) + { + object payload = Assert.Single(failedEvent.Payload); + string exceptionMessage = Assert.IsType(payload); + Assert.Equal(new OperationCanceledException().Message, exceptionMessage); + } + ValidateSameActivityIds(starts, failures); } else @@ -470,8 +480,8 @@ private static void ValidateRequestResponseStartStopEvents(ConcurrentQueue<(Even foreach (EventWrittenEventArgs requestContentStop in requestContentStops.Select(e => e.Event)) { object payload = Assert.Single(requestContentStop.Payload); - Assert.True(payload is long); - Assert.Equal(requestContentLength.Value, (long)payload); + long contentLength = Assert.IsType(payload); + Assert.Equal(requestContentLength.Value, contentLength); } ValidateSameActivityIds(requestContentStarts, requestContentStops); @@ -482,7 +492,12 @@ private static void ValidateRequestResponseStartStopEvents(ConcurrentQueue<(Even (EventWrittenEventArgs Event, Guid ActivityId)[] responseHeadersStops = events.Where(e => e.Event.EventName == "ResponseHeadersStop").ToArray(); Assert.Equal(count, responseHeadersStops.Length); - Assert.All(responseHeadersStops, r => Assert.Empty(r.Event.Payload)); + foreach (EventWrittenEventArgs responseHeadersStop in responseHeadersStops.Select(e => e.Event)) + { + object payload = Assert.Single(responseHeadersStop.Payload); + int statusCode = Assert.IsType(payload); + Assert.Equal(200, statusCode); + } ValidateSameActivityIds(responseHeadersStarts, responseHeadersStops); diff --git a/src/libraries/System.Net.Http/tests/UnitTests/Fakes/HttpTelemetry.cs b/src/libraries/System.Net.Http/tests/UnitTests/Fakes/HttpTelemetry.cs index 5667687e632e2f..26ac057e31bd8d 100644 --- a/src/libraries/System.Net.Http/tests/UnitTests/Fakes/HttpTelemetry.cs +++ b/src/libraries/System.Net.Http/tests/UnitTests/Fakes/HttpTelemetry.cs @@ -11,9 +11,9 @@ public class HttpTelemetry public void RequestStart(HttpRequestMessage request) { } - public void RequestStop() { } + public void RequestStop(HttpResponseMessage response) { } - public void RequestFailed() { } + public void RequestFailed(Exception exception) { } public void ResponseContentStart() { } diff --git a/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj b/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj index 85139c5391ff85..0c06f6eb21f194 100644 --- a/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj +++ b/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj @@ -322,6 +322,8 @@ Link="HPack\HPackIntegerTest.cs" /> + @@ -393,8 +395,12 @@ Link="Common\System\Net\Http\aspnetcore\Http3\QPack\HeaderField.cs" /> + + if it has completed. Another delegate if OnCompleted was called before the operation could complete, /// in which case it's the delegate to invoke when the operation does complete. /// - private Action? _continuation; + private volatile Action? _continuation; private ExecutionContext? _executionContext; private object? _scheduler; /// Current token value given to a ValueTask and then verified against the value it passes back to us. @@ -1007,7 +1007,7 @@ protected override void OnCompleted(SocketAsyncEventArgs _) /// This instance. public ValueTask AcceptAsync(Socket socket, CancellationToken cancellationToken) { - Debug.Assert(Volatile.Read(ref _continuation) == null, "Expected null continuation to indicate reserved for use"); + Debug.Assert(_continuation == null, "Expected null continuation to indicate reserved for use"); if (socket.AcceptAsync(this, cancellationToken)) { @@ -1031,7 +1031,7 @@ public ValueTask AcceptAsync(Socket socket, CancellationToken cancellati /// This instance. public ValueTask ReceiveAsync(Socket socket, CancellationToken cancellationToken) { - Debug.Assert(Volatile.Read(ref _continuation) == null, "Expected null continuation to indicate reserved for use"); + Debug.Assert(_continuation == null, "Expected null continuation to indicate reserved for use"); if (socket.ReceiveAsync(this, cancellationToken)) { @@ -1051,7 +1051,7 @@ public ValueTask ReceiveAsync(Socket socket, CancellationToken cancellation public ValueTask ReceiveFromAsync(Socket socket, CancellationToken cancellationToken) { - Debug.Assert(Volatile.Read(ref _continuation) == null, "Expected null continuation to indicate reserved for use"); + Debug.Assert(_continuation == null, "Expected null continuation to indicate reserved for use"); if (socket.ReceiveFromAsync(this, cancellationToken)) { @@ -1072,7 +1072,7 @@ public ValueTask ReceiveFromAsync(Socket socket, Cancel public ValueTask ReceiveMessageFromAsync(Socket socket, CancellationToken cancellationToken) { - Debug.Assert(Volatile.Read(ref _continuation) == null, "Expected null continuation to indicate reserved for use"); + Debug.Assert(_continuation == null, "Expected null continuation to indicate reserved for use"); if (socket.ReceiveMessageFromAsync(this, cancellationToken)) { @@ -1097,7 +1097,7 @@ public ValueTask ReceiveMessageFromAsync(Socket /// This instance. public ValueTask SendAsync(Socket socket, CancellationToken cancellationToken) { - Debug.Assert(Volatile.Read(ref _continuation) == null, "Expected null continuation to indicate reserved for use"); + Debug.Assert(_continuation == null, "Expected null continuation to indicate reserved for use"); if (socket.SendAsync(this, cancellationToken)) { @@ -1117,7 +1117,7 @@ public ValueTask SendAsync(Socket socket, CancellationToken cancellationTok public ValueTask SendAsyncForNetworkStream(Socket socket, CancellationToken cancellationToken) { - Debug.Assert(Volatile.Read(ref _continuation) == null, "Expected null continuation to indicate reserved for use"); + Debug.Assert(_continuation == null, "Expected null continuation to indicate reserved for use"); if (socket.SendAsync(this, cancellationToken)) { @@ -1136,7 +1136,7 @@ public ValueTask SendAsyncForNetworkStream(Socket socket, CancellationToken canc public ValueTask SendPacketsAsync(Socket socket, CancellationToken cancellationToken) { - Debug.Assert(Volatile.Read(ref _continuation) == null, "Expected null continuation to indicate reserved for use"); + Debug.Assert(_continuation == null, "Expected null continuation to indicate reserved for use"); if (socket.SendPacketsAsync(this, cancellationToken)) { @@ -1155,7 +1155,7 @@ public ValueTask SendPacketsAsync(Socket socket, CancellationToken cancellationT public ValueTask SendToAsync(Socket socket, CancellationToken cancellationToken) { - Debug.Assert(Volatile.Read(ref _continuation) == null, "Expected null continuation to indicate reserved for use"); + Debug.Assert(_continuation == null, "Expected null continuation to indicate reserved for use"); if (socket.SendToAsync(this, cancellationToken)) { @@ -1175,7 +1175,7 @@ public ValueTask SendToAsync(Socket socket, CancellationToken cancellationT public ValueTask ConnectAsync(Socket socket) { - Debug.Assert(Volatile.Read(ref _continuation) == null, "Expected null continuation to indicate reserved for use"); + Debug.Assert(_continuation == null, "Expected null continuation to indicate reserved for use"); try { @@ -1201,7 +1201,7 @@ public ValueTask ConnectAsync(Socket socket) public ValueTask DisconnectAsync(Socket socket, CancellationToken cancellationToken) { - Debug.Assert(Volatile.Read(ref _continuation) == null, $"Expected null continuation to indicate reserved for use"); + Debug.Assert(_continuation == null, $"Expected null continuation to indicate reserved for use"); if (socket.DisconnectAsync(this, cancellationToken)) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs index 703738efbc3c94..1c8a6012ca99fa 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs @@ -46,24 +46,46 @@ private void RegisterCommandCallback() private void OnEventSourceCommand(object? sender, EventCommandEventArgs e) { - if (e.Command == EventCommand.Enable || e.Command == EventCommand.Update) - { - Debug.Assert(e.Arguments != null); + // Should only be enable or disable + Debug.Assert(e.Command == EventCommand.Enable || e.Command == EventCommand.Disable); - if (e.Arguments.TryGetValue("EventCounterIntervalSec", out string? valueStr) && float.TryParse(valueStr, out float value)) + lock (s_counterGroupLock) // Lock the CounterGroup + { + if (e.Command == EventCommand.Enable || e.Command == EventCommand.Update) { - lock (s_counterGroupLock) // Lock the CounterGroup + Debug.Assert(e.Arguments != null); + + if (!e.Arguments.TryGetValue("EventCounterIntervalSec", out string? valueStr) + || !float.TryParse(valueStr, out float intervalValue)) { - EnableTimer(value); + // Command is Enable but no EventCounterIntervalSec arg so ignore + return; } + + EnableTimer(intervalValue); } - } - else if (e.Command == EventCommand.Disable) - { - lock (s_counterGroupLock) + else if (e.Command == EventCommand.Disable) { - DisableTimer(); + // Since we allow sessions to send multiple Enable commands to update the interval, we cannot + // rely on ref counting to determine when to enable and disable counters. You will get an arbitrary + // number of Enables and one Disable per session. + // + // Previously we would turn off counters when we received any Disable command, but that meant that any + // session could turn off counters for all other sessions. To get to a good place we now will only + // turn off counters once the EventSource that provides the counters is disabled. We can then end up + // keeping counters on too long in certain circumstances - if one session enables counters, then a second + // session enables the EventSource but not counters we will stay on until both sessions terminate, even + // if the first session terminates first. + if (!_eventSource.IsEnabled()) + { + DisableTimer(); + } } + + Debug.Assert((s_counterGroupEnabledList == null && !_eventSource.IsEnabled()) + || (_eventSource.IsEnabled() && s_counterGroupEnabledList!.Contains(this)) + || (_pollingIntervalInMilliseconds == 0 && !s_counterGroupEnabledList!.Contains(this)) + || (!_eventSource.IsEnabled() && !s_counterGroupEnabledList!.Contains(this))); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs index e3737a8d0b3870..145a85264920c0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs @@ -2645,9 +2645,6 @@ internal void DoCommand(EventCommandEventArgs commandArgs) m_eventSourceEnabled = true; } - this.OnEventCommand(commandArgs); - this.m_eventCommandExecuted?.Invoke(this, commandArgs); - if (!commandArgs.enable) { // If we are disabling, maybe we can turn on 'quick checks' to filter @@ -2679,6 +2676,9 @@ internal void DoCommand(EventCommandEventArgs commandArgs) m_eventSourceEnabled = false; } } + + this.OnEventCommand(commandArgs); + this.m_eventCommandExecuted?.Invoke(this, commandArgs); } else { diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs index f6590136448336..c764b3b84a1026 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs @@ -55,21 +55,9 @@ public void Initialize(IncrementalGeneratorInitializationContext context) { // Collect all methods adorned with JSExportAttribute var attributedMethods = context.SyntaxProvider - .CreateSyntaxProvider( - static (node, ct) => ShouldVisitNode(node), - static (context, ct) => - { - MethodDeclarationSyntax syntax = (MethodDeclarationSyntax)context.Node; - if (context.SemanticModel.GetDeclaredSymbol(syntax, ct) is IMethodSymbol methodSymbol - && methodSymbol.GetAttributes().Any(static attribute => attribute.AttributeClass?.ToDisplayString() == Constants.JSExportAttribute)) - { - return new { Syntax = syntax, Symbol = methodSymbol }; - } - - return null; - }) - .Where( - static modelData => modelData is not null); + .ForAttributeWithMetadataName(Constants.JSExportAttribute, + static (node, ct) => node is MethodDeclarationSyntax, + static (context, ct) => new { Syntax = (MethodDeclarationSyntax)context.TargetNode, Symbol = (IMethodSymbol)context.TargetSymbol }); // Validate if attributed methods can have source generated var methodsWithDiagnostics = attributedMethods.Select(static (data, ct) => @@ -301,19 +289,6 @@ private static (MemberDeclarationSyntax, ImmutableArray) GenerateSou return (PrintGeneratedSource(incrementalContext.StubMethodSyntaxTemplate, incrementalContext.SignatureContext, wrapper, registration), incrementalContext.Diagnostics.AddRange(diagnostics.Diagnostics)); } - private static bool ShouldVisitNode(SyntaxNode syntaxNode) - { - // We only support C# method declarations. - if (syntaxNode.Language != LanguageNames.CSharp - || !syntaxNode.IsKind(SyntaxKind.MethodDeclaration)) - { - return false; - } - - // Filter out methods with no attributes early. - return ((MethodDeclarationSyntax)syntaxNode).AttributeLists.Count > 0; - } - private static Diagnostic? GetDiagnosticIfInvalidMethodForGeneration(MethodDeclarationSyntax methodSyntax, IMethodSymbol method) { // Verify the method has no generic types or defined implementation diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportGenerator.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportGenerator.cs index 1d4ef3812b6401..54b03ec734d589 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportGenerator.cs @@ -60,21 +60,9 @@ public void Initialize(IncrementalGeneratorInitializationContext context) { // Collect all methods adorned with JSImportAttribute var attributedMethods = context.SyntaxProvider - .CreateSyntaxProvider( - static (node, ct) => ShouldVisitNode(node), - static (context, ct) => - { - MethodDeclarationSyntax syntax = (MethodDeclarationSyntax)context.Node; - if (context.SemanticModel.GetDeclaredSymbol(syntax, ct) is IMethodSymbol methodSymbol - && methodSymbol.GetAttributes().Any(static attribute => attribute.AttributeClass?.ToDisplayString() == Constants.JSImportAttribute)) - { - return new { Syntax = syntax, Symbol = methodSymbol }; - } - - return null; - }) - .Where( - static modelData => modelData is not null); + .ForAttributeWithMetadataName(Constants.JSImportAttribute, + static (node, ct) => node is MethodDeclarationSyntax, + static (context, ct) => new { Syntax = (MethodDeclarationSyntax)context.TargetNode, Symbol = (IMethodSymbol)context.TargetSymbol }); // Validate if attributed methods can have source generated var methodsWithDiagnostics = attributedMethods.Select(static (data, ct) => @@ -304,19 +292,6 @@ private static (MemberDeclarationSyntax, ImmutableArray) GenerateSou return (PrintGeneratedSource(incrementalContext.StubMethodSyntaxTemplate, incrementalContext.SignatureContext, code), incrementalContext.Diagnostics.AddRange(diagnostics.Diagnostics)); } - private static bool ShouldVisitNode(SyntaxNode syntaxNode) - { - // We only support C# method declarations. - if (syntaxNode.Language != LanguageNames.CSharp - || !syntaxNode.IsKind(SyntaxKind.MethodDeclaration)) - { - return false; - } - - // Filter out methods with no attributes early. - return ((MethodDeclarationSyntax)syntaxNode).AttributeLists.Count > 0; - } - private static Diagnostic? GetDiagnosticIfInvalidMethodForGeneration(MethodDeclarationSyntax methodSyntax, IMethodSymbol method) { // Verify the method has no generic types or defined implementation diff --git a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs index 92f19a6b0c023e..d48880285c5e53 100644 --- a/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/ApplyUpdateTest.cs @@ -231,7 +231,6 @@ public void CustomAttributeDelete() }); } - [ActiveIssue("https://github.com/dotnet/runtime/issues/52993", TestRuntimes.Mono)] [ConditionalFact(typeof(ApplyUpdateUtil), nameof (ApplyUpdateUtil.IsSupported))] public void AsyncMethodChanges() { diff --git a/src/libraries/System.ServiceProcess.ServiceController/src/System.ServiceProcess.ServiceController.csproj b/src/libraries/System.ServiceProcess.ServiceController/src/System.ServiceProcess.ServiceController.csproj index 12e4831c2ee807..e976953653d338 100644 --- a/src/libraries/System.ServiceProcess.ServiceController/src/System.ServiceProcess.ServiceController.csproj +++ b/src/libraries/System.ServiceProcess.ServiceController/src/System.ServiceProcess.ServiceController.csproj @@ -5,8 +5,8 @@ $(NoWarn);CA2249 true - false - 0 + true + 1 Provides the System.ServiceProcess.ServiceContainer class, which allows you to connect to a running or stopped service, manipulate it, or get information about it. Commonly Used Types: diff --git a/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceBase.cs b/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceBase.cs index ddc3e2ea601c5f..59123a336ec3a2 100644 --- a/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceBase.cs +++ b/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceBase.cs @@ -31,6 +31,7 @@ public class ServiceBase : Component private bool _commandPropsFrozen; // set to true once we've use the Can... properties. private bool _disposed; private bool _initialized; + private object _stopLock = new object(); private EventLog? _eventLog; /// @@ -501,27 +502,34 @@ private void DeferredSessionChange(int eventType, int sessionId) // This is a problem when multiple services are hosted in a single process. private unsafe void DeferredStop() { - fixed (SERVICE_STATUS* pStatus = &_status) + lock (_stopLock) { - int previousState = _status.currentState; - - _status.checkPoint = 0; - _status.waitHint = 0; - _status.currentState = ServiceControlStatus.STATE_STOP_PENDING; - SetServiceStatus(_statusHandle, pStatus); - try + // never call SetServiceStatus again after STATE_STOPPED is set. + if (_status.currentState != ServiceControlStatus.STATE_STOPPED) { - OnStop(); - WriteLogEntry(SR.StopSuccessful); - _status.currentState = ServiceControlStatus.STATE_STOPPED; - SetServiceStatus(_statusHandle, pStatus); - } - catch (Exception e) - { - _status.currentState = previousState; - SetServiceStatus(_statusHandle, pStatus); - WriteLogEntry(SR.Format(SR.StopFailed, e), EventLogEntryType.Error); - throw; + fixed (SERVICE_STATUS* pStatus = &_status) + { + int previousState = _status.currentState; + + _status.checkPoint = 0; + _status.waitHint = 0; + _status.currentState = ServiceControlStatus.STATE_STOP_PENDING; + SetServiceStatus(_statusHandle, pStatus); + try + { + OnStop(); + WriteLogEntry(SR.StopSuccessful); + _status.currentState = ServiceControlStatus.STATE_STOPPED; + SetServiceStatus(_statusHandle, pStatus); + } + catch (Exception e) + { + _status.currentState = previousState; + SetServiceStatus(_statusHandle, pStatus); + WriteLogEntry(SR.Format(SR.StopFailed, e), EventLogEntryType.Error); + throw; + } + } } } } @@ -533,14 +541,17 @@ private unsafe void DeferredShutdown() OnShutdown(); WriteLogEntry(SR.ShutdownOK); - if (_status.currentState == ServiceControlStatus.STATE_PAUSED || _status.currentState == ServiceControlStatus.STATE_RUNNING) + lock (_stopLock) { - fixed (SERVICE_STATUS* pStatus = &_status) + if (_status.currentState == ServiceControlStatus.STATE_PAUSED || _status.currentState == ServiceControlStatus.STATE_RUNNING) { - _status.checkPoint = 0; - _status.waitHint = 0; - _status.currentState = ServiceControlStatus.STATE_STOPPED; - SetServiceStatus(_statusHandle, pStatus); + fixed (SERVICE_STATUS* pStatus = &_status) + { + _status.checkPoint = 0; + _status.waitHint = 0; + _status.currentState = ServiceControlStatus.STATE_STOPPED; + SetServiceStatus(_statusHandle, pStatus); + } } } } @@ -654,7 +665,7 @@ private void Initialize(bool multipleServices) { if (!_initialized) { - //Cannot register the service with NT service manatger if the object has been disposed, since finalization has been suppressed. + //Cannot register the service with NT service manager if the object has been disposed, since finalization has been suppressed. if (_disposed) throw new ObjectDisposedException(GetType().Name); @@ -923,8 +934,14 @@ public unsafe void ServiceMainCallback(int argCount, IntPtr argPointer) { string errorMessage = new Win32Exception().Message; WriteLogEntry(SR.Format(SR.StartFailed, errorMessage), EventLogEntryType.Error); - _status.currentState = ServiceControlStatus.STATE_STOPPED; - SetServiceStatus(_statusHandle, pStatus); + lock (_stopLock) + { + if (_status.currentState != ServiceControlStatus.STATE_STOPPED) + { + _status.currentState = ServiceControlStatus.STATE_STOPPED; + SetServiceStatus(_statusHandle, pStatus); + } + } } } } diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/TimerQueue.Browser.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/TimerQueue.Browser.Mono.cs index 153783fa1707c0..06298a30fc3acd 100644 --- a/src/mono/System.Private.CoreLib/src/System/Threading/TimerQueue.Browser.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Threading/TimerQueue.Browser.Mono.cs @@ -65,7 +65,7 @@ private bool SetTimer(uint actualDuration) // shortest time of all TimerQueues private static void ReplaceNextSetTimeout(long shortestDueTimeMs, long currentTimeMs) { - if (shortestDueTimeMs == int.MaxValue) + if (shortestDueTimeMs == long.MaxValue) { return; } @@ -85,7 +85,7 @@ private static long ShortestDueTime() { if (s_scheduledTimers == null) { - return int.MaxValue; + return long.MaxValue; } long shortestDueTimeMs = long.MaxValue; @@ -112,7 +112,7 @@ private static long PumpTimerQueue(long currentTimeMs) List timersToFire = s_scheduledTimersToFire!; List timers; timers = s_scheduledTimers!; - long shortestDueTimeMs = int.MaxValue; + long shortestDueTimeMs = long.MaxValue; for (int i = timers.Count - 1; i >= 0; --i) { TimerQueue timer = timers[i]; diff --git a/src/mono/mono/metadata/metadata.c b/src/mono/mono/metadata/metadata.c index 057c4c3a802acf..50948c060061ba 100644 --- a/src/mono/mono/metadata/metadata.c +++ b/src/mono/mono/metadata/metadata.c @@ -7003,18 +7003,26 @@ mono_class_get_overrides_full (MonoImage *image, guint32 type_token, MonoMethod if (num_overrides) *num_overrides = 0; - if (!tdef->base) + if (!tdef->base && !image->has_updates) return; loc.t = tdef; loc.col_idx = MONO_METHODIMPL_CLASS; loc.idx = mono_metadata_token_index (type_token); + loc.result = 0; - /* FIXME metadata-update */ - - if (!mono_binary_search (&loc, tdef->base, table_info_get_rows (tdef), tdef->row_size, table_locator)) + gboolean found = tdef->base && mono_binary_search (&loc, tdef->base, table_info_get_rows (tdef), tdef->row_size, table_locator) != NULL; + if (!found && !image->has_updates) return; + if (G_UNLIKELY (image->has_updates)) { + if (!found && !mono_metadata_update_metadata_linear_search (image, tdef, &loc, table_locator)) { + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_METADATA_UPDATE, "NO Found interfaces for class 0x%08x", type_token); + return; + } + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_METADATA_UPDATE, "Found interfaces for class 0x%08x starting at 0x%08x", type_token, loc.result); + } + start = loc.result; end = start + 1; /* @@ -7026,7 +7034,7 @@ mono_class_get_overrides_full (MonoImage *image, guint32 type_token, MonoMethod else break; } - guint32 rows = table_info_get_rows (tdef); + guint32 rows = mono_metadata_table_num_rows (image, MONO_TABLE_METHODIMPL); while (end < rows) { if (loc.idx == mono_metadata_decode_row_col (tdef, end, MONO_METHODIMPL_CLASS)) end++; diff --git a/src/mono/mono/metadata/native-library.c b/src/mono/mono/metadata/native-library.c index e89a741752f2af..fc35c3723b02ca 100644 --- a/src/mono/mono/metadata/native-library.c +++ b/src/mono/mono/metadata/native-library.c @@ -532,15 +532,23 @@ netcore_probe_for_module (MonoImage *image, const char *file_name, int flags, Mo // If the difference becomes a problem, overhaul this algorithm to match theirs exactly ERROR_DECL (bad_image_error); + gboolean probe_first_without_prepend = FALSE; #if defined(HOST_ANDROID) // On Android, try without any path additions first. It is sensitive to probing that will always miss // and lookup for some libraries is required to use a relative path - module = netcore_probe_for_module_variations (NULL, file_name, lflags, error); - if (!module && !is_ok (error) && mono_error_get_error_code (error) == MONO_ERROR_BAD_IMAGE) - mono_error_move (bad_image_error, error); + probe_first_without_prepend = TRUE; +#else + if (file_name != NULL && g_path_is_absolute (file_name)) + probe_first_without_prepend = TRUE; #endif + if (module == NULL && probe_first_without_prepend) { + module = netcore_probe_for_module_variations (NULL, file_name, lflags, error); + if (!module && !is_ok (error) && mono_error_get_error_code (error) == MONO_ERROR_BAD_IMAGE) + mono_error_move (bad_image_error, error); + } + // Check the NATIVE_DLL_SEARCH_DIRECTORIES for (int i = 0; i < pinvoke_search_directories_count && module == NULL; ++i) { mono_error_cleanup (error); @@ -563,15 +571,13 @@ netcore_probe_for_module (MonoImage *image, const char *file_name, int flags, Mo g_free (mdirname); } -#if !defined(HOST_ANDROID) - // Try without any path additions - if (module == NULL) + // Try without any path additions, if we didn't try it already + if (module == NULL && !probe_first_without_prepend) { module = netcore_probe_for_module_variations (NULL, file_name, lflags, error); if (!module && !is_ok (error) && mono_error_get_error_code (error) == MONO_ERROR_BAD_IMAGE) mono_error_move (bad_image_error, error); } -#endif // TODO: Pass remaining flags on to LoadLibraryEx on Windows where appropriate, see https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.dllimportsearchpath?view=netcore-3.1 diff --git a/src/mono/mono/utils/mono-os-mutex.h b/src/mono/mono/utils/mono-os-mutex.h index 30f914b0893a29..20055973f81cf8 100644 --- a/src/mono/mono/utils/mono-os-mutex.h +++ b/src/mono/mono/utils/mono-os-mutex.h @@ -36,7 +36,7 @@ #if !defined(HOST_WIN32) -#if !defined(CLOCK_MONOTONIC) || defined(HOST_DARWIN) || defined(HOST_WASM) +#if !defined(CLOCK_MONOTONIC) || defined(HOST_DARWIN) || defined(HOST_WASI) #define BROKEN_CLOCK_SOURCE #endif diff --git a/src/mono/mono/utils/mono-time.c b/src/mono/mono/utils/mono-time.c index 68831393bc7c34..2a89bd9d3d0772 100644 --- a/src/mono/mono/utils/mono-time.c +++ b/src/mono/mono/utils/mono-time.c @@ -119,9 +119,10 @@ gint64 mono_msec_boottime (void) { /* clock_gettime () is found by configure on Apple builds, but its only present from ios 10, macos 10.12, tvos 10 and watchos 3 */ -#if !defined (TARGET_WASM) && ((defined(HAVE_CLOCK_MONOTONIC_COARSE) || defined(HAVE_CLOCK_MONOTONIC)) && !(defined(TARGET_IOS) || defined(TARGET_OSX) || defined(TARGET_WATCHOS) || defined(TARGET_TVOS))) +#if ((defined(HAVE_CLOCK_MONOTONIC_COARSE) || defined(HAVE_CLOCK_MONOTONIC)) && !(defined(TARGET_IOS) || defined(TARGET_OSX) || defined(TARGET_WATCHOS) || defined(TARGET_TVOS))) clockid_t clockType = -#if HAVE_CLOCK_MONOTONIC_COARSE + /* emscripten exposes CLOCK_MONOTONIC_COARSE but doesn't implement it */ +#if defined(HAVE_CLOCK_MONOTONIC_COARSE) && !defined(TARGET_WASM) CLOCK_MONOTONIC_COARSE; /* good enough resolution, fastest speed */ #else CLOCK_MONOTONIC; diff --git a/src/native/corehost/apphost/static/CMakeLists.txt b/src/native/corehost/apphost/static/CMakeLists.txt index c37885bf5691ce..a632d993c0f2a1 100644 --- a/src/native/corehost/apphost/static/CMakeLists.txt +++ b/src/native/corehost/apphost/static/CMakeLists.txt @@ -65,8 +65,8 @@ if(CLR_CMAKE_TARGET_WIN32) add_linker_flag("/DEF:${CMAKE_CURRENT_SOURCE_DIR}/singlefilehost.def") else() - if(CLR_CMAKE_TARGET_OSX) - set(DEF_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/singlefilehost_OSXexports.src) + if(CLR_CMAKE_TARGET_FREEBSD) + set(DEF_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/singlefilehost_freebsdexports.src) else() set(DEF_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/singlefilehost_unixexports.src) endif() diff --git a/src/native/corehost/apphost/static/singlefilehost_OSXexports.src b/src/native/corehost/apphost/static/singlefilehost_freebsdexports.src similarity index 81% rename from src/native/corehost/apphost/static/singlefilehost_OSXexports.src rename to src/native/corehost/apphost/static/singlefilehost_freebsdexports.src index 18d5697e84580e..1f9c5178218555 100644 --- a/src/native/corehost/apphost/static/singlefilehost_OSXexports.src +++ b/src/native/corehost/apphost/static/singlefilehost_freebsdexports.src @@ -9,3 +9,7 @@ g_dacTable ; Used by profilers MetaDataGetDispenser + +; FreeBSD needs to reexport these +__progname +environ diff --git a/src/native/corehost/apphost/static/singlefilehost_unixexports.src b/src/native/corehost/apphost/static/singlefilehost_unixexports.src index 1f9c5178218555..18d5697e84580e 100644 --- a/src/native/corehost/apphost/static/singlefilehost_unixexports.src +++ b/src/native/corehost/apphost/static/singlefilehost_unixexports.src @@ -9,7 +9,3 @@ g_dacTable ; Used by profilers MetaDataGetDispenser - -; FreeBSD needs to reexport these -__progname -environ diff --git a/src/tests/issues.targets b/src/tests/issues.targets index db7896e9d99325..aa3693e3f715c9 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -3587,6 +3587,9 @@ needs triage + + Loads an assembly from file + Loads an assembly from file