MSMPI 10.0
Signed-off-by: Jithin Jose <jijos@microsoft.com>
This commit is contained in:
Родитель
9c79e0ec6a
Коммит
df55333afa
Двоичный файл не отображается.
|
@ -0,0 +1,158 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project InitialTargets="ShowCBTParseErrors;RestoreCBTModules" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Ensures that if this file changes, projects will be rebuilt -->
|
||||
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||
|
||||
<EnlistmentRoot Condition=" '$(EnlistmentRoot)' != '' ">$(EnlistmentRoot.TrimEnd('\\'))</EnlistmentRoot>
|
||||
|
||||
<!-- Default CBT global to this directory if not specified -->
|
||||
<CBTGlobalPath Condition=" '$(CBTGlobalPath)' == '' ">$(MSBuildThisFileDirectory)</CBTGlobalPath>
|
||||
<CBTGlobalPath>$(CBTGlobalPath.TrimEnd('\\'))</CBTGlobalPath>
|
||||
|
||||
<!-- Default CBT local to ..\Local if not specified -->
|
||||
<CBTLocalPath Condition=" '$(CBTLocalPath)' == '' And Exists('$([System.IO.Path]::GetDirectoryName($(CBTGlobalPath)))\Local') ">$([System.IO.Path]::GetDirectoryName($(CBTGlobalPath)))\Local</CBTLocalPath>
|
||||
<CBTLocalPath>$(CBTLocalPath.TrimEnd('\\'))</CBTLocalPath>
|
||||
|
||||
<CBTLocalBuildExtensionsPath Condition=" '$(CBTLocalBuildExtensionsPath)' == '' And '$(CBTLocalPath)' != '' And Exists('$(CBTLocalPath)\Extensions') ">$(CBTLocalPath)\Extensions</CBTLocalBuildExtensionsPath>
|
||||
|
||||
<DefaultProjectConfiguration Condition=" '$(DefaultProjectConfiguration)' == '' ">Debug</DefaultProjectConfiguration>
|
||||
<Configuration Condition=" '$(Configuration)' == '' And '$(DefaultProjectConfiguration)' != '' ">$(DefaultProjectConfiguration)</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' And '$(DefaultProjectPlatform)' != '' ">$(DefaultProjectPlatform)</Platform>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(CBTLocalBuildExtensionsPath)\Before.$(MSBuildThisFile)" Condition=" '$(CBTLocalBuildExtensionsPath)' != '' And Exists('$(CBTLocalBuildExtensionsPath)\Before.$(MSBuildThisFile)') " />
|
||||
|
||||
<PropertyGroup>
|
||||
<CBTModulePackageConfigPath Condition=" '$(CBTModulePackageConfigPath)' == '' And '$(CBTLocalPath)' != '' And Exists('$(CBTLocalPath)\CBTModules\CBTModules.proj') ">$([System.IO.Path]::Combine($(CBTLocalPath), 'CBTModules', 'CBTModules.proj'))</CBTModulePackageConfigPath>
|
||||
<CBTModulePackageConfigPath Condition=" '$(CBTModulePackageConfigPath)' == '' And '$(CBTLocalPath)' != '' And Exists('$(CBTLocalPath)\CBTModules.proj') ">$([System.IO.Path]::Combine($(CBTLocalPath), 'CBTModules.proj'))</CBTModulePackageConfigPath>
|
||||
<CBTModulePackageConfigPath Condition=" '$(CBTModulePackageConfigPath)' == '' And '$(CBTLocalPath)' != '' And Exists('$(CBTLocalPath)\CBTModules\packages.config') ">$([System.IO.Path]::Combine($(CBTLocalPath), 'CBTModules', 'packages.config'))</CBTModulePackageConfigPath>
|
||||
<CBTModulePackageConfigPath Condition=" '$(CBTModulePackageConfigPath)' == '' And '$(CBTLocalPath)' != '' And Exists('$(CBTLocalPath)\packages.config') ">$([System.IO.Path]::Combine($(CBTLocalPath), 'packages.config'))</CBTModulePackageConfigPath>
|
||||
<CBTModulePackageConfigPath Condition=" '$(CBTModulePackageConfigPath)' != '' ">$([System.IO.Path]::GetFullPath($(CBTModulePackageConfigPath)))</CBTModulePackageConfigPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<CBTCoreAssemblyPath Condition=" '$(CBTCoreAssemblyPath)' == '' ">$(MSBuildThisFileDirectory)CBT.Core.dll</CBTCoreAssemblyPath>
|
||||
<CBTModuleRestoreInputs Condition=" '$(CBTModuleRestoreInputs)' == '' ">$(MSBuildThisFileFullPath);$(CBTCoreAssemblyPath);$(CBTModulePackageConfigPath)</CBTModuleRestoreInputs>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Load modules -->
|
||||
|
||||
<PropertyGroup Condition=" '$(EnlistmentRoot)' != '' And '$(CBTModulePackageConfigPath)' != '' ">
|
||||
<CBTIntermediateOutputPath Condition=" '$(CBTIntermediateOutputPath)' == '' ">$(MSBuildThisFileDirectory)obj</CBTIntermediateOutputPath>
|
||||
|
||||
<CBTModulePath Condition=" '$(CBTModulePath)' == '' ">$(CBTIntermediateOutputPath)\Modules</CBTModulePath>
|
||||
<CBTModulePropertiesFile Condition=" '$(CBTModulePropertiesFile)' == '' ">$(CBTModulePath)\$(MSBuildThisFile)</CBTModulePropertiesFile>
|
||||
<CBTModuleExtensionsPath Condition=" '$(CBTModuleExtensionsPath)' == '' ">$(CBTModulePath)\Extensions</CBTModuleExtensionsPath>
|
||||
<CBTModuleImportsBefore Condition=" '$(CBTModuleImportsBefore)' == '' ">%24(CBTLocalBuildExtensionsPath)\%24(MSBuildThisFile)</CBTModuleImportsBefore>
|
||||
<CBTModuleImportsAfter Condition=" '$(CBTModuleImportsAfter)' == '' "></CBTModuleImportsAfter>
|
||||
|
||||
<CBTNuGetBinDir Condition=" '$(CBTNuGetBinDir)' == '' ">$(CBTIntermediateOutputPath)\NuGet</CBTNuGetBinDir>
|
||||
<CBTNuGetDownloaderAssemblyPath Condition=" '$(CBTNuGetDownloaderAssemblyPath)' == '' ">$(CBTCoreAssemblyPath)</CBTNuGetDownloaderAssemblyPath>
|
||||
<CBTNuGetDownloaderClassName Condition=" '$(CBTNuGetDownloaderClassName)' == '' ">CBT.Core.Internal.DefaultNuGetDownloader</CBTNuGetDownloaderClassName>
|
||||
<CBTModuleRestoreTaskName Condition=" '$(CBTModuleRestoreTaskName)' == '' ">CBT.Core.Tasks.RestoreModules</CBTModuleRestoreTaskName>
|
||||
<CBTModuleRestoreCommand Condition=" '$(CBTModuleRestoreCommand)' == '' ">$(CBTNuGetBinDir)\NuGet.exe</CBTModuleRestoreCommand>
|
||||
<CBTModuleRestoreCommandArguments Condition=" '$(CBTModuleRestoreCommandArguments)' == '' ">restore "$(CBTModulePackageConfigPath)" -NonInteractive</CBTModuleRestoreCommandArguments>
|
||||
<CBTModuleRestoreCommandArguments Condition=" '$(CBTModuleRestoreCommandAdditionalArguments)' != '' ">$(CBTModuleRestoreCommandArguments) $(CBTModuleRestoreCommandAdditionalArguments)</CBTModuleRestoreCommandArguments>
|
||||
|
||||
<!-- Do not restore CBT modules when NuGet is evaluating CBTModules.proj. -->
|
||||
<RestoreCBTModules Condition=" $(RestoreGraphProjectInput.Contains($(CBTModulePackageConfigPath))) ">false</RestoreCBTModules>
|
||||
<!--
|
||||
Evaluating this property loads CBT.Core.dll as a byte[] and stores the result in the AppDomain via SetData(). This is the only way we could find to load an assembly from bytes and be able to access it in a later call.
|
||||
Normally when assemblies are loaded with this context, other calls can't reuse the loaded assembly. Since the Assembly object is stored in the data of the AppDomain, subsequent calls can access via the GetData() method.
|
||||
The condition on this property also ensures that the Assembly is only loaded once per AppDomain and since property evaluation is single threaded we don't have to worry about synchronization. Another piece of this
|
||||
property is that the the SetData() method returns void so immediately after SetData() we call GetData() which returns the Assembly and the property evaluates to something like:
|
||||
"CBT.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
|
||||
If the CBTCoreAssemblyName property has a value then we know we were able to successfully load the assembly.
|
||||
|
||||
The most complicated part of this call is how to get an object[] to pass to the ReadAllBytes() method. MSBuild coerces the arguments to a method but creating a populated object[] with one call is not possible. By calling
|
||||
System.IO.Directory.GetFiles(), we are returned a string[] which MSBuild coerces to an object[] to ReadAllBytes().
|
||||
-->
|
||||
<CBTCoreAssemblyName Condition=" Exists('$(CBTCoreAssemblyPath)') And '$(CBTCoreAssemblyPath.GetType().Assembly.GetType(`System.AppDomain`).GetProperty(`CurrentDomain`).GetValue(null).GetData(`CBT_CORE_ASSEMBLY`))' == '' ">$(CBTCoreAssemblyPath.GetType().Assembly.GetType('System.AppDomain').GetProperty('CurrentDomain').GetValue(null).SetData('CBT_CORE_ASSEMBLY', $(CBTCoreAssemblyPath.GetType().Assembly.GetType('System.AppDomain').GetProperty('CurrentDomain').GetValue(null).Load($(CBTCoreAssemblyPath.GetType().Assembly.GetType('System.IO.File').GetMethod('ReadAllBytes').Invoke(null, $([System.IO.Directory]::GetFiles($([System.IO.Path]::GetDirectoryName($(CBTCoreAssemblyPath))), $([System.IO.Path]::GetFileName($(CBTCoreAssemblyPath)))))))))))</CBTCoreAssemblyName>
|
||||
<CBTCoreAssemblyName>$(CBTCoreAssemblyPath.GetType().Assembly.GetType('System.AppDomain').GetProperty('CurrentDomain').GetValue(null).GetData('CBT_CORE_ASSEMBLY'))</CBTCoreAssemblyName>
|
||||
<CBTModulesRestored Condition=" '$(RestoreCBTModules)' != 'false' And '$(BuildingInsideVisualStudio)' != 'true' And '$(CBTModulesRestored)' != 'true' And '$(CBTCoreAssemblyName)' != '' ">$(CBTCoreAssemblyPath.GetType().Assembly.GetType('System.AppDomain').GetProperty('CurrentDomain').GetValue(null).GetData('CBT_CORE_ASSEMBLY').CreateInstance($(CBTModuleRestoreTaskName)).Execute($(CBTModuleImportsAfter.Split(';')), $(CBTModuleImportsBefore.Split(';')), $(CBTModuleExtensionsPath), $(CBTModulePropertiesFile), $(CBTNuGetDownloaderAssemblyPath), $(CBTNuGetDownloaderClassName), '$(CBTNuGetDownloaderArguments)', $(CBTModuleRestoreInputs.Split(';')), $(CBTModulePackageConfigPath), $(CBTModuleRestoreCommand), $(CBTModuleRestoreCommandArguments), $(MSBuildProjectFullPath), $(MSBuildBinPath)))</CBTModulesRestored>
|
||||
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<CBTParseError Condition=" '$(EnlistmentRoot)' == '' " Include="The 'EnlistmentRoot' property must be set. Please ensure it is declared in a properties file before CBT Core is imported.">
|
||||
<Code>CBT1000</Code>
|
||||
</CBTParseError>
|
||||
<CBTParseError Condition=" '$(CBTModulesRestored)' == 'false' " Include="Modules were not restored and the build cannot continue. Refer to other errors for more information.">
|
||||
<Code>CBT1001</Code>
|
||||
</CBTParseError>
|
||||
<CBTParseError Condition=" '$(CBTModulePackageConfigPath)' == '' " Include="The CBT module configuration file packages.config or CBTModules.proj was not found under $(CBTLocalPath) or $(CBTLocalPath)\CBTModules. Please add a CBT module package configuration file or set the property 'CBTModulePackageConfigPath' to your custom location.">
|
||||
<Code>CBT1002</Code>
|
||||
</CBTParseError>
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="$(CBTModulePropertiesFile)" Condition=" ('$(CBTModulesRestored)' == 'true' Or '$(BuildingInsideVisualStudio)' == 'true') And Exists('$(CBTModulePropertiesFile)') "/>
|
||||
|
||||
<UsingTask TaskName="RestoreModules" AssemblyFile="$(CBTCoreAssemblyPath)" />
|
||||
<UsingTask TaskName="WriteModuleRestoreInfo" AssemblyFile="$(CBTCoreAssemblyPath)" />
|
||||
|
||||
<Target Name="ShowCBTParseErrors" Condition=" '@(CBTParseError)' != '' ">
|
||||
<Error Text="%(CBTParseError.Identity)" Code="%(CBTParseError.Code)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="RestoreCBTModules"
|
||||
Condition=" '$(RestoreCBTModules)' != 'false' And '$(CBTModulesRestored)' != 'true' "
|
||||
Inputs="$(CBTModuleRestoreInputs)"
|
||||
Outputs="$([MSBuild]::ValueOrDefault($(CBTModulePropertiesFile), 'null'))">
|
||||
|
||||
<RestoreModules
|
||||
AfterImports="$(CBTModuleImportsAfter.Split(';'))"
|
||||
BeforeImports="$(CBTModuleImportsBefore.Split(';'))"
|
||||
ExtensionsPath="$(CBTModuleExtensionsPath)"
|
||||
ImportsFile="$(CBTModulePropertiesFile)"
|
||||
MSBuildBinPath="$(MSBuildBinPath)"
|
||||
NuGetDownloaderAssemblyPath="$(CBTNuGetDownloaderAssemblyPath)"
|
||||
NuGetDownloaderClassName="$(CBTNuGetDownloaderClassName)"
|
||||
NuGetDownloaderArguments="$(CBTNuGetDownloaderArguments)"
|
||||
PackageConfig="$(CBTModulePackageConfigPath)"
|
||||
ProjectFullPath="$(MSBuildProjectFullPath)"
|
||||
RestoreCommand="$(CBTModuleRestoreCommand)"
|
||||
RestoreCommandArguments="$(CBTModuleRestoreCommandArguments)"
|
||||
/>
|
||||
|
||||
<PropertyGroup>
|
||||
<CBTModulesRestored Condition=" '$(CBTModulesRestored)' != 'true' ">true</CBTModulesRestored>
|
||||
</PropertyGroup>
|
||||
|
||||
<MSBuild Projects="$(MSBuildProjectFullPath)"
|
||||
Targets="CBTDesignTimeBuild"
|
||||
Properties="DesignTimeBuild=$(DesignTimeBuild);BuildingProject=$(BuildingProject);BuildingInsideVisualStudio=$(BuildingInsideVisualStudio);CBTModulesRestored=$(CBTModulesRestored)"
|
||||
Condition=" '$(CBTModulesRestored)' == 'true' And '$(BuildingInsideVisualStudio)' == 'true' "
|
||||
/>
|
||||
|
||||
</Target>
|
||||
|
||||
<!-- _GenerateRestoreProjectSpec is a from the nuget.targets new to NuGet 4.x. -->
|
||||
<Target Name="GenerateModuleRestoreInfo" AfterTargets="_GenerateRestoreProjectSpec" Condition=" '$(RestoreOutputAbsolutePath)' != '' And '$(MSBuildProjectFullPath)' == '$(CBTModulePackageConfigPath)' " >
|
||||
<ItemGroup>
|
||||
<CBTModuleRestoreInfo Remove="@(CBTModuleRestoreInfo)"/>
|
||||
<CBTModuleRestoreInfo Include="ProjectJsonPath">
|
||||
<value>$(_CurrentProjectJsonPath)</value>
|
||||
</CBTModuleRestoreInfo>
|
||||
<CBTModuleRestoreInfo Include="RestoreProjectStyle">
|
||||
<value>$(RestoreProjectStyle)</value>
|
||||
<value Condition=" '$(RestoreProjectStyle)' == '' " >$(NuGetProjectStyle)</value>
|
||||
</CBTModuleRestoreInfo>
|
||||
<CBTModuleRestoreInfo Include="RestoreOutputAbsolutePath">
|
||||
<value>$(RestoreOutputAbsolutePath)</value>
|
||||
</CBTModuleRestoreInfo>
|
||||
<CBTModuleRestoreInfo Include="PackageReference">
|
||||
<id>%(PackageReference.Identity)</id>
|
||||
<version>%(PackageReference.Version)</version>
|
||||
</CBTModuleRestoreInfo>
|
||||
</ItemGroup>
|
||||
<WriteModuleRestoreInfo File="$(CBTModuleRestoreInfoFile)" Input="@(CBTModuleRestoreInfo)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CBTDesignTimeBuild" DependsOnTargets="$(CBTDesignTimeBuildDependsOn)" />
|
||||
|
||||
<Import Project="$(CBTLocalBuildExtensionsPath)\After.$(MSBuildThisFile)" Condition=" '$(CBTLocalBuildExtensionsPath)' != '' And Exists('$(CBTLocalBuildExtensionsPath)\After.$(MSBuildThisFile)') " />
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net46</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<!--
|
||||
*******************************************************************************************************************
|
||||
This file contains the CBT modules that you want to use. Modules are standard NuGet packages that apply to the
|
||||
whole project tree rather than on a per-project basis. Modules provide extensions to your build in a centralized
|
||||
way and act as a replacement of having to check-in all of the build logic.
|
||||
|
||||
Modules include build extensions such as:
|
||||
|
||||
1. Analyzing source code and/or build output
|
||||
2. Assembly versioning
|
||||
3. Policy enforcement
|
||||
4. Strong-name signing of build output
|
||||
|
||||
To find more modules, use "NuGet.exe list CBT.*" or browse a list at http://commonbuildtoolset.github.io
|
||||
*******************************************************************************************************************
|
||||
-->
|
||||
|
||||
<ItemGroup>
|
||||
<!--
|
||||
*******************************************************************************************************************
|
||||
CBT.Traversal module provides the build logic to have a dirs.proj which defines the projects you want built in a
|
||||
hosted build environment. Use this module if you want more control over your official build output and are willing
|
||||
to move away from Visual Studio solution files.
|
||||
*******************************************************************************************************************
|
||||
-->
|
||||
<PackageReference Include="CBT.Traversal" Version="2.0.53" />
|
||||
|
||||
<!--
|
||||
*******************************************************************************************************************
|
||||
CBT.NuGet module provides NuGet package restore from the command-line prior to build. This allows users to not
|
||||
have to restore before building a project tree. This is mostly useful for hosted builds which run from a command-
|
||||
line environment rather than Visual Studio.
|
||||
*******************************************************************************************************************
|
||||
-->
|
||||
<PackageReference Include="CBT.NuGet" Version="2.2.2" />
|
||||
|
||||
<!--
|
||||
*******************************************************************************************************************
|
||||
CBT.DotNetFx provides the .NET Framework reference assemblies so that users do not have to have them installed to
|
||||
build your projects. When using this module, be sure to include ALL of the versions of the target frameworks that
|
||||
your projects use. For example, if your projects target .NET 4.5 and .NET 4.6, you'll need to include both of the
|
||||
corresponding modules.
|
||||
|
||||
By default build packages are disabled when added to the cbtmodules project.
|
||||
To use any build package globally it must be enabled for the code base.
|
||||
Do this by setting Enable#NuGetPackageID# where the . is replaced with _.
|
||||
Example add this property to your Directory.Build.props for the CBT.DotNetFx-net46 package.
|
||||
<EnableCBT_DotNetFx-net46>true</EnableCBT_DotNetFx-net46>
|
||||
*******************************************************************************************************************
|
||||
-->
|
||||
<PackageReference Include="CBT.DotNetFx-net46" Version="1.0.0-beta01" />
|
||||
|
||||
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
COPYRIGHT
|
||||
|
||||
The following is a notice of limited availability of the code, and disclaimer
|
||||
which must be included in the prologue of the code and in all source listings
|
||||
of the code.
|
||||
|
||||
Copyright Notice
|
||||
+ 2002 University of Chicago
|
||||
|
||||
Permission is hereby granted to use, reproduce, prepare derivative works, and
|
||||
to redistribute to others. This software was authored by:
|
||||
|
||||
Argonne National Laboratory Group
|
||||
W. Gropp: (630) 252-4318; FAX: (630) 252-5986; e-mail: gropp@mcs.anl.gov
|
||||
E. Lusk: (630) 252-7852; FAX: (630) 252-5986; e-mail: lusk@mcs.anl.gov
|
||||
Mathematics and Computer Science Division
|
||||
Argonne National Laboratory, Argonne IL 60439
|
||||
|
||||
|
||||
GOVERNMENT LICENSE
|
||||
|
||||
Portions of this material resulted from work developed under a U.S.
|
||||
Government Contract and are subject to the following license: the Government
|
||||
is granted for itself and others acting on its behalf a paid-up, nonexclusive,
|
||||
irrevocable worldwide license in this computer software to reproduce, prepare
|
||||
derivative works, and perform publicly and display publicly.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This computer code material was prepared, in part, as an account of work
|
||||
sponsored by an agency of the United States Government. Neither the United
|
||||
States, nor the University of Chicago, nor any of their employees, makes any
|
||||
warranty express or implied, or assumes any legal liability or responsibility
|
||||
for the accuracy, completeness, or usefulness of any information, apparatus,
|
||||
product, or process disclosed, or represents that its use would not infringe
|
||||
privately owned rights.
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,190 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
This root MSBuild file should be imported by all projects in the tree and serves as the central entry point for CBT.
|
||||
You can have a hierarchy of imports but make sure that this file is still imported.
|
||||
-->
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Label="Global locations">
|
||||
<!--
|
||||
$(MSBuildAllProjects) is a list of files that determine if a project is up-to-date or not. By including this
|
||||
file in the list, it ensures that all projects will be rebuilt if it changes.
|
||||
-->
|
||||
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||
|
||||
<!--
|
||||
Enlistment root is based off of wherever this file is. Be sure not to set this property anywhere else.
|
||||
-->
|
||||
<EnlistmentRoot>$(MSBuildThisFileDirectory.TrimEnd('\\'))</EnlistmentRoot>
|
||||
<NuGetPackagesPath Condition=" '$(NuGetPackagesPath)' == '' ">$(EnlistmentRoot)\packages</NuGetPackagesPath>
|
||||
|
||||
<!--
|
||||
Enable CBT.DotNetFx-net452 build package to be used globally
|
||||
-->
|
||||
<!-- <EnableCBT_DotNetFx-net452>true</EnableCBT_DotNetFx-net452> -->
|
||||
<!--
|
||||
Set a default TargetFrameworkVersion if needed
|
||||
<TargetFrameworkVersion Condition=" '$(TargetFrameworkVersion)' == '' ">v4.5.2</TargetFrameworkVersion>
|
||||
-->
|
||||
</PropertyGroup>
|
||||
|
||||
<!--
|
||||
StyleCop.json and Code Analysis Custom Dictionary settings
|
||||
-->
|
||||
<ItemGroup Condition="Exists('$(SRCROOT)\stylecop.json') and Exists('$(SRCROOT)\CustomDictionary.xml')" >
|
||||
<AdditionalFiles Include="$(SRCROOT)\stylecop.json" />
|
||||
<CodeAnalysisDictionary Include="$(SRCROOT)\CustomDictionary.xml">
|
||||
<Link>CustomDictionary.xml</Link>
|
||||
</CodeAnalysisDictionary>
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<RunCodeAnalysis>False</RunCodeAnalysis>
|
||||
<CodeAnalysisSummary>true</CodeAnalysisSummary>
|
||||
<CodeAnalysisTimeout>300</CodeAnalysisTimeout>
|
||||
<CodeAnalysisTreatWarningsAsErrors>false</CodeAnalysisTreatWarningsAsErrors>
|
||||
<CodeAnalysisSearchGlobalAssemblyCache>false</CodeAnalysisSearchGlobalAssemblyCache>
|
||||
</PropertyGroup>
|
||||
|
||||
<!--
|
||||
Nuproj ProjectReference dependency assembly resolution
|
||||
-->
|
||||
<PropertyGroup Condition=" '$(MSBuildProjectExtension)' != '.nuproj' And !Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.targets\ImportAfter\Microsoft.Common.NuProj.targets') ">
|
||||
<EnableNuProj_Common Condition=" '$(EnableNuProj_Common)' == '' ">true</EnableNuProj_Common>
|
||||
</PropertyGroup>
|
||||
|
||||
<!--
|
||||
Importing the "global" CBT build.props is what activates CBT.Core to restore modules. You will want to set
|
||||
properties before or after it depending on what you're injecting. The "global" build.props will also import
|
||||
files located in the $(CBTLocalPath) folder at certain points.
|
||||
-->
|
||||
<Import Project="$(EnlistmentRoot)\.build\CBT\build.props" />
|
||||
|
||||
<!--
|
||||
The NuProjPath property allows .nuproj projects to build without having NuProj installed.
|
||||
-->
|
||||
<PropertyGroup Condition=" '$(MSBuildProjectExtension)' == '.nuproj'" >
|
||||
<NuProjPath Condition=" Exists('$(MSBuildExtensionsPath)\NuProj\NuProj.props') ">$(MSBuildExtensionsPath)\NuProj</NuProjPath>
|
||||
<NuProjPath Condition=" '$(CBTModule_NuProj)' != '' And '$(NuProjPath)' == '' ">$(CBTModule_NuProj)\tools</NuProjPath>
|
||||
<!-- Whenever a project manually imports Directory.Build.props and it could be imported again by Microsoft.Common.props, you set ImportDirectoryBuildProps to false -->
|
||||
<ImportDirectoryBuildProps>false</ImportDirectoryBuildProps>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- The root folder to stage the outputs at -->
|
||||
<StagingOutputRootPath>$(EnlistmentRoot)\out\$(Configuration)-$(Platform)\</StagingOutputRootPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<BuildArchitecture Condition="'$(Platform)'=='x64'">amd64</BuildArchitecture>
|
||||
<BuildArchitecture Condition="'$(Platform)'=='x86'">i386</BuildArchitecture>
|
||||
<OtherArchitecture Condition="'$(Platform)'=='x64'">i386</OtherArchitecture>
|
||||
<OtherArchitecture Condition="'$(Platform)'=='x86'">amd64</OtherArchitecture>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<SrcRoot>$(EnlistmentRoot)/src</SrcRoot>
|
||||
|
||||
<MPI_INC_ROOT>$(SrcRoot)\include</MPI_INC_ROOT>
|
||||
<MPI_INC_ARCH_ROOT Condition="'$(Platform)'=='x64'">$(MPI_INC_ROOT)\x64</MPI_INC_ARCH_ROOT>
|
||||
<MPI_INC_ARCH_ROOT Condition="'$(Platform)'=='x86'">$(MPI_INC_ROOT)\x86</MPI_INC_ARCH_ROOT>
|
||||
<MPI_INC_PATH>$(MPI_INC_ROOT);$(MPI_INC_ARCH_ROOT)</MPI_INC_PATH>
|
||||
<MPI_SRC_ROOT>$(SrcRoot)\mpi</MPI_SRC_ROOT>
|
||||
|
||||
<MPI_DESTINATION>bin</MPI_DESTINATION>
|
||||
<MPI_BIN_DESTINATION>$(MPI_DESTINATION)</MPI_BIN_DESTINATION>
|
||||
<MPI_BIN_OUTPUT_DESTINATION>$(StagingOutputRootPath)\$(MPI_BIN_DESTINATION)</MPI_BIN_OUTPUT_DESTINATION>
|
||||
<BinariesBuildTypeArchDirectory>$(StagingOutputRootPath)</BinariesBuildTypeArchDirectory>
|
||||
<MPI_SDK_DESTINATION>$(MPI_DESTINATION)\sdk</MPI_SDK_DESTINATION>
|
||||
<DEFAULT_STACKCOMMIT>0x2000</DEFAULT_STACKCOMMIT>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TrackFileAccess>false</TrackFileAccess>
|
||||
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
|
||||
<WDKCONTENTROOT Condition="'$(WDKCONTENTROOT)'==''">$(WindowsSdkDir)</WDKCONTENTROOT>
|
||||
|
||||
<Configuration Condition="'$(Configuration)' == ''">Release</Configuration>
|
||||
<Platform Condition="'$(Platform)' == 'Win32'">x86</Platform>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
<_COMPONENTNAME_>mpi</_COMPONENTNAME_>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<GFORTRAN_BIN>"C:\Program Files\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin"</GFORTRAN_BIN>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputPath>$(StagingOutputRootPath)$(MSBuildProjectName)\</OutputPath>
|
||||
<VCToolsVersion>14.15.26726</VCToolsVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<OutDir>$(OutputPath)</OutDir>
|
||||
<O>$(Platform)\$(Configuration)</O>
|
||||
<O Condition="'$(Platform)' == 'x86'">$(Configuration)</O>
|
||||
<ResolveNugetpackages>false</ResolveNugetpackages>
|
||||
<IntDirSharingDetected>None</IntDirSharingDetected>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<Target Name="CopyFilesToStagingOutputDirectory" AfterTargets="CopyFilesToOutputDirectory" Condition=" '$(StagingOutputPath)' != '' ">
|
||||
<ItemGroup>
|
||||
<!-- Gather all files in the output directory recursively -->
|
||||
<StagingFiles Include="$(OutputPath)\$(OutFileType)" />
|
||||
</ItemGroup>
|
||||
<!-- Copy the build output to the drop staging location -->
|
||||
<Copy
|
||||
SourceFiles="@(StagingFiles)"
|
||||
DestinationFolder="$(StagingOutputRootPath)\$(StagingOutputPath)"
|
||||
SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
|
||||
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
|
||||
Retries="$(CopyRetryCount)"
|
||||
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
|
||||
UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
|
||||
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)">
|
||||
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
|
||||
</Copy>
|
||||
</Target>
|
||||
|
||||
<!-- NuProj.props sets a default TargetFrameworkVersion if none is set. Import this before any DotNetFx module props/targets that rely on TargetFrameworkVersion. -->
|
||||
<!-- <Import Project="$(NuProjPath)\NuProj.props" Condition="Exists('$(NuProjPath)\NuProj.props') AND '$(MSBuildProjectExtension)' == '.nuproj'" /> -->
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<config>
|
||||
<add key="repositoryPath" value=".\packages" />
|
||||
</config>
|
||||
<packageRestore>
|
||||
<add key="enabled" value="true" />
|
||||
<add key="automatic" value="true" />
|
||||
</packageRestore>
|
||||
<activePackageSource>
|
||||
<add key="All" value="(Aggregate source)" />
|
||||
</activePackageSource>
|
||||
<packageSources>
|
||||
<clear />
|
||||
<add key="CBT" value="https://www.myget.org/F/cbt/api/v3/index.json" />
|
||||
<add key="NuGet.org" value="https://www.nuget.org/api/v2/" />
|
||||
</packageSources>
|
||||
</configuration>
|
56
README.md
56
README.md
|
@ -1,3 +1,59 @@
|
|||
# Microsoft MPI
|
||||
|
||||
Microsoft MPI (MS-MPI) is a Microsoft implementation of the [Message Passing Interface standard](https://www.mpi-forum.org) for developing and running parallel applications on the Windows platform.
|
||||
|
||||
MS-MPI offers several benefits:
|
||||
|
||||
- Ease of porting existing code that uses [MPICH](https://www.mpich.org).
|
||||
- Security based on Active Directory Domain Services.
|
||||
- High performance on the Windows operating system.
|
||||
- Binary compatibility across different types of interconnectivity options.
|
||||
|
||||
## MS-MPI downloads
|
||||
|
||||
The following are current downloads for MS-MPI:
|
||||
|
||||
- [MS-MPI v10.0](https://www.microsoft.com/download/details.aspx?id=57467) (new\!) - see [Release notes](microsoft-mpi-release-notes.md)
|
||||
- The MS-MPI SDK is also available on [Nuget](https://www.nuget.org/packages/msmpisdk/).
|
||||
|
||||
Earlier versions of MS-MPI are available from the [Microsoft Download Center](https://go.microsoft.com/fwlink/p/?linkid=390734).
|
||||
|
||||
## Community resources
|
||||
|
||||
- [Windows HPC MPI Forum](https://social.microsoft.com/forums/en-us/home?forum=windowshpcmpi)
|
||||
- [Contact the MS-MPI Team](mailto:askmpi@microsoft.com)
|
||||
|
||||
## Microsoft high performance computing resources
|
||||
|
||||
- Featured tutorial: [How to compile and run a simple MS-MPI program](https://blogs.technet.com/b/windowshpc/archive/2015/02/02/how-to-compile-and-run-a-simple-ms-mpi-program.aspx)
|
||||
- Featured guide: [Set up a Windows RDMA cluster with HPC Pack and A8 and A9 instances to run MPI applications](https://azure.microsoft.com/documentation/articles/virtual-machines-windows-hpcpack-cluster-rdma/)
|
||||
- [Microsoft High Performance Computing for Developers](https://msdn.microsoft.com/en-us/library/ff976568.aspx)
|
||||
- [Microsoft HPC Pack (Windows HPC Server) Technical Library](https://technet.microsoft.com/library/cc514029)
|
||||
- [Azure HPC Scenarios](https://www.microsoft.com/hpc)
|
||||
|
||||
# Building
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [Visial Studio 2017](https://docs.microsoft.com/visualstudio/install/install-visual-studio)
|
||||
|
||||
Please make sure to select the following workloads during installation:
|
||||
- .NET desktop development (required for CBT/Nuget packages)
|
||||
- Desktop development with C++
|
||||
|
||||
- [Windows SDK](https://developer.microsoft.com/windows/downloads/windows-10-sdk)
|
||||
- [Windows WDK](https://docs.microsoft.com/windows-hardware/drivers/download-the-wdk)
|
||||
- [GFortran](http://mingw-w64.org/doku.php)
|
||||
- Update _GFORTRAN_BIN_ in Derectory.Build.props to the install location of GFortran
|
||||
- [Perl](https://www.perl.org/get.html#win32)
|
||||
|
||||
Based on the installed VS/SDK/WDK versions, update _VCToolsVersion_ and _WindowsTargetPlatformVersion_ in Directory.Build.props
|
||||
|
||||
Note that the build system uses [CommonBuildToolSet(CBT)](https://commonbuildtoolset.github.io/). You may need to unblock __CBT.core.dll__ (under .build/CBT) depending on your security configurations. Please refer to [CBT documentation](https://commonbuildtoolset.github.io/#/getting-started) for additional details.
|
||||
|
||||
|
||||
## Build
|
||||
To build, open a __Native Tools Command Prompt for Visual Studio__ and run ``msbuild`` from root folder.
|
||||
|
||||
# Contributing
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<ItemGroup>
|
||||
<ProjectFile Include="$(MSBuildThisFileDirectory)src\dirs.proj" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(TraversalTargets)" Condition=" '$(CBTModulesRestored)' == 'true' " />
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectFile Include="$(MSBuildThisFileDirectory)include\binplace.proj"/>
|
||||
<ProjectFile Include="$(MSBuildThisFileDirectory)launchSvc\msmpiLaunchSvc.vcxproj"/>
|
||||
<ProjectFile Include="$(MSBuildThisFileDirectory)launchSvc\msmpiLaunchSvcMc.vcxproj"/>
|
||||
<ProjectFile Include="$(MSBuildThisFileDirectory)mpi\dirs.proj"/>
|
||||
</ItemGroup>
|
||||
<Import Project="$(TraversalTargets)" Condition=" '$(CBTModulesRestored)' == 'true' " />
|
||||
</Project>
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="CopyFiles" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Import Project="$(SrcRoot)\mpi.props" />
|
||||
|
||||
<ItemGroup>
|
||||
<_CopyItems Include="**\*.h;**\*.f90" Exclude="oacr.h"/>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="CopyFiles">
|
||||
<Copy
|
||||
SourceFiles="@(_CopyItems)"
|
||||
DestinationFolder="$(BinariesBuildTypeArchDirectory)\$(MPI_SDK_DESTINATION)\inc\%(RecursiveDir)"
|
||||
/>
|
||||
</Target>
|
||||
|
||||
<Target Name="Clean">
|
||||
<RemoveDir Directories="$(BinariesBuildTypeArchDirectory)\$(MPI_SDK_DESTINATION)\inc" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,536 @@
|
|||
! /* -*- Mode: Fortran; -*- */
|
||||
!
|
||||
! Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
! Licensed under the MIT License.
|
||||
!
|
||||
! (C) 2001 by Argonne National Laboratory.
|
||||
! (C) 2015 by Microsoft Corporation
|
||||
!
|
||||
! MPICH COPYRIGHT
|
||||
!
|
||||
! The following is a notice of limited availability of the code, and disclaimer
|
||||
! which must be included in the prologue of the code and in all source listings
|
||||
! of the code.
|
||||
!
|
||||
! Copyright Notice
|
||||
! + 2002 University of Chicago
|
||||
!
|
||||
! Permission is hereby granted to use, reproduce, prepare derivative works, and
|
||||
! to redistribute to others. This software was authored by:
|
||||
!
|
||||
! Mathematics and Computer Science Division
|
||||
! Argonne National Laboratory, Argonne IL 60439
|
||||
!
|
||||
! (and)
|
||||
!
|
||||
! Department of Computer Science
|
||||
! University of Illinois at Urbana-Champaign
|
||||
!
|
||||
!
|
||||
! GOVERNMENT LICENSE
|
||||
!
|
||||
! Portions of this material resulted from work developed under a U.S.
|
||||
! Government Contract and are subject to the following license: the Government
|
||||
! is granted for itself and others acting on its behalf a paid-up, nonexclusive,
|
||||
! irrevocable worldwide license in this computer software to reproduce, prepare
|
||||
! derivative works, and perform publicly and display publicly.
|
||||
!
|
||||
! DISCLAIMER
|
||||
!
|
||||
! This computer code material was prepared, in part, as an account of work
|
||||
! sponsored by an agency of the United States Government. Neither the United
|
||||
! States, nor the University of Chicago, nor any of their employees, makes any
|
||||
! warranty express or implied, or assumes any legal liability or responsibility
|
||||
! for the accuracy, completeness, or usefulness of any information, apparatus,
|
||||
! product, or process disclosed, or represents that its use would not infringe
|
||||
! privately owned rights.
|
||||
!
|
||||
!
|
||||
INTEGER MPI_SOURCE, MPI_TAG, MPI_ERROR
|
||||
PARAMETER (MPI_SOURCE=3,MPI_TAG=4,MPI_ERROR=5)
|
||||
INTEGER MPI_STATUS_SIZE
|
||||
PARAMETER (MPI_STATUS_SIZE=5)
|
||||
INTEGER MPI_STATUS_IGNORE(MPI_STATUS_SIZE)
|
||||
INTEGER MPI_STATUSES_IGNORE(MPI_STATUS_SIZE,1)
|
||||
INTEGER MPI_ERRCODES_IGNORE(1)
|
||||
CHARACTER*1 MPI_ARGVS_NULL(1,1)
|
||||
CHARACTER*1 MPI_ARGV_NULL(1)
|
||||
INTEGER MPI_SUCCESS
|
||||
PARAMETER (MPI_SUCCESS=0)
|
||||
INTEGER MPI_ERR_OTHER
|
||||
PARAMETER (MPI_ERR_OTHER=15)
|
||||
INTEGER MPI_ERR_WIN
|
||||
PARAMETER (MPI_ERR_WIN=45)
|
||||
INTEGER MPI_ERR_FILE
|
||||
PARAMETER (MPI_ERR_FILE=27)
|
||||
INTEGER MPI_ERR_COUNT
|
||||
PARAMETER (MPI_ERR_COUNT=2)
|
||||
INTEGER MPI_ERR_SPAWN
|
||||
PARAMETER (MPI_ERR_SPAWN=42)
|
||||
INTEGER MPI_ERR_BASE
|
||||
PARAMETER (MPI_ERR_BASE=46)
|
||||
INTEGER MPI_ERR_RMA_CONFLICT
|
||||
PARAMETER (MPI_ERR_RMA_CONFLICT=49)
|
||||
INTEGER MPI_ERR_IN_STATUS
|
||||
PARAMETER (MPI_ERR_IN_STATUS=17)
|
||||
INTEGER MPI_ERR_INFO_KEY
|
||||
PARAMETER (MPI_ERR_INFO_KEY=29)
|
||||
INTEGER MPI_ERR_LOCKTYPE
|
||||
PARAMETER (MPI_ERR_LOCKTYPE=47)
|
||||
INTEGER MPI_ERR_OP
|
||||
PARAMETER (MPI_ERR_OP=9)
|
||||
INTEGER MPI_ERR_ARG
|
||||
PARAMETER (MPI_ERR_ARG=12)
|
||||
INTEGER MPI_ERR_READ_ONLY
|
||||
PARAMETER (MPI_ERR_READ_ONLY=40)
|
||||
INTEGER MPI_ERR_SIZE
|
||||
PARAMETER (MPI_ERR_SIZE=51)
|
||||
INTEGER MPI_ERR_BUFFER
|
||||
PARAMETER (MPI_ERR_BUFFER=1)
|
||||
INTEGER MPI_ERR_DUP_DATAREP
|
||||
PARAMETER (MPI_ERR_DUP_DATAREP=24)
|
||||
INTEGER MPI_ERR_UNSUPPORTED_DATAREP
|
||||
PARAMETER (MPI_ERR_UNSUPPORTED_DATAREP=43)
|
||||
INTEGER MPI_ERR_LASTCODE
|
||||
PARAMETER (MPI_ERR_LASTCODE=1073741823)
|
||||
INTEGER MPI_ERR_TRUNCATE
|
||||
PARAMETER (MPI_ERR_TRUNCATE=14)
|
||||
INTEGER MPI_ERR_DISP
|
||||
PARAMETER (MPI_ERR_DISP=52)
|
||||
INTEGER MPI_ERR_PORT
|
||||
PARAMETER (MPI_ERR_PORT=38)
|
||||
INTEGER MPI_ERR_INFO_NOKEY
|
||||
PARAMETER (MPI_ERR_INFO_NOKEY=31)
|
||||
INTEGER MPI_ERR_ASSERT
|
||||
PARAMETER (MPI_ERR_ASSERT=53)
|
||||
INTEGER MPI_ERR_FILE_EXISTS
|
||||
PARAMETER (MPI_ERR_FILE_EXISTS=25)
|
||||
INTEGER MPI_ERR_PENDING
|
||||
PARAMETER (MPI_ERR_PENDING=18)
|
||||
INTEGER MPI_ERR_COMM
|
||||
PARAMETER (MPI_ERR_COMM=5)
|
||||
INTEGER MPI_ERR_KEYVAL
|
||||
PARAMETER (MPI_ERR_KEYVAL=48)
|
||||
INTEGER MPI_ERR_NAME
|
||||
PARAMETER (MPI_ERR_NAME=33)
|
||||
INTEGER MPI_ERR_REQUEST
|
||||
PARAMETER (MPI_ERR_REQUEST=19)
|
||||
INTEGER MPI_ERR_GROUP
|
||||
PARAMETER (MPI_ERR_GROUP=8)
|
||||
INTEGER MPI_ERR_TOPOLOGY
|
||||
PARAMETER (MPI_ERR_TOPOLOGY=10)
|
||||
INTEGER MPI_ERR_TYPE
|
||||
PARAMETER (MPI_ERR_TYPE=3)
|
||||
INTEGER MPI_ERR_TAG
|
||||
PARAMETER (MPI_ERR_TAG=4)
|
||||
INTEGER MPI_ERR_INFO_VALUE
|
||||
PARAMETER (MPI_ERR_INFO_VALUE=30)
|
||||
INTEGER MPI_ERR_NOT_SAME
|
||||
PARAMETER (MPI_ERR_NOT_SAME=35)
|
||||
INTEGER MPI_ERR_RMA_SYNC
|
||||
PARAMETER (MPI_ERR_RMA_SYNC=50)
|
||||
INTEGER MPI_ERR_INFO
|
||||
PARAMETER (MPI_ERR_INFO=28)
|
||||
INTEGER MPI_ERR_NO_MEM
|
||||
PARAMETER (MPI_ERR_NO_MEM=34)
|
||||
INTEGER MPI_ERR_BAD_FILE
|
||||
PARAMETER (MPI_ERR_BAD_FILE=22)
|
||||
INTEGER MPI_ERR_FILE_IN_USE
|
||||
PARAMETER (MPI_ERR_FILE_IN_USE=26)
|
||||
INTEGER MPI_ERR_UNKNOWN
|
||||
PARAMETER (MPI_ERR_UNKNOWN=13)
|
||||
INTEGER MPI_ERR_UNSUPPORTED_OPERATION
|
||||
PARAMETER (MPI_ERR_UNSUPPORTED_OPERATION=44)
|
||||
INTEGER MPI_ERR_QUOTA
|
||||
PARAMETER (MPI_ERR_QUOTA=39)
|
||||
INTEGER MPI_ERR_AMODE
|
||||
PARAMETER (MPI_ERR_AMODE=21)
|
||||
INTEGER MPI_ERR_ROOT
|
||||
PARAMETER (MPI_ERR_ROOT=7)
|
||||
INTEGER MPI_ERR_RANK
|
||||
PARAMETER (MPI_ERR_RANK=6)
|
||||
INTEGER MPI_ERR_DIMS
|
||||
PARAMETER (MPI_ERR_DIMS=11)
|
||||
INTEGER MPI_ERR_NO_SUCH_FILE
|
||||
PARAMETER (MPI_ERR_NO_SUCH_FILE=37)
|
||||
INTEGER MPI_ERR_SERVICE
|
||||
PARAMETER (MPI_ERR_SERVICE=41)
|
||||
INTEGER MPI_ERR_INTERN
|
||||
PARAMETER (MPI_ERR_INTERN=16)
|
||||
INTEGER MPI_ERR_IO
|
||||
PARAMETER (MPI_ERR_IO=32)
|
||||
INTEGER MPI_ERR_ACCESS
|
||||
PARAMETER (MPI_ERR_ACCESS=20)
|
||||
INTEGER MPI_ERR_NO_SPACE
|
||||
PARAMETER (MPI_ERR_NO_SPACE=36)
|
||||
INTEGER MPI_ERR_CONVERSION
|
||||
PARAMETER (MPI_ERR_CONVERSION=23)
|
||||
INTEGER MPI_ERRORS_ARE_FATAL
|
||||
PARAMETER (MPI_ERRORS_ARE_FATAL=1409286144)
|
||||
INTEGER MPI_ERRORS_RETURN
|
||||
PARAMETER (MPI_ERRORS_RETURN=1409286145)
|
||||
INTEGER MPI_IDENT
|
||||
PARAMETER (MPI_IDENT=0)
|
||||
INTEGER MPI_CONGRUENT
|
||||
PARAMETER (MPI_CONGRUENT=1)
|
||||
INTEGER MPI_SIMILAR
|
||||
PARAMETER (MPI_SIMILAR=2)
|
||||
INTEGER MPI_UNEQUAL
|
||||
PARAMETER (MPI_UNEQUAL=3)
|
||||
INTEGER MPI_MAX
|
||||
PARAMETER (MPI_MAX=1476395009)
|
||||
INTEGER MPI_MIN
|
||||
PARAMETER (MPI_MIN=1476395010)
|
||||
INTEGER MPI_SUM
|
||||
PARAMETER (MPI_SUM=1476395011)
|
||||
INTEGER MPI_PROD
|
||||
PARAMETER (MPI_PROD=1476395012)
|
||||
INTEGER MPI_LAND
|
||||
PARAMETER (MPI_LAND=1476395013)
|
||||
INTEGER MPI_BAND
|
||||
PARAMETER (MPI_BAND=1476395014)
|
||||
INTEGER MPI_LOR
|
||||
PARAMETER (MPI_LOR=1476395015)
|
||||
INTEGER MPI_BOR
|
||||
PARAMETER (MPI_BOR=1476395016)
|
||||
INTEGER MPI_LXOR
|
||||
PARAMETER (MPI_LXOR=1476395017)
|
||||
INTEGER MPI_BXOR
|
||||
PARAMETER (MPI_BXOR=1476395018)
|
||||
INTEGER MPI_MINLOC
|
||||
PARAMETER (MPI_MINLOC=1476395019)
|
||||
INTEGER MPI_MAXLOC
|
||||
PARAMETER (MPI_MAXLOC=1476395020)
|
||||
INTEGER MPI_REPLACE
|
||||
PARAMETER (MPI_REPLACE=1476395021)
|
||||
INTEGER MPI_NO_OP
|
||||
PARAMETER (MPI_NO_OP=1476395022)
|
||||
INTEGER MPI_COMM_WORLD
|
||||
PARAMETER (MPI_COMM_WORLD=1140850688)
|
||||
INTEGER MPI_COMM_SELF
|
||||
PARAMETER (MPI_COMM_SELF=1140850689)
|
||||
INTEGER MPI_COMM_TYPE_SHARED
|
||||
PARAMETER (MPI_COMM_TYPE_SHARED=1)
|
||||
INTEGER MPI_GROUP_EMPTY
|
||||
PARAMETER (MPI_GROUP_EMPTY=1207959552)
|
||||
INTEGER MPI_COMM_NULL
|
||||
PARAMETER (MPI_COMM_NULL=67108864)
|
||||
INTEGER MPI_WIN_NULL
|
||||
PARAMETER (MPI_WIN_NULL=536870912)
|
||||
INTEGER MPI_FILE_NULL
|
||||
PARAMETER (MPI_FILE_NULL=0)
|
||||
INTEGER MPI_GROUP_NULL
|
||||
PARAMETER (MPI_GROUP_NULL=134217728)
|
||||
INTEGER MPI_OP_NULL
|
||||
PARAMETER (MPI_OP_NULL=402653184)
|
||||
INTEGER MPI_DATATYPE_NULL
|
||||
PARAMETER (MPI_DATATYPE_NULL=z'0c000000')
|
||||
INTEGER MPI_REQUEST_NULL
|
||||
PARAMETER (MPI_REQUEST_NULL=738197504)
|
||||
INTEGER MPI_ERRHANDLER_NULL
|
||||
PARAMETER (MPI_ERRHANDLER_NULL=335544320)
|
||||
INTEGER MPI_INFO_NULL
|
||||
PARAMETER (MPI_INFO_NULL=469762048)
|
||||
INTEGER MPI_MESSAGE_NULL
|
||||
PARAMETER (MPI_MESSAGE_NULL=805306368)
|
||||
INTEGER MPI_MESSAGE_NO_PROC
|
||||
PARAMETER (MPI_MESSAGE_NO_PROC=1879048192)
|
||||
INTEGER MPI_TAG_UB
|
||||
PARAMETER (MPI_TAG_UB=1681915906)
|
||||
INTEGER MPI_HOST
|
||||
PARAMETER (MPI_HOST=1681915908)
|
||||
INTEGER MPI_IO
|
||||
PARAMETER (MPI_IO=1681915910)
|
||||
INTEGER MPI_WTIME_IS_GLOBAL
|
||||
PARAMETER (MPI_WTIME_IS_GLOBAL=1681915912)
|
||||
INTEGER MPI_UNIVERSE_SIZE
|
||||
PARAMETER (MPI_UNIVERSE_SIZE=1681915914)
|
||||
INTEGER MPI_LASTUSEDCODE
|
||||
PARAMETER (MPI_LASTUSEDCODE=1681915916)
|
||||
INTEGER MPI_APPNUM
|
||||
PARAMETER (MPI_APPNUM=1681915918)
|
||||
INTEGER MPI_WIN_BASE
|
||||
PARAMETER (MPI_WIN_BASE=1711276034)
|
||||
INTEGER MPI_WIN_SIZE
|
||||
PARAMETER (MPI_WIN_SIZE=1711276036)
|
||||
INTEGER MPI_WIN_DISP_UNIT
|
||||
PARAMETER (MPI_WIN_DISP_UNIT=1711276038)
|
||||
INTEGER MPI_MAX_ERROR_STRING
|
||||
PARAMETER (MPI_MAX_ERROR_STRING=511)
|
||||
INTEGER MPI_MAX_PORT_NAME
|
||||
PARAMETER (MPI_MAX_PORT_NAME=255)
|
||||
INTEGER MPI_MAX_OBJECT_NAME
|
||||
PARAMETER (MPI_MAX_OBJECT_NAME=127)
|
||||
INTEGER MPI_MAX_INFO_KEY
|
||||
PARAMETER (MPI_MAX_INFO_KEY=254)
|
||||
INTEGER MPI_MAX_INFO_VAL
|
||||
PARAMETER (MPI_MAX_INFO_VAL=1023)
|
||||
INTEGER MPI_MAX_PROCESSOR_NAME
|
||||
PARAMETER (MPI_MAX_PROCESSOR_NAME=128-1)
|
||||
INTEGER MPI_MAX_DATAREP_STRING
|
||||
PARAMETER (MPI_MAX_DATAREP_STRING=127)
|
||||
INTEGER MPI_MAX_LIBRARY_VERSION_STRING
|
||||
PARAMETER (MPI_MAX_LIBRARY_VERSION_STRING=64-1)
|
||||
INTEGER MPI_UNDEFINED
|
||||
PARAMETER (MPI_UNDEFINED=(-32766))
|
||||
INTEGER MPI_KEYVAL_INVALID
|
||||
PARAMETER (MPI_KEYVAL_INVALID=603979776)
|
||||
INTEGER MPI_BSEND_OVERHEAD
|
||||
PARAMETER (MPI_BSEND_OVERHEAD=(95))
|
||||
INTEGER MPI_PROC_NULL
|
||||
PARAMETER (MPI_PROC_NULL=-1)
|
||||
INTEGER MPI_ANY_SOURCE
|
||||
PARAMETER (MPI_ANY_SOURCE=-2)
|
||||
INTEGER MPI_ANY_TAG
|
||||
PARAMETER (MPI_ANY_TAG=-1)
|
||||
INTEGER MPI_ROOT
|
||||
PARAMETER (MPI_ROOT=-3)
|
||||
INTEGER MPI_GRAPH
|
||||
PARAMETER (MPI_GRAPH=1)
|
||||
INTEGER MPI_CART
|
||||
PARAMETER (MPI_CART=2)
|
||||
INTEGER MPI_DIST_GRAPH
|
||||
PARAMETER (MPI_DIST_GRAPH=3)
|
||||
INTEGER MPI_VERSION
|
||||
PARAMETER (MPI_VERSION=2)
|
||||
INTEGER MPI_SUBVERSION
|
||||
PARAMETER (MPI_SUBVERSION=0)
|
||||
INTEGER MPI_LOCK_EXCLUSIVE
|
||||
PARAMETER (MPI_LOCK_EXCLUSIVE=234)
|
||||
INTEGER MPI_LOCK_SHARED
|
||||
PARAMETER (MPI_LOCK_SHARED=235)
|
||||
INTEGER MPI_CHAR
|
||||
PARAMETER (MPI_CHAR=z'4c000101')
|
||||
INTEGER MPI_UNSIGNED_CHAR
|
||||
PARAMETER (MPI_UNSIGNED_CHAR=z'4c000102')
|
||||
INTEGER MPI_SHORT
|
||||
PARAMETER (MPI_SHORT=z'4c000203')
|
||||
INTEGER MPI_UNSIGNED_SHORT
|
||||
PARAMETER (MPI_UNSIGNED_SHORT=z'4c000204')
|
||||
INTEGER MPI_INT
|
||||
PARAMETER (MPI_INT=z'4c000405')
|
||||
INTEGER MPI_UNSIGNED
|
||||
PARAMETER (MPI_UNSIGNED=z'4c000406')
|
||||
INTEGER MPI_LONG
|
||||
PARAMETER (MPI_LONG=z'4c000407')
|
||||
INTEGER MPI_UNSIGNED_LONG
|
||||
PARAMETER (MPI_UNSIGNED_LONG=z'4c000408')
|
||||
INTEGER MPI_LONG_LONG
|
||||
PARAMETER (MPI_LONG_LONG=z'4c000809')
|
||||
INTEGER MPI_LONG_LONG_INT
|
||||
PARAMETER (MPI_LONG_LONG_INT=z'4c000809')
|
||||
INTEGER MPI_FLOAT
|
||||
PARAMETER (MPI_FLOAT=z'4c00040a')
|
||||
INTEGER MPI_DOUBLE
|
||||
PARAMETER (MPI_DOUBLE=z'4c00080b')
|
||||
INTEGER MPI_LONG_DOUBLE
|
||||
PARAMETER (MPI_LONG_DOUBLE=z'4c00080c')
|
||||
INTEGER MPI_BYTE
|
||||
PARAMETER (MPI_BYTE=z'4c00010d')
|
||||
INTEGER MPI_WCHAR
|
||||
PARAMETER (MPI_WCHAR=z'4c00020e')
|
||||
INTEGER MPI_PACKED
|
||||
PARAMETER (MPI_PACKED=z'4c00010f')
|
||||
INTEGER MPI_LB
|
||||
PARAMETER (MPI_LB=z'4c000010')
|
||||
INTEGER MPI_UB
|
||||
PARAMETER (MPI_UB=z'4c000011')
|
||||
INTEGER MPI_2INT
|
||||
PARAMETER (MPI_2INT=z'4c000816')
|
||||
INTEGER MPI_SIGNED_CHAR
|
||||
PARAMETER (MPI_SIGNED_CHAR=z'4c000118')
|
||||
INTEGER MPI_UNSIGNED_LONG_LONG
|
||||
PARAMETER (MPI_UNSIGNED_LONG_LONG=z'4c000819')
|
||||
INTEGER MPI_CHARACTER
|
||||
PARAMETER (MPI_CHARACTER=z'4c00011a')
|
||||
INTEGER MPI_INTEGER
|
||||
PARAMETER (MPI_INTEGER=z'4c00041b')
|
||||
INTEGER MPI_REAL
|
||||
PARAMETER (MPI_REAL=z'4c00041c')
|
||||
INTEGER MPI_LOGICAL
|
||||
PARAMETER (MPI_LOGICAL=z'4c00041d')
|
||||
INTEGER MPI_COMPLEX
|
||||
PARAMETER (MPI_COMPLEX=z'4c00081e')
|
||||
INTEGER MPI_DOUBLE_PRECISION
|
||||
PARAMETER (MPI_DOUBLE_PRECISION=z'4c00081f')
|
||||
INTEGER MPI_2INTEGER
|
||||
PARAMETER (MPI_2INTEGER=z'4c000820')
|
||||
INTEGER MPI_2REAL
|
||||
PARAMETER (MPI_2REAL=z'4c000821')
|
||||
INTEGER MPI_DOUBLE_COMPLEX
|
||||
PARAMETER (MPI_DOUBLE_COMPLEX=z'4c001022')
|
||||
INTEGER MPI_2DOUBLE_PRECISION
|
||||
PARAMETER (MPI_2DOUBLE_PRECISION=z'4c001023')
|
||||
INTEGER MPI_2COMPLEX
|
||||
PARAMETER (MPI_2COMPLEX=z'4c001024')
|
||||
INTEGER MPI_2DOUBLE_COMPLEX
|
||||
PARAMETER (MPI_2DOUBLE_COMPLEX=z'4c002025')
|
||||
INTEGER MPI_REAL2
|
||||
PARAMETER (MPI_REAL2=z'0c000000')
|
||||
INTEGER MPI_REAL4
|
||||
PARAMETER (MPI_REAL4=z'4c000427')
|
||||
INTEGER MPI_COMPLEX8
|
||||
PARAMETER (MPI_COMPLEX8=z'4c000828')
|
||||
INTEGER MPI_REAL8
|
||||
PARAMETER (MPI_REAL8=z'4c000829')
|
||||
INTEGER MPI_COMPLEX16
|
||||
PARAMETER (MPI_COMPLEX16=z'4c00102a')
|
||||
INTEGER MPI_REAL16
|
||||
PARAMETER (MPI_REAL16=z'0c000000')
|
||||
INTEGER MPI_COMPLEX32
|
||||
PARAMETER (MPI_COMPLEX32=z'0c000000')
|
||||
INTEGER MPI_INTEGER1
|
||||
PARAMETER (MPI_INTEGER1=z'4c00012d')
|
||||
INTEGER MPI_COMPLEX4
|
||||
PARAMETER (MPI_COMPLEX4=z'0c000000')
|
||||
INTEGER MPI_INTEGER2
|
||||
PARAMETER (MPI_INTEGER2=z'4c00022f')
|
||||
INTEGER MPI_INTEGER4
|
||||
PARAMETER (MPI_INTEGER4=z'4c000430')
|
||||
INTEGER MPI_INTEGER8
|
||||
PARAMETER (MPI_INTEGER8=z'4c000831')
|
||||
INTEGER MPI_INTEGER16
|
||||
PARAMETER (MPI_INTEGER16=z'0c000000')
|
||||
|
||||
INCLUDE 'mpifptr.h'
|
||||
|
||||
INTEGER MPI_OFFSET
|
||||
PARAMETER (MPI_OFFSET=z'4c00083c')
|
||||
INTEGER MPI_COUNT
|
||||
PARAMETER (MPI_COUNT=z'4c00083d')
|
||||
INTEGER MPI_FLOAT_INT
|
||||
PARAMETER (MPI_FLOAT_INT=z'8c000000')
|
||||
INTEGER MPI_DOUBLE_INT
|
||||
PARAMETER (MPI_DOUBLE_INT=z'8c000001')
|
||||
INTEGER MPI_LONG_INT
|
||||
PARAMETER (MPI_LONG_INT=z'8c000002')
|
||||
INTEGER MPI_SHORT_INT
|
||||
PARAMETER (MPI_SHORT_INT=z'8c000003')
|
||||
INTEGER MPI_LONG_DOUBLE_INT
|
||||
PARAMETER (MPI_LONG_DOUBLE_INT=z'8c000004')
|
||||
INTEGER MPI_INTEGER_KIND
|
||||
PARAMETER (MPI_INTEGER_KIND=4)
|
||||
INTEGER MPI_OFFSET_KIND
|
||||
PARAMETER (MPI_OFFSET_KIND=8)
|
||||
INTEGER MPI_COUNT_KIND
|
||||
PARAMETER (MPI_COUNT_KIND=8)
|
||||
INTEGER MPI_COMBINER_NAMED
|
||||
PARAMETER (MPI_COMBINER_NAMED=1)
|
||||
INTEGER MPI_COMBINER_DUP
|
||||
PARAMETER (MPI_COMBINER_DUP=2)
|
||||
INTEGER MPI_COMBINER_CONTIGUOUS
|
||||
PARAMETER (MPI_COMBINER_CONTIGUOUS=3)
|
||||
INTEGER MPI_COMBINER_VECTOR
|
||||
PARAMETER (MPI_COMBINER_VECTOR=4)
|
||||
INTEGER MPI_COMBINER_HVECTOR_INTEGER
|
||||
PARAMETER (MPI_COMBINER_HVECTOR_INTEGER=5)
|
||||
INTEGER MPI_COMBINER_HVECTOR
|
||||
PARAMETER (MPI_COMBINER_HVECTOR=6)
|
||||
INTEGER MPI_COMBINER_INDEXED
|
||||
PARAMETER (MPI_COMBINER_INDEXED=7)
|
||||
INTEGER MPI_COMBINER_HINDEXED_INTEGER
|
||||
PARAMETER (MPI_COMBINER_HINDEXED_INTEGER=8)
|
||||
INTEGER MPI_COMBINER_HINDEXED
|
||||
PARAMETER (MPI_COMBINER_HINDEXED=9)
|
||||
INTEGER MPI_COMBINER_INDEXED_BLOCK
|
||||
PARAMETER (MPI_COMBINER_INDEXED_BLOCK=10)
|
||||
INTEGER MPI_COMBINER_STRUCT_INTEGER
|
||||
PARAMETER (MPI_COMBINER_STRUCT_INTEGER=11)
|
||||
INTEGER MPI_COMBINER_STRUCT
|
||||
PARAMETER (MPI_COMBINER_STRUCT=12)
|
||||
INTEGER MPI_COMBINER_SUBARRAY
|
||||
PARAMETER (MPI_COMBINER_SUBARRAY=13)
|
||||
INTEGER MPI_COMBINER_DARRAY
|
||||
PARAMETER (MPI_COMBINER_DARRAY=14)
|
||||
INTEGER MPI_COMBINER_F90_REAL
|
||||
PARAMETER (MPI_COMBINER_F90_REAL=15)
|
||||
INTEGER MPI_COMBINER_F90_COMPLEX
|
||||
PARAMETER (MPI_COMBINER_F90_COMPLEX=16)
|
||||
INTEGER MPI_COMBINER_F90_INTEGER
|
||||
PARAMETER (MPI_COMBINER_F90_INTEGER=17)
|
||||
INTEGER MPI_COMBINER_RESIZED
|
||||
PARAMETER (MPI_COMBINER_RESIZED=18)
|
||||
INTEGER MPI_COMBINER_HINDEXED_BLOCK
|
||||
PARAMETER (MPI_COMBINER_HINDEXED_BLOCK=19)
|
||||
INTEGER MPI_MODE_NOCHECK
|
||||
PARAMETER (MPI_MODE_NOCHECK=1024)
|
||||
INTEGER MPI_MODE_NOSTORE
|
||||
PARAMETER (MPI_MODE_NOSTORE=2048)
|
||||
INTEGER MPI_MODE_NOPUT
|
||||
PARAMETER (MPI_MODE_NOPUT=4096)
|
||||
INTEGER MPI_MODE_NOPRECEDE
|
||||
PARAMETER (MPI_MODE_NOPRECEDE=8192)
|
||||
INTEGER MPI_MODE_NOSUCCEED
|
||||
PARAMETER (MPI_MODE_NOSUCCEED=16384)
|
||||
INTEGER MPI_THREAD_SINGLE
|
||||
PARAMETER (MPI_THREAD_SINGLE=0)
|
||||
INTEGER MPI_THREAD_FUNNELED
|
||||
PARAMETER (MPI_THREAD_FUNNELED=1)
|
||||
INTEGER MPI_THREAD_SERIALIZED
|
||||
PARAMETER (MPI_THREAD_SERIALIZED=2)
|
||||
INTEGER MPI_THREAD_MULTIPLE
|
||||
PARAMETER (MPI_THREAD_MULTIPLE=3)
|
||||
INTEGER MPI_MODE_RDONLY
|
||||
PARAMETER (MPI_MODE_RDONLY=2)
|
||||
INTEGER MPI_MODE_RDWR
|
||||
PARAMETER (MPI_MODE_RDWR=8)
|
||||
INTEGER MPI_MODE_WRONLY
|
||||
PARAMETER (MPI_MODE_WRONLY=4)
|
||||
INTEGER MPI_MODE_DELETE_ON_CLOSE
|
||||
PARAMETER (MPI_MODE_DELETE_ON_CLOSE=16)
|
||||
INTEGER MPI_MODE_UNIQUE_OPEN
|
||||
PARAMETER (MPI_MODE_UNIQUE_OPEN=32)
|
||||
INTEGER MPI_MODE_CREATE
|
||||
PARAMETER (MPI_MODE_CREATE=1)
|
||||
INTEGER MPI_MODE_EXCL
|
||||
PARAMETER (MPI_MODE_EXCL=64)
|
||||
INTEGER MPI_MODE_APPEND
|
||||
PARAMETER (MPI_MODE_APPEND=128)
|
||||
INTEGER MPI_MODE_SEQUENTIAL
|
||||
PARAMETER (MPI_MODE_SEQUENTIAL=256)
|
||||
INTEGER MPI_SEEK_SET
|
||||
PARAMETER (MPI_SEEK_SET=600)
|
||||
INTEGER MPI_SEEK_CUR
|
||||
PARAMETER (MPI_SEEK_CUR=602)
|
||||
INTEGER MPI_SEEK_END
|
||||
PARAMETER (MPI_SEEK_END=604)
|
||||
INTEGER MPI_ORDER_C
|
||||
PARAMETER (MPI_ORDER_C=56)
|
||||
INTEGER MPI_ORDER_FORTRAN
|
||||
PARAMETER (MPI_ORDER_FORTRAN=57)
|
||||
INTEGER MPI_DISTRIBUTE_BLOCK
|
||||
PARAMETER (MPI_DISTRIBUTE_BLOCK=121)
|
||||
INTEGER MPI_DISTRIBUTE_CYCLIC
|
||||
PARAMETER (MPI_DISTRIBUTE_CYCLIC=122)
|
||||
INTEGER MPI_DISTRIBUTE_NONE
|
||||
PARAMETER (MPI_DISTRIBUTE_NONE=123)
|
||||
INTEGER MPI_DISTRIBUTE_DFLT_DARG
|
||||
PARAMETER (MPI_DISTRIBUTE_DFLT_DARG=-49767)
|
||||
INTEGER (KIND=8) MPI_DISPLACEMENT_CURRENT
|
||||
PARAMETER (MPI_DISPLACEMENT_CURRENT=-54278278)
|
||||
INTEGER MPI_BOTTOM, MPI_IN_PLACE
|
||||
INTEGER MPI_UNWEIGHTED, MPI_WEIGHTS_EMPTY
|
||||
EXTERNAL MPI_DUP_FN, MPI_NULL_DELETE_FN, MPI_NULL_COPY_FN
|
||||
EXTERNAL MPI_WTIME, MPI_WTICK
|
||||
EXTERNAL PMPI_WTIME, PMPI_WTICK
|
||||
EXTERNAL MPI_COMM_DUP_FN, MPI_COMM_NULL_DELETE_FN
|
||||
EXTERNAL MPI_COMM_NULL_COPY_FN
|
||||
EXTERNAL MPI_WIN_DUP_FN, MPI_WIN_NULL_DELETE_FN
|
||||
EXTERNAL MPI_WIN_NULL_COPY_FN
|
||||
EXTERNAL MPI_TYPE_DUP_FN, MPI_TYPE_NULL_DELETE_FN
|
||||
EXTERNAL MPI_TYPE_NULL_COPY_FN
|
||||
EXTERNAL MPI_CONVERSION_FN_NULL
|
||||
DOUBLE PRECISION MPI_WTIME, MPI_WTICK
|
||||
DOUBLE PRECISION PMPI_WTIME, PMPI_WTICK
|
||||
|
||||
COMMON /MPIPRIV1/ MPI_BOTTOM, MPI_IN_PLACE, MPI_STATUS_IGNORE
|
||||
|
||||
COMMON /MPIPRIV2/ MPI_STATUSES_IGNORE, MPI_ERRCODES_IGNORE
|
||||
!DEC$ ATTRIBUTES DLLIMPORT :: /MPIPRIV1/, /MPIPRIV2/
|
||||
|
||||
COMMON /MPIFCMB5/ MPI_UNWEIGHTED
|
||||
COMMON /MPIFCMB9/ MPI_WEIGHTS_EMPTY
|
||||
!DEC$ ATTRIBUTES DLLIMPORT :: /MPIFCMB5/, /MPIFCMB9/
|
||||
|
||||
COMMON /MPIPRIVC/ MPI_ARGVS_NULL, MPI_ARGV_NULL
|
||||
!DEC$ ATTRIBUTES DLLIMPORT :: /MPIPRIVC/
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#error do not include mpio.h, use mpi.h
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma warning(disable:4200) // nonstandard extension used : zero-sized array in struct/union
|
||||
#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union
|
||||
#pragma warning(disable:4204) // nonstandard extension used : non-constant aggregate initializer
|
||||
#ifdef _PREFIX_
|
||||
#pragma warning(disable:4616) // #pragma warning : warning number 'number' not a valid compiler warning
|
||||
#endif
|
|
@ -0,0 +1,209 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
Licensed under the MIT License.
|
||||
|
||||
Module:
|
||||
|
||||
mspms.h
|
||||
|
||||
Abstract:
|
||||
|
||||
MSMPI process management service interface definitions.
|
||||
|
||||
--*/
|
||||
|
||||
#ifdef DEFINE_GUID
|
||||
|
||||
DEFINE_GUID(
|
||||
PM_SERVICE_INTERFACE_V1,
|
||||
0x5aa2c905,
|
||||
0xd8af,
|
||||
0x4cf2,
|
||||
0x92, 0x56, 0x80, 0xf3, 0xbc, 0xa0, 0x0f, 0x94
|
||||
);
|
||||
|
||||
DEFINE_GUID(
|
||||
PM_MANAGER_INTERFACE_V1,
|
||||
0x4b1130e6,
|
||||
0x724d,
|
||||
0x43b8,
|
||||
0xb7, 0x63, 0x75, 0x72, 0xcb, 0xe6, 0x00, 0xfa
|
||||
);
|
||||
|
||||
DEFINE_GUID(
|
||||
PM_SERVICE_INTERFACE_LAUNCH,
|
||||
0x2a89cc11,
|
||||
0x21ff,
|
||||
0x47d5,
|
||||
0x94, 0xf4, 0x28, 0x52, 0x9f, 0x7f, 0x4f, 0x5e
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef _MSPMS_H_
|
||||
#define _MSPMS_H_
|
||||
|
||||
#ifndef MSMPI_NO_SAL
|
||||
#include <sal.h>
|
||||
#endif
|
||||
|
||||
#include <WS2tcpip.h>
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* SAL ANNOTATIONS */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*
|
||||
* Define SAL annotations if they aren't defined yet.
|
||||
*/
|
||||
#ifndef _In_
|
||||
#define _In_
|
||||
#endif
|
||||
#ifndef _In_z_
|
||||
#define _In_z_
|
||||
#endif
|
||||
#ifndef _Inout_
|
||||
#define _Inout_
|
||||
#endif
|
||||
#ifndef _Out_
|
||||
#define _Out_
|
||||
#endif
|
||||
#ifndef _Outptr_
|
||||
#define _Outptr_
|
||||
#endif
|
||||
|
||||
|
||||
#define MSPMS_MAX_NAME_LENGTH 256
|
||||
|
||||
//
|
||||
// The launch type allows launch managers to specify their security context
|
||||
// requirements for their launch callback.
|
||||
// PmiLaunchTypeSelf:
|
||||
// The launch callback is invoked without any impersonation or client context.
|
||||
// This is used to launch processes under the same credentials as the launch manager.
|
||||
// PmiLaunchTypeImpersonate:
|
||||
// The client security context is impersonated for the launch callback.
|
||||
// PmiLaunchTypeUserSid:
|
||||
// The client's user identifier is passed to the launch callback.
|
||||
//
|
||||
enum PmiLaunchType
|
||||
{
|
||||
PmiLaunchTypeSelf,
|
||||
PmiLaunchTypeImpersonate,
|
||||
PmiLaunchTypeUserSid
|
||||
};
|
||||
|
||||
typedef HRESULT (WINAPI FN_PmiLaunch)(
|
||||
_In_z_ const char* App, //smpd.exe
|
||||
_In_z_ const char* Args, //args to smpd.exe
|
||||
_In_z_ const char* Context //job context string
|
||||
);
|
||||
|
||||
typedef HRESULT (WINAPI FN_PmiLaunchUserSid)(
|
||||
_In_opt_ PSID Sid,
|
||||
_In_z_ const char* App, //smpd.exe
|
||||
_In_z_ const char* Args, //args to smpd.exe
|
||||
_In_z_ const char* Context //job context string
|
||||
);
|
||||
|
||||
typedef struct _PmiManagerInterface
|
||||
{
|
||||
size_t Size;
|
||||
union
|
||||
{
|
||||
FN_PmiLaunch* AsSelf;
|
||||
FN_PmiLaunch* Impersonate;
|
||||
FN_PmiLaunchUserSid* UserSid;
|
||||
} Launch;
|
||||
enum PmiLaunchType LaunchType;
|
||||
} PmiManagerInterface;
|
||||
|
||||
typedef struct _PmiServiceInitData
|
||||
{
|
||||
size_t Size;
|
||||
const char* Name;
|
||||
} PmiServiceInitData;
|
||||
|
||||
//
|
||||
// Initialize the service
|
||||
//
|
||||
typedef HRESULT (WINAPI FN_PmiServiceInitialize)(
|
||||
_In_ const PmiServiceInitData* InitData // Init data
|
||||
);
|
||||
|
||||
//
|
||||
// Cause the calling thread to listen on the supplied address for requests
|
||||
// from Mpiexec.exe to launch the manager process.
|
||||
//
|
||||
typedef HRESULT (WINAPI FN_PmiServiceListen)(
|
||||
_In_ const SOCKADDR_INET* Address, // INET address on which to listen
|
||||
_In_ const PmiManagerInterface* Manager, // Interface to use to launch the smpd manager
|
||||
_In_ REFGUID Version // Version GUID of the PmiManagerInterface
|
||||
);
|
||||
|
||||
//
|
||||
// Signal to the thread that it is time to stop processing completions.
|
||||
//
|
||||
typedef HRESULT (WINAPI FN_PmiServicePostStop)();
|
||||
|
||||
//
|
||||
// Finalize the service
|
||||
//
|
||||
typedef VOID (WINAPI FN_PmiServiceFinalize)();
|
||||
|
||||
typedef struct _PmiServiceInterface
|
||||
{
|
||||
size_t Size;
|
||||
FN_PmiServiceInitialize* Initialize;
|
||||
FN_PmiServiceListen* Listen;
|
||||
FN_PmiServicePostStop* PostStop;
|
||||
FN_PmiServiceFinalize* Finalize;
|
||||
} PmiServiceInterface;
|
||||
|
||||
|
||||
HRESULT
|
||||
WINAPI
|
||||
MSMPI_Get_pm_interface(
|
||||
_In_ REFGUID RequestedVersion,
|
||||
_Inout_ PmiServiceInterface* Interface
|
||||
);
|
||||
|
||||
|
||||
HRESULT
|
||||
WINAPI
|
||||
MSMPI_pm_query_interface(
|
||||
_In_ REFGUID RequestedVersion,
|
||||
_Inout_ void** Interface
|
||||
);
|
||||
|
||||
|
||||
typedef HRESULT(WINAPI FN_PmiCreateLaunchCtx)(
|
||||
_In_ HANDLE clientToken,
|
||||
_In_z_ const void* launchCtx,
|
||||
_In_z_ const char* jobCtx
|
||||
);
|
||||
|
||||
typedef HRESULT(WINAPI FN_PmiStartLaunchCtx)(_In_ const void* launchCtx);
|
||||
typedef HRESULT(WINAPI FN_PmiEndLaunchCtx)(_In_ const void* launchCtx);
|
||||
typedef HRESULT(WINAPI FN_PmiCleanupLaunchCtx)(_In_ const void* launchCtx);
|
||||
typedef void (WINAPI FN_PmiGetLaunchInfo)(
|
||||
_In_ const void* launchCtx,
|
||||
_Outptr_opt_ const char** ppJobObjName,
|
||||
_Outptr_opt_ const char** ppPwd,
|
||||
_Out_opt_ BOOL* pSaveCreds
|
||||
);
|
||||
|
||||
typedef struct _PmiServiceLaunchInterface
|
||||
{
|
||||
FN_PmiCreateLaunchCtx* CreateLaunchCtx;
|
||||
FN_PmiStartLaunchCtx* StartLaunchCtx;
|
||||
FN_PmiEndLaunchCtx* EndLaunchCtx;
|
||||
FN_PmiCleanupLaunchCtx* CleanupLaunchCtx;
|
||||
FN_PmiGetLaunchInfo* GetLaunchInfo;
|
||||
}PmiServiceLaunchInterface;
|
||||
|
||||
|
||||
|
||||
#endif // _MSPMS_H_
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#ifndef OACR_INC_H
|
||||
#define OACR_INC_H
|
||||
|
||||
#define HRESULT_NOT_CHECKED 25031
|
||||
#define COMPARING_HRESULT_TO_INT 6221
|
||||
#define RETVAL_IGNORED_FUNC_COULD_FAIL 6031
|
||||
#define NONCONST_BUFFER_PARAM 25033
|
||||
#define EXCEPT_BLOCK_EMPTY 6322
|
||||
#define PRINTF_FORMAT_STRING_PARAM_NEEDS_REVIEW 25141
|
||||
#define UNSAFE_STRING_FUNCTION 25025
|
||||
#define USE_WIDE_API 25068
|
||||
#define DIFFERENT_PARAM_TYPE_SIZE 25054
|
||||
|
||||
#define OACR_REVIEWED_CALL( reviewer, functionCall ) functionCall
|
||||
#define OACR_WARNING_SUPPRESS( cWarning, comment ) __pragma ( warning( suppress: cWarning ) )
|
||||
#define OACR_WARNING_ENABLE( cWarning, comment ) __pragma ( warning( default: cWarning ) )
|
||||
#define OACR_USE_PTR(p) __noop
|
||||
#define OACR_WARNING_DISABLE( cWarning, comment ) __pragma(warning(disable:cWarning))
|
||||
#endif
|
|
@ -0,0 +1,500 @@
|
|||
#pragma once
|
||||
#ifndef _PmiDbg_H
|
||||
#define _PmiDbg_H
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
//
|
||||
// Summary:
|
||||
// This header provides the extensions interface for the MSMPI Process
|
||||
// Management Interface (PMI) for debuggers and profiling tools.
|
||||
//
|
||||
// Loading and Initialization:
|
||||
// The PMI infrastructure will load the registered extensions in each
|
||||
// process created to support a job. Each created PMI process will
|
||||
// enumerate all extensions and load these extensions. Once all
|
||||
// extensions are loaded, the PMIDBG_NOTIFY_INITIALIZE notification
|
||||
// will be sent to all loaded extensions using the mechanism described
|
||||
// in the Notifications section described below.
|
||||
// NOTE:
|
||||
// There are no implied or explicit ordering guarantees to the loading
|
||||
// or notification system. The only guarantee provided is that the
|
||||
// initialization function PmiDbgInitExtension provided by the
|
||||
// extension will be the first function that is called and the
|
||||
// notifications (if there is any) will be sent to all the loaded
|
||||
// extension via the Notification mechanism
|
||||
//
|
||||
// Registration and Installation:
|
||||
// The actual extension DLLs may be installed anywhere. A 32 bit and a
|
||||
// 64 bit version should be provided. To register the extension to be
|
||||
// loaded, the user, either manually or through some installer, should
|
||||
// create a registry key under
|
||||
// HKLM\Software\Microsoft\Mpi\PmiExtensions. The default value of
|
||||
// this key must be the path to the extension DLL. If just the DLL
|
||||
// name is provided, standard DLL load paths will apply.
|
||||
//
|
||||
// Notifications, Interogation, and Injection:
|
||||
// Each extension will receive notifications through the "Notify"
|
||||
// callback during the various phases of execution. This "Notify"
|
||||
// callback should be provided by the extension. During these
|
||||
// callbacks, the extension can use the provided Control callback to
|
||||
// exchange information with the host process.
|
||||
//
|
||||
// Versioning:
|
||||
// The PMIDBG version is defined as a 16bit value where the high 8
|
||||
// bits represent the major and the low 8 bits minor version. All
|
||||
// versions are incremental and only additive. When the extension is
|
||||
// loaded, it is given the local version information supported by the
|
||||
// host process. The extension must do a min() of the two to determine
|
||||
// the common version. For extensions supporting a lower version than
|
||||
// the host, nothing special is required. For extensions supporting a
|
||||
// higher version than the host, they must to restrict their
|
||||
// extensions use of the PMIDBG APIs to those based on the actual
|
||||
// version of the host.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef MSMPI_NO_SAL
|
||||
#include <sal.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* SAL ANNOTATIONS */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*
|
||||
* Define SAL annotations if they aren't defined yet.
|
||||
*/
|
||||
#ifndef __in
|
||||
#define __in
|
||||
#endif
|
||||
#ifndef __inout_bcount
|
||||
#define __inout_bcount( x )
|
||||
#endif
|
||||
#ifndef __out
|
||||
#define __out
|
||||
#endif
|
||||
|
||||
|
||||
#define PMIDBG_VERSION_1 MAKEWORD(1,0)
|
||||
#define PMIDBG_VERSION_1_1 MAKEWORD(1,1)
|
||||
#ifndef PMIDBG_VERSION
|
||||
# define PMIDBG_VERSION PMIDBG_VERSION_1_1
|
||||
#endif
|
||||
|
||||
//
|
||||
// To register an extension, create a key under the below path in HKLM
|
||||
// with a default value of the path to the dll. The 64 bit registry
|
||||
// root should point to the 64 bit version of the extension, and the
|
||||
// 32 bit registry root should point to the 32 bit version.
|
||||
//
|
||||
#define PMIDBG_REG_PATH_A "Software\\Microsoft\\Mpi\\PmiExtensions"
|
||||
#define PMIDBG_REG_PATH_W L##PMIDBG_REG_PATH_A
|
||||
#define PMIDBG_REG_PATH TEXT(PMIDBG_REG_PATH_A)
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Enumeration values used to identify the role of the host process
|
||||
// that has loaded the extension.
|
||||
//
|
||||
typedef enum _PMIDBG_HOST_TYPE
|
||||
{
|
||||
//
|
||||
// Signifies that the extension is being loaded by the controller
|
||||
// (MPIEXEC). This extension will remain loaded until the entire
|
||||
// task completes or aborts. The extension will be loaded once per
|
||||
// task on a single machine.
|
||||
//
|
||||
PMIDBG_HOST_CONTROLLER = 1,
|
||||
|
||||
//
|
||||
// Signifies that the extension is being loaded by the node
|
||||
// manager (SMPD). This extension will remain loaded until the
|
||||
// entire task completes or aborts. The extension will be loaded
|
||||
// once on each machine that is involved in the job.
|
||||
//
|
||||
PMIDBG_HOST_MANAGER,
|
||||
|
||||
} PMIDBG_HOST_TYPE;
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Enumeration values used to identify the notification event that is
|
||||
// occurring. This value is sent through the notification callback
|
||||
// provided by the extension.
|
||||
//
|
||||
typedef enum _PMIDBG_NOTIFY_TYPE
|
||||
{
|
||||
//
|
||||
// This notification is sent in all host types after all
|
||||
// extensions have been loaded into the host process. Extensions
|
||||
// should use this to collect global information and open any
|
||||
// communication ports that are required.
|
||||
//
|
||||
PMIDBG_NOTIFY_INITIALIZE = 0,
|
||||
|
||||
|
||||
//
|
||||
// This notification is sent when the controller is about to tell
|
||||
// all managers to create the worker processes. Extensions can
|
||||
// use this get to the list of machines and world size
|
||||
// information.
|
||||
//
|
||||
PMIDBG_NOTIFY_BEFORE_CREATE_PROCESSES,
|
||||
|
||||
//
|
||||
// This notification is sent when the controller has receive
|
||||
// confirmation that all worker processes have been created
|
||||
// successfully.
|
||||
//
|
||||
PMIDBG_NOTIFY_AFTER_CREATE_PROCESSES,
|
||||
|
||||
|
||||
//
|
||||
// This notification is sent when the manager is about to create
|
||||
// the worker process. Extensions can obtain the program,
|
||||
// arguments, and rank information of the process that is about to
|
||||
// be created.
|
||||
//
|
||||
PMIDBG_NOTIFY_BEFORE_CREATE_PROCESS,
|
||||
|
||||
//
|
||||
// This notification is sent when the manager has created a
|
||||
// suspended the worker process. Extensions can obtain the
|
||||
// program, arguments, startup info, and rank information of the
|
||||
// process that is about to be created. Additionally, they can
|
||||
// also get the process and thread handles and ids and override
|
||||
// the default behavior to call ResumeThread on the new thread
|
||||
// handle.
|
||||
//
|
||||
PMIDBG_NOTIFY_AFTER_CREATE_PROCESS,
|
||||
|
||||
//
|
||||
// This notification is send before unloading the extension in any
|
||||
// role. This notification is sent either at the end of the task,
|
||||
// or immediately following a notification where the Unload
|
||||
// callback was invoked because of an error.
|
||||
//
|
||||
PMIDBG_NOTIFY_FINALIZE,
|
||||
|
||||
} PMIDBG_NOTIFY_TYPE;
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Identifies the various interogaton routines that can be performed
|
||||
// by extensions.
|
||||
//
|
||||
typedef enum _PMIDBG_OPCODE_TYPE
|
||||
{
|
||||
//
|
||||
// This operation may be sent during any notification on any host
|
||||
// type. The pBuffer argument must point to a PMIDBG_SYSTEM_INFO*
|
||||
// and cbBuffer must be greater than or equal to
|
||||
// sizeof(PMIDBG_SYSTEM_INFO*).
|
||||
//
|
||||
PMIDBG_OPCODE_GET_SYSTEM_INFO = 0,
|
||||
|
||||
//
|
||||
// This operation may be sent during any notification on any host
|
||||
// type. The pBuffer argument must point to a char* and cbBuffer
|
||||
// must be greater than or equal to sizeof(char*).
|
||||
//
|
||||
PMIDBG_OPCODE_GET_JOB_CONTEXT,
|
||||
|
||||
//
|
||||
// This operation may only be sent during the
|
||||
// PMIDBG_NOTIFY_BEFORE_CREATE_PROCESSES notification on the
|
||||
// controller for the job. The pBuffer argument must point to a
|
||||
// UINT and cbBuffer must be greater than or equal to
|
||||
// sizeof(UINT).
|
||||
//
|
||||
PMIDBG_OPCODE_GET_WORLD_SIZE,
|
||||
|
||||
//
|
||||
// This operation may only be sent during the
|
||||
// PMIDBG_NOTIFY_BEFORE_CREATE_PROCESSES notification on the
|
||||
// controller for the job. The pBuffer argument must point to a
|
||||
// PMIDBG_ENUM_WORLD_NODES structure and cbBuffer must be greater
|
||||
// than or equal to sizeof(PMIDBG_ENUM_WORLD_NODES). To start the
|
||||
// enumeration, set the Context field of the
|
||||
// PMIDBG_ENUM_WORLD_NODES structure to PMIDBG_ENUM_BEGIN. The
|
||||
// name of the machine can be obtained from the Hostname field of
|
||||
// the PMIDBG_ENUM_WORLD_NODES structure on return of the Control
|
||||
// callback. The Context field will be set to PMIDBG_ENUM_END
|
||||
// when there are no more items in the list.
|
||||
//
|
||||
PMIDBG_OPCODE_ENUM_WORLD_NODES,
|
||||
|
||||
//
|
||||
// This operation may only be sent during the
|
||||
// PMIDBG_NOTIFY_BEFORE_CREATE_PROCESS and
|
||||
// PMIDBG_NOTIFY_AFTER_CREATE_PROCESS notifications on the manager
|
||||
// for a machine. The pBuffer argument must point to a char* and
|
||||
// cbBuffer must be greater than or equal to sizeof(char*).
|
||||
//
|
||||
PMIDBG_OPCODE_GET_PROCESS_COMMAND,
|
||||
|
||||
//
|
||||
// This operation may only be sent during the
|
||||
// PMIDBG_NOTIFY_BEFORE_CREATE_PROCESS and
|
||||
// PMIDBG_NOTIFY_AFTER_CREATE_PROCESS notifications on the manager
|
||||
// for a machine. The pBuffer argument must point to a char* and
|
||||
// cbBuffer must be greater than or equal to sizeof(char*).
|
||||
//
|
||||
PMIDBG_OPCODE_GET_PROCESS_ARGUMENTS,
|
||||
|
||||
//
|
||||
// This operation may only be sent during the
|
||||
// PMIDBG_NOTIFY_BEFORE_CREATE_PROCESS and
|
||||
// PMIDBG_NOTIFY_AFTER_CREATE_PROCESS notifications on the manager
|
||||
// for a machine. The pBuffer argument must point to a int and
|
||||
// cbBuffer must be greater than or equal to sizeof(int).
|
||||
//
|
||||
PMIDBG_OPCODE_GET_PROCESS_RANK,
|
||||
|
||||
//
|
||||
// This operation may only be sent during the
|
||||
// PMIDBG_NOTIFY_AFTER_CREATE_PROCESS notification on the manager
|
||||
// for a machine. The pBuffer argument must point to a
|
||||
// PROCESS_INFORMATION* and cbBuffer must be greater than or equal
|
||||
// to sizeof(PROCESS_INFORMATION*).
|
||||
//
|
||||
PMIDBG_OPCODE_GET_PROCESS_INFORMATION,
|
||||
|
||||
//
|
||||
// This operation may only be sent during the
|
||||
// PMIDBG_NOTIFY_AFTER_CREATE_PROCESS notification on the manager
|
||||
// for a machine to prevent ResumeThread from being called on the
|
||||
// process that was just created. This leaves the process in a
|
||||
// suspended state. The extension can then use the handle of the
|
||||
// thread to control the startup of the worker process. The
|
||||
// pBuffer and cbBuffer arguments are unused.
|
||||
//
|
||||
PMIDBG_OPCODE_OVERRIDE_PROCESS_RESUME,
|
||||
|
||||
//
|
||||
// This operation may only be sent during the
|
||||
// PMIDBG_NOTIFY_BEFORE_CREATE_PROCESSES notification on the
|
||||
// controller for the job. The pBuffer argument must point to an
|
||||
// int* and cbBuffer must be greater than or equal to sizeof(int*).
|
||||
//
|
||||
PMIDBG_OPCODE_GET_PROCSIZE_ADDR,
|
||||
|
||||
//
|
||||
// This operation may only be sent during the
|
||||
// PMIDBG_NOTIFY_BEFORE_CREATE_PROCESSES notification on the
|
||||
// controller for the job. The pBuffer argument must point to a
|
||||
// MPIR_PROCDESC* and cbBuffer must be greater
|
||||
// than or equal to sizeof(MPIR_PROCDESC*).
|
||||
//
|
||||
PMIDBG_OPCODE_GET_PROCTABLE_ADDR,
|
||||
|
||||
//
|
||||
// This operation may only be sent during the
|
||||
// PMIDBG_NOTIFY_BEFORE_CREATE_PROCESSES notification on the
|
||||
// controller for the job. The pBuffer argument must point to an
|
||||
// int and cbBuffer must be greater than or equal to sizeof(int).
|
||||
// The possible returned values are described in the
|
||||
// MPIDBG_DBG_MODE enum
|
||||
//
|
||||
PMIDBG_OPCODE_GET_DEBUG_MODE,
|
||||
|
||||
} PMIDBG_OPCODE_TYPE;
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// This is the callback function provided by the system to extensions
|
||||
// to allow the extension to get and set information from within host
|
||||
// process.
|
||||
//
|
||||
// Parameters:
|
||||
// type - The type of operation requested by the extension.
|
||||
// pData - The pointer to the data buffer provided in the
|
||||
// notification callback.
|
||||
// Note: This must be the pData argument from the Notify
|
||||
// callback.
|
||||
// pBuffer - This is a pointer to a buffer that is used by the
|
||||
// operation type. See the details of the specific
|
||||
// operation to know the type of data to pass here.
|
||||
// cbBuffer - This is the size of the buffer pointed to by pBuffer
|
||||
//
|
||||
// Returns:
|
||||
// An HRESULT indicating status. Callers should use SUCCEEDED and
|
||||
// FAILED macros to test for error conditions.
|
||||
//
|
||||
typedef HRESULT ( __stdcall FN_PmiDbgControl ) (
|
||||
__in PMIDBG_OPCODE_TYPE type,
|
||||
__in void* pData,
|
||||
__inout_bcount(cbBuffer) void* pBuffer,
|
||||
__in SIZE_T cbBuffer
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// This callback function can be used during notification events to
|
||||
// signify that the extension has entered an error state and needs to
|
||||
// be unloaded. Once the notification returns, the extension will be
|
||||
// finalized and unloaded.
|
||||
//
|
||||
typedef HRESULT ( __stdcall FN_PmiDbgUnload)();
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// This callback is provided by the extension to receive notification
|
||||
// from the host process.
|
||||
//
|
||||
// Parameters:
|
||||
// type - The type of notification that is being sent.
|
||||
// pData - The opaque data buffer that can be used for
|
||||
// Control operations.
|
||||
//
|
||||
typedef VOID ( __stdcall FN_PmiDbgNotify)(
|
||||
__in PMIDBG_NOTIFY_TYPE type,
|
||||
__in void* pData
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// This structure provides the information about the host process.
|
||||
//
|
||||
// Fields:
|
||||
// Version - The current supported version of the host process
|
||||
// Host - The role of the current host process.
|
||||
// AppName - The simple text name for the host process.
|
||||
// LocalName - The hostname of the local machine.
|
||||
// Control - The callback function to get and set information
|
||||
// within the host process
|
||||
// Unload - The callback function used to trigger an
|
||||
// unload of the current extension
|
||||
//
|
||||
typedef struct _PMIDBG_SYSTEM_INFO
|
||||
{
|
||||
ULONG Version;
|
||||
PMIDBG_HOST_TYPE Host;
|
||||
const char* AppName;
|
||||
const char* LocalName;
|
||||
FN_PmiDbgControl* Control;
|
||||
FN_PmiDbgUnload* Unload;
|
||||
|
||||
} PMIDBG_SYSTEM_INFO;
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// This structure provides the information about the extension and
|
||||
// the its supported callbacks.
|
||||
//
|
||||
// Fields:
|
||||
// Version - The min version of the host process and the extension.
|
||||
// Notify - The notification callback invoked when events occur
|
||||
// in the host process.
|
||||
//
|
||||
// Remarks:
|
||||
// The value specified in the Version field is the maximum supported
|
||||
// version by the extension, it may not be fully supported by the
|
||||
// PMI Host process, so the extension must inspect the Version field
|
||||
// of the PMIDBG_SYSTEM_INFO struct during the Initialize callback to
|
||||
// determine the actual version of the interface being supported.
|
||||
//
|
||||
typedef struct _PMIDBG_FUNCTIONS
|
||||
{
|
||||
ULONG Version;
|
||||
FN_PmiDbgNotify* Notify;
|
||||
|
||||
} PMIDBG_FUNCTIONS;
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// This is the export provided by all extensions. It is called after
|
||||
// the DLL is loaded into the host process. If the extension returns
|
||||
// FALSE, the extension is immediately removed from the list and
|
||||
// unloaded.
|
||||
//
|
||||
typedef BOOL ( __stdcall FN_PmiDbgInitExtension)(
|
||||
__in HKEY hKey,
|
||||
__in const PMIDBG_SYSTEM_INFO* pInfo,
|
||||
__out PMIDBG_FUNCTIONS* pFunctions
|
||||
);
|
||||
|
||||
#define PMIDBG_INIT_EXTENSION_FN_NAME "PmiDbgInitExtension"
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// This structure is used during the PMIDBG_OPCODE_ENUM_WORLD_NODES
|
||||
// control operation to access the list of nodes involved in a job.
|
||||
//
|
||||
// Fields:
|
||||
// Context - Opaque context value to identify the current
|
||||
// element in the list. To begin the iteration,
|
||||
// set the value to PMIDBG_ENUM_BEGIN. This field
|
||||
// will be set to PMIDBG_ENUM_END when there are
|
||||
// no more items in the list.
|
||||
// Hostname - On return from the Control callback, this
|
||||
// contains the hostname of the node.
|
||||
//
|
||||
typedef struct _PMIDBG_ENUM_WORLD_NODES
|
||||
{
|
||||
LONG_PTR Context;
|
||||
const char* Hostname;
|
||||
|
||||
} PMIDBG_ENUM_WORLD_NODES;
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// This structure is used during the PMIDBG_OPCODE_GET_PROCTABLE_ADDR
|
||||
// operation to access the information about the MPI processes.
|
||||
//
|
||||
// Fields:
|
||||
// hostname - The name of the host where the process lives in
|
||||
// executable_name - The executable name of the process
|
||||
// pid - The pid of the process
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
char* host_name;
|
||||
char* executable_name;
|
||||
int pid;
|
||||
} MPIR_PROCDESC;
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// This enum describe the possible returned values for the
|
||||
// PMIDBG_OPCODE_GET_DEBUG_MODE operation
|
||||
//
|
||||
// Values:
|
||||
// MPIDBG_DBG_LAUNCH - The job was launched under the debugger
|
||||
// MPIDBG_DBG_ATTACH - The job was not launched under the debugger.
|
||||
// The debugger has attached to the processes
|
||||
// MPIDBG_DBG_DUMP - The job is a debugging job for dump files
|
||||
//
|
||||
typedef enum _MPIDBG_DBG_MODE
|
||||
{
|
||||
MPIDBG_DBG_LAUNCH = 0,
|
||||
MPIDBG_DBG_ATTACH,
|
||||
MPIDBG_DBG_DUMP
|
||||
} MPIDBG_DBG_MODE;
|
||||
|
||||
|
||||
//
|
||||
// Values for the debug_state, this seems to be all we need at the moment
|
||||
// but that may change...
|
||||
//
|
||||
#define MPIR_NULL 0
|
||||
#define MPIR_DEBUG_SPAWNED 1
|
||||
#define MPIR_DEBUG_ABORTING 2
|
||||
|
||||
|
||||
#define PMIDBG_ENUM_BEGIN ((LONG_PTR)0)
|
||||
#define PMIDBG_ENUM_END ((LONG_PTR)-1)
|
||||
|
||||
#endif //#ifndef _PmiDbg_H
|
|
@ -0,0 +1,9 @@
|
|||
! -*- Mode: F77; F90; -*-
|
||||
!
|
||||
! Copyright(c) Microsoft Corporation.All rights reserved.
|
||||
! Licensed under the MIT License.
|
||||
!
|
||||
INTEGER MPI_AINT
|
||||
PARAMETER (MPI_AINT=z'4c00083b')
|
||||
INTEGER MPI_ADDRESS_KIND
|
||||
PARAMETER(MPI_ADDRESS_KIND = 8)
|
|
@ -0,0 +1,9 @@
|
|||
! -*- Mode: F77; F90; -*-
|
||||
!
|
||||
! Copyright(c) Microsoft Corporation.All rights reserved.
|
||||
! Licensed under the MIT License.
|
||||
!
|
||||
INTEGER MPI_AINT
|
||||
PARAMETER (MPI_AINT=z'4c00043b')
|
||||
INTEGER MPI_ADDRESS_KIND
|
||||
PARAMETER(MPI_ADDRESS_KIND = 4)
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include "MsmpiLaunchSvc.h"
|
||||
|
||||
//
|
||||
// Service settings
|
||||
//
|
||||
#define SERVICE_NAME L"MsmpiLaunchSvc"
|
||||
#define SERVICE_START_TYPE SERVICE_AUTO_START
|
||||
|
||||
//
|
||||
// A singleton class that will run as a windows service application.
|
||||
// It handles the interaction with SCM and manages the launch service.
|
||||
//
|
||||
class WindowsSvc
|
||||
{
|
||||
private:
|
||||
SERVICE_TABLE_ENTRYW m_ctrlDispatchTable[2];
|
||||
SERVICE_STATUS_HANDLE m_serviceStatusHandle;
|
||||
SERVICE_STATUS m_serviceStatus;
|
||||
|
||||
private:
|
||||
WindowsSvc();
|
||||
HRESULT ChangeState(_In_ DWORD newState);
|
||||
|
||||
public:
|
||||
MsmpiLaunchService m_launcher;
|
||||
|
||||
HRESULT Start();
|
||||
|
||||
static WindowsSvc ms_windowsSvc;
|
||||
|
||||
static VOID WINAPI ServiceMain(_In_ DWORD argc, _In_ LPWSTR * argv);
|
||||
static VOID WINAPI ServiceCtrlHandler(_In_ DWORD ctrl);
|
||||
};
|
|
@ -0,0 +1,244 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "LaunchSvc.h"
|
||||
#include <oacr.h>
|
||||
|
||||
EventLogger gEventLogger;
|
||||
WindowsSvc WindowsSvc::ms_windowsSvc;
|
||||
|
||||
MsmpiLaunchService& Launcher()
|
||||
{
|
||||
return WindowsSvc::ms_windowsSvc.m_launcher;
|
||||
}
|
||||
|
||||
//
|
||||
// Entry point
|
||||
//
|
||||
int __cdecl main(int /*argc*/, const char* /*argv[]*/)
|
||||
{
|
||||
if (!gEventLogger.Open(SERVICE_NAME))
|
||||
{
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
gEventLogger.WriteEvent(EVENTLOG_INFORMATION_TYPE, SVC_CATEGORY, SERVICE_EVENT, L"Starting Launch Service");
|
||||
|
||||
//
|
||||
// Start MsMpi Launch Service
|
||||
//
|
||||
HRESULT result = WindowsSvc::ms_windowsSvc.Start();
|
||||
|
||||
if (FAILED(result))
|
||||
{
|
||||
gEventLogger.WriteEvent(
|
||||
EVENTLOG_ERROR_TYPE,
|
||||
SVC_CATEGORY,
|
||||
SERVICE_EVENT,
|
||||
L"Failed to start launch service. Error=0x%x\n",
|
||||
result);
|
||||
return result;
|
||||
}
|
||||
|
||||
gEventLogger.WriteEvent(
|
||||
EVENTLOG_INFORMATION_TYPE,
|
||||
SVC_CATEGORY,
|
||||
SERVICE_EVENT,
|
||||
L"Ended Launch Service. Result=0x%x\n",
|
||||
result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* WindowsSvc Class Member Functions */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
WindowsSvc::WindowsSvc()
|
||||
{
|
||||
m_serviceStatus.dwCheckPoint = 0;
|
||||
m_serviceStatus.dwControlsAccepted = 0;
|
||||
m_serviceStatus.dwCurrentState = SERVICE_START_PENDING;
|
||||
m_serviceStatus.dwServiceSpecificExitCode = 0;
|
||||
m_serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||
m_serviceStatus.dwWaitHint = 0;
|
||||
m_serviceStatus.dwWin32ExitCode = 0;
|
||||
|
||||
m_serviceStatusHandle = nullptr;
|
||||
|
||||
m_ctrlDispatchTable[0] = { SERVICE_NAME, ServiceMain };
|
||||
m_ctrlDispatchTable[1] = { nullptr, nullptr };
|
||||
}
|
||||
|
||||
|
||||
HRESULT WindowsSvc::ChangeState(_In_ DWORD newState)
|
||||
{
|
||||
switch (newState)
|
||||
{
|
||||
case SERVICE_RUNNING:
|
||||
m_serviceStatus.dwCurrentState = SERVICE_RUNNING;
|
||||
m_serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
|
||||
break;
|
||||
default:
|
||||
m_serviceStatus.dwCurrentState = newState;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!SetServiceStatus(m_serviceStatusHandle, &m_serviceStatus))
|
||||
{
|
||||
HRESULT result = HRESULT_FROM_WIN32(GetLastError());
|
||||
gEventLogger.WriteEvent(
|
||||
EVENTLOG_ERROR_TYPE,
|
||||
SVC_CATEGORY,
|
||||
SERVICE_EVENT,
|
||||
L"Failed to change service state to %d. Error=0x%x\n",
|
||||
newState,
|
||||
result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Does service specific initializations and registers service loop and control handlers
|
||||
//
|
||||
HRESULT WindowsSvc::Start()
|
||||
{
|
||||
HANDLE processToken;
|
||||
HRESULT result;
|
||||
|
||||
//
|
||||
// Adjust process priviliges so it is able to load user profiles
|
||||
//
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &processToken))
|
||||
{
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
result = SecurityUtils::GrantPrivilege(processToken, SE_BACKUP_NAME, TRUE);
|
||||
if (FAILED(result))
|
||||
{
|
||||
CloseHandle(processToken);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = SecurityUtils::GrantPrivilege(processToken, SE_RESTORE_NAME, TRUE);
|
||||
|
||||
CloseHandle(processToken);
|
||||
|
||||
if (FAILED(result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// Load msmpi service launcher
|
||||
//
|
||||
result = m_launcher.Load();
|
||||
if (FAILED(result))
|
||||
{
|
||||
gEventLogger.WriteEvent(
|
||||
EVENTLOG_ERROR_TYPE,
|
||||
SVC_CATEGORY,
|
||||
SERVICE_EVENT,
|
||||
L"msmpi.dll did not load properly. Error=0x%x\n",
|
||||
result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// Register to SCM
|
||||
//
|
||||
if (!StartServiceCtrlDispatcherW(m_ctrlDispatchTable))
|
||||
{
|
||||
gEventLogger.WriteEvent(
|
||||
EVENTLOG_ERROR_TYPE,
|
||||
SVC_CATEGORY,
|
||||
SERVICE_EVENT,
|
||||
L"Failed to start launch service. Error=0x%x\n",
|
||||
result);
|
||||
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Handles service control requests
|
||||
//
|
||||
VOID WINAPI WindowsSvc::ServiceCtrlHandler(_In_ DWORD ctrl)
|
||||
{
|
||||
switch (ctrl)
|
||||
{
|
||||
//case SERVICE_CONTROL_SHUTDOWN ?
|
||||
case SERVICE_CONTROL_STOP:
|
||||
ms_windowsSvc.m_launcher.Stop();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Main service loop
|
||||
//
|
||||
VOID WINAPI WindowsSvc::ServiceMain(_In_ DWORD argc, _In_ LPWSTR *argv)
|
||||
{
|
||||
ms_windowsSvc.m_serviceStatusHandle =
|
||||
RegisterServiceCtrlHandlerW(SERVICE_NAME, ServiceCtrlHandler);
|
||||
|
||||
if (ms_windowsSvc.m_serviceStatusHandle == nullptr)
|
||||
{
|
||||
gEventLogger.WriteEvent(
|
||||
EVENTLOG_ERROR_TYPE,
|
||||
SVC_CATEGORY,
|
||||
SERVICE_EVENT,
|
||||
L"Failed to register service control handler. Error=0x%x\n",
|
||||
HRESULT_FROM_WIN32(GetLastError()));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ms_windowsSvc.m_launcher.ParseOptions(argc, argv))
|
||||
{
|
||||
ms_windowsSvc.m_serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
|
||||
ms_windowsSvc.m_serviceStatus.dwServiceSpecificExitCode = ERROR_INVALID_PARAMETER;
|
||||
OACR_WARNING_SUPPRESS(HRESULT_NOT_CHECKED, "Don't care about the status of state change - no possible recovery.");
|
||||
ms_windowsSvc.ChangeState(SERVICE_STOPPED);
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Start running launch service
|
||||
//
|
||||
|
||||
HRESULT result = ms_windowsSvc.ChangeState(SERVICE_RUNNING);
|
||||
if (FAILED(result))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
result = ms_windowsSvc.m_launcher.Run();
|
||||
if (FAILED(result))
|
||||
{
|
||||
gEventLogger.WriteEvent(
|
||||
EVENTLOG_ERROR_TYPE,
|
||||
SVC_CATEGORY,
|
||||
SERVICE_EVENT,
|
||||
L"Failed to start listening to PMI clients. Error=0x%x\n",
|
||||
result);
|
||||
|
||||
ms_windowsSvc.m_serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
|
||||
ms_windowsSvc.m_serviceStatus.dwServiceSpecificExitCode = result;
|
||||
}
|
||||
|
||||
OACR_WARNING_SUPPRESS(HRESULT_NOT_CHECKED, "Don't care about the status of state change - no possible recovery.");
|
||||
ms_windowsSvc.ChangeState(SERVICE_STOPPED);
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,186 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include <initguid.h>
|
||||
#include "SvcUtils.h"
|
||||
#include "mspms.h"
|
||||
#include "launchSvcMsg.h"
|
||||
|
||||
|
||||
//
|
||||
// MSMPI PMI settings
|
||||
//
|
||||
#define MSPMI_MODULE_PATH_KEY L"Software\\Microsoft\\MPI"
|
||||
#define MSPMI_PROVIDER_VALUE L"MSPMSProvider"
|
||||
#define MSPMI_PROC_GET_PMI "MSMPI_Get_pm_interface"
|
||||
#define MSPMI_PROC_PMI_QUERY_IF "MSMPI_pm_query_interface"
|
||||
#define MSPMI_CREDENTIAL_VALUE L"MSMPI_Credentials"
|
||||
#define DEFAULT_SERVICE_PORT 8677
|
||||
#define MAXIMUM_CONTEXTS (MAXIMUM_WAIT_OBJECTS - 1)
|
||||
#define SHUTDOWN_TIMEOUT 60000
|
||||
#define NEW_PROCESS_EVENT_IDX 0
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* LaunchContext */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
//
|
||||
// Holds information that is related to a launch context, between start and
|
||||
// end of launch context calls from PMI
|
||||
//
|
||||
class LaunchContext
|
||||
{
|
||||
public:
|
||||
const void* m_pmiHandle;
|
||||
HANDLE m_parentThread;
|
||||
HANDLE m_primaryToken;
|
||||
|
||||
HANDLE m_mgrProcess;
|
||||
HANDLE m_userToken;
|
||||
HANDLE m_userProfile;
|
||||
|
||||
LaunchContext();
|
||||
~LaunchContext();
|
||||
|
||||
void Dispose();
|
||||
};
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* ContextPool */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
//
|
||||
// Thread-safe collection of active launch contexts
|
||||
//
|
||||
class ContextPool
|
||||
{
|
||||
private:
|
||||
LaunchContext m_contexts[MAXIMUM_CONTEXTS];
|
||||
DWORD m_activeIndices[MAXIMUM_CONTEXTS];
|
||||
UINT m_activeContextCount;
|
||||
SRWLOCK m_lock;
|
||||
|
||||
public:
|
||||
template<typename T>
|
||||
using IsMatch = BOOL(*)(_In_ const LaunchContext* pCtx, _In_ const T* pData);
|
||||
|
||||
ContextPool();
|
||||
|
||||
~ContextPool();
|
||||
|
||||
LaunchContext* CreateNewContext();
|
||||
|
||||
BOOL DestroyContext(_In_ LaunchContext* pDeleteContext);
|
||||
|
||||
template<typename T>
|
||||
LaunchContext*
|
||||
FindContext(
|
||||
_In_ IsMatch<T> compareFunct,
|
||||
_In_ const T* pData
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* ProcessQueue */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
class ProcessQueue
|
||||
{
|
||||
private:
|
||||
HANDLE m_runningProcesses[MAXIMUM_WAIT_OBJECTS];
|
||||
HANDLE m_newProcessEvent;
|
||||
volatile DWORD m_count;
|
||||
HANDLE m_thread;
|
||||
volatile BOOL m_run;
|
||||
CRITICAL_SECTION m_lock;
|
||||
|
||||
static DWORD WINAPI WaitProcesses(_In_ LPVOID pData);
|
||||
|
||||
DWORD GetCountSafe();
|
||||
|
||||
HANDLE DeleteProcess(_In_ DWORD idx);
|
||||
|
||||
public:
|
||||
ProcessQueue();
|
||||
|
||||
~ProcessQueue();
|
||||
|
||||
HRESULT Initialize();
|
||||
|
||||
HRESULT AddProcess(_In_ HANDLE newProcess);
|
||||
|
||||
HRESULT Start();
|
||||
|
||||
HRESULT Stop();
|
||||
};
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* MsmpiLaunchService */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
class MsmpiLaunchService
|
||||
{
|
||||
typedef
|
||||
HRESULT
|
||||
(WINAPI *PFN_MSMPI_GET_PM_INTERFACE)(
|
||||
_In_ REFGUID RequestedVersion,
|
||||
_Inout_ PmiServiceInterface* Interface
|
||||
);
|
||||
|
||||
typedef
|
||||
HRESULT
|
||||
(WINAPI *PFN_MSMPI_PM_QUERY_INTERFACE)(
|
||||
_In_ REFGUID RequestedVersion,
|
||||
_Inout_ void** Interface
|
||||
);
|
||||
|
||||
private:
|
||||
HMODULE m_pmiModule;
|
||||
PmiServiceInterface m_pmiService;
|
||||
PmiServiceLaunchInterface* m_pMspmiServiceLaunch;
|
||||
USHORT m_servicePort;
|
||||
PSID m_pMemberGroupSid;
|
||||
ContextPool m_contextPool;
|
||||
ProcessQueue m_mgrQueue;
|
||||
|
||||
public:
|
||||
MsmpiLaunchService();
|
||||
~MsmpiLaunchService();
|
||||
HRESULT Load();
|
||||
BOOL ParseOptions(_In_ DWORD argc, _In_ LPWSTR *argv);
|
||||
HRESULT Run();
|
||||
VOID Stop();
|
||||
VOID ManagerProcessTerminated(_In_ HANDLE mgrProcess);
|
||||
|
||||
static HRESULT
|
||||
WINAPI ServiceCreateManagerProcess(
|
||||
_In_z_ PCSTR app,
|
||||
_In_z_ PCSTR args,
|
||||
_In_z_ PCSTR context
|
||||
);
|
||||
|
||||
static HRESULT
|
||||
WINAPI ServiceCreateLaunchCtx(
|
||||
_In_ HANDLE clientToken,
|
||||
_In_ const void* launchCtx,
|
||||
_In_z_ const char* jobCtx
|
||||
);
|
||||
|
||||
static HRESULT WINAPI ServiceStartLaunchCtx(_In_ const void* launchCtx);
|
||||
static HRESULT WINAPI ServiceCleanupLaunchCtx(_In_ const void* launchCtx);
|
||||
|
||||
private:
|
||||
|
||||
HRESULT
|
||||
DoLogonUser(
|
||||
_In_ LPCWSTR pPwd,
|
||||
_In_ BOOL saveCreds,
|
||||
_Outptr_ PHANDLE pLogonHandle
|
||||
);
|
||||
};
|
|
@ -0,0 +1,84 @@
|
|||
;
|
||||
; // Launch Service Message Texts
|
||||
;
|
||||
|
||||
|
||||
;
|
||||
; // Header
|
||||
;
|
||||
|
||||
SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS
|
||||
Informational=0x1:STATUS_SEVERITY_INFORMATIONAL
|
||||
Warning=0x2:STATUS_SEVERITY_WARNING
|
||||
Error=0x3:STATUS_SEVERITY_ERROR
|
||||
)
|
||||
|
||||
|
||||
FacilityNames=(System=0x0:FACILITY_SYSTEM
|
||||
Runtime=0x2:FACILITY_RUNTIME
|
||||
Stubs=0x3:FACILITY_STUBS
|
||||
Io=0x4:FACILITY_IO_ERROR_CODE
|
||||
)
|
||||
|
||||
LanguageNames=(English=0x409:MSG00409)
|
||||
|
||||
|
||||
;
|
||||
; // Event Categories
|
||||
;
|
||||
|
||||
MessageIdTypedef=WORD
|
||||
|
||||
MessageId=0x1
|
||||
SymbolicName=SVC_CATEGORY
|
||||
Language=English
|
||||
MsMpi Launch Service Events
|
||||
.
|
||||
|
||||
MessageId=0x2
|
||||
SymbolicName=CLIENT_CATEGORY
|
||||
Language=English
|
||||
MsMpi Launch Service Client Events
|
||||
.
|
||||
|
||||
|
||||
;
|
||||
; // Message Definitions
|
||||
;
|
||||
|
||||
MessageIdTypedef=DWORD
|
||||
|
||||
MessageId=0x1
|
||||
Severity=Success
|
||||
Facility=Runtime
|
||||
SymbolicName=SERVICE_EVENT
|
||||
Language=English
|
||||
%1
|
||||
.
|
||||
|
||||
MessageId=0x100
|
||||
Severity=Success
|
||||
Facility=Runtime
|
||||
SymbolicName=SERVICE_STARTED
|
||||
Language=English
|
||||
MsMpi Launch Service started succesfully.
|
||||
.
|
||||
|
||||
|
||||
MessageId=0x101
|
||||
Severity=Informational
|
||||
Facility=Runtime
|
||||
SymbolicName=SERVICE_STATE_CHANGE
|
||||
Language=English
|
||||
MsMpi Launch Service state change from %1 to %2.
|
||||
.
|
||||
|
||||
|
||||
MessageId=0x102
|
||||
Severity=Error
|
||||
Facility=System
|
||||
;// !!!!!!!!!!!!!!!
|
||||
SymbolicName=MSG_BAD_FILE_CONTENTS
|
||||
Language=English
|
||||
File %1 contains content that is not valid.
|
||||
.
|
|
@ -0,0 +1,11 @@
|
|||
#include <windows.h>
|
||||
#include <ntverp.h>
|
||||
|
||||
#define VER_FILETYPE VFT_APP
|
||||
#define VER_FILESUBTYPE VFT2_UNKNOWN
|
||||
#define VER_FILEDESCRIPTION_STR "Microsoft MPI Launch Service"
|
||||
#define VER_INTERNALNAME_STR "msmpilaunchsvc"
|
||||
#define VER_ORIGINALFILENAME_STR "msmpilaunchsvc.exe"
|
||||
|
||||
#include "common.ver"
|
||||
#include "launchsvcmsg.rc"
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<Import Project="$(SrcRoot)\mpi.props" />
|
||||
|
||||
<PropertyGroup Label="Globals">
|
||||
<TargetName>msmpiLaunchSvc</TargetName>
|
||||
<ProjectGuid>{03cfde58-e72e-41d7-85ed-43150db0ca44}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<AssemblyDescription>Microsoft MPI Launch Service</AssemblyDescription>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Configuration">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>
|
||||
%(AdditionalIncludeDirectories);
|
||||
$(SrcRoot)\mpi\msmpi\include;
|
||||
$(SrcRoot)\mpi\common;
|
||||
.\$(O);
|
||||
</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
|
||||
<AdditionalDependencies>
|
||||
%(AdditionalDependencies);
|
||||
$(PUBLIC_SDK_LIB)\kernel32.lib;
|
||||
$(PUBLIC_SDK_LIB)\crypt32.lib;
|
||||
$(PUBLIC_SDK_LIB)\advapi32.lib;
|
||||
$(PUBLIC_SDK_LIB)\userenv.lib;
|
||||
$(CRT_Libs);
|
||||
</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="msmpiLaunchSvcMc.vcxproj" />
|
||||
<ProjectReference Include="$(MPI_SRC_ROOT)\stub\mpistub.vcxproj" />
|
||||
<ProjectReference Include="$(MPI_SRC_ROOT)\common\mpicommon.vcxproj" />
|
||||
<Link Include="$(StagingOutputRootPath)\mpicommon\mpicommon.lib"/>
|
||||
<Link Include="$(StagingOutputRootPath)\mpistub\mpistub.lib"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ClCompile Include=".\msmpilaunchsvc.cpp" />
|
||||
<ClCompile Include=".\launchsvcmain.cpp" />
|
||||
<ResourceCompile Include="$(O)\launchsvcmsg.rc" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<StagingOutputPath>$(MPI_BIN_DESTINATION)</StagingOutputPath>
|
||||
<OutFileType>*.exe</OutFileType>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{8E3235C8-9024-4915-BFA6-8F79FFAEC14A}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<Import Project="$(SrcRoot)\mpi.props" />
|
||||
<PropertyGroup>
|
||||
<AssemblyDescription>Microsoft MPI Launch Service</AssemblyDescription>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>None</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ItemGroup>
|
||||
<MessageCompile Include="launchsvcmsg.mc">
|
||||
<GeneratedHeaderPath>true</GeneratedHeaderPath>
|
||||
<HeaderFilePath>$(SrcRoot)\launchsvc\$(O)</HeaderFilePath>
|
||||
<GeneratedRCAndMessagesPath>true</GeneratedRCAndMessagesPath>
|
||||
<RCFilePath>$(SrcRoot)\launchsvc\$(O)</RCFilePath>
|
||||
</MessageCompile>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
|
@ -0,0 +1,168 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<Target Name="SetMSMPIVersion" BeforeTargets="ClCompile" >
|
||||
<PropertyGroup>
|
||||
<!-- No shift operation, so multiply by powers of 2.
|
||||
Also, hex numbers don't seem to be allowed, so the bitwise AND operations use decimal instead of all Fs.
|
||||
-->
|
||||
|
||||
<ProductMajorVersion>10</ProductMajorVersion>
|
||||
<ProductMinorVersion>0</ProductMinorVersion>
|
||||
<BuildMajorVersion>12498</BuildMajorVersion>
|
||||
<BuildMinorVersion>5</BuildMinorVersion>
|
||||
|
||||
<_MSMPI_VER_>$([MSBuild]::BitwiseOr(`$([MSBuild]::Multiply(`$(ProductMajorVersion)`, `256`))`, `$([MSBuild]::BitwiseAnd(`$(ProductMinorVersion)`, `255`))`))</_MSMPI_VER_>
|
||||
<_MSMPI_VER_EX_>$([MSBuild]::BitwiseOr(`$([MSBuild]::Multiply(`$(_MSMPI_VER_)`, `65536`))`, `$([MSBuild]::BitwiseAnd(`$(BuildMinorVersion)`, `65535`))`))</_MSMPI_VER_EX_>
|
||||
<_MSMPI_BUILDNUM_>$(BuildMajorVersion)</_MSMPI_BUILDNUM_>
|
||||
<_MSMPI_FILEREV_>$(BuildMinorVersion)</_MSMPI_FILEREV_>
|
||||
|
||||
</PropertyGroup>
|
||||
<GetFrameworkSdkPath>
|
||||
<Output TaskParameter="Path" PropertyName="WindowsSdkPath"/>
|
||||
</GetFrameworkSdkPath>
|
||||
<ItemGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>
|
||||
%(PreprocessorDefinitions);
|
||||
MSMPI_VER=$(_MSMPI_VER_);
|
||||
MSMPI_VER_EX=$(_MSMPI_VER_EX_);
|
||||
_BLDVERMAJOR=$(ProductMajorVersion);
|
||||
_BLDVERMINOR=$(ProductMinorVersion);
|
||||
_BLDNUMMAJOR=$(BuildMajorVersion);
|
||||
_BLDNUMMINOR=$(BuildMinorVersion);
|
||||
</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<Message Text="MSMPI Version $(ProductMajorVersion).$(ProductMinorVersion).$(BuildMajorVersion).$(BuildMinorVersion) - $(_MSMPI_VER_) - $(_MSMPI_VER_EX_)" />
|
||||
</Target>
|
||||
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x86">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x86">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<CRT_Libs>libucrtd.lib;libcmtd.lib;libvcruntimed.lib</CRT_Libs>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
<CRT_Libs>libucrt.lib;libcmt.lib;libvcruntime.lib</CRT_Libs>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(BuildArchitecture)'=='amd64'" >
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_WIN64=1;_AMD64_=1;AMD64=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalOptions>%(AdditionalOptions) /favor:AMD64</AdditionalOptions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(BuildArchitecture)'=='i386'" >
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_X86_=1;i386=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>DBG=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<Optimization>Full</Optimization>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PreprocessorDefinitions>NDEBUG=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ControlFlowGuard>Guard</ControlFlowGuard>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>
|
||||
%(PreprocessorDefinitions);
|
||||
_WIN32_WINNT=_WIN32_WINNT_WIN10;
|
||||
</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>
|
||||
%(AdditionalIncludeDirectories);
|
||||
</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<UseFullPaths>true</UseFullPaths>
|
||||
<OmitDefaultLibName>true</OmitDefaultLibName>
|
||||
<StringPooling>true</StringPooling>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<ExceptionHandling>false</ExceptionHandling>
|
||||
<StructMemberAlignment>8Bytes</StructMemberAlignment>
|
||||
<DebugInformationFormat>OldStyle</DebugInformationFormat>
|
||||
<TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
|
||||
<DisableSpecificWarnings>
|
||||
4986;4987;4471;4369;4309;4603;4627;
|
||||
28251;28252;28253;
|
||||
%(DisableSpecificWarnings)
|
||||
</DisableSpecificWarnings>
|
||||
<FloatingPointModel Condition="'$(BuildArchitecture)'=='i386'">Strict</FloatingPointModel>
|
||||
<CallingConvention Condition="'$(BuildArchitecture)'=='i386'">stdcall</CallingConvention>
|
||||
<ForcedIncludeFiles>
|
||||
warning.h;
|
||||
$(MPI_INC_ROOT)\mpiwarning.h
|
||||
</ForcedIncludeFiles>
|
||||
<AdditionalIncludeDirectories>
|
||||
%(AdditionalIncludeDirectories);
|
||||
$(MPI_INC_PATH);
|
||||
$(MPI_SRC_ROOT)\common
|
||||
</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>
|
||||
%(PreprocessorDefinitions);
|
||||
_WINSOCK_DEPRECATED_NO_WARNINGS;
|
||||
VER_USE_OTHER_MAJOR_MINOR_VER;
|
||||
HAVE_DEBUGGER_SUPPORT=1;
|
||||
HAVE_FORTRAN_BINDING=1;
|
||||
USE_HUMAN_READABLE_TOKENS=1;
|
||||
_USE_DECLSPECS_FOR_SAL=1;
|
||||
WIN32_LEAN_AND_MEAN=1;
|
||||
CONDITION_HANDLING=1;
|
||||
_CRT_SECURE_NO_WARNINGS=1;
|
||||
</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions Condition="'$(NO_MPICH_DLL)'==''">
|
||||
%(PreprocessorDefinitions);
|
||||
_MPICH_DLL_=1;
|
||||
</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<LinkTimeCodeGeneration Condition="'$(BuildType)'!='Debug'">UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,270 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "MpiLock.h"
|
||||
//
|
||||
// This file defines function pointers to the core Win32 lock functions
|
||||
// that are used by the MSMPI stack. We store these as function pointers
|
||||
// so that we can replace them with "NOP" functions when we run in single
|
||||
// threaded mode.
|
||||
//
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Prototype functions for the platform locking functions we wrap.
|
||||
//
|
||||
|
||||
typedef void WINAPI
|
||||
FN_InitializeCriticalSection(
|
||||
_Out_ LPCRITICAL_SECTION lpCriticalSection
|
||||
);
|
||||
|
||||
typedef void WINAPI
|
||||
FN_DeleteCriticalSection(
|
||||
_Inout_ LPCRITICAL_SECTION lpCriticalSection
|
||||
);
|
||||
|
||||
typedef void WINAPI
|
||||
FN_EnterCriticalSection(
|
||||
_Inout_ LPCRITICAL_SECTION CriticalSection
|
||||
);
|
||||
|
||||
typedef void WINAPI
|
||||
FN_LeaveCriticalSection(
|
||||
_Inout_ LPCRITICAL_SECTION CriticalSection
|
||||
);
|
||||
|
||||
typedef VOID WINAPI
|
||||
FN_InitializeSRWLock(
|
||||
_Out_ PSRWLOCK SRWLock
|
||||
);
|
||||
|
||||
typedef VOID WINAPI
|
||||
FN_AcquireSRWLockExclusive(
|
||||
_Inout_ PSRWLOCK SRWLock
|
||||
);
|
||||
|
||||
typedef VOID WINAPI
|
||||
FN_AcquireSRWLockShared(
|
||||
_Inout_ PSRWLOCK SRWLock
|
||||
);
|
||||
|
||||
typedef VOID WINAPI
|
||||
FN_ReleaseSRWLockExclusive(
|
||||
_Inout_ PSRWLOCK SRWLock
|
||||
);
|
||||
|
||||
typedef VOID WINAPI
|
||||
FN_ReleaseSRWLockShared(
|
||||
_Inout_ PSRWLOCK SRWLock
|
||||
);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Empty lock function for SingleThread mode
|
||||
//
|
||||
static void WINAPI
|
||||
MpiLockNoThread(
|
||||
_Inout_ LPCRITICAL_SECTION
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Empty read/writer lock function for SingleThread mode
|
||||
//
|
||||
static VOID WINAPI
|
||||
MpiRwLockNoThread(
|
||||
_Inout_ PSRWLOCK
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Global list of all Locking functions MPI will use in
|
||||
// both ST and MT scenarios (IE, Shared code paths).
|
||||
//
|
||||
static struct _MpiLockFunctions
|
||||
{
|
||||
|
||||
FN_InitializeCriticalSection* LockInitialize;
|
||||
FN_DeleteCriticalSection* LockDelete;
|
||||
FN_EnterCriticalSection* LockEnter;
|
||||
FN_LeaveCriticalSection* LockLeave;
|
||||
|
||||
|
||||
FN_InitializeSRWLock* RwLockInitialize;
|
||||
FN_AcquireSRWLockExclusive* RwLockAcquireExclusive;
|
||||
FN_ReleaseSRWLockExclusive* RwLockReleaseExclusive;
|
||||
|
||||
FN_AcquireSRWLockShared* RwLockAcquireShared;
|
||||
FN_ReleaseSRWLockShared* RwLockReleaseShared;
|
||||
|
||||
} MpiLockFunctions =
|
||||
//
|
||||
// NOTE: We set the default locking behavior to be ON
|
||||
// this means that all locks function as expected by default
|
||||
// and can be disabled with a call to MpiLockInitializeSingleThreadMode
|
||||
//
|
||||
{
|
||||
InitializeCriticalSection,
|
||||
DeleteCriticalSection,
|
||||
EnterCriticalSection,
|
||||
LeaveCriticalSection,
|
||||
InitializeSRWLock,
|
||||
AcquireSRWLockExclusive,
|
||||
ReleaseSRWLockExclusive,
|
||||
AcquireSRWLockShared,
|
||||
ReleaseSRWLockShared
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Initialize the local process to skip all locking functions.
|
||||
//
|
||||
VOID
|
||||
MpiLockInitializeSingleThreadMode()
|
||||
{
|
||||
MpiLockFunctions.LockInitialize = MpiLockNoThread;
|
||||
MpiLockFunctions.LockDelete = MpiLockNoThread;
|
||||
MpiLockFunctions.LockEnter = MpiLockNoThread;
|
||||
MpiLockFunctions.LockLeave = MpiLockNoThread;
|
||||
MpiLockFunctions.RwLockInitialize = MpiRwLockNoThread;
|
||||
MpiLockFunctions.RwLockAcquireExclusive = MpiRwLockNoThread;
|
||||
MpiLockFunctions.RwLockReleaseExclusive = MpiRwLockNoThread;
|
||||
MpiLockFunctions.RwLockAcquireShared = MpiRwLockNoThread;
|
||||
MpiLockFunctions.RwLockReleaseShared = MpiRwLockNoThread;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Initializes a MPI_LOCK (CRITICAL_SECTION)
|
||||
//
|
||||
VOID
|
||||
MpiLockInitialize(
|
||||
_Out_ MPI_LOCK* Lock
|
||||
)
|
||||
{
|
||||
MpiLockFunctions.LockInitialize(Lock);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Deletes a MPI_LOCK (CRITICAL_SECTION)
|
||||
//
|
||||
VOID
|
||||
MpiLockDelete(
|
||||
_Inout_ MPI_LOCK* Lock
|
||||
)
|
||||
{
|
||||
MpiLockFunctions.LockDelete(Lock);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Enters a MPI_LOCK (CRITICAL_SECTION)
|
||||
//
|
||||
VOID
|
||||
MpiLockEnter(
|
||||
_Inout_ MPI_LOCK* Lock
|
||||
)
|
||||
{
|
||||
MpiLockFunctions.LockEnter(Lock);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Leaves a MPI_LOCK (CRITICAL_SECTION)
|
||||
//
|
||||
VOID
|
||||
MpiLockLeave(
|
||||
_Inout_ MPI_LOCK* Lock
|
||||
)
|
||||
{
|
||||
MpiLockFunctions.LockLeave(Lock);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Initialize a MPI_RWLOCK (SRWLOCK)
|
||||
//
|
||||
VOID
|
||||
MpiRwLockInitialize(
|
||||
_Out_ MPI_RWLOCK* RwLock
|
||||
)
|
||||
{
|
||||
MpiLockFunctions.RwLockInitialize(RwLock);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Acquire Exclusive access for a MPI_RWLOCK (SRWLOCK)
|
||||
//
|
||||
VOID
|
||||
MpiRwLockAcquireExclusive(
|
||||
_Inout_ MPI_RWLOCK* RwLock
|
||||
)
|
||||
{
|
||||
MpiLockFunctions.RwLockAcquireExclusive(RwLock);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Release Exclusive access for a MPI_RWLOCK (SRWLOCK)
|
||||
//
|
||||
VOID
|
||||
MpiRwLockReleaseExclusive(
|
||||
_Inout_ MPI_RWLOCK* RwLock
|
||||
)
|
||||
{
|
||||
MpiLockFunctions.RwLockReleaseExclusive(RwLock);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Acquire Shared access for a MPI_RWLOCK (SRWLOCK)
|
||||
//
|
||||
VOID
|
||||
MpiRwLockAcquireShared(
|
||||
_Inout_ MPI_RWLOCK* RwLock
|
||||
)
|
||||
{
|
||||
MpiLockFunctions.RwLockAcquireShared(RwLock);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Release Shared access for a MPI_RWLOCK (SRWLOCK)
|
||||
//
|
||||
VOID
|
||||
MpiRwLockReleaseShared(
|
||||
_Inout_ MPI_RWLOCK* RwLock
|
||||
)
|
||||
{
|
||||
MpiLockFunctions.RwLockReleaseShared(RwLock);
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} //extern "C" {
|
||||
#endif
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef SRWLOCK MPI_RWLOCK;
|
||||
typedef CRITICAL_SECTION MPI_LOCK;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
VOID
|
||||
MpiLockInitializeSingleThreadMode();
|
||||
|
||||
VOID
|
||||
MpiLockInitialize(
|
||||
_Out_ MPI_LOCK* Lock
|
||||
);
|
||||
|
||||
VOID
|
||||
MpiLockDelete(
|
||||
_Inout_ MPI_LOCK* Lock
|
||||
);
|
||||
|
||||
VOID
|
||||
MpiLockEnter(
|
||||
_Inout_ MPI_LOCK* Lock
|
||||
);
|
||||
|
||||
VOID
|
||||
MpiLockLeave(
|
||||
_Inout_ MPI_LOCK* Lock
|
||||
);
|
||||
|
||||
#define MPI_RWLOCK_INIT SRWLOCK_INIT
|
||||
|
||||
VOID
|
||||
MpiRwLockInitialize(
|
||||
_Out_ MPI_RWLOCK* RwLock
|
||||
);
|
||||
|
||||
VOID
|
||||
MpiRwLockAcquireExclusive(
|
||||
_Inout_ MPI_RWLOCK* RwLock
|
||||
);
|
||||
|
||||
VOID
|
||||
MpiRwLockReleaseExclusive(
|
||||
_Inout_ MPI_RWLOCK* RwLock
|
||||
);
|
||||
|
||||
VOID
|
||||
MpiRwLockAcquireShared(
|
||||
_Inout_ MPI_RWLOCK* RwLock
|
||||
);
|
||||
|
||||
VOID
|
||||
MpiRwLockReleaseShared(
|
||||
_Inout_ MPI_RWLOCK* RwLock
|
||||
);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} //extern "C" {
|
||||
#endif
|
|
@ -0,0 +1,546 @@
|
|||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*
|
||||
* This file includes definitions of utility functions:
|
||||
* Windows Event Logger Utilities
|
||||
* Registry Utilities
|
||||
* Security Utilities
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
#include "SvcUtils.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Windows Event Logger Utility Class */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
EventLogger::EventLogger()
|
||||
: m_eventLog(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
EventLogger::~EventLogger()
|
||||
{
|
||||
DeregisterEventSource(m_eventLog);
|
||||
}
|
||||
|
||||
|
||||
BOOL EventLogger::Open(_In_z_ PCWSTR pEventSource)
|
||||
{
|
||||
m_eventLog = RegisterEventSourceW(nullptr, pEventSource);
|
||||
if (m_eventLog == nullptr)
|
||||
{
|
||||
wprintf(
|
||||
L"Cannot register event source %s with error 0x%x\n",
|
||||
pEventSource,
|
||||
GetLastError()
|
||||
);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Writes formatted sting to event log.
|
||||
//
|
||||
void
|
||||
EventLogger::WriteEvent(
|
||||
_In_ WORD type,
|
||||
_In_ WORD category,
|
||||
_In_ DWORD eventId,
|
||||
_Printf_format_string_ LPCWSTR pFormatStr,
|
||||
...
|
||||
)
|
||||
{
|
||||
WCHAR buffer[MAX_LOG_TEXT];
|
||||
va_list args;
|
||||
|
||||
va_start(args, pFormatStr);
|
||||
|
||||
HRESULT hr = StringCchVPrintfW(buffer, _countof(buffer), pFormatStr, args);
|
||||
|
||||
va_end(args);
|
||||
|
||||
LPCWSTR eventStr = buffer;
|
||||
|
||||
if(hr != S_OK && hr != STRSAFE_E_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
//
|
||||
// STRSAFE_E_INSUFFICIENT_BUFFER is acceptable since truncated messages
|
||||
// are good enough.
|
||||
//
|
||||
eventStr = L"Failed to form event message.";
|
||||
}
|
||||
|
||||
ReportEventW(
|
||||
m_eventLog,
|
||||
type,
|
||||
category,
|
||||
eventId,
|
||||
nullptr,
|
||||
1,
|
||||
0,
|
||||
&eventStr,
|
||||
nullptr
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Registry Access Utility Class */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
HRESULT
|
||||
RegistryUtils::ReadKey(
|
||||
_In_ HKEY key,
|
||||
_In_opt_z_ LPCWSTR pSubKey,
|
||||
_In_z_ LPCWSTR pValueName,
|
||||
_Inout_ LPDWORD pcbValue,
|
||||
_Out_ LPWSTR pValue
|
||||
)
|
||||
{
|
||||
HKEY readKey;
|
||||
|
||||
LONG result = RegOpenKeyExW(key, pSubKey, 0, KEY_READ, &readKey);
|
||||
|
||||
if( result != ERROR_SUCCESS )
|
||||
{
|
||||
return HRESULT_FROM_WIN32( result );
|
||||
}
|
||||
|
||||
result = RegGetValueW(
|
||||
readKey,
|
||||
nullptr,
|
||||
pValueName,
|
||||
RRF_RT_REG_SZ,
|
||||
nullptr,
|
||||
pValue,
|
||||
pcbValue
|
||||
);
|
||||
|
||||
RegCloseKey(readKey);
|
||||
|
||||
return HRESULT_FROM_WIN32( result );
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Reads a key in HKEY_CURRENT_USER for the user the current thread is impersonating.
|
||||
//
|
||||
HRESULT
|
||||
RegistryUtils::ReadCurrentUserKey(
|
||||
_In_opt_z_ LPCWSTR pSubKey,
|
||||
_In_z_ LPCWSTR pValueName,
|
||||
_Inout_ LPDWORD pCapValue,
|
||||
_Out_writes_z_(*pCapValue) LPWSTR pValue
|
||||
)
|
||||
{
|
||||
HKEY currentUser = nullptr;
|
||||
LONG result = RegOpenCurrentUser(KEY_READ, ¤tUser);
|
||||
if (result != ERROR_SUCCESS)
|
||||
{
|
||||
return HRESULT_FROM_WIN32(result);
|
||||
}
|
||||
|
||||
result = RegGetValueW(
|
||||
currentUser,
|
||||
pSubKey,
|
||||
pValueName,
|
||||
RRF_RT_REG_SZ,
|
||||
nullptr,
|
||||
pValue,
|
||||
pCapValue
|
||||
);
|
||||
|
||||
RegCloseKey(currentUser);
|
||||
return HRESULT_FROM_WIN32(result);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Writes to a key in HKEY_CURRENT_USER for the user the current thread is impersonating.
|
||||
// Creates the key if it does not exist.
|
||||
//
|
||||
HRESULT
|
||||
RegistryUtils::WriteCurrentUserKey(
|
||||
_In_opt_z_ LPCWSTR pSubKey,
|
||||
_In_ LPCWSTR pValueName,
|
||||
_In_ DWORD capValue,
|
||||
_In_ LPCWSTR pValue
|
||||
)
|
||||
{
|
||||
HKEY currentUser = nullptr;
|
||||
HKEY hWrite = nullptr;
|
||||
LONG result = ERROR_SUCCESS;
|
||||
DWORD disposition;
|
||||
|
||||
result = RegOpenCurrentUser(KEY_WRITE, ¤tUser);
|
||||
if (result != ERROR_SUCCESS)
|
||||
{
|
||||
goto exit_fn;
|
||||
}
|
||||
|
||||
//
|
||||
// Opens or creates registry key.
|
||||
//
|
||||
result = RegCreateKeyExW(
|
||||
currentUser,
|
||||
pSubKey,
|
||||
0,
|
||||
nullptr,
|
||||
0,
|
||||
KEY_WRITE,
|
||||
nullptr,
|
||||
&hWrite,
|
||||
&disposition
|
||||
);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
{
|
||||
goto exit_fn;
|
||||
}
|
||||
|
||||
result = RegSetValueExW(
|
||||
hWrite,
|
||||
pValueName,
|
||||
0,
|
||||
RRF_RT_REG_SZ,
|
||||
reinterpret_cast<const BYTE*>(pValue),
|
||||
capValue
|
||||
);
|
||||
|
||||
exit_fn:
|
||||
RegCloseKey(currentUser);
|
||||
RegCloseKey(hWrite);
|
||||
return HRESULT_FROM_WIN32(result);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Security Access Utility Class */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
//
|
||||
// Creates a primary token that duplicates the access token of the calling thread.
|
||||
// Caller must CloseHandle when it is no longer needed.
|
||||
//
|
||||
HRESULT SecurityUtils::GetCurrentThreadPrimaryToken(_Out_ PHANDLE pPrimaryToken)
|
||||
{
|
||||
HANDLE token;
|
||||
HRESULT result = NO_ERROR;
|
||||
|
||||
if (!OpenThreadToken(
|
||||
GetCurrentThread(),
|
||||
TOKEN_ALL_ACCESS,
|
||||
TRUE,
|
||||
&token)
|
||||
)
|
||||
{
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
if (!DuplicateTokenEx(
|
||||
token,
|
||||
TOKEN_ALL_ACCESS,
|
||||
nullptr,
|
||||
SecurityImpersonation,
|
||||
TokenPrimary,
|
||||
pPrimaryToken)
|
||||
)
|
||||
{
|
||||
result = HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
CloseHandle(token);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Checks if given token is a member of the well known group.
|
||||
//
|
||||
HRESULT
|
||||
SecurityUtils::IsGroupMember(
|
||||
_In_ WELL_KNOWN_SID_TYPE wellKnownSidType,
|
||||
_In_ HANDLE token,
|
||||
_Out_ PBOOL pIsMember
|
||||
)
|
||||
{
|
||||
SID* pGroupSid = nullptr;
|
||||
DWORD cbSid = 0;
|
||||
HRESULT result = NO_ERROR;
|
||||
|
||||
*pIsMember = FALSE;
|
||||
|
||||
//
|
||||
// Get the size of group sid
|
||||
//
|
||||
if (!CreateWellKnownSid(wellKnownSidType, nullptr, pGroupSid, &cbSid))
|
||||
{
|
||||
DWORD gle = GetLastError();
|
||||
if (gle != ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
result = HRESULT_FROM_WIN32(gle);
|
||||
goto exit_fn;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Allocate necessary memory for group sid and create it
|
||||
//
|
||||
pGroupSid = static_cast<SID*>(malloc(cbSid));
|
||||
if (pGroupSid == nullptr)
|
||||
{
|
||||
result = ERROR_OUTOFMEMORY;
|
||||
goto exit_fn;
|
||||
}
|
||||
|
||||
if (!CreateWellKnownSid(wellKnownSidType, nullptr, pGroupSid, &cbSid))
|
||||
{
|
||||
result = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto exit_fn;
|
||||
}
|
||||
|
||||
//
|
||||
// Check token membership
|
||||
//
|
||||
if (!CheckTokenMembership(token, pGroupSid, pIsMember))
|
||||
{
|
||||
result = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto exit_fn;
|
||||
}
|
||||
|
||||
exit_fn:
|
||||
free(pGroupSid);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
HRESULT
|
||||
SecurityUtils::IsCurrentProcessInteractive(
|
||||
_Out_ PBOOL pIsInteractive
|
||||
)
|
||||
{
|
||||
if (pIsInteractive == nullptr)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
//
|
||||
// nullptr token makes API use an impersonation token of the calling thread
|
||||
//
|
||||
return IsGroupMember(WinInteractiveSid, nullptr, pIsInteractive);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Gets the user name and domain for given token.
|
||||
//
|
||||
HRESULT
|
||||
SecurityUtils::GetTokenUser(
|
||||
_In_ HANDLE token,
|
||||
_Out_opt_ LPWSTR pUser,
|
||||
_Inout_ LPDWORD pcchUser,
|
||||
_Out_opt_ LPWSTR pDomain,
|
||||
_Inout_ LPDWORD pcchDomain
|
||||
)
|
||||
{
|
||||
PTOKEN_USER pTokenUser = nullptr;
|
||||
DWORD cbTokenUser = 0;
|
||||
HRESULT result = S_OK;
|
||||
SID_NAME_USE snu;
|
||||
|
||||
while (!GetTokenInformation(
|
||||
token,
|
||||
TokenUser,
|
||||
pTokenUser,
|
||||
cbTokenUser,
|
||||
&cbTokenUser)
|
||||
)
|
||||
{
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
result = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto exit_fn;
|
||||
}
|
||||
|
||||
free(pTokenUser);
|
||||
pTokenUser = static_cast<PTOKEN_USER>(malloc(cbTokenUser));
|
||||
if (pTokenUser == nullptr)
|
||||
{
|
||||
result = E_OUTOFMEMORY;
|
||||
goto exit_fn;
|
||||
}
|
||||
}
|
||||
|
||||
Assert(pTokenUser != nullptr);
|
||||
|
||||
if (!LookupAccountSidW(
|
||||
nullptr,
|
||||
pTokenUser->User.Sid,
|
||||
pUser,
|
||||
pcchUser,
|
||||
pDomain,
|
||||
pcchDomain,
|
||||
&snu))
|
||||
{
|
||||
result = HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
exit_fn:
|
||||
free(pTokenUser);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Gets the user name and domain of the current user.
|
||||
//
|
||||
HRESULT
|
||||
SecurityUtils::GetCurrentUser(
|
||||
_Out_opt_ LPWSTR pUser,
|
||||
_Inout_ LPDWORD pcchUser,
|
||||
_Out_opt_ LPWSTR pDomain,
|
||||
_Inout_ LPDWORD pcchDomain
|
||||
)
|
||||
{
|
||||
HANDLE currentToken = nullptr;
|
||||
HRESULT result;
|
||||
|
||||
if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, ¤tToken))
|
||||
{
|
||||
DWORD gle = GetLastError();
|
||||
if (gle != ERROR_NO_TOKEN)
|
||||
{
|
||||
result = HRESULT_FROM_WIN32(gle);
|
||||
goto exit_fn;
|
||||
}
|
||||
|
||||
//
|
||||
// If current thread does not have a token, use process token
|
||||
//
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, ¤tToken))
|
||||
{
|
||||
result = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto exit_fn;
|
||||
}
|
||||
}
|
||||
|
||||
result = GetTokenUser(currentToken, pUser, pcchUser, pDomain, pcchDomain);
|
||||
|
||||
exit_fn:
|
||||
CloseHandle(currentToken);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
HRESULT
|
||||
SecurityUtils::GrantPrivilege(
|
||||
_In_ HANDLE hToken,
|
||||
_In_ LPCTSTR privilege,
|
||||
_In_ BOOL enable
|
||||
)
|
||||
{
|
||||
TOKEN_PRIVILEGES adjustedPrivs;
|
||||
LUID luid;
|
||||
|
||||
if (!LookupPrivilegeValue(
|
||||
nullptr,
|
||||
privilege,
|
||||
&luid))
|
||||
{
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
adjustedPrivs.PrivilegeCount = 1;
|
||||
adjustedPrivs.Privileges[0].Luid = luid;
|
||||
adjustedPrivs.Privileges[0].Attributes = (enable ? SE_PRIVILEGE_ENABLED : 0);
|
||||
|
||||
AdjustTokenPrivileges(
|
||||
hToken,
|
||||
FALSE,
|
||||
&adjustedPrivs,
|
||||
0,
|
||||
nullptr,
|
||||
nullptr);
|
||||
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Get the SID for a given account/group name.
|
||||
// Caller is responsible for invoking free(*ppSid).
|
||||
//
|
||||
HRESULT
|
||||
SecurityUtils::GetSidForAccount(
|
||||
_In_opt_z_ LPCWSTR pSystemName,
|
||||
_In_ LPCWSTR pAccountName,
|
||||
_Outptr_ PSID* ppSid
|
||||
)
|
||||
{
|
||||
PSID pSid = nullptr;
|
||||
LPWSTR pRefDomain = nullptr;
|
||||
DWORD cbRefDomain = 0;
|
||||
DWORD cbSid = 0;
|
||||
SID_NAME_USE eUse;
|
||||
|
||||
if (LookupAccountNameW(
|
||||
pSystemName,
|
||||
pAccountName,
|
||||
0,
|
||||
&cbSid,
|
||||
0,
|
||||
&cbRefDomain,
|
||||
&eUse))
|
||||
{
|
||||
return HRESULT_FROM_WIN32(ERROR_NONE_MAPPED);
|
||||
}
|
||||
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
if (cbSid != 0)
|
||||
{
|
||||
pSid = static_cast<PSID>(malloc(cbSid));
|
||||
if (pSid == nullptr)
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
if (cbRefDomain != 0)
|
||||
{
|
||||
pRefDomain = static_cast<LPWSTR>(malloc(cbRefDomain * sizeof(wchar_t)));
|
||||
if (pRefDomain == nullptr)
|
||||
{
|
||||
free(pSid);
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
if (!LookupAccountNameW(
|
||||
pSystemName,
|
||||
pAccountName,
|
||||
pSid,
|
||||
&cbSid,
|
||||
pRefDomain,
|
||||
&cbRefDomain,
|
||||
&eUse))
|
||||
{
|
||||
free(pRefDomain);
|
||||
free(pSid);
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
free(pRefDomain);
|
||||
*ppSid = pSid;
|
||||
return S_OK;
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*
|
||||
* This file includes declarations of utility classes:
|
||||
* Windows Event Logger Utilities
|
||||
* Registry Utilities
|
||||
* Security Utilities
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <Windows.h>
|
||||
#include <strsafe.h>
|
||||
#include <sddl.h>
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Windows Event Logger Utility Class */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#define MAX_LOG_TEXT 1024
|
||||
|
||||
class EventLogger
|
||||
{
|
||||
private:
|
||||
HANDLE m_eventLog;
|
||||
|
||||
public:
|
||||
EventLogger();
|
||||
|
||||
BOOL Open(_In_z_ PCWSTR pEventSource);
|
||||
|
||||
void
|
||||
WriteEvent(
|
||||
_In_ WORD type,
|
||||
_In_ WORD category,
|
||||
_In_ DWORD eventId,
|
||||
_Printf_format_string_ PCWSTR pFormatStr,
|
||||
...
|
||||
);
|
||||
|
||||
~EventLogger();
|
||||
};
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Registry Access Utility Class */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
class RegistryUtils
|
||||
{
|
||||
public:
|
||||
static HRESULT
|
||||
ReadKey(
|
||||
_In_ HKEY key,
|
||||
_In_opt_z_ LPCWSTR pSubKey,
|
||||
_In_z_ LPCWSTR pValueName,
|
||||
_Inout_ LPDWORD pcbValue,
|
||||
_Out_ LPWSTR pValue
|
||||
);
|
||||
|
||||
static HRESULT
|
||||
ReadCurrentUserKey(
|
||||
_In_opt_z_ LPCWSTR pSubKey,
|
||||
_In_z_ LPCWSTR pValueName,
|
||||
_Inout_ LPDWORD pcbValue,
|
||||
_Out_writes_z_(*pcbValue) LPWSTR pValue
|
||||
);
|
||||
|
||||
static HRESULT
|
||||
WriteCurrentUserKey(
|
||||
_In_opt_z_ LPCWSTR pSubKey,
|
||||
_In_z_ LPCWSTR pValueName,
|
||||
_In_ DWORD cbValue,
|
||||
_In_z_ LPCWSTR pValue
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Security Access Utility Class */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
class SecurityUtils
|
||||
{
|
||||
public:
|
||||
static HRESULT GetCurrentThreadPrimaryToken(_Out_ PHANDLE pPrimaryToken);
|
||||
|
||||
static HRESULT
|
||||
IsGroupMember(
|
||||
_In_ WELL_KNOWN_SID_TYPE wellKnownSidType,
|
||||
_In_ HANDLE token,
|
||||
_Out_ PBOOL pIsMember
|
||||
);
|
||||
|
||||
static HRESULT
|
||||
GetTokenUser(
|
||||
_In_ HANDLE token,
|
||||
_Out_opt_ LPWSTR pUser,
|
||||
_Inout_ LPDWORD pcchUser,
|
||||
_Out_opt_ LPWSTR pDomain,
|
||||
_Inout_ LPDWORD pcchDomain
|
||||
);
|
||||
|
||||
static HRESULT
|
||||
GetCurrentUser(
|
||||
_Out_opt_ LPWSTR pUser,
|
||||
_Inout_ LPDWORD pcchUser,
|
||||
_Out_opt_ LPWSTR pDomain,
|
||||
_Inout_ LPDWORD pcchDomain
|
||||
);
|
||||
|
||||
static HRESULT
|
||||
GrantPrivilege(
|
||||
_In_ HANDLE token,
|
||||
_In_ LPCTSTR privilege,
|
||||
_In_ BOOL enable
|
||||
);
|
||||
|
||||
static HRESULT
|
||||
GetSidForAccount(
|
||||
_In_opt_z_ LPCWSTR pSystemName,
|
||||
_In_z_ LPCWSTR pAccountName,
|
||||
_Outptr_ PSID* ppSid
|
||||
);
|
||||
|
||||
static HRESULT
|
||||
IsCurrentProcessInteractive(
|
||||
_Out_ PBOOL pIsInteractive
|
||||
);
|
||||
};
|
|
@ -0,0 +1,95 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "util.h"
|
||||
#include "kernel32util.h"
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Ensure that the OS version is greater than or equal to the specified version.
|
||||
//
|
||||
// Parameters:
|
||||
// major - Windows major version
|
||||
// minor - Windows minor version
|
||||
//
|
||||
_Success_(return!=FALSE)
|
||||
BOOL
|
||||
CheckOSVersion(
|
||||
_In_ DWORD major,
|
||||
_In_ DWORD minor
|
||||
)
|
||||
{
|
||||
OSVERSIONINFOEX version = {};
|
||||
ULONG mask = VER_MAJORVERSION | VER_MINORVERSION;
|
||||
ULONGLONG conditions = 0;
|
||||
|
||||
version.dwOSVersionInfoSize = sizeof(version);
|
||||
version.dwMajorVersion = major;
|
||||
version.dwMinorVersion = minor;
|
||||
|
||||
conditions = ::VerSetConditionMask( conditions, VER_MAJORVERSION, VER_GREATER_EQUAL );
|
||||
conditions = ::VerSetConditionMask( conditions, VER_MINORVERSION, VER_GREATER_EQUAL );
|
||||
|
||||
return ::VerifyVersionInfo( &version, mask, conditions );
|
||||
}
|
||||
|
||||
|
||||
static const wchar_t * const AZURE_REGISTRY_VALUE = L"NodeLogicalName";
|
||||
static const wchar_t * const AZURE_REGISTRY_KEY = L"SOFTWARE\\MICROSOFT\\HPC";
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Check if the smpd instance is running on azure and if so,
|
||||
// return the logical name of the node
|
||||
//
|
||||
// Input:
|
||||
// szBuffer: the size of the name buffer
|
||||
//
|
||||
// Output:
|
||||
// buffer : store the logical name. If null, name is not returned
|
||||
//
|
||||
// Return:
|
||||
// true if the node is on azure
|
||||
// false if the node is not on azure, or if the size of the buffer is
|
||||
// too small
|
||||
//
|
||||
//
|
||||
bool get_azure_node_logical_name(
|
||||
_Out_opt_z_cap_(szBuffer) wchar_t* buffer,
|
||||
_In_ DWORD szBuffer )
|
||||
{
|
||||
HKEY key;
|
||||
DWORD size = szBuffer - 1;
|
||||
DWORD status = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
|
||||
AZURE_REGISTRY_KEY,
|
||||
NULL,
|
||||
KEY_READ,
|
||||
&key );
|
||||
|
||||
if( status != ERROR_SUCCESS )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
status = RegQueryValueExW( key,
|
||||
AZURE_REGISTRY_VALUE,
|
||||
NULL,
|
||||
NULL,
|
||||
reinterpret_cast<BYTE*>(buffer),
|
||||
&size );
|
||||
|
||||
RegCloseKey( key );
|
||||
|
||||
if( status != ERROR_SUCCESS )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( buffer != NULL )
|
||||
{
|
||||
buffer[size] = L'\0';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,697 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
* Copyright (C) 1997 University of Chicago.
|
||||
* See COPYRIGHT notice in top-level directory.
|
||||
*/
|
||||
#include "precomp.h"
|
||||
|
||||
|
||||
#define MPIU_STR_TRUNCATED MPIU_STR_NOMEM
|
||||
|
||||
_Success_(return != nullptr)
|
||||
_Ret_z_
|
||||
static const char *
|
||||
first_token(
|
||||
_In_opt_z_ const char *str
|
||||
)
|
||||
{
|
||||
if (str == nullptr)
|
||||
return nullptr;
|
||||
/* isspace is defined only if isascii is true */
|
||||
while (/*isascii(*str) && isspace(*str)*/ *str == MPIU_STR_SEPAR_CHAR)
|
||||
str++;
|
||||
if (*str == '\0')
|
||||
return nullptr;
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
_Ret_maybenull_z_
|
||||
static const char*
|
||||
next_token(
|
||||
_In_opt_z_ const char *str
|
||||
)
|
||||
{
|
||||
if (str == nullptr)
|
||||
return nullptr;
|
||||
str = first_token(str);
|
||||
if (str == nullptr)
|
||||
return nullptr;
|
||||
if (*str == MPIU_STR_QUOTE_CHAR)
|
||||
{
|
||||
/* move over string */
|
||||
str++; /* move over the first quote */
|
||||
if (*str == '\0')
|
||||
return nullptr;
|
||||
while (*str != MPIU_STR_QUOTE_CHAR)
|
||||
{
|
||||
/* move until the last quote, ignoring escaped characters */
|
||||
if (*str == MPIU_STR_ESCAPE_CHAR)
|
||||
{
|
||||
str++;
|
||||
}
|
||||
str++;
|
||||
if (*str == '\0')
|
||||
return nullptr;
|
||||
}
|
||||
str++; /* move over the last quote */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*str == MPIU_STR_DELIM_CHAR)
|
||||
{
|
||||
/* move over the DELIM token */
|
||||
str++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* move over literal */
|
||||
while (/*(isascii(*str) &&
|
||||
!isspace(*str)) &&*/
|
||||
*str != MPIU_STR_SEPAR_CHAR &&
|
||||
*str != MPIU_STR_DELIM_CHAR &&
|
||||
*str != '\0')
|
||||
str++;
|
||||
}
|
||||
}
|
||||
return first_token(str);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_token(
|
||||
_In_opt_z_ const char *token,
|
||||
_In_opt_z_ const char *str
|
||||
)
|
||||
{
|
||||
if (token == nullptr || str == nullptr)
|
||||
return -1;
|
||||
|
||||
if (*token == MPIU_STR_QUOTE_CHAR)
|
||||
{
|
||||
/* compare quoted strings */
|
||||
token++; /* move over the first quote */
|
||||
/* compare characters until reaching the end of the string or the end quote character */
|
||||
for(;;)
|
||||
{
|
||||
if (*token == MPIU_STR_ESCAPE_CHAR)
|
||||
{
|
||||
token++;
|
||||
if (*token != *str)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*token != *str || *token == MPIU_STR_QUOTE_CHAR)
|
||||
break;
|
||||
}
|
||||
if (*str == '\0')
|
||||
break;
|
||||
token++;
|
||||
str++;
|
||||
}
|
||||
if (*str == '\0' && *token == MPIU_STR_QUOTE_CHAR)
|
||||
return 0;
|
||||
if (*token == MPIU_STR_QUOTE_CHAR)
|
||||
return 1;
|
||||
if (*str < *token)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* compare DELIM token */
|
||||
if (*token == MPIU_STR_DELIM_CHAR)
|
||||
{
|
||||
if (*str == MPIU_STR_DELIM_CHAR)
|
||||
{
|
||||
str++;
|
||||
if (*str == '\0')
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
if (*token < *str)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* compare literals */
|
||||
while (*token == *str &&
|
||||
*str != '\0' &&
|
||||
*token != MPIU_STR_DELIM_CHAR &&
|
||||
(/*isascii(*token) && !isspace(*token)*/ *token != MPIU_STR_SEPAR_CHAR) )
|
||||
{
|
||||
token++;
|
||||
str++;
|
||||
}
|
||||
if ( (*str == '\0') &&
|
||||
(*token == MPIU_STR_DELIM_CHAR ||
|
||||
(/*isascii(*token) && isspace(*token)*/ *token == MPIU_STR_SEPAR_CHAR) || *token == '\0') )
|
||||
return 0;
|
||||
if (*token == MPIU_STR_DELIM_CHAR ||
|
||||
(/*isascii(*token) && isspace(*token)*/ *token == MPIU_STR_SEPAR_CHAR) || *token < *str)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
_Success_(return == MPIU_STR_SUCCESS)
|
||||
static int
|
||||
token_copy(
|
||||
_In_opt_z_ const char *token,
|
||||
_Out_writes_z_(maxlen) char *str,
|
||||
_In_ size_t maxlen
|
||||
)
|
||||
{
|
||||
/* check parameters */
|
||||
if (token == nullptr || str == nullptr)
|
||||
return MPIU_STR_FAIL;
|
||||
|
||||
/* check special buffer lengths */
|
||||
if (maxlen < 1)
|
||||
return MPIU_STR_FAIL;
|
||||
if (maxlen == 1)
|
||||
{
|
||||
*str = '\0';
|
||||
return (token[0] == '\0') ? MPIU_STR_SUCCESS : MPIU_STR_TRUNCATED;
|
||||
}
|
||||
|
||||
/* cosy up to the token */
|
||||
token = first_token(token);
|
||||
if (token == nullptr)
|
||||
{
|
||||
*str = '\0';
|
||||
return MPIU_STR_SUCCESS;
|
||||
}
|
||||
|
||||
if (*token == MPIU_STR_DELIM_CHAR)
|
||||
{
|
||||
/* copy the special deliminator token */
|
||||
str[0] = MPIU_STR_DELIM_CHAR;
|
||||
str[1] = '\0';
|
||||
return MPIU_STR_SUCCESS;
|
||||
}
|
||||
|
||||
if (*token == MPIU_STR_QUOTE_CHAR)
|
||||
{
|
||||
/* quoted copy */
|
||||
token++; /* move over the first quote */
|
||||
|
||||
do
|
||||
{
|
||||
if (*token == MPIU_STR_QUOTE_CHAR)
|
||||
{
|
||||
*str = '\0';
|
||||
return MPIU_STR_SUCCESS;
|
||||
}
|
||||
|
||||
if (*token == MPIU_STR_ESCAPE_CHAR)
|
||||
{
|
||||
token++;
|
||||
}
|
||||
|
||||
if( *token == '\0' )
|
||||
{
|
||||
//
|
||||
// Bad input - we're expecting a closing quote
|
||||
//
|
||||
return MPIU_STR_FAIL;
|
||||
}
|
||||
|
||||
*str = *token;
|
||||
str++;
|
||||
token++;
|
||||
|
||||
} while( --maxlen > 0 );
|
||||
|
||||
/* we've run out of destination characters so back up and null terminate the string */
|
||||
str--;
|
||||
*str = '\0';
|
||||
return MPIU_STR_TRUNCATED;
|
||||
}
|
||||
|
||||
/* literal copy */
|
||||
while (*token != MPIU_STR_DELIM_CHAR &&
|
||||
(/*isascii(*token) && !isspace(*token)*/ *token != MPIU_STR_SEPAR_CHAR) && *token != '\0' && maxlen)
|
||||
{
|
||||
*str = *token;
|
||||
str++;
|
||||
token++;
|
||||
maxlen--;
|
||||
}
|
||||
if (maxlen)
|
||||
{
|
||||
*str = '\0';
|
||||
return MPIU_STR_SUCCESS;
|
||||
}
|
||||
str--;
|
||||
*str = '\0';
|
||||
return MPIU_STR_TRUNCATED;
|
||||
}
|
||||
|
||||
|
||||
/*@ MPIU_Str_get_string_arg - Extract an option from a string with a maximum length
|
||||
|
||||
Input Parameters:
|
||||
+ str - Source string
|
||||
. key - key
|
||||
- val_len - Maximum total length of 'val'
|
||||
|
||||
Output Parameter:
|
||||
. val - output string
|
||||
|
||||
Return value:
|
||||
MPIU_STR_SUCCESS, MPIU_STR_NOMEM, MPIU_STR_FAIL
|
||||
|
||||
Notes:
|
||||
This routine searches for a "key = value" entry in a string
|
||||
|
||||
Module:
|
||||
Utility
|
||||
@*/
|
||||
_Success_(return == MPIU_STR_SUCCESS)
|
||||
int
|
||||
MPIU_Str_get_string_arg(
|
||||
_In_opt_z_ const char* str,
|
||||
_In_opt_z_ const char* flag,
|
||||
_Out_writes_z_(val_len) char* val,
|
||||
_In_ size_t val_len
|
||||
)
|
||||
{
|
||||
if (val_len < 1)
|
||||
return MPIU_STR_FAIL;
|
||||
|
||||
/* line up with the first token */
|
||||
str = first_token(str);
|
||||
if (str == nullptr)
|
||||
return MPIU_STR_FAIL;
|
||||
|
||||
/* This loop will match the first instance of "flag = value" in the string. */
|
||||
do
|
||||
{
|
||||
if (compare_token(str, flag) == 0)
|
||||
{
|
||||
str = next_token(str);
|
||||
if (compare_token(str, MPIU_STR_DELIM_STR) == 0)
|
||||
{
|
||||
str = next_token(str);
|
||||
if (str == nullptr)
|
||||
return MPIU_STR_FAIL;
|
||||
return token_copy(str, val, val_len);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
str = next_token(str);
|
||||
}
|
||||
} while (str);
|
||||
return MPIU_STR_FAIL;
|
||||
}
|
||||
|
||||
|
||||
/*@ MPIU_Str_get_int_arg - Extract an option from a string
|
||||
|
||||
Input Parameters:
|
||||
+ str - Source string
|
||||
- key - key
|
||||
|
||||
Output Parameter:
|
||||
. val_ptr - pointer to the output integer
|
||||
|
||||
Return value:
|
||||
MPIU_STR_SUCCESS, MPIU_STR_NOMEM, MPIU_STR_FAIL
|
||||
|
||||
Notes:
|
||||
This routine searches for a "key = value" entry in a string and decodes the value
|
||||
back to an int.
|
||||
|
||||
Module:
|
||||
Utility
|
||||
@*/
|
||||
_Success_(return == MPIU_STR_SUCCESS)
|
||||
int
|
||||
MPIU_Str_get_int_arg(
|
||||
_In_z_ const char *str,
|
||||
_In_z_ const char *flag,
|
||||
_Out_ int *val_ptr
|
||||
)
|
||||
{
|
||||
int result;
|
||||
char int_str[12];
|
||||
|
||||
result = MPIU_Str_get_string_arg(str, flag, int_str, _countof(int_str));
|
||||
if (result == MPIU_STR_SUCCESS)
|
||||
{
|
||||
*val_ptr = atoi(int_str);
|
||||
return MPIU_STR_SUCCESS;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* quoted_printf does not nullptr terminate the string if maxlen is reached */
|
||||
_Success_(return < maxlen)
|
||||
static
|
||||
int
|
||||
quoted_printf(
|
||||
_Out_writes_z_(maxlen) char *str,
|
||||
_In_ int maxlen,
|
||||
_In_z_ const char *val)
|
||||
{
|
||||
int count = 0;
|
||||
if (maxlen < 1)
|
||||
return 0;
|
||||
*str = MPIU_STR_QUOTE_CHAR;
|
||||
str++;
|
||||
maxlen--;
|
||||
count++;
|
||||
while (maxlen)
|
||||
{
|
||||
if (*val == '\0')
|
||||
break;
|
||||
if (*val == MPIU_STR_QUOTE_CHAR || *val == MPIU_STR_ESCAPE_CHAR)
|
||||
{
|
||||
*str = MPIU_STR_ESCAPE_CHAR;
|
||||
str++;
|
||||
maxlen--;
|
||||
count++;
|
||||
if (maxlen == 0)
|
||||
return count;
|
||||
}
|
||||
*str = *val;
|
||||
str++;
|
||||
maxlen--;
|
||||
count++;
|
||||
val++;
|
||||
}
|
||||
if (maxlen)
|
||||
{
|
||||
*str = MPIU_STR_QUOTE_CHAR;
|
||||
str++;
|
||||
maxlen--;
|
||||
count++;
|
||||
if (maxlen == 0)
|
||||
return count;
|
||||
*str = '\0';
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/*@ MPIU_Str_add_string - Add a string to a string
|
||||
|
||||
Input Parameters:
|
||||
+ str_ptr - pointer to the destination string
|
||||
. maxlen_ptr - pointer to the maximum length of '*str_ptr'
|
||||
- val - string to add
|
||||
|
||||
Output Parameter:
|
||||
+ str_ptr - The string pointer is updated to the next available location in the string
|
||||
- maxlen_ptr - maxlen is decremented by the amount str_ptr is incremented
|
||||
|
||||
Return value:
|
||||
MPIU_STR_SUCCESS, MPIU_STR_NOMEM, MPIU_STR_FAIL
|
||||
|
||||
Notes:
|
||||
This routine adds a string to a string in such a way that MPIU_Str_get_string can
|
||||
retreive the same string back. It takes into account spaces and quote characters.
|
||||
The string pointer is updated to the start of the next string in the string and maxlen
|
||||
is updated accordingly.
|
||||
|
||||
Module:
|
||||
Utility
|
||||
@*/
|
||||
_Success_(return == MPIU_STR_SUCCESS)
|
||||
int
|
||||
MPIU_Str_add_string(
|
||||
_Inout_ _Outptr_result_buffer_(*maxlen_ptr) PSTR* str_ptr,
|
||||
_Inout_ int *maxlen_ptr,
|
||||
_In_z_ const char *val
|
||||
)
|
||||
{
|
||||
int num_chars;
|
||||
char *str;
|
||||
int maxlen;
|
||||
|
||||
str = *str_ptr;
|
||||
maxlen = *maxlen_ptr;
|
||||
|
||||
if (strchr(val, MPIU_STR_SEPAR_CHAR) ||
|
||||
strchr(val, MPIU_STR_QUOTE_CHAR) ||
|
||||
strchr(val, MPIU_STR_DELIM_CHAR))
|
||||
{
|
||||
num_chars = quoted_printf(str, maxlen, val);
|
||||
if (num_chars == maxlen)
|
||||
{
|
||||
/* truncation, cleanup string */
|
||||
*str = '\0';
|
||||
return -1;
|
||||
}
|
||||
if (num_chars < maxlen - 1)
|
||||
{
|
||||
str[num_chars] = MPIU_STR_SEPAR_CHAR;
|
||||
str[num_chars+1] = '\0';
|
||||
num_chars++;
|
||||
}
|
||||
else
|
||||
{
|
||||
str[num_chars] = '\0';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*val == '\0')
|
||||
{
|
||||
num_chars = MPIU_Snprintf(str, maxlen, MPIU_STR_QUOTE_STR MPIU_STR_QUOTE_STR/*"\"\""*/);
|
||||
}
|
||||
else
|
||||
{
|
||||
num_chars = MPIU_Snprintf(str, maxlen, "%s%c", val, MPIU_STR_SEPAR_CHAR);
|
||||
}
|
||||
if ((num_chars < 0) || (num_chars == maxlen))
|
||||
{
|
||||
*str = '\0';
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
*str_ptr += num_chars;
|
||||
*maxlen_ptr -= num_chars;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*@ MPIU_Str_get_string - Get the next string from a string
|
||||
|
||||
Input Parameters:
|
||||
+ str_ptr - pointer to the destination string
|
||||
- val_len - to the maximum length of '*str_ptr'
|
||||
|
||||
Output Parameter:
|
||||
+ str_ptr - location of the next string
|
||||
- val - location to store the string
|
||||
|
||||
Return Value:
|
||||
The return value is 0 for success, -1 for insufficient buffer space, and -2 for failure.
|
||||
|
||||
Notes:
|
||||
This routine gets a string that was previously added by MPIU_Str_add_string.
|
||||
It takes into account spaces and quote characters. The string pointer is updated to the
|
||||
start of the next string in the string.
|
||||
|
||||
Module:
|
||||
Utility
|
||||
@*/
|
||||
|
||||
_Success_(return == 0)
|
||||
int
|
||||
MPIU_Str_get_string(
|
||||
_Inout_ _Outptr_result_maybenull_z_ PCSTR* str_ptr,
|
||||
_Out_writes_z_(val_len)char *val,
|
||||
_In_ size_t val_len
|
||||
)
|
||||
{
|
||||
int result;
|
||||
PCSTR str;
|
||||
|
||||
if (str_ptr == nullptr)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (val_len < 1)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
str = *str_ptr;
|
||||
*val = '\0';
|
||||
|
||||
/* line up with the first token */
|
||||
str = first_token(str);
|
||||
if (str == nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* copy the token */
|
||||
result = token_copy(str, val, val_len);
|
||||
if (result == MPIU_STR_SUCCESS)
|
||||
{
|
||||
str = next_token(str);
|
||||
*str_ptr = str;
|
||||
return 0;
|
||||
}
|
||||
else if (result == MPIU_STR_TRUNCATED)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* failure */
|
||||
return -2;
|
||||
}
|
||||
|
||||
/*@ MPIU_Str_add_string_arg - Add an option to a string with a maximum length
|
||||
|
||||
Input Parameters:
|
||||
+ str_ptr - Pointer to the destination string
|
||||
. maxlen_ptr - Pointer to the maximum total length of '*str_ptr'
|
||||
. key - key
|
||||
- val - input string
|
||||
|
||||
Output Parameter:
|
||||
+ str_ptr - The string pointer is updated to the next available location in the string
|
||||
- maxlen_ptr - maxlen is reduced by the number of characters written
|
||||
|
||||
Return value:
|
||||
MPIU_STR_SUCCESS, MPIU_STR_NOMEM, MPIU_STR_FAIL
|
||||
|
||||
Notes:
|
||||
This routine adds a string option to a string in the form "key = value".
|
||||
|
||||
Module:
|
||||
Utility
|
||||
@*/
|
||||
_Success_(return == MPIU_STR_SUCCESS)
|
||||
int
|
||||
MPIU_Str_add_string_arg(
|
||||
_Inout_ _Outptr_result_buffer_(*maxlen_ptr) PSTR* str_ptr,
|
||||
_Inout_ int *maxlen_ptr,
|
||||
_In_z_ const char *flag,
|
||||
_In_z_ const char *val
|
||||
)
|
||||
{
|
||||
int num_chars;
|
||||
char *orig_str_ptr;
|
||||
int orig_maxlen;
|
||||
|
||||
if (maxlen_ptr == nullptr)
|
||||
return MPIU_STR_FAIL;
|
||||
|
||||
orig_maxlen = *maxlen_ptr;
|
||||
orig_str_ptr = *str_ptr;
|
||||
|
||||
if (*maxlen_ptr < 1)
|
||||
return MPIU_STR_FAIL;
|
||||
|
||||
/* add the flag */
|
||||
/* printf("strstr flag\n"); */
|
||||
if (strstr(flag, MPIU_STR_SEPAR_STR) || strstr(flag, MPIU_STR_DELIM_STR) || flag[0] == MPIU_STR_QUOTE_CHAR)
|
||||
{
|
||||
num_chars = quoted_printf(*str_ptr, *maxlen_ptr, flag);
|
||||
}
|
||||
else
|
||||
{
|
||||
num_chars = MPIU_Snprintf(*str_ptr, *maxlen_ptr, "%s", flag);
|
||||
}
|
||||
|
||||
if(num_chars < 0)
|
||||
{
|
||||
num_chars = *maxlen_ptr;
|
||||
}
|
||||
|
||||
*maxlen_ptr = *maxlen_ptr - num_chars;
|
||||
if (*maxlen_ptr < 1)
|
||||
{
|
||||
**str_ptr = '\0';
|
||||
/*(*str_ptr)[num_chars-1] = '\0';*/
|
||||
return MPIU_STR_NOMEM;
|
||||
}
|
||||
*str_ptr = *str_ptr + num_chars;
|
||||
|
||||
/* add the deliminator character */
|
||||
**str_ptr = MPIU_STR_DELIM_CHAR;
|
||||
*str_ptr = *str_ptr + 1;
|
||||
*maxlen_ptr = *maxlen_ptr - 1;
|
||||
|
||||
/* add the value string */
|
||||
/* printf("strstr val\n"); */
|
||||
if (strstr(val, MPIU_STR_SEPAR_STR) || strstr(val, MPIU_STR_DELIM_STR) || val[0] == MPIU_STR_QUOTE_CHAR)
|
||||
{
|
||||
num_chars = quoted_printf(*str_ptr, *maxlen_ptr, val);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*val == '\0')
|
||||
{
|
||||
num_chars = MPIU_Snprintf(*str_ptr, *maxlen_ptr, MPIU_STR_QUOTE_STR MPIU_STR_QUOTE_STR/*"\"\""*/);
|
||||
}
|
||||
else
|
||||
{
|
||||
num_chars = MPIU_Snprintf(*str_ptr, *maxlen_ptr, "%s", val);
|
||||
}
|
||||
}
|
||||
|
||||
if(num_chars < 0)
|
||||
{
|
||||
num_chars = *maxlen_ptr;
|
||||
}
|
||||
|
||||
*str_ptr = *str_ptr + num_chars;
|
||||
*maxlen_ptr = *maxlen_ptr - num_chars;
|
||||
if (*maxlen_ptr < 2)
|
||||
{
|
||||
*orig_str_ptr = '\0';
|
||||
*str_ptr = orig_str_ptr;
|
||||
*maxlen_ptr = orig_maxlen;
|
||||
return MPIU_STR_NOMEM;
|
||||
}
|
||||
|
||||
/* add the trailing space */
|
||||
**str_ptr = MPIU_STR_SEPAR_CHAR;
|
||||
*str_ptr = *str_ptr + 1;
|
||||
**str_ptr = '\0';
|
||||
*maxlen_ptr = *maxlen_ptr - 1;
|
||||
|
||||
return MPIU_STR_SUCCESS;
|
||||
}
|
||||
|
||||
/*@ MPIU_Str_add_int_arg - Add an option to a string with a maximum length
|
||||
|
||||
Input Parameters:
|
||||
+ str_ptr - Pointer to the destination string
|
||||
. maxlen_ptr - Pointer to the maximum total length of '*str_ptr'
|
||||
. key - key
|
||||
- val - input integer
|
||||
|
||||
Output Parameter:
|
||||
+ str_ptr - The string pointer is updated to the next available location in the string
|
||||
- maxlen_ptr - maxlen is reduced by the number of characters written
|
||||
|
||||
Return value:
|
||||
MPIU_STR_SUCCESS, MPIU_STR_NOMEM, MPIU_STR_FAIL
|
||||
|
||||
Notes:
|
||||
This routine adds an integer option to a string in the form "key = value".
|
||||
|
||||
Module:
|
||||
Utility
|
||||
@*/
|
||||
_Success_(return == MPIU_STR_SUCCESS)
|
||||
int
|
||||
MPIU_Str_add_int_arg(
|
||||
_Inout_ _Outptr_result_buffer_(*maxlen_ptr) PSTR* str_ptr,
|
||||
_Inout_ int *maxlen_ptr,
|
||||
_In_z_ const char *flag,
|
||||
_In_ int val
|
||||
)
|
||||
{
|
||||
char val_str[12];
|
||||
MPIU_Snprintf(val_str, 12, "%d", val);
|
||||
return MPIU_Str_add_string_arg(str_ptr, maxlen_ptr, flag, val_str);
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
|
||||
//
|
||||
//
|
||||
// Summary:
|
||||
// This file contains the assert utility macros.
|
||||
// Note: the "Invariant" versions that are included in retail.
|
||||
//
|
||||
// InvariantAssert/Assert(exp_) :
|
||||
// This uses interupt 2c, which enables new assert break and skip features.
|
||||
// If this assert fires, it will raise a fatal error and crash the host process.
|
||||
// If AeDebug key is set, this will cause the debugger to launch
|
||||
// When debugger attached, the 'ahi' command can be used to ignore the assertion and continue.
|
||||
// NOTE: Unlike the CRT assert, the strings for these asserts are stored in the symbols,
|
||||
// so asserts do not add strings to the image.
|
||||
//
|
||||
// InvariantAssertP/AssertP(exp_) :
|
||||
// This is the same as the InvariantAssert/Assert macro, except that it will only passively fire
|
||||
// when a debugger is actually attached.
|
||||
//
|
||||
//
|
||||
|
||||
#define InvariantAssert(exp_) \
|
||||
((!(exp_)) ? \
|
||||
(__annotation(L"Debug", L"AssertFail", L#exp_), \
|
||||
__int2c(), FALSE) : \
|
||||
TRUE)
|
||||
|
||||
#define InvariantAssertP( exp_ ) \
|
||||
((!(exp_) && IsDebuggerPresent()) ? \
|
||||
(__annotation(L"Debug", L"PassiveAssertFail", L#exp_), \
|
||||
__int2c(), FALSE) : \
|
||||
TRUE)
|
||||
|
||||
#if DBG
|
||||
# define Assert(exp_) __analysis_assume(exp_);InvariantAssert(exp_)
|
||||
# define AssertP( exp_ ) __analysis_assume(exp_);InvariantAssertP(exp_)
|
||||
#else
|
||||
# define Assert( exp_ ) __analysis_assume(exp_)
|
||||
# define AssertP( exp_ ) __analysis_assume(exp_)
|
||||
#endif
|
|
@ -0,0 +1,78 @@
|
|||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License.
|
||||
#
|
||||
#
|
||||
# This file maps each MPI error class to a short name form.
|
||||
# This is used to support MPI_Error_string when applied to one of the
|
||||
# MPI classes rather than to an error code created by MPIR_Err_create_code.
|
||||
# By mapping the MPI codes to short generic names, we ensure that the
|
||||
# message strings for the defined MPI classes matches some message that
|
||||
# may be created by MPIR_Err_create_code.
|
||||
#
|
||||
# The format of this file is
|
||||
# mpi_err_xxx integer-value short-name
|
||||
# where "integer-value" is the same as in mpi.h (eventually, we should
|
||||
# generate this automatically).
|
||||
MPI_SUCCESS 0 **success
|
||||
# Communication argument parameters
|
||||
MPI_ERR_BUFFER 1 **buffer
|
||||
MPI_ERR_COUNT 2 **count
|
||||
MPI_ERR_TYPE 3 **dtype
|
||||
MPI_ERR_TAG 4 **tag
|
||||
MPI_ERR_COMM 5 **comm
|
||||
MPI_ERR_RANK 6 **rank
|
||||
MPI_ERR_ROOT 7 **root
|
||||
# MPI Objects (other than COMM)
|
||||
MPI_ERR_GROUP 8 **group
|
||||
MPI_ERR_OP 9 **op
|
||||
# Special topology argument parameters
|
||||
MPI_ERR_TOPOLOGY 10 **topology
|
||||
MPI_ERR_DIMS 11 **dims
|
||||
# All other arguments. This is a class with many kinds
|
||||
MPI_ERR_ARG 12 **arg
|
||||
# Other errors that are not simply an invalid argument
|
||||
MPI_ERR_UNKNOWN 13 **unknown
|
||||
MPI_ERR_TRUNCATE 14 **truncate
|
||||
MPI_ERR_OTHER 15 **other
|
||||
MPI_ERR_INTERN 16 **intern
|
||||
# Multiple completion has two special error classes
|
||||
MPI_ERR_IN_STATUS 17 **instatus
|
||||
MPI_ERR_PENDING 18 **inpending
|
||||
MPI_ERR_REQUEST 19 **request
|
||||
# New MPI-2 Error classes
|
||||
MPI_ERR_ACCESS 20 **fileaccess
|
||||
MPI_ERR_AMODE 21 **fileamode
|
||||
MPI_ERR_BAD_FILE 22 **filename
|
||||
MPI_ERR_CONVERSION 23 **conversion
|
||||
MPI_ERR_DUP_DATAREP 24 **datarepused
|
||||
MPI_ERR_FILE_EXISTS 25 **fileexist
|
||||
MPI_ERR_FILE_IN_USE 26 **fileinuse
|
||||
MPI_ERR_FILE 27 **file
|
||||
# MPI_ERR_INFO is NOT defined in the MPI-2 standard. I believe that
|
||||
# this is an oversight
|
||||
MPI_ERR_INFO 28 **info
|
||||
MPI_ERR_INFO_KEY 29 **infokey
|
||||
MPI_ERR_INFO_VALUE 30 **infoval
|
||||
MPI_ERR_INFO_NOKEY 31 **infonokey
|
||||
MPI_ERR_IO 32 **io
|
||||
MPI_ERR_NAME 33 **nameservice
|
||||
MPI_ERR_NO_MEM 34 **allocmem
|
||||
MPI_ERR_NOT_SAME 35 **notsame
|
||||
MPI_ERR_NO_SPACE 36 **filenospace
|
||||
MPI_ERR_NO_SUCH_FILE 37 **filenoexist
|
||||
MPI_ERR_PORT 38 **port
|
||||
MPI_ERR_QUOTA 39 **filequota
|
||||
MPI_ERR_READ_ONLY 40 **filerdonly
|
||||
MPI_ERR_SERVICE 41 **servicename
|
||||
MPI_ERR_SPAWN 42 **spawn
|
||||
MPI_ERR_UNSUPPORTED_DATAREP 43 **datarepunsupported
|
||||
MPI_ERR_UNSUPPORTED_OPERATION 44 **fileopunsupported
|
||||
MPI_ERR_WIN 45 **win
|
||||
MPI_ERR_BASE 46 **base
|
||||
MPI_ERR_LOCKTYPE 47 **locktype
|
||||
MPI_ERR_KEYVAL 48 **keyval
|
||||
MPI_ERR_RMA_CONFLICT 49 **rmaconflict
|
||||
MPI_ERR_RMA_SYNC 50 **rmasync
|
||||
MPI_ERR_SIZE 51 **rmasize
|
||||
MPI_ERR_DISP 52 **rmadisp
|
||||
MPI_ERR_ASSERT 53 **assert
|
|
@ -0,0 +1,134 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
* (C) 2001 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
#include "precomp.h"
|
||||
|
||||
#include "dbg_printf.h"
|
||||
|
||||
//
|
||||
// This constant is used only by the debug extension to query about the minimum
|
||||
// version of the extension that this version of MSMPI can support.
|
||||
// When the debug extension attaches to a running MPI process, it does not know
|
||||
// whether the current MSMPI has the correct data structure layout to support
|
||||
// this current version of the debugger extension (or that the user would need
|
||||
// to upgrade to a newer version of the debug extension, as indicated by this
|
||||
// constant).
|
||||
//
|
||||
static const unsigned int MSMPI_DBGEXT_VER = 200;
|
||||
|
||||
|
||||
//
|
||||
// enable breaking on initialization
|
||||
//
|
||||
// -env MSMPI_INIT_BREAK preinit
|
||||
// breaks into all ranks before initialization
|
||||
//
|
||||
// -env MSMPI_INIT_BREAK all
|
||||
// breaks into all ranks after initialization
|
||||
//
|
||||
// -env MSMPI_INIT_BREAK a,b,d-f,x-z
|
||||
// breaks into ranks "a b d e f x y z" after initialization.
|
||||
// ranks are decimal numbers; separator is any character except '-'
|
||||
//
|
||||
|
||||
_Success_(return==true)
|
||||
static inline
|
||||
bool
|
||||
get_break_env(
|
||||
_Out_writes_z_(cchEnv) char* env,
|
||||
_In_ DWORD cchEnv
|
||||
)
|
||||
{
|
||||
DWORD err = MPIU_Getenv( "MSMPI_INIT_BREAK",
|
||||
env,
|
||||
cchEnv );
|
||||
if( err == ERROR_ENVVAR_NOT_FOUND )
|
||||
{
|
||||
err = MPIU_Getenv( "MPICH_INIT_BREAK",
|
||||
env,
|
||||
cchEnv );
|
||||
}
|
||||
|
||||
return err == NOERROR;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MPIU_dbg_preinit()
|
||||
{
|
||||
char env[_countof("preinit")];
|
||||
if( get_break_env( env, _countof(env) ) == false )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( CompareStringA( LOCALE_INVARIANT,
|
||||
0,
|
||||
env,
|
||||
-1,
|
||||
"preinit",
|
||||
-1 ) != CSTR_EQUAL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MPIU_Debug_break();
|
||||
}
|
||||
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int
|
||||
MPIU_dbg_init(
|
||||
_In_ unsigned int rank,
|
||||
_In_ unsigned int world_size
|
||||
)
|
||||
{
|
||||
char env[32767];
|
||||
if( get_break_env(env, _countof(env) ) == false )
|
||||
{
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// This one is called after MPIU_dbg_preinit but it parses the same
|
||||
// environment variable so if we already parsed preinit earlier we
|
||||
// will not do it again here.
|
||||
//
|
||||
if( CompareStringA( LOCALE_INVARIANT,
|
||||
0,
|
||||
env,
|
||||
-1,
|
||||
"preinit",
|
||||
-1 ) == CSTR_EQUAL )
|
||||
{
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
unsigned int unique_ranks;
|
||||
bool isDebug;
|
||||
int mpi_errno = MPI_SUCCESS;
|
||||
|
||||
mpi_errno = MPIU_Parse_rank_range( rank, env, world_size, &isDebug, &unique_ranks);
|
||||
|
||||
if ( mpi_errno == MPI_SUCCESS &&
|
||||
isDebug == true )
|
||||
{
|
||||
MPIU_Debug_break();
|
||||
}
|
||||
return mpi_errno;
|
||||
}
|
||||
|
||||
void
|
||||
MPIU_dbg_printf(
|
||||
_Printf_format_string_ const char * str,
|
||||
...
|
||||
)
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, str);
|
||||
vfprintf(stderr, str, list); fflush(stderr);
|
||||
va_end(list);
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
|
||||
void MPIU_dbg_preinit();
|
||||
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int
|
||||
MPIU_dbg_init(
|
||||
_In_ unsigned int rank,
|
||||
_In_ unsigned int world_size
|
||||
);
|
||||
|
||||
void
|
||||
MPIU_dbg_printf(
|
||||
_Printf_format_string_ const char * str,
|
||||
...
|
||||
);
|
|
@ -0,0 +1,260 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
Licensed under the MIT License.
|
||||
|
||||
dump.cpp - MPI minidump functionality
|
||||
|
||||
--*/
|
||||
#include "precomp.h"
|
||||
#include "mpidump.h"
|
||||
#include <dbghelp.h>
|
||||
#include <excpt.h>
|
||||
|
||||
|
||||
typedef BOOL
|
||||
(WINAPI *PFN_MiniDumpWriteDump)(
|
||||
__in HANDLE hProcess,
|
||||
__in DWORD ProcessId,
|
||||
__in HANDLE hFile,
|
||||
__in MINIDUMP_TYPE DumpType,
|
||||
__in_opt PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
||||
__in_opt PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
||||
__in_opt PMINIDUMP_CALLBACK_INFORMATION CallbackParam
|
||||
);
|
||||
|
||||
|
||||
MSMPI_DUMP_MODE GetDumpMode()
|
||||
{
|
||||
wchar_t env[12];
|
||||
|
||||
DWORD err = MPIU_Getenv( L"MSMPI_DUMP_MODE", env, _countof(env) );
|
||||
if( err != NOERROR )
|
||||
{
|
||||
return MsmpiDumpNone;
|
||||
}
|
||||
|
||||
int val = _wtoi(env);
|
||||
if( val > MsmpiDumpNone && val < MsmpiDumpMaximumValue )
|
||||
{
|
||||
return static_cast<MSMPI_DUMP_MODE>(val);
|
||||
}
|
||||
|
||||
return MsmpiDumpNone;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CreateFinalDumpFile(
|
||||
_In_ HANDLE tempFileHandle,
|
||||
_In_ int rank,
|
||||
_In_z_ const wchar_t* dumpPath,
|
||||
_In_ int jobid,
|
||||
_In_ int taskid,
|
||||
_In_ int taskinstid
|
||||
)
|
||||
{
|
||||
MPIU_Assert( tempFileHandle != INVALID_HANDLE_VALUE );
|
||||
wchar_t tempFileName[MAX_PATH];
|
||||
DWORD err = GetFinalPathNameByHandleW(
|
||||
tempFileHandle,
|
||||
tempFileName,
|
||||
_countof( tempFileName ),
|
||||
0
|
||||
);
|
||||
|
||||
if( err == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
wchar_t dPath[MAX_PATH];
|
||||
HRESULT hr;
|
||||
|
||||
if( dumpPath != NULL && dumpPath[0] != L'\0' )
|
||||
{
|
||||
hr = StringCchCopyW( dPath, _countof( dPath ), dumpPath );
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = StringCchCopyW( dPath, _countof( dPath ), L"%USERPROFILE%");
|
||||
}
|
||||
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
wchar_t name[MAX_PATH];
|
||||
|
||||
//
|
||||
// For CCP, task instance id starts at 0. Thus, we only verify
|
||||
// jobid and taskid
|
||||
//
|
||||
if( jobid == 0 || taskid == 0 )
|
||||
{
|
||||
//
|
||||
// In the SDK environment use the sdk default dumpfile
|
||||
//
|
||||
hr = StringCchPrintfW(
|
||||
name,
|
||||
_countof( name ),
|
||||
L"%s\\mpi_dump_%d.dmp",
|
||||
dPath,
|
||||
rank
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// In the cluster environment use the cluster default dumpfile
|
||||
// (incl. jobid.taskid.taskinstid)
|
||||
//
|
||||
hr = StringCchPrintfW(
|
||||
name,
|
||||
_countof( name ),
|
||||
L"%s\\mpi_dump_%d.%d.%d.%d.dmp",
|
||||
dPath,
|
||||
jobid,
|
||||
taskid,
|
||||
taskinstid,
|
||||
rank
|
||||
);
|
||||
}
|
||||
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DWORD ccPath = ExpandEnvironmentStringsW(
|
||||
name,
|
||||
dPath,
|
||||
_countof( dPath )
|
||||
);
|
||||
if( ccPath == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// For MPI Process, it is possible that it will be suspended
|
||||
// by SMPD during the CopyFile operation. However, if this happens,
|
||||
// this means this process is not the failing process (otherwise SPMD
|
||||
// would not have suspended it). In the case of all processes generating
|
||||
// dump files, SMPD will then write the dump for this process, which will
|
||||
// result in a good dupm file.
|
||||
//
|
||||
CopyFileW( tempFileName, dPath, FALSE );
|
||||
}
|
||||
|
||||
|
||||
HANDLE
|
||||
CreateTempDumpFile(
|
||||
__in HANDLE hProcess,
|
||||
__in DWORD pid,
|
||||
__in MINIDUMP_TYPE dumpType,
|
||||
__in const wchar_t* dumpPath,
|
||||
__in_opt MINIDUMP_EXCEPTION_INFORMATION* pExrParam
|
||||
)
|
||||
{
|
||||
HANDLE hFile = INVALID_HANDLE_VALUE;
|
||||
|
||||
// Create target file
|
||||
wchar_t path[MAX_PATH];
|
||||
|
||||
// Load dbghelp library.
|
||||
DWORD ccPath = GetSystemDirectoryW( path, _countof(path) );
|
||||
if( ccPath == 0 )
|
||||
{
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
HRESULT hr = StringCchCopyW( &path[ccPath],
|
||||
_countof(path) - ccPath,
|
||||
L"\\dbghelp.dll" );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
HMODULE hDbgHelp;
|
||||
OACR_REVIEWED_CALL(
|
||||
mpicr,
|
||||
hDbgHelp = LoadLibraryExW( path, nullptr, 0 ) );
|
||||
if( hDbgHelp == NULL )
|
||||
{
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
PFN_MiniDumpWriteDump pfnWriteDump = (PFN_MiniDumpWriteDump)GetProcAddress(
|
||||
hDbgHelp,
|
||||
"MiniDumpWriteDump"
|
||||
);
|
||||
if( pfnWriteDump == NULL )
|
||||
{
|
||||
goto free_dbghelp_and_exit;
|
||||
}
|
||||
|
||||
if( dumpPath != NULL && dumpPath[0] != L'\0' )
|
||||
{
|
||||
ccPath = ExpandEnvironmentStringsW(
|
||||
dumpPath,
|
||||
path,
|
||||
_countof(path)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
ccPath = ExpandEnvironmentStringsW(
|
||||
L"%USERPROFILE%",
|
||||
path,
|
||||
_countof(path)
|
||||
);
|
||||
}
|
||||
|
||||
if( ccPath == 0 )
|
||||
{
|
||||
goto free_dbghelp_and_exit;
|
||||
}
|
||||
|
||||
wchar_t name[MAX_PATH];
|
||||
int err = GetTempFileNameW(
|
||||
path,
|
||||
L"_mp",
|
||||
0,
|
||||
name
|
||||
);
|
||||
if( err == 0 )
|
||||
{
|
||||
goto free_dbghelp_and_exit;
|
||||
}
|
||||
|
||||
hFile = CreateFileW(
|
||||
name,
|
||||
GENERIC_WRITE,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
|
||||
NULL
|
||||
);
|
||||
if( hFile == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
goto free_dbghelp_and_exit;
|
||||
}
|
||||
|
||||
pfnWriteDump(
|
||||
hProcess,
|
||||
pid,
|
||||
hFile,
|
||||
dumpType,
|
||||
pExrParam,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
|
||||
free_dbghelp_and_exit:
|
||||
FreeLibrary( hDbgHelp );
|
||||
return hFile;
|
||||
}
|
|
@ -0,0 +1,773 @@
|
|||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License.
|
||||
#
|
||||
# Error messages for error classes referenced in baseerrnames.txt
|
||||
#
|
||||
**success:No MPI error
|
||||
**buffer:Invalid buffer pointer
|
||||
**count:Invalid count
|
||||
**dtype:Invalid datatype
|
||||
**tag:Invalid tag
|
||||
**comm:Invalid communicator
|
||||
**rank:Invalid rank
|
||||
**root:Invalid root
|
||||
**group:Invalid group
|
||||
**op:Invalid MPI_Op
|
||||
**request:Invalid MPI_Request
|
||||
**topology:Invalid topology
|
||||
**dims:Invalid dimension argument
|
||||
**arg:Invalid argument
|
||||
**unknown:Unknown error. Please file a bug report.
|
||||
**truncate:Message truncated
|
||||
**other:Other MPI error
|
||||
**intern:Internal MPI error!
|
||||
**instatus:See the MPI_ERROR field in MPI_Status for the error code
|
||||
**inpending:Pending request (no error)
|
||||
**fileaccess:Access denied to file
|
||||
**fileamode:Invalid amode value in MPI_File_open
|
||||
**filename:Invalid file name
|
||||
**conversion:An error occurred in a user-defined data conversion function
|
||||
**datarepused:The requested datarep name has already been specified to \
|
||||
MPI_REGISTER_DATAREP
|
||||
**fileexist:File exists
|
||||
**fileinuse:File in use by some process
|
||||
**file:Invalid MPI_File
|
||||
**info:Invalid MPI_Info
|
||||
**infokey:Invalid key for MPI_Info
|
||||
**infoval:Invalid MPI_Info value
|
||||
**infonokey:MPI_Info key is not defined
|
||||
**io:Other I/O error
|
||||
**nameservice:Invalid service name (see MPI_Publish_name)
|
||||
**allocmem:Unable to allocate memory for MPI_Alloc_mem
|
||||
**notsame:Inconsistent arguments to collective routine
|
||||
**filenospace:Not enough space for file
|
||||
**filenoexist:File does not exist
|
||||
**port:Invalid port
|
||||
**filequota:Quota exceeded for files
|
||||
**filerdonly:Read-only file or filesystem name
|
||||
**servicename:Attempt to lookup an unknown service name
|
||||
**spawn:Error in spawn call
|
||||
**datarepunsupported:Unsupported datarep
|
||||
**datarepunsupported %s:Unsupported datarep passed to %s
|
||||
**fileopunsupported:Unsupported file operation
|
||||
**win:Invalid MPI_Win
|
||||
**winnotshm:A shared memory window is required but a local window was provided.
|
||||
**base:Invalid base address
|
||||
**locktype:Invalid lock type
|
||||
**keyval:Invalid keyval
|
||||
**rmaconflict:Conflicting accesses to window
|
||||
**rmasync:Wrong synchronization of RMA calls
|
||||
**rmasyncq %d %d %d %d:Wrong synchronization of RMA calls - rank %d, target %d, found lock state %d, expected lock state %d
|
||||
**rmasize:Invalid size argument in RMA call
|
||||
**rmadisp:Invalid displacement argument in RMA call
|
||||
**rmatype:Invalid datatype for RMA operation
|
||||
**assert:Invalid assert argument
|
||||
|
||||
# NOTE: The following error messages are not defined in the standard,
|
||||
# but, are internally used.
|
||||
#
|
||||
**message:Invalid message handle
|
||||
|
||||
|
||||
**argnonpos %s %d:Invalid value for %s; must be positive but is %d
|
||||
**argneg %s %d:Invalid value for %s, must be non-negative but is %d
|
||||
**countneg %d:Negative count, value is %d
|
||||
**inittwice:Cannot call MPI_INIT or MPI_INIT_THREAD more than once
|
||||
**nomem:Out of memory
|
||||
**notimpl:Function not implemented
|
||||
**notimpl %s:Function %s not implemented
|
||||
**nullptr %s:Null pointer in parameter %s
|
||||
**nullptrtype %s:Null %s pointer
|
||||
**typenamelen %d:Specified datatype name is too long (%d characters)
|
||||
**commnamelen %d:Specified communicator name is too long (%d characters)
|
||||
**winnamelen %d:Specified window name is too long (%d characters)
|
||||
**keyvalobj %s:Keyval was not defined for %s objects
|
||||
**keyvalinvalid:Attribute key was MPI_KEYVAL_INVALID
|
||||
**permattr:Cannot set permanent attribute
|
||||
**noerrclasses:No more user-defined error classes
|
||||
**noerrcodes:No more user-defined error codes
|
||||
**rankdup %d %d %d:Duplicate ranks in rank array at index %d, has value %d which is \
|
||||
also the value at index %d
|
||||
**topotoolarge %d %d:Topology size %d is larger than communicator size (%d)
|
||||
**notcarttopo:No Cartesian topology associated with this communicator
|
||||
**dimszero:Communicator associated with zero-dimensional cartesian topology
|
||||
**notgraphtopo:No Graph topology associated with this communicator
|
||||
**notopology:No topology associated with this communicator
|
||||
**dimsmany %d %d:Number of dimensions %d is too large (maximum is %d)
|
||||
**neighborsmany %d %d:Number of neighbors %d is too large (maximum is %d)
|
||||
**dimspartition:Cannot partition nodes as requested
|
||||
**cartcoordinvalid %d %d %d:Cartesian coordinate for the %d coordinate \
|
||||
is %d but must be between 0 and %d
|
||||
**cartdim %d %d:Size of the communicator (%d) is smaller than the size of the \
|
||||
Cartesian topology (%d)
|
||||
**edgeoutrange %d %d %d:Edge index edges[%d] is %d but must be nonnegative \
|
||||
and less than %d
|
||||
**nulledge %d %d:Edge for node %d (entry edges[%d]) is to itself
|
||||
**indexneg %d %d:Index value for index[%d] is %d but must be nonnegative
|
||||
**indexnonmonotone %d %d %d:Index values in graph topology must be monotone \
|
||||
nondecreasing but index[%d] is %d but the next index value is %d
|
||||
**graphnnodes:Number of graph nodes exceeds size of communicator.
|
||||
**rangedup %d %d %d:The range array specifies duplicate entries; process %d \
|
||||
specified in range array %d was previously specified in range array %d
|
||||
**rank %d %d:Invalid rank has value %d but must be nonnegative and less than %d
|
||||
**rank %d %g %d:Invalid rank %d in group %g but must be nonnegative and less than %d
|
||||
**stride %d %d %d:Range (start = %d, end = %d, stride = %d) does not terminate
|
||||
**stridezero:Zero stride is invalid
|
||||
**rangestartinvalid %d %d %d:The %dth element of a range array starts at %d \
|
||||
but must be nonnegative and less than %d
|
||||
**rangeendinvalid %d %d %d:The %dth element of a range array ends at %d \
|
||||
but must be nonnegative and less than %d
|
||||
**argrange %s %d %d:Argument %s has value %d but must be within [0,%d]
|
||||
**argarrayneg %s %d %d:Negative value in array %s[%d] (value is %d)
|
||||
**bufexists:Buffer already attached with MPI_BUFFER_ATTACH.
|
||||
**bsendbufsmall %d %d:Buffer size of %d is smaller than MPI_BSEND_OVERHEAD (%d)
|
||||
**notgenreq:Attempt to complete a request with MPI_GREQUEST_COMPLETE that \
|
||||
was not started with MPI_GREQUEST_START
|
||||
**cancelunknown:Attempt to cancel an unknown type of request
|
||||
**permop:Cannot free permanent MPI_Op
|
||||
**toomanycomm:Too many communicators
|
||||
**commperm %s:Cannot free permanent communicator %s
|
||||
**groupperm:Cannot free permanent group
|
||||
**groupnotincomm %d:Rank %d of the specified group is not a member of this communicator
|
||||
**commnotintra:An intracommunicator is required but an intercommunicator \
|
||||
was provided.
|
||||
**commnotinter:An intercommunicator is required but an intracommunicator \
|
||||
was provided.
|
||||
**nosplittype %d:Communicator cannot be split for type %d.
|
||||
**ranklocal %d %d:Error specifying local_leader; rank given was %d but must \
|
||||
be in the range 0 to %d
|
||||
**rankremote %d %d:Error specifying remote_leader; rank given was %d but must \
|
||||
be in the range 0 to %d
|
||||
**ranksdistinct:Local and remote leaders must be different processes
|
||||
**dupprocesses %d:Local and remote groups in MPI_Intercomm_create must not \
|
||||
contain the same processes; both contain process %d
|
||||
**tag %d:Invalid tag, value is %d
|
||||
**count %d:Invalid count, value = %d
|
||||
**bufnull:Null buffer pointer
|
||||
**bufbsend %d %d:Insufficient space in Bsend buffer; requested %d; total \
|
||||
buffer size is %d
|
||||
**namepubnotpub %s:Lookup failed for service name %s
|
||||
**nonamepub:No name publishing service available
|
||||
**namepubnotfound %s:Lookup failed for service name %s
|
||||
**namepubnotunpub %s:Failed to unpublish service name %s
|
||||
**sendbuf_inplace:sendbuf cannot be MPI_IN_PLACE
|
||||
**recvbuf_inplace:recvbuf cannot be MPI_IN_PLACE
|
||||
**buf_inplace:buffer cannot be MPI_IN_PLACE
|
||||
**typematchnoclass:The value of typeclass is not one of MPI_TYPECLASS_REAL, \
|
||||
MPI_TYPECLASS_INTEGER, or MPI_TYPECLASS_COMPLEX
|
||||
**typematchsize %s %d:No MPI datatype available for typeclass %s and size %d
|
||||
**f90typetoomany:Too many requests for unnamed, predefined f90 types
|
||||
**f90typeintnone %d: No integer type with %d digits of range is avaiable
|
||||
**f90typerealnone %d %d: No REAL type with precision %d and %d digits of range is avaiable
|
||||
**f90typecomplexnone %d %d: No COMPLEX type with precision %d and %d digits of range is avaiable
|
||||
**getConnStringFailed:Failed to obtain connection info for this process group
|
||||
**version %d %d %d %d %d %d:Version mismatch in connection request, received version %d.%d.%d, expected %d.%d.%d. \
|
||||
Check cluster configuration and ensure MSMPI versions match.
|
||||
**comm_split_type %d:Split type %d is not valid.
|
||||
**overflow %s:Operation overflow in %s
|
||||
**intoverflow %l:The value %l passed to the internal operation is bigger than MAX_INT and may cause data corruption
|
||||
**invalidarg %s %s:Invalid argument value specified in parameter %s. %s
|
||||
**unweightedboth:Must specify MPI_UNWEIGHTED for both or neither weight arguments
|
||||
**argarrayrange %s %d %d %d:Argument %s[%d] has value %d but must be within [0,%d]
|
||||
|
||||
# -- FIXME: Some (but not all) of the messages below this line have been used
|
||||
#---- The messages below this line haven't been used yet.
|
||||
#
|
||||
**bufalias %s %s:Buffer parameters %s and %s must not be aliased
|
||||
**dtypenull %s:Datatype for argument %s is a null datatype
|
||||
**dtypecommit:Datatype has not been committed
|
||||
**dtypeperm:Cannot free permanent data type
|
||||
**dtypecomm:Pack buffer not packed for this communicator.
|
||||
**dtypemismatch:Receiving data with a datatype whose signature does not match that of the sending datatype.
|
||||
**intercomm:Intercommunicator is not allowed
|
||||
**rankarray %d %d %d:Invalid rank in rank array at index %d; value is %d but must \
|
||||
be in the range 0 to %d
|
||||
**rankarraysize %d %d:Invalid rank array size %d: the number of ranks must be between 0 \
|
||||
and the size of the group (%d)
|
||||
**rangessize %d %d:Invalid number of ranges %d: the number of ranges must be between 0 \
|
||||
and the size of the group (%d)
|
||||
**root %d:Invalid root (value given was %d)
|
||||
**opundefined %s:MPI_Op %s operation not defined for this datatype
|
||||
**noopnotallowed:MPI_NO_OP operation is not allowed in this call
|
||||
**replacenotallowed:MPI_REPLACE operation is not allowed in this call
|
||||
**dims %d:Invalid dimension argument (value is %d)
|
||||
**arg %s:Invalid argument %s
|
||||
**argerrcode %d:Invalid error code %d
|
||||
**errhandler:Invalid errhandler
|
||||
**errhandnotcomm:Error handler is not a comm error handler
|
||||
**errhandnotfile:Error handler is not a file error handler
|
||||
**errhandnotwin:Error handler is not a win error handler
|
||||
**argarray %s %d %d:Invalid value in %s[%d] = %d
|
||||
**darraydist %d %d:For MPI_DISTRIBUTE_NONE, the value of array_of_psizes[%d] \
|
||||
is %d but must have value 1
|
||||
**darrayunknown:Unknown distribution type
|
||||
**darrayblock %d:Value of m in block(m) distribution is %d must must be \
|
||||
positive
|
||||
**darrayblock2 %d %d:m * nprocs is %d but must equal the array size %d and is \
|
||||
not valid for block(m) distribution
|
||||
**darraycyclic %d:Value of m is %d but must be positive for a cyclic(m) \
|
||||
distribution
|
||||
**argposneg %d:Value of position is %d but must be nonnegative
|
||||
**argpackbuf %l %l:Size of data to pack (%l bytes) is larger than remaining (%l bytes) \
|
||||
space in pack buffer (%d bytes)
|
||||
**truncate %d %d:Message truncated; %d bytes received but buffer size is %d
|
||||
**truncate %d %d %d %d:Message from rank %d and tag %d truncated; \
|
||||
%d bytes received but buffer size is %d
|
||||
**rsendnomatch %d %d %d:Ready send from source %d, for destination %d and \
|
||||
with tag %d had no matching receive
|
||||
**rsendnomatch %d %d:Ready send from source %d and with tag %d had no matching receive
|
||||
**intern %s:Internal MPI error! %s
|
||||
**unknowngpid %d %d:Internal MPI error: Unknown gpid (%d)%d
|
||||
**request_invalid_kind %d:The supplied request was invalid (kind=%d)
|
||||
**requestnotpersist:Request is not persistent in MPI_Start or MPI_Startall.
|
||||
**requestpersistactive:Persistent request passed to MPI_Start or MPI_Startall is already active.
|
||||
**requestrmacancel:Cannot cancel RMA request
|
||||
**requestrmanotexpected:Request-based RMA operations are only valid within a passive target epoch
|
||||
**requestrmaoutofbounds:The requested displacement specifies memory outside of the RMA window
|
||||
**requestrmaremoteerror:RMA operation caused an error on the target process
|
||||
**fileamode %d:Invalid amode value of %d in MPI_File_open
|
||||
**fileamodeone:Exactly one of MPI_MODE_RDONLY, MPI_MODE_WRONLY, or \
|
||||
MPI_MODE_RDWR must be specified
|
||||
**fileamoderead:Cannot use MPI_MODE_CREATE or MPI_MODE_EXCL with \
|
||||
MPI_MODE_RDONLY
|
||||
**fileamodeseq:Cannot specify MPI_MODE_SEQUENTIAL with MPI_MODE_RDWR
|
||||
**infokeynull:Null key
|
||||
**infokeylong %s %d %d:Key %s is too long (length is %d but maximum allowed is %d)
|
||||
**infokeyempty:Empty or blank key
|
||||
**infovalnull:Null value
|
||||
**infovallong %s %d %d:Value %s is too long (length is %d but maximum length is %d)
|
||||
**infonokey %s:MPI_Info key %s is not defined
|
||||
**infonkey %d %d:Requested key %d but this MPI_Info only has %d keys
|
||||
**io %s:Other I/O error %s
|
||||
**ioetype:Only an integral number of etypes can be accessed
|
||||
**iosplitcoll:Only one active split collective I/O operation is allowed per file handle
|
||||
**iosplitcollnone:No split collective I/O operation is active
|
||||
**iofiletype:Filetype must be constructed out of one or more etypes
|
||||
**ioamodeseq %s:Cannot use function %s when the file is opened with amode \
|
||||
MPI_MODE_SEQUENTIAL
|
||||
**iowronly:Cannot read from a file opened with amode MPI_MODE_WRONLY
|
||||
**iordonly:Cannot write to a file opened with amode MPI_MODE_RDONLY
|
||||
**iodispifseq:disp must be set to MPI_DISPLACEMENT_CURRENT since file \
|
||||
was opened with MPI_MODE_SEQUENTIAL
|
||||
**iobaddisp:Invalid displacement argument
|
||||
**iobadoffset:Invalid offset argument
|
||||
**ionegoffset:Negative offset argument
|
||||
**iobadwhence:Invalid whence argument
|
||||
**iobadfh:Invalid file handle
|
||||
**ioagnomatch:No aggregators match
|
||||
**iobadsize:Invalid size argument
|
||||
**unsupporteddatarep:Only native data representation currently supported
|
||||
**iodatarepnomem:User must allocate memory for datarep
|
||||
**ioverlapping:Filetype specifies overlapping write regions
|
||||
**ioinfokey %s:Value for info key %s not same across processes
|
||||
**allocmem %d %d:Unable to allocate %d memory for MPI_Alloc_mem; only %d available
|
||||
**notsame %s %s:Inconsistent arguments %s to collective routine %s
|
||||
**rmasize %d:Invalid size argument in RMA call (value is %d)
|
||||
**winunlockrank %d %d:Invalid rank argument %d, should be %d
|
||||
**winlockall: A window locked with MPI_WIN_LOCK_ALL should be unlocked with MPI_WIN_UNLOCK_ALL
|
||||
**winrmaop: Unexpected type of RMA operation
|
||||
**notcstatignore:MPI_STATUS_IGNORE cannot be passed to MPI_Status_c2f()
|
||||
**notfstatignore:MPI_STATUS_IGNORE cannot be passed to MPI_Status_f2c()
|
||||
**user:user defined function returned an error code
|
||||
**userdel %d:user delete function returned error code %d
|
||||
**usercopy %d:user copy function returned error code %d
|
||||
**userquery %d:user request query function returned error code %d
|
||||
**usercancel %d:user request cancel function returned error code %d
|
||||
**userfree %d:user request free function returned error code %d
|
||||
**oremote_fail:open failed on a remote node
|
||||
**join_portname %s %s:local %s, remote %s
|
||||
**join_send %d:send on the socket failed (errno %d)
|
||||
**join_recv %d:recv from the socket failed (errno %d)
|
||||
**flag %d:invalid flag parameter (flag = %d)
|
||||
**badcase %d:INTERNAL ERROR: unexpected value in case statement (value=%d)
|
||||
**MapViewOfFile %d:MapViewOfFile failed, error %d
|
||||
**errcontextid:Creating Remote ContextID Failed
|
||||
**uuidgenfailed:Generating ContextID Failed
|
||||
**interuptiblenotsupported:Interuptible Waits not supported.
|
||||
|
||||
#
|
||||
# Errors common to several devices
|
||||
#
|
||||
**dev|selfsenddeadlock:DEADLOCK: attempting to send a message to the local process without a prior matching receive
|
||||
|
||||
#
|
||||
# CH3 errors
|
||||
#
|
||||
**ch3|badreqtype %d:request contained an invalid request type (%d)
|
||||
**ch3|unknownpkt %d:received unknown packet type (type=%d)
|
||||
**opnotpredefined %d:only predefined ops are valid (op = %d)
|
||||
**ch3|conn_parent:spawned process group was unable to connect back to the parent
|
||||
**ch3|conn_parent %s:spawned process group was unable to connect back to the parent on port <%s>
|
||||
|
||||
#
|
||||
# CH3:sock errors
|
||||
#
|
||||
**ch3|sock|connrefused %s %d %s:[ch3:sock] failed to connect to process %s:%d (%s)
|
||||
**ch3|sock|connfailed %d %d:[ch3:sock] failed to connnect to remote process %d:%d
|
||||
**ch3|sock|connfailed %g %d:[ch3:sock] failed to connnect to remote process %g:%d
|
||||
**ch3|sock|badpacket %d:[ch3:sock] received packet of unknown type (%d)
|
||||
**ch3|sock|postread %p %p %p:attempt to post a read operation failed (rreq=%p,conn=%p,vc=%p)
|
||||
**ch3|sock|postwrite %p %p %p:attempt to post a write operation failed (sreq=%p,conn=%p,vc=%p)
|
||||
**ch3|sock|postconnect %d %d %s:[ch3:sock] rank %d unable to connect to rank %d using business card <%s>
|
||||
**ch3|sock|open_lrecv_data:[ch3:sock] failed to handle open lrecv data packet
|
||||
**ch3|sock|badhost %s %d %s:[ch3:sock] invalid host description, %s:%d (%s)
|
||||
**pglookup %g:unable to find the process group structure with id %g
|
||||
|
||||
#
|
||||
# CH3:nd
|
||||
#
|
||||
**ch3|nd|startup %x:[ch3:nd] NdStartup failed with %x
|
||||
**ch3|nd|query_addr %x:[ch3:nd] NdQueryAddressList failed with %x
|
||||
**ch3|nd|badbuscard:[ch3:nd] Invalid business card
|
||||
**ch3|nd|not_here_fallback %d %s:[ch3:nd] Could not connect via NetworkDirect to rank %d with business card (%s).\n\
|
||||
There is no matching NetworkDirect adapter and fallback to the socket interconnect is disabled.\n\
|
||||
Check the local NetworkDirect configuration or set the MPICH_ND_ENABLE_FALLBACK environment variable to true.
|
||||
**ch3|nd|not_both_force %d %s:[ch3:nd] Could not connect via NetworkDirect to rank %d with business card (%s).\n\
|
||||
A matching NetworkDirect adapter is not available on either rank and the socket interconnect is disabled.\n\
|
||||
Check NetworkDirect configuration or clear the MPICH_DISABLE_SOCK environment variable.
|
||||
**ch3|nd|not_here_force %d %s:[ch3:nd] Could not connect via NetworkDirect to rank %d with business card (%s).\n\
|
||||
There is no matching NetworkDirect adapter and the socket interconnect is disabled.\n\
|
||||
Check the local NetworkDirect configuration or clear the MPICH_DISABLE_SOCK environment variable.
|
||||
**ch3|nd|not_there_fallback %d %s:[ch3:nd] Could not connect via NetworkDirect to rank %d with business card (%s).\n\
|
||||
There is no NetworkDirect information in the business card and fallback to the socket interconnect is disabled.\n\
|
||||
Check the remote NetworkDirect configuration or set the MPICH_ND_ENABLE_FALLBACK environment variable to true.
|
||||
**ch3|nd|not_there_force %d %s:[ch3:nd] Could not connect via NetworkDirect to rank %d with business card (%s).\n\
|
||||
There is no NetworkDirect information in the business card and the socket interconnect is disabled.\n\
|
||||
Check the remote NetworkDirect configuration or clear the MPICH_DISABLE_SOCK environment variable.
|
||||
**ch3|nd|no_path_fallback %d %s:[ch3:nd] Could not connect via NetworkDirect to rank %d with business card (%s).\n\
|
||||
The local and remote ranks have active NetworkDirect adapters but a route via NetworkDirect could not \
|
||||
be resolved and fallback to the socket interconnect is disabled.\n\
|
||||
Check NetworkDirect configuration or set the MPICH_ND_ENABLE_FALLBACK environment variable to true.
|
||||
**ch3|nd|no_path_force %d %s:[ch3:nd] Could not connect via NetworkDirect to rank %d with business card (%s).\n\
|
||||
The local and remote ranks have active NetworkDirect adapters but a route via NetworkDirect could not \
|
||||
be resolved and the socket interconnect is disabled.\n\
|
||||
Check NetworkDirect configuration or clear the MPICH_DISABLE_SOCK environment variable.
|
||||
**ch3|nd|open %x:[ch3:nd] NdOpenAdapter failed with %x
|
||||
**ch3|nd|query %x:[ch3:nd] IND2Adapter::Query failed with %x
|
||||
**ch3|nd|max_cq %d %d:[ch3:nd] Adapter's MaxCompletionQueueDepth: %d, need %d
|
||||
**ch3|nd|max_sq %d %d:[ch3:nd] Adapter's MaxInitiatorQueueDepth: %d, need %d
|
||||
**ch3|nd|max_rq %d %d:[ch3:nd] Adapter's MaxReceiveQueueDepth: %d, need %d
|
||||
**ch3|nd|ov_file %x:[ch3:nd] IND2Adapter::CreateOverlappedFile failed with %x
|
||||
**ch3|nd|create_cq %x:[ch3:nd] IND2Adapter::CreateCompletionQueue failed with %x
|
||||
**ch3|nd|notify %x:[ch3:nd] IND2CompletionQueue::Notify failed with %x
|
||||
**ch3|nd|create_mr %x:[ch3:nd] IND2Adapter::CreateMemoryRegion failed with %x
|
||||
**ch3|nd|regmem %x:[ch3:nd] IND2MemoryRegion::Register failed with %x
|
||||
**ch3|nd|deregmem %x:[ch3:nd] IND2MemoryRegion::Deregister failed with %x
|
||||
**ch3|nd|create_listen %x:[ch3:nd] IND2Adapter::CreateListener failed with %x
|
||||
**ch3|nd|bindlisten %x:[ch3:nd] IND2Listener::Bind failed with %x
|
||||
**ch3|nd|listen %x:[ch3:nd] IND2Listener::Listen failed with %x
|
||||
**ch3|nd|listen_addr %x:[ch3:nd] IND2Listener::GetLocalAddress failed with %x
|
||||
**ch3|nd|create_conn %x:[ch3:nd] IND2Adapter::CreateConnector failed with %x
|
||||
**ch3|nd|bindconn %x:[ch3:nd] IND2Connector::Bind failed with %x
|
||||
**ch3|nd|get_conn %x:[ch3:nd] IND2Listener::GetConnectionRequest failed with %x
|
||||
**ch3|nd|conn_data %x:[ch3:nd] IND2Connector::GetPrivateData failed with %x
|
||||
**ch3|nd|conn_data_len %d:[ch3:nd] IND2Connector::GetPrivateData returned insufficient private data (%d)
|
||||
**ch3|nd|conn_data %s %d %x:[ch3:nd] IND2Connector::GetPrivateData from %s:%d failed with %x
|
||||
**ch3|nd|conn_data_len %s %d %d:[ch3:nd] IND2Connector::GetPrivateData from %s:%d returned insufficient private data (%d)
|
||||
**ch3|nd|peer_addr %x:[ch3:nd] IND2Connector::GetPeerAddr failed with %x
|
||||
**ch3|nd|accept %x:[ch3:nd] IND2Listener::Accept failed with %x
|
||||
**ch3|nd|create_ep %x:[ch3:nd] IND2Adapter::CreateEndpoint failed with %x
|
||||
**ch3|nd|conn %x:[ch3:nd] IND2Connector::Connect failed with %x
|
||||
**ch3|nd|conn %s %d %x:[ch3:nd] IND2Connector::Connect to %s:%d failed with %x
|
||||
**ch3|nd|comp_conn %s %d %x:[ch3:nd] IND2Connector::CompleteConnect to %s:%d failed with %x
|
||||
**ch3|nd|recv %x:[ch3:nd] IND2Endpoint::Receive failed with %x
|
||||
**ch3|nd|recv_err %s %d %x:[ch3:nd] Recv from %s:%d completed in error with %x
|
||||
**ch3|nd|send %x:[ch3:nd] IND2Endpoint::Send failed with %x
|
||||
**ch3|nd|send %s %d %x:[ch3:nd] IND2Endpoint::Send to %s:%d failed with %x
|
||||
**ch3|nd|send_err %s %d %x:[ch3:nd] Send to %s:%d completed in error with %x
|
||||
**ch3|nd|dconn %x:[ch3:nd] IND2Connector::Disconnect failed with %x
|
||||
**ch3|nd|flush %x:[ch3:nd] IND2Endpoint::Flush failed with %x
|
||||
**ch3|nd|create_mw %x:[ch3:nd] IND2Adapter::CreateMemoryWindow failed with %x
|
||||
**ch3|nd|bind %x:[ch3:nd] IND2Endpoint::Bind failed with %x
|
||||
**ch3|nd|bind_err %x:[ch3:nd] Bind failed with %x
|
||||
**ch3|nd|unbind %x:[ch3:nd] IND2Endpoint::Invalidate failed with %x
|
||||
**ch3|nd|unbind_err %x:[ch3:nd] Invalidate failed with %x
|
||||
**ch3|nd|read %s %d %x:[ch3:nd] IND2Endpoint::Read from %s:%d failed with %x
|
||||
**ch3|nd|read_err %s %d %x:[ch3:nd] Read from %s:%d completed in error with %x
|
||||
|
||||
#
|
||||
# CH3:ssm
|
||||
#
|
||||
**OpenProcess %d %d:OpenProcess failed for process %d, error %d
|
||||
**CreateFileMapping %d:CreateFileMapping failed, error %d
|
||||
**MapViewOfFileEx %d:MapViewOfFileEx failed, error %d
|
||||
**snprintf %d:snprintf returned %d
|
||||
**boot_attach %s:failed to attach to a bootstrap queue - %s
|
||||
**attach_to_mem:attach to shared memory segment failed
|
||||
**boot_send:sending bootstrap message failed
|
||||
**shmconnect_getmem:failed to allocate shared memory for a write queue
|
||||
**attach_to_mem %d:attach to shared memory returned error %d
|
||||
**ca %d:invalid completion action (%d)
|
||||
**vc_state %d:invalid vc state (%d)
|
||||
**argstr_port:no space for the listener port
|
||||
**argstr_port_name_tag:no space for port_name tag
|
||||
**argstr_no_port_name_tag:no port_name tag in MPI port. Make sure that port \
|
||||
was created with MPI_Open_port
|
||||
**argstr_shmq:no space for the shared memory queue name
|
||||
**argstr_missinghost:Missing hostname or invalid host/port description in business card
|
||||
**argstr_missingport:Missing port or invalid host/port description in business card
|
||||
**buscard:unable to create a business card
|
||||
**buscard_len:no space left in the business card to add a parameter
|
||||
**desc_len:host description buffer too small
|
||||
**duphandle %d:unable to duplicate a handle (errno %d)
|
||||
**duphandle %s %d:unable to duplicate a handle, %s (errno %d)
|
||||
**fail:
|
||||
**fail %d:generic failure with errno = %d
|
||||
**fail %s:%s
|
||||
**fail %s %d:%s (errno %d)
|
||||
**gethostbyname %d:gethostbyname failed (errno %d)
|
||||
**gethostbyname %s %d:gethostbyname failed, %s (errno %d)
|
||||
**sock_connect %d:connect failed (errno %d)
|
||||
**sock_connect %s %d:connect failed - %s (errno %d)
|
||||
**sock_connect %s %d %d:unable to connect to %s on port %d, error %d
|
||||
**sock_connect %s %d %s:unable to connect to %s on port %d, %s
|
||||
**sock_connect %s %d %s %d:unable to connect to %s on port %d, %s (errno %d)
|
||||
**vcfailedstate %d:Failed to communicate with %d on previous attempts
|
||||
|
||||
#
|
||||
# Sock
|
||||
#
|
||||
**sock|connclosed:connection closed by peer
|
||||
**sock|getport:failed to obtain port number of the listener
|
||||
|
||||
#
|
||||
# mpi functions
|
||||
#
|
||||
**mpi_send %p %d %D %i %t %C:MPI_Send(buf=%p, count=%d, %D, dest=%i, tag=%t, %C) failed
|
||||
**mpi_recv %p %d %D %i %t %C %p:MPI_Recv(buf=%p, count=%d, %D, src=%i, tag=%t, %C, status=%p) failed
|
||||
**mpi_get_count %p %D %p:MPI_Get_count(status=%p, %D, count=%p) failed
|
||||
**mpi_bsend %p %d %D %i %t %C:MPI_Bsend(buf=%p, count=%d, %D, dest=%i, tag=%t, %C) failed
|
||||
**mpi_ssend %p %d %D %i %t %C:MPI_Ssend(buf=%p, count=%d, %D, dest=%i, tag=%t, %C) failed
|
||||
**mpi_rsend %p %d %D %i %t %C:MPI_Rsend(buf=%p, count=%d, %D, src=%i, tag=%t, %C) failed
|
||||
**mpi_buffer_attach %p %d:MPI_Buffer_attach(buf=%p, size=%d) failed
|
||||
**mpi_buffer_detach %p %p:MPI_Buffer_detach(buf=%p, size=%p) failed
|
||||
**mpi_isend %p %d %D %i %t %C %p:MPI_Isend(buf=%p, count=%d, %D, dest=%i, tag=%t, %C, request=%p) failed
|
||||
**mpi_ibsend %p %d %D %i %t %C %p:MPI_Ibsend(buf=%p, count=%d, %D, dest=%i, tag=%t, %C, request=%p) failed
|
||||
**mpi_issend %p %d %D %i %t %C %p:MPI_Issend(buf=%p, count=%d, %D, dest=%i, tag=%t, %C, request=%p) failed
|
||||
**mpi_irsend %p %d %D %i %t %C %p:MPI_Irsend(buf=%p, count=%d, %D, dest=%i, tag=%t, %C, request=%p) failed
|
||||
**mpi_irecv %p %d %D %i %t %C %p:MPI_Irecv(buf=%p, count=%d, %D, src=%i, tag=%t, %C, request=%p) failed
|
||||
**mpi_wait %p %p:MPI_Wait(request=%p, status%p) failed
|
||||
**mpi_test %p %p %p:MPI_Test(request=%p, flag=%p, status=%p) failed
|
||||
**mpi_request_free %p:MPI_Request_free(request=%p) failed
|
||||
**mpi_waitany %d %p %p %p:MPI_Waitany(count=%d, req_array=%p, index=%p, status=%p) failed
|
||||
**mpi_testany %d %p %p %p %p:MPI_Testany(count=%d, req_array=%p, index=%p, flag=%p, status=%p) failed
|
||||
**mpi_waitall %d %p %p:MPI_Waitall(count=%d, req_array=%p, status_array=%p) failed
|
||||
**mpi_testall %d %p %p %p:MPI_Testall(count=%d, req_array=%p, flag=%p, status_array=%p) failed
|
||||
**mpi_waitsome %d %p %p %p %p:MPI_Waitsome(count=%d, req_array=%p, out_count=%p, indices=%p, status_array=%p) failed
|
||||
**mpi_testsome %d %p %p %p %p:MPI_Testsome(count=%d, req_array=%p, out_count=%p, indices=%p, status_array=%p) failed
|
||||
**mpi_iprobe %i %t %C %p %p:MPI_Iprobe(src=%i, tag=%t, %C, flag=%p, status=%p) failed
|
||||
**mpi_probe %i %t %C %p:MPI_Probe(src=%i, tag=%t, %C, status=%p) failed
|
||||
**mpi_improbe %i %t %C %p %p %p:MPI_Improbe(src=%i, tag=%t, %C, flag=%p, message=%p, status=%p) failed
|
||||
**mpi_mprobe %i %t %C %p %p:MPI_Mprobe(src=%i, tag=%t, %C, message=%p, status=%p) failed
|
||||
**mpi_mrecv %p %d %D %p %p:MPI_Mrecv(buf=%p, count=%d, %D, message=%p, status=%p) failed
|
||||
**mpi_imrecv %p %d %D %p %p:MPI_Imrecv(buf=%p, count=%d, %D, message=%p, request=%p) failed
|
||||
**mpi_cancel %p:MPI_Cancel(request=%p) failed
|
||||
**mpi_test_cancelled %p %p:MPI_Test_cancelled(status=%p, flag=%p) failed
|
||||
**mpi_send_init %p %d %D %i %t %C %p:MPI_Send_init(buf=%p, count=%d, %D, dest=%i, tag=%t, %C, request=%p) failed
|
||||
**mpi_bsend_init %p %d %D %i %t %C %p:MPI_Bsend_init(buf=%p, count=%d, %D, dest=%i, tag=%t, %C, request=%p) failed
|
||||
**mpi_ssend_init %p %d %D %i %t %C %p:MPI_Ssend_init(buf=%p, count=%d, %D, dest=%i, tag=%t, %C, request=%p) failed
|
||||
**mpi_rsend_init %p %d %D %i %t %C %p:MPI_Rsend_init(buf=%p, count=%d, %D, dest=%i, tag=%t, %C, request=%p) failed
|
||||
**mpi_recv_init %p %d %D %i %t %C %p:MPI_Recv_init(buf=%p, count=%d, %D, src=%i, tag=%t, %C, request=%p) failed
|
||||
**mpi_start %p:MPI_Start(request=%p) failed
|
||||
**mpi_startall %d %p:MPI_Startall(count=%d, req_array=%p) failed
|
||||
**mpi_sendrecv %p %d %D %i %t %p %d %D %i %t %C %p:MPI_Sendrecv(sbuf=%p, scount=%d, %D, dest=%i, stag=%t, rbuf=%p, rcount=%d, %D, src=%i, rtag=%t, %C, status=%p) failed
|
||||
**mpi_sendrecv_replace %p %d %D %i %t %i %t %C %p:MPI_Sendrecv_replace(buf=%p, count=%d, %D, dest=%i, stag=%t, src=%i, rtag=%t, %C, status=%p) failed
|
||||
**mpi_type_contiguous %d %D %p:MPI_Type_contiguous(count=%d, %D, new_type_p=%p) failed
|
||||
**mpi_type_vector %d %d %d %D %p:MPI_Type_vector(count=%d, blocklength=%d, stride=%d, %D, new_type_p=%p) failed
|
||||
**mpi_type_indexed %d %p %p %D %p:MPI_Type_indexed(count=%d, blocklens=%p, indices=%p, %D, new_type_p=%p) failed
|
||||
**mpi_type_size %D %p:MPI_Type_size(%D, size=%p) failed
|
||||
**mpi_type_size_x %D %p:MPI_Type_size_x(%D, size=%p) failed
|
||||
**mpi_type_commit %p:MPI_Type_commit(datatype_p=%p) failed
|
||||
**mpi_type_free %p:MPI_Type_free(datatype_p=%p) failed
|
||||
**mpi_get_elements %p %D %p:MPI_Get_elements(status=%p, %D, count=%p) failed
|
||||
**mpi_get_elements_x %p %D %p:MPI_Get_elements_x(status=%p, %D, count=%p) failed
|
||||
**mpi_pack %p %d %D %p %d %p %C:MPI_Pack(inbuf=%p, incount=%d, %D, outbuf=%p, outcount=%d, position=%p, %C) failed
|
||||
**mpi_unpack %p %d %p %p %d %D %C:MPI_Unpack(inbuf=%p, insize=%d, position=%p, outbuf=%p, outcount=%d, %D, %C) failed
|
||||
**mpi_pack_size %d %D %C %p:MPI_Pack_size(count=%d, %D, %C, size=%p) failed
|
||||
**mpi_barrier %C:MPI_Barrier(%C) failed
|
||||
**mpi_bcast %p %d %D %d %C:MPI_Bcast(buf=%p, count=%d, %D, root=%d, %C) failed
|
||||
**mpi_gather %p %d %D %p %d %D %d %C:MPI_Gather(sbuf=%p, scount=%d, %D, rbuf=%p, rcount=%d, %D, root=%d, %C) failed
|
||||
**mpi_gatherv %p %d %D %p %p %p %D %d %C:MPI_Gatherv failed(sbuf=%p, scount=%d, %D, rbuf=%p, rcnts=%p, displs=%p, %D, root=%d, %C) failed
|
||||
**mpi_scatter %p %d %D %p %d %D %d %C:MPI_Scatter(sbuf=%p, scount=%d, %D, rbuf=%p, rcount=%d, %D, root=%d, %C) failed
|
||||
**mpi_scatterv %p %p %p %D %p %d %D %d %C:MPI_Scatterv(sbuf=%p, scnts=%p, displs=%p, %D, rbuf=%p, rcount=%d, %D, root=%d, %C) failed
|
||||
**mpi_allgather %p %d %D %p %d %D %C:MPI_Allgather(sbuf=%p, scount=%d, %D, rbuf=%p, rcount=%d, %D, %C) failed
|
||||
**mpi_allgatherv %p %d %D %p %p %p %D %C:MPI_Allgatherv(sbuf=%p, scount=%d, %D, rbuf=%p, rcounts=%p, displs=%p, %D, %C) failed
|
||||
**mpi_alltoall %p %d %D %p %d %D %C:MPI_Alltoall(sbuf=%p, scount=%d, %D, rbuf=%p, rcount=%d, %D, %C) failed
|
||||
**mpi_alltoallv %p %p %p %D %p %p %p %D %C:MPI_Alltoallv(sbuf=%p, scnts=%p, sdispls=%p, %D, rbuf=%p, rcnts=%p, rdispls=%p, %D, %C) failed
|
||||
**mpi_reduce %p %p %d %D %O %d %C:MPI_Reduce(sbuf=%p, rbuf=%p, count=%d, %D, %O, root=%d, %C) failed
|
||||
**mpi_reduce_local %p %p %d %D %O:MPI_Reduce_local(inbuf=%p, inoutbuf=%p, count=%p, %D, %O) failed
|
||||
**mpi_iallgather %p %d %D %p %d %D %C %p:MPI_Iallgather(sbuf=%p, scount=%d, %D, rbuf=%p, rcount=%d, %D, %C, request=%p) failed
|
||||
**mpi_iallgatherv %p %d %D %p %p %p %D %C %p:MPI_Iallgatherv(sbuf=%p, scount=%d, %D, rbuf=%p, rcounts=%p, displs=%p, %D, %C, request=%p) failed
|
||||
**mpi_iallreduce %p %p %d %D %O %C %p:MPI_Iallreduce(sbuf=%p, rbuf=%p, count=%d, %D, %O, %C, request=%p) failed
|
||||
**mpi_ialltoall %p %d %D %p %d %D %C %p:MPI_Ialltoall(sbuf=%p, scount=%d, %D, rbuf=%p, rcount=%d, %D, %C, request=%p) failed
|
||||
**mpi_ialltoallv %p %p %p %D %p %p %p %D %C %p:MPI_Ialltoallv(sbuf=%p, scnts=%p, sdispls=%p, %D, rbuf=%p, rcnts=%p, rdispls=%p, %D, %C, request=%p) failed
|
||||
**mpi_ialltoallw %p %p %p %p %p %p %p %p %C %p:MPI_Ialltoallw(sbuf=%p, scnts=%p, sdispls=%p, stypes=%p, rbuf=%p, rcnts=%p, rdispls=%p, rtypes=%p, %C, request=%p) failed
|
||||
**mpi_ibarrier %C %p:MPI_Ibarrier(%C, request=%p) failed
|
||||
**mpi_ibcast %p %d %D %d %C %p:MPI_Ibcast(buf=%p, count=%d, %D, root=%d, %C, request=%p) failed
|
||||
**mpi_iexscan %p %p %d %D %O %C %p:MPI_Iexscan(sbuf=%p, rbuf=%p, count=%d, %D, %O, %C, request=%p) failed
|
||||
**mpi_igather %p %d %D %p %d %D %d %C %p:MPI_Igather(sbuf=%p, scount=%d, %D, rbuf=%p, rcount=%d, %D, root=%d, %C, request=%p) failed
|
||||
**mpi_igatherv %p %d %D %p %p %p %D %d %C %p:MPI_Igatherv failed(sbuf=%p, scount=%d, %D, rbuf=%p, rcnts=%p, displs=%p, %D, root=%d, %C, request=%p) failed
|
||||
**mpi_ireduce %p %p %d %D %O %d %C %p:MPI_Ireduce(sbuf=%p, rbuf=%p, count=%d, %D, %O, root=%d, %C, request=%p) failed
|
||||
**mpi_ireduce_scatter %p %p %p %D %O %C %p:MPI_Ireduce_scatter(sbuf=%p, rbuf=%p, rcnts=%p, %D, %O, %C, request=%p) failed
|
||||
**mpi_ireduce_scatter_block %p %p %d %D %O %C %p:MPI_Reduce_scatter_block(sbuf=%p, rbuf=%p, rcnt=%d, %D, %O, %C, request=%p) failed
|
||||
**mpi_iscan %p %p %d %D %O %C %p:MPI_Iscan(sbuf=%p, rbuf=%p, count=%d, %D, %O, %C, request=%p) failed
|
||||
**mpi_iscatter %p %d %D %p %d %D %d %C %p:MPI_Iscatter(sbuf=%p, scount=%d, %D, rbuf=%p, rcount=%d, %D, root=%d, %C, request=%p) failed
|
||||
**mpi_iscatterv %p %p %p %D %p %d %D %d %C %p:MPI_Iscatterv(sbuf=%p, scnts=%p, displs=%p, %D, rbuf=%p, rcount=%d, %D, root=%d, %C, request=%p) failed
|
||||
**mpi_op_commutative %O:MPI_Op_commutative(%O) failed
|
||||
**mpi_op_create %p %d %p:MPI_Op_create(fn=%p, commute=%d, op=%p) failed
|
||||
**mpi_op_free %p:MPI_Op_free(op=%p) failed
|
||||
**mpi_allreduce %p %p %d %D %O %C:MPI_Allreduce(sbuf=%p, rbuf=%p, count=%d, %D, %O, %C) failed
|
||||
**mpi_reduce_scatter %p %p %p %D %O %C:MPI_Reduce_scatter(sbuf=%p, rbuf=%p, rcnts=%p, %D, %O, %C) failed
|
||||
**mpi_reduce_scatter_block %p %p %d %D %O %C:MPI_Reduce_scatter_block(sbuf=%p, rbuf=%p, rcnt=%d, %D, %O, %C) failed
|
||||
**mpi_scan %p %p %d %D %O %C:MPI_Scan(sbuf=%p, rbuf=%p, count=%d, %D, %O, %C) failed
|
||||
**mpi_group_size %G %p:MPI_Group_size(%G, size=%p) failed
|
||||
**mpi_group_rank %G %p:MPI_Group_rank(%G, rank=%p) failed
|
||||
**mpi_group_translate_ranks %G %d %p %G %p:MPI_Group_translate_ranks(%G, n=%d, ranks1=%p, %G, ranks2=%p) failed
|
||||
**mpi_group_compare %G %G %p:MPI_Group_compare(%G, %G, result=%p) failed
|
||||
**mpi_comm_group %C %p:MPI_Comm_group(%C, group=%p) failed
|
||||
**mpi_group_union %G %G %p:MPI_Group_union(%G, %G, new_group=%p) failed
|
||||
**mpi_group_intersection %G %G %p:MPI_Group_intersection(%G, %G, new_group=%p) failed
|
||||
**mpi_group_difference %G %G %p:MPI_Group_difference(%G, %G, new_group=%p) failed
|
||||
**mpi_group_incl %G %d %p %p:MPI_Group_incl(%G, n=%d, ranks=%p, new_group=%p) failed
|
||||
**mpi_group_excl %G %d %p %p:MPI_Group_excl(%G, n=%d, ranks=%p, new_group=%p) failed
|
||||
**mpi_group_range_incl %G %d %p %p:MPI_Group_range_incl(%G, n=%d, ranges=%p, new_group=%p) failed
|
||||
**mpi_group_range_excl %G %d %p %p:MPI_Group_range_excl(%G, n=%d, ranges=%p, new_group=%p) failed
|
||||
**mpi_group_free %p:MPI_Group_free(group=%p) failed
|
||||
**mpi_comm_size %C %p:MPI_Comm_size(%C, size=%p) failed
|
||||
**mpi_comm_rank %C %p:MPI_Comm_rank(%C, rank=%p) failed
|
||||
**mpi_comm_compare %C %C %p:MPI_Comm_compare(%C, %C, result=%p) failed
|
||||
**mpi_comm_dup %C %p:MPI_Comm_dup(%C, new_comm=%p) failed
|
||||
**mpi_comm_create %C %G %p:MPI_Comm_create(%C, %G, new_comm=%p) failed
|
||||
**mpi_comm_split %C %d %d %p:MPI_Comm_split(%C, color=%d, key=%d, new_comm=%p) failed
|
||||
**mpi_comm_split_type %C %d %d %I %p:MPI_Comm_split_type(%C, split_type=%d, key=%d, info=%I new_comm=%p) failed
|
||||
**mpi_comm_free %p:MPI_Comm_free(comm=%p) failed
|
||||
**mpi_comm_test_inter %C %p:MPI_Comm_test_inter(%C, flag=%p) failed
|
||||
**mpi_comm_remote_size %C %p:MPI_Comm_remote_size(%C, size=%p) failed
|
||||
**mpi_comm_remote_group %C %p:MPI_Comm_remote_group(%C, group=%p) failed
|
||||
**mpi_intercomm_create %C %d %C %d %d %p:MPI_Intercomm_create(%C, local_leader=%d, %C, remote_leader=%d, tag=%d, newintercomm=%p) failed
|
||||
**mpi_intercomm_merge %C %d %p:MPI_Intercomm_merge(%C, high=%d, newintracomm=%p) failed
|
||||
**mpi_topo_test %C %p:MPI_Topo_test(%C, topo_type=%p) failed
|
||||
**mpi_cart_create %C %d %p %p %d %p:MPI_Cart_create(%C, ndims=%d, dims=%p, periods=%p, reorder=%d, comm_cart=%p) failed
|
||||
**mpi_dims_create %d %d %p:MPI_Dims_create(nnodes=%d, ndims=%d, dims=%p) failed
|
||||
**mpi_graph_create %C %d %p %p %d %p:MPI_Graph_create(%C, nnodes=%d, index=%p, edges=%p, reorder=%d, comm_graph=%p) failed
|
||||
**mpi_graphdims_get %C %p %p:MPI_Graphdims_get(%C, nnodes=%p, nedges=%p) failed
|
||||
**mpi_graph_get %C %d %d %p %p:MPI_Graph_get(%C, maxindex=%d, maxedges=%d, index=%p, edges=%p) failed
|
||||
**mpi_cartdim_get %C %p:MPI_Cartdim_get(%C, ndims=%p) failed
|
||||
**mpi_cart_get %C %d %p %p %p:MPI_Cart_get(%C, maxdims=%d, dims=%p, periods=%p, coords=%p) failed
|
||||
**mpi_cart_rank %C %p %p:MPI_Cart_rank(%C, coords=%p, rank=%p) failed
|
||||
**mpi_cart_coords %C %d %d %p:MPI_Cart_coords(%C, rank=%d, maxdims=%d, coords=%p) failed
|
||||
**mpi_graph_neighbors_count %C %d %p:MPI_Graph_neighbors_count(%C, rank=%d, nneighbors=%p) failed
|
||||
**mpi_graph_neighbors %C %d %d %p:MPI_Graph_neighbors(%C, rank=%d, maxneighbors=%d, neighbors=%p) failed
|
||||
**mpi_cart_shift %C %d %d %p %p:MPI_Cart_shift(%C, direction=%d, displ=%d, source=%p, dest=%p) failed
|
||||
**mpi_cart_sub %C %p %p:MPI_Cart_sub(%C, remain_dims=%p, comm_new=%p) failed
|
||||
**mpi_cart_map %C %d %p %p %p:MPI_Cart_map(%C, ndims=%d, dims=%p, periods=%p, newrank=%p) failed
|
||||
**mpi_graph_map %C %d %p %p %p:MPI_Graph_map(%C, nnodes=%d, index=%p, edges=%p, newrank=%p) failed
|
||||
**mpi_dist_graph_neighbors_count %C:MPI_Dist_graph_neighbors_count(%C) failed
|
||||
**mpi_dist_graph_neighbors %C %d %d:MPI_Dist_graph_neighbors(%C, maxindegree=%d, maxoutdegree=%d) failed
|
||||
**mpi_dist_graph_create_adjacent %C %d %p %p %d %p %p %d %d:MPI_Dist_graph_create_adjacent(%C, indegree=%d, sources=%p, sourceweights=%p, outdegree=%d, destinations=%p, destweights=%p, info=%d, reorder=%d) failed
|
||||
**mpi_dist_graph_create %C %d %p %p %p %p %d %d:MPI_Dist_graph_create(%C, n=%d, sources=%p, degrees=%p, destinations=%p, weights=%p, info=%d, reorder=%d) failed
|
||||
**mpi_get_processor_name %p %p:MPI_Get_processor_name(name=%p, resultlen=%p) failed
|
||||
**mpi_get_version %p %p:MPI_Get_version(version=%p, subversion=%p) failed
|
||||
**mpi_get_library_version %p %p:MPI_Get_library_version(version=%p, resultlen=%p) failed
|
||||
**mpi_errhandler_free %p:MPI_Errhandler_free(errhandler=%p) failed
|
||||
**mpi_error_string %d %s %p:MPI_Error_string(errorcode=%d, string=%s, resultlen=%p) failed
|
||||
**mpi_error_class %d %p:MPI_Error_class(errorcode=%d, errorclass=%p) failed
|
||||
**mpi_init %p %p:MPI_Init(argc_p=%p, argv_p=%p) failed
|
||||
**mpi_finalize:MPI_Finalize failed
|
||||
**mpi_initialized %p:MPI_Initialized(flag=%p) failed
|
||||
**mpi_abort %C %d:MPI_Abort(%C, errorcode=%d) failed
|
||||
**mpi_close_port %s:MPI_Close_port(port=\"%s\") failed
|
||||
**mpi_comm_accept %s %I %d %C %p:MPI_Comm_accept(port=\"%s\", %I, root=%d, %C, newcomm=%p) failed
|
||||
**mpi_comm_connect %s %I %d %C %p:MPI_Comm_connect(port=\"%s\", %I, root=%d, %C, newcomm=%p) failed
|
||||
**mpi_comm_disconnect %C:MPI_Comm_disconnect(comm=%C) failed
|
||||
**mpi_comm_get_parent %p:MPI_Comm_get_parent(comm=%p) failed
|
||||
**mpi_comm_join %d %p:MPI_Comm_join(fd=%d, intercomm=%p) failed
|
||||
**mpi_comm_spawn %s %p %d %I %d %C %p %p:MPI_Comm_spawn(cmd=\"%s\", argv=%p, maxprocs=%d, %I, root=%d, %C, intercomm=%p, errors=%p) failed
|
||||
**mpi_comm_spawn_multiple %d %p %p %p %p %d %C %p %p:MPI_Comm_spawn_multiple(count=%d, cmds=%p, argvs=%p, maxprocs=%p, infos=%p, root=%d, %C, intercomm=%p, errors=%p) failed
|
||||
**mpi_lookup_name %s %I %p:MPI_Lookup_name(service=\"%s\", %I, port=%p) failed
|
||||
**mpi_open_port %I %p:MPI_Open_port(%I, port=%p) failed
|
||||
**mpi_publish_name %s %I %s:MPI_Publish_name(service=\"%s\", %I, port=\"%s\") failed
|
||||
**mpi_unpublish_name %s %I %s:MPI_Unpublish_name(service=\"%s\", %I, port=\"%s\") failed
|
||||
**mpi_accumulate %p %d %D %d %d %d %D %O %W:MPI_Accumulate(origin_addr=%p, origin_count=%d, %D, target_rank=%d, target_disp=%d, target_count=%d, %D, %O, %W) failed
|
||||
**mpi_raccumulate %p %d %D %d %d %d %D %O %W %p:MPI_Raccumulate(origin_addr=%p, origin_count=%d, %D, target_rank=%d, target_disp=%d, target_count=%d, %D, %O, %W, request=%p) failed
|
||||
**mpi_get %p %d %D %d %d %d %D %W:MPI_Get(origin_addr=%p, origin_count=%d, %D, target_rank=%d, target_disp=%d, target_count=%d, %D, %W) failed
|
||||
**mpi_rget %p %d %D %d %d %d %D %W %p:MPI_Rget(origin_addr=%p, origin_count=%d, %D, target_rank=%d, target_disp=%d, target_count=%d, %D, %W, request=%p) failed
|
||||
**mpi_put %p %d %D %d %d %d %D %W:MPI_Put(origin_addr=%p, origin_count=%d, %D, target_rank=%d, target_disp=%d, target_count=%d, %D, %W) failed
|
||||
**mpi_rput %p %d %D %d %d %d %D %W %p:MPI_Rput(origin_addr=%p, origin_count=%d, %D, target_rank=%d, target_disp=%d, target_count=%d, %D, %W, request=%p) failed
|
||||
**mpi_get_accumulate %p %d %D %p %d %D %d %d %d %D %O %W:MPI_Get_accumulate(origin_addr=%p, origin_count=%d, %D, result_addr=%p, result_count=%d, %D, target_rank=%d, target_disp=%d, target_count=%d, %D, %O, %W) failed
|
||||
**mpi_rget_accumulate %p %d %D %p %d %D %d %d %d %D %O %W %p:MPI_Rget_accumulate(origin_addr=%p, origin_count=%d, %D, result_addr=%p, result_count=%d, %D, target_rank=%d, target_disp=%d, target_count=%d, %D, %O, %W, request=%p) failed
|
||||
**mpi_fetch_and_op %p %p %D %d %d %O %W:MPI_Fetch_and_op(origin_addr=%p, result_addr=%p, %D, target_rank=%d, target_disp=%d, %O, %W) failed
|
||||
**mpi_compare_and_swap %p %p %p %D %d %d %W:MPI_Compare_and_swap(origin_addr=%p, compare_addr=%p, result_addr=%p, %D, target_rank=%d, target_disp=%d, %W) failed
|
||||
**mpi_win_complete %W:MPI_Win_complete(%W) failed
|
||||
**mpi_win_create %p %d %d %I %C %p:MPI_Win_create(base=%p, size=%d, disp_unit=%d, %I, %C, win=%p) failed
|
||||
**mpi_win_allocate %d %d %I %C %p %p:MPI_Win_allocate(size=%d, disp_unit=%d, %I, %C, baseptr=%p, win=%p) failed
|
||||
**mpi_win_allocate_shared %d %d %I %C %p %p:MPI_Win_allocate_shared(size=%d, disp_unit=%d, %I, %C, baseptr=%p, win=%p) failed
|
||||
**mpi_win_create_dynamic %I %C %p:MPI_Win_create(%I, %C, win=%p) failed
|
||||
**mpi_win_shared_query %p %d %d %d %p:MPI_Win_shared_query(win=%p, rank=%d, size=%d, disp_unit=%d, baseptr=%p) failed
|
||||
**mpi_win_fence %A %W:MPI_Win_fence(%A, %W) failed
|
||||
**mpi_win_free %p:MPI_Win_free(win=%p) failed
|
||||
**mpi_win_get_group %W %p:MPI_Win_get_group(%W, group=%p) failed
|
||||
**mpi_win_lock %d %d %A %W:MPI_Win_lock(lock_type=%d, rank=%d, %A, %W) failed
|
||||
**mpi_win_lock_all %A %W:MPI_Win_lock_all(%A, %W) failed
|
||||
**mpi_win_post %G %A %W:MPI_Win_post(%G, %A, %W) failed
|
||||
**mpi_win_start %G %A %W:MPI_Win_start(%G, %A, %W) failed
|
||||
**mpi_win_test %W %p:MPI_Win_test(%W, flag=%p) failed
|
||||
**mpi_win_unlock %d %W:MPI_Win_unlock(rank=%d, %W) failed
|
||||
**mpi_win_unlock_all %W:MPI_Win_unlock_all(%W) failed
|
||||
**mpi_win_flush %d %W:MPI_Win_flush(rank=%d, %W) failed
|
||||
**mpi_win_flush_all %W:MPI_Win_flush_all(%W) failed
|
||||
**mpi_win_flush_local %d %W:MPI_Win_flush_local(rank=%d, %W) failed
|
||||
**mpi_win_flush_local_all %W:MPI_Win_flush_local_all(%W) failed
|
||||
**mpi_win_sync %W:MPI_Win_sync(%W) failed
|
||||
**mpi_win_wait %W:MPI_Win_wait(%W) failed
|
||||
**mpi_win_attach %W %p %d:MPI_Win_attach(win=%W, base=%p, size=%d) failed
|
||||
**mpi_win_detach %W %p:MPI_Win_detach(win=%W, base=%p) failed
|
||||
**mpi_alltoallw %p %p %p %p %p %p %p %p %C:MPI_Alltoallw(sbuf=%p, scnts=%p, sdispls=%p, stypes=%p, rbuf=%p, rcnts=%p, rdispls=%p, rtypes=%p, %C) failed
|
||||
**mpi_exscan %p %p %d %D %O %C:MPI_Exscan(sbuf=%p, rbuf=%p, count=%d, %D, %O, %C) failed
|
||||
**mpi_add_error_class %p:MPI_Add_error_class(errorclass=%p) failed
|
||||
**mpi_add_error_code %d %p:MPI_Add_error_code(errorclass=%d, errorcode=%p) failed
|
||||
**mpi_add_error_string %d %s:MPI_Add_error_string(code=%d, str=\"%s\") failed
|
||||
**mpi_comm_call_errhandler %C %d:MPI_Comm_call_errhandler(%C, errorcode=%d) failed
|
||||
**mpi_comm_create_keyval %p %p %p %p:MPI_Comm_create_keyval(comm_copy_attr_fn=%p, comm_delete_attr_fn=%p, comm_keyval=%p, extra_state=%p) failed
|
||||
**mpi_comm_delete_attr %C %d:MPI_Comm_delete_attr(%C, comm_keyval=%d) failed
|
||||
**mpi_comm_free_keyval %p:MPI_Comm_free_keyval(comm_keyval=%p) failed
|
||||
**mpi_comm_get_attr %C %d %p %p:MPI_Comm_get_attr(%C, comm_keyval=%d, attribute_val=%p, flag=%p) failed
|
||||
**mpi_comm_get_name %C %p %p:MPI_Comm_get_name(%C, comm_name=%p, resultlen=%p) failed
|
||||
**mpi_comm_set_attr %C %d %p:MPI_Comm_set_attr(%C, comm_keyval=%d, attribute_val=%p) failed
|
||||
**mpi_comm_set_name %C %s:MPI_Comm_set_name(%C, comm_name=%s) failed
|
||||
**mpi_grequest_complete %R:MPI_Grequest_complete(%R) failed
|
||||
**mpi_grequest_start %p %p %p %p %p:MPI_Grequest_start(query_fn=%p, free_fn=%p, cancel_fn=%p, extra_state=%p, request=%p) failed
|
||||
**mpi_init_thread %p %p %d %p:MPI_Init_thread(argc_p=%p, argv_p=%p, required=%d, provided=%p)
|
||||
**mpi_is_thread_main %p:MPI_Is_thread_main(flag=%p) failed
|
||||
**mpi_query_thread %p:MPI_Query_thread(provided=%p) failed
|
||||
**mpi_status_set_cancelled %p %d:MPI_Status_set_cancelled(status=%p, flag=%d) failed
|
||||
**mpi_status_set_elements %p %D %d:MPI_Status_set_elements(status=%p, %D, count=%d) failed
|
||||
**mpi_status_set_elements_x %p %D %l:MPI_Status_set_elements_x(status=%p, %D, count=%l) failed
|
||||
**mpi_type_create_keyval %p %p %p %p:MPI_Type_create_keyval(type_copy_attr_fn=%p, type_delete_attr_fn=%p, type_keyval=%p, extra_state=%p) failed
|
||||
**mpi_type_delete_attr %D %d:MPI_Type_delete_attr(%D, type_keyval=%d) failed
|
||||
**mpi_type_dup %D %p:MPI_Type_dup(%D, newtype=%p) failed
|
||||
**mpi_type_free_keyval %p:MPI_Type_free_keyval(type_keyval=%p) failed
|
||||
**mpi_type_get_attr %D %d %p %p:MPI_Type_get_attr(%D, type_keyval=%d, attribute_val=%p, flag=%p) failed
|
||||
**mpi_type_get_contents %D %d %d %d %p %p %p:MPI_Type_get_contents(%D, max_integers=%d, max_addresses=%d, max_datatypes=%d, array_of_integers=%p, array_of_addresses=%p, array_of_datatypes=%p) failed
|
||||
**mpi_type_get_envelope %D %p %p %p %p:MPI_Type_get_envelope(%D, num_integers=%p, num_addresses=%p, num_datatypes=%p, combiner=%p) failed
|
||||
**mpi_type_get_name %D %p %p:MPI_Type_get_name(%D, type_name=%p, resultlen=%p) failed
|
||||
**mpi_type_set_attr %D %d %p:MPI_Type_set_attr(%D, type_keyval=%d, attribute_val=%p) failed
|
||||
**mpi_type_set_name %D %s:MPI_Type_set_name(%D, type_name=%s) failed
|
||||
**mpi_type_match_size %d %d %p:MPI_Type_match_size(typeclass=%d, size=%d, datatype=%p) failed
|
||||
**mpi_win_call_errhandler %W %d:MPI_Win_call_errhandler(%W, errorcode=%d) failed
|
||||
**mpi_win_create_keyval %p %p %p %p:MPI_Win_create_keyval(win_copy_attr_fn=%p, win_delete_attr_fn=%p, win_keyval=%p, extra_state=%p) failed
|
||||
**mpi_win_delete_attr %W %d:MPI_Win_delete_attr(%W, win_keyval=%d) failed
|
||||
**mpi_win_free_keyval %p:MPI_Win_free_keyval(win_keyval=%p) failed
|
||||
**mpi_win_get_attr %W %d %p %p:MPI_Win_get_attr(%W, win_keyval=%d, attribute_val=%p, flag=%p) failed
|
||||
**mpi_win_get_name %W %p %p:MPI_Win_get_name(%W, win_name=%p, resultlen=%p) failed
|
||||
**mpi_win_set_attr %W %d %p:MPI_Win_set_attr(%W, win_keyval=%d, attribute_val=%p) failed
|
||||
**mpi_win_set_name %W %s:MPI_Win_set_name(%W, win_name=%s) failed
|
||||
**mpi_alloc_mem %p %I %p:MPI_Alloc_mem(size=%p, %I, baseptr=%p) failed
|
||||
**mpi_comm_create_errhandler %p %p:MPI_Comm_create_errhandler(function=%p, errhandler=%p) failed
|
||||
**mpi_comm_get_errhandler %C %p:MPI_Comm_get_errhandler(%C, errhandler=%p) failed
|
||||
**mpi_comm_set_errhandler %C %E:MPI_Comm_set_errhandler(%C, %E) failed
|
||||
**mpi_file_create_errhandler %p %p:MPI_File_create_errhandler(function=%p, errhandler=%p) failed
|
||||
**mpi_file_get_errhandler %F %p:MPI_File_get_errhandler(%F, errhandler=%p) failed
|
||||
**mpi_file_set_errhandler %F %E:MPI_File_set_errhandler(%F, %E) failed
|
||||
**mpi_finalized %p:MPI_Finalized(flag=%p) failed
|
||||
**mpi_get_address %p %p:MPI_Get_address(location=%p, address=%p) failed
|
||||
**mpi_info_create %p:MPI_Info_create(info=%p) failed
|
||||
**mpi_info_delete %I %s:MPI_Info_delete(%I, key=%s) failed
|
||||
**mpi_info_dup %I %p:MPI_Info_dup(%I, newinfo=%p) failed
|
||||
**mpi_info_free %p:MPI_Info_free(info=%p) failed
|
||||
**mpi_info_get %I %s %d %p %p:MPI_Info_get(%I, key=%s, valuelen=%d, value=%p, flag=%p) failed
|
||||
**mpi_info_get_nkeys %I %p:MPI_Info_get_nkeys(%I, nkeys=%p) failed
|
||||
**mpi_info_get_nthkey %I %d %p:MPI_Info_get_nthkey(%I, n=%d, key=%p) failed
|
||||
**mpi_info_get_valuelen %I %s %p %p:MPI_Info_get_valuelen(%I, key=%s, valuelen=%p, flag=%p) failed
|
||||
**mpi_info_set %I %s %s:MPI_Info_set(%I, key=%s, value=%s) failed
|
||||
**mpi_pack_external %s %p %d %D %p %d %p:MPI_Pack_external(datarep=%s, inbuf=%p, incount=%d, %D, outbuf=%p, outcount=%d, position=%p) failed
|
||||
**mpi_pack_external_size %s %d %D %p:MPI_Pack_external_size(datarep=%s, incount=%d, %D, size=%p) failed
|
||||
**mpi_request_get_status %R %p %p:MPI_Request_get_status(%R, flag=%p, status=%p) failed
|
||||
**mpi_type_create_darray %d %d %d %p %p %p %p %d %D %p:MPI_Type_create_darray(size=%d, rank=%d, ndims=%d, array_of_gsizes=%p, array_of_distribs=%p, array_of_dargs=%p, array_of_psizes=%p, order=%d, %D, newtype=%p) failed
|
||||
**mpi_type_create_hindexed %d %p %p %D %p:MPI_Type_create_hindexed(count=%d, array_of_blocklengths=%p, array_of_displacements=%p, %D, newtype=%p) failed
|
||||
**mpi_type_create_hindexed_block %d %d %p %D %p:MPI_Type_create_hindexed_block(count=%d, blocklength=%d, array_of_displacements=%p, %D, newtype=%p) failed
|
||||
**mpi_type_create_hvector %d %d %d %D %p:MPI_Type_create_hvector(count=%d, blocklength=%d, stride=%d, %D, newtype=%p) failed
|
||||
**mpi_type_create_indexed_block %d %d %p %D %p:MPI_Type_create_indexed_block(count=%d, blocklength=%d, array_of_displacements=%p, %D, newtype=%p) failed
|
||||
**mpi_type_create_resized %D %d %d %p:MPI_Type_create_resized(%D, lb=%d, extent=%d, newtype=%p) failed
|
||||
**mpi_type_create_struct %d %p %p %p %p:MPI_Type_create_struct(count=%d, array_of_blocklengths=%p, array_of_displacements=%p, array_of_types=%p, newtype=%p) failed
|
||||
**mpi_type_create_subarray %d %p %p %p %d %D %p:MPI_Type_create_subarray(ndims=%d, array_of_sizes=%p, array_of_subsizes=%p, array_of_starts=%p, order=%d, %D, newtype=%p) failed
|
||||
**mpi_type_get_extent %D %p %p:MPI_Type_get_extent(%D, lb=%p, extent=%p) failed
|
||||
**mpi_type_get_extent_x %D %p %p:MPI_Type_get_extent_x(%D, lb=%p, extent=%p) failed
|
||||
**mpi_type_get_true_extent %D %p %p:MPI_Type_get_true_extent(%D, lb=%p, true_extent=%p) failed
|
||||
**mpi_type_get_true_extent_x %D %p %p:MPI_Type_get_true_extent_x(%D, lb=%p, true_extent=%p) failed
|
||||
**mpi_unpack_external %s %p %d %p %p %d %D:MPI_Unpack_external(datarep=%s, inbuf=%p, insize=%d, position=%p, outbuf=%p, outcount=%d, %D) failed
|
||||
**mpi_win_create_errhandler %p %p:MPI_Win_create_errhandler(function=%p, errhandler=%p) failed
|
||||
**mpi_win_get_errhandler %W %p:MPI_Win_get_errhandler(%W, errhandler=%p) failed
|
||||
**mpi_win_set_errhandler %W %E:MPI_Win_set_errhandler(%W, %E) failed
|
||||
**mpi_register_datarep %s %p %p %p %p:MPI_Register_datarep(datarep=%s, read_conversion_fn=%p, write_conversion_fn=%p, dtype_file_extent_fn=%p, extra_state=%p) failed
|
||||
|
||||
#
|
||||
# msmpi functions
|
||||
#
|
||||
**msmpi_req_set_apc %R %p %p:MSMPI_Request_set_apc(%R, callback_fn=%p, callback_status=%p) failed
|
||||
**msmpi_waitsome_interruptible %d %p %p %p %p:MSMPI_Waitsome_interruptible(count=%d, req_array=%p, out_count=%p, indices=%p, status_array=%p) failed
|
||||
|
||||
#
|
||||
# Compression
|
||||
#
|
||||
**unableToLoadDLL: Unable to load a dynamically loadable library
|
||||
**failureGetProcAddress %d:Call to GetProcAddress failed (errno %d)
|
||||
**failureCompressionWorkSpace %d:Call to RtlGetCompressionWorkSpaceSize failed (errno %d)
|
||||
**compressionMinimum %d %d:The provided compression threshold of %d was too small. \
|
||||
Try again with a threshold no less than %d
|
||||
**decompressFailure %d:Decompression of a message failed (errno %d)
|
||||
**nullPayloadRequest:The initial clear to send request has an invalid sender request id.
|
||||
|
||||
#
|
||||
# SMP Awareness
|
||||
#
|
||||
**frequency:This machine does not support high frequency performance counters.
|
||||
**measurementfailed:Measurement of collective failed.
|
||||
**nodeids:Unable to read node ids.
|
||||
**badenv %s:Invalid value for %s environment variable.
|
||||
|
||||
|
||||
#
|
||||
# Parsing Util
|
||||
#
|
||||
**rangedup %s %d:The specified range %s contains duplicate entries; rank %d \
|
||||
appeared more than once
|
||||
**invalidrange %s: The specified range %s is invalid
|
||||
|
||||
#
|
||||
# Dynamic Process related
|
||||
#
|
||||
**dynamicStartFailedEnv:The dynamic server failed to start. Invalid environment variable value given for MSMPI_ACCEPT_PORT.
|
||||
**dynamicStartFailed %d:The dynamic server failed to start with status %d.
|
||||
**dynamicNewPortFailed:The dynamic server failed to open a new port.
|
||||
**dynamicInvalidPort %s:No server is accepting connection on port %s.
|
||||
**dynamicInvalidBindingString %s:The specified binding %s is invalid.
|
||||
**dynamicBindingFromStringFailed %s %d:Failed to create RPC binding from the specified port string %s (errno %d).
|
||||
**dynamicBindingSetAuthFailed %d:Failed to set authentication on the RPC binding (errno %d).
|
||||
**dynamicTimedOut:The accept server is too busy.
|
||||
**dynamicCreateContextFailed %d:Failed to establish context with the server (errno %d).
|
||||
**dynamicInternalFailure:Internal error while trying to collect process groups information from the local communicator.
|
||||
**dynamicInitializeAsyncFailed %d:Failed to initialize Asynchronous RPC (errno %d).
|
||||
**dynamicWaitForAsyncFailed %d:Failed to initialize asynchronous RPC (errno %d).
|
||||
**dynamicCompleteAsyncFailed %d:Failed to complete asynchronous RPC (errno %d).
|
||||
**dynamicExchangeInfoFailed %d:Failed to exchange information with the Accept Server (errno %d).
|
||||
**dynamicRootConnectAcceptFailed:The root of this operation indicated that it experienced an error.
|
||||
**dynamicClientRPCFailed:An error on the client side resulted in the cancellation of the RPC call.
|
||||
|
||||
#
|
||||
# Print environment block
|
||||
#
|
||||
**badfile %s:The requested file could not be opened to write the environment block. %s.
|
||||
**envexpand:The environment variables in MSMPI_PRINT_ENVIRONMENT_BLOCK_FILE could not be expanded.
|
||||
**getenvfailed:Unable to get the environment block for the process.
|
||||
**freeenvfailed:Unable to free the environment block for the process.
|
||||
|
||||
#
|
||||
# Casting values to type int results in truncation
|
||||
#
|
||||
**packtruncate:The size of the packed data was larger than could be represented using an integer.
|
||||
**unpacktruncate:The size of the unpacked data was larger than could be represented using an integer.
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# The following names are defined but not used (see the -careful option
|
||||
# for extracterrmsgs) (still to do: move the undefined names here)
|
|
@ -0,0 +1,732 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
*
|
||||
* (C) 2001 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
/* defmsg is generated automatically from the source files and contains
|
||||
all of the error messages */
|
||||
#include "defmsg.h"
|
||||
|
||||
#include "mpidump.h"
|
||||
#include <excpt.h>
|
||||
#include <evntprov.h>
|
||||
|
||||
|
||||
/*
|
||||
* Instance-specific error messages are stored in a ring. The elements of this
|
||||
* ring are MPIR_Err_msg_t structures, which contain the following fields:
|
||||
* id - this is used to check that the entry is valid; it is computed from
|
||||
* the error code and location in the ring. The routine
|
||||
* ErrcodeToId( errcode, &id ) is used to extract the id from an
|
||||
* error code and
|
||||
* ErrcodeCreateID( class, generic, msg, &id, &seq ) is used to
|
||||
* create the id from an error class, generic index, and message
|
||||
* string. The "seq" field is inserted into the error code as a
|
||||
* check.
|
||||
*
|
||||
* prev_error - The full MPI error code of the previous error attached
|
||||
* to this list of errors, or MPI_SUCCESSS (which has value 0).
|
||||
* This is the last error code, not the index in the ring of the last
|
||||
* error code. That's the right choice, because we want to ensure
|
||||
* that the value is valid if the ring overflows. In addition,
|
||||
* we allow this to be an error CLASS (one of the predefined MPI
|
||||
* error classes). This is particularly important for
|
||||
* MPI_ERR_IN_STATUS, which may be returned as a valid error code.
|
||||
* (classes are valid error codes).
|
||||
*
|
||||
* use_user_error_code and user_error_code - Used to handle a few cases
|
||||
* in MPI where a user-provided routine returns an error code;
|
||||
* this allows us to provide information about the chain of
|
||||
* routines that were involved, while returning the users prefered
|
||||
* error value to the users environment.
|
||||
*
|
||||
* location - A string that indicates what function and line number
|
||||
* where the error code was set.
|
||||
*
|
||||
* msg - A message about the error. This may be instance-specific (e.g.,
|
||||
* it may have been created at the time the error was detected with
|
||||
* information about the parameters that caused the error).
|
||||
*
|
||||
* Note that both location and msg are defined as length MAX_xxx+1. This
|
||||
* isn't really necessary (at least for msg), since the MPI standard
|
||||
* requires that MAX_MPI_ERROR_STRING include the space for the trailing null,
|
||||
* but using the extra byte makes the code a little simpler.
|
||||
*
|
||||
* The "id" value is used to keep a sort of "checkvalue" to ensure that the
|
||||
|
||||
* error code that points at this message is in fact for this particular
|
||||
* message. This is used to handle the unlikely but possible situation where
|
||||
* so many error messages are generated that the ring is overlapped.
|
||||
*
|
||||
* The message arrays are preallocated to ensure that there is space for these
|
||||
* messages when an error occurs. One variation would be to allow these
|
||||
* to be dynamically allocated, but it is probably better to either preallocate
|
||||
* these or turn off all error message generation (which will eliminate these
|
||||
* arrays).
|
||||
*
|
||||
* One possible alternative is to use the message ring *only* for instance
|
||||
* messages and use the predefined messages in-place for the generic
|
||||
* messages. This approach is used to provide uniform handling of all
|
||||
* error messages.
|
||||
*/
|
||||
|
||||
#define MAX_LOCATION_LEN 63
|
||||
|
||||
/* The maximum error string in this case may be a multi-line message,
|
||||
constructed from multiple entries in the error message ring. The
|
||||
individual ring messages should be shorter than MPI_MAX_ERROR_STRING,
|
||||
perhaps as small a 256. We define a separate value for the error lines.
|
||||
*/
|
||||
#define MPIR_MAX_ERROR_LINE 512
|
||||
|
||||
/* See the description above for the fields in this structure */
|
||||
struct MPIR_Err_msg_t
|
||||
{
|
||||
int id;
|
||||
int prev_error;
|
||||
|
||||
int use_user_error_code;
|
||||
int user_error_code;
|
||||
|
||||
char location[MAX_LOCATION_LEN+1];
|
||||
char msg[MPIR_MAX_ERROR_LINE+1];
|
||||
};
|
||||
|
||||
static MPIR_Err_msg_t ErrorRing[128];
|
||||
static volatile long error_ring_loc = 0;
|
||||
|
||||
#define GET_RING_INDEX(code) \
|
||||
(ERROR_GET_INDEX(code) % _countof(ErrorRing))
|
||||
|
||||
static MPIR_Err_to_string_fn MPIR_Err_code_to_string;
|
||||
|
||||
void
|
||||
MPIR_Err_set_dynerr_fn(
|
||||
_In_ MPIR_Err_to_string_fn fn
|
||||
)
|
||||
{
|
||||
MPIU_Assert(MPIR_Err_code_to_string == nullptr);
|
||||
MPIR_Err_code_to_string = fn;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* The following block of code manages the instance-specific error messages */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#if DBG
|
||||
|
||||
static int
|
||||
ErrcodeIsValid(
|
||||
_In_ int errcode
|
||||
)
|
||||
{
|
||||
int idx;
|
||||
|
||||
/* If the errcode is a class, then it is valid */
|
||||
if (errcode >= 0 && errcode <= MPICH_ERR_LAST_CLASS)
|
||||
return TRUE;
|
||||
|
||||
/* check for extra bits set. note: dynamic error codes are not valid here */
|
||||
if((errcode & ~(ERROR_CLASS_MASK | ERROR_INDEX_MASK | ERROR_FATAL_FLAG)) != ERROR_COD_FLAG)
|
||||
return FALSE;
|
||||
|
||||
idx = GET_RING_INDEX(errcode);
|
||||
if (ErrorRing[idx].id != errcode)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif // DBG
|
||||
|
||||
|
||||
_Post_satisfies_( return != MPI_SUCCESS )
|
||||
int
|
||||
MPIR_Err_get_user_error_code(
|
||||
_In_ int errcode
|
||||
)
|
||||
{
|
||||
int idx;
|
||||
|
||||
/* check for class only error code */
|
||||
if(!ERROR_IS_CODE(errcode))
|
||||
return errcode;
|
||||
|
||||
/* Can we get a more specific error message */
|
||||
idx = GET_RING_INDEX(errcode);
|
||||
if (ErrorRing[idx].id == errcode && ErrorRing[idx].use_user_error_code)
|
||||
return ErrorRing[idx].user_error_code;
|
||||
|
||||
return errcode;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Given a message string abbreviation (e.g., one that starts "**"),
|
||||
* return the corresponding index.
|
||||
*/
|
||||
static int __cdecl
|
||||
compare_key_map(
|
||||
_In_ const void* pv1,
|
||||
_In_ const void* pv2
|
||||
)
|
||||
{
|
||||
const char* key = (const char*)pv1;
|
||||
const msgpair* pair = (const msgpair*)pv2;
|
||||
return strcmp( key, pair->key );
|
||||
}
|
||||
|
||||
static int
|
||||
FindMessageIndex(
|
||||
_In_z_ const char *msg
|
||||
)
|
||||
{
|
||||
const void* p;
|
||||
p = bsearch(
|
||||
msg,
|
||||
errors_map,
|
||||
_countof(errors_map),
|
||||
sizeof(errors_map[0]),
|
||||
compare_key_map
|
||||
);
|
||||
|
||||
MPIU_Assert(p != nullptr);
|
||||
|
||||
return (int)((const msgpair*)p - errors_map);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* The following routines create an MPI error code, handling optional, */
|
||||
/* instance-specific error message information. There are two key routines:*/
|
||||
/* MPIR_Err_create_code - Create the error code; this is the routine used*/
|
||||
/* by most routines */
|
||||
/* MPIR_Err_create_code_valist - Create the error code; accept a valist */
|
||||
/* instead of a variable argument list (this is */
|
||||
/* used to allow this routine to be used from */
|
||||
/* within another varargs routine) */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* --BEGIN ERROR MACROS-- */
|
||||
|
||||
_Post_satisfies_( return != MPI_SUCCESS )
|
||||
MPI_RESULT
|
||||
MPIR_Err_create_code(
|
||||
_In_ int lastcode,
|
||||
_In_ int fatal,
|
||||
_In_ int error_class,
|
||||
_Printf_format_string_ const char specific_msg[],
|
||||
...
|
||||
)
|
||||
{
|
||||
int rc;
|
||||
va_list Argp;
|
||||
va_start(Argp, specific_msg);
|
||||
__analysis_assert(error_class != 0);
|
||||
rc = MPIR_Err_create_code_valist(
|
||||
lastcode,
|
||||
fatal,
|
||||
error_class,
|
||||
specific_msg,
|
||||
Argp
|
||||
);
|
||||
|
||||
__analysis_assume(rc != 0);
|
||||
va_end(Argp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* --END ERROR MACROS-- */
|
||||
|
||||
static int
|
||||
TakeDump(
|
||||
_In_ EXCEPTION_POINTERS* exp,
|
||||
_In_ int dumpMode
|
||||
)
|
||||
{
|
||||
MINIDUMP_EXCEPTION_INFORMATION exrParam;
|
||||
exrParam.ExceptionPointers = exp;
|
||||
exrParam.ThreadId = GetCurrentThreadId();
|
||||
exrParam.ClientPointers = FALSE;
|
||||
|
||||
MINIDUMP_TYPE dumpType;
|
||||
if( dumpMode >= MsmpiDumpFull )
|
||||
{
|
||||
dumpType = MiniDumpWithFullMemory;
|
||||
}
|
||||
else
|
||||
{
|
||||
dumpType = MiniDumpNormal;
|
||||
}
|
||||
|
||||
wchar_t dumpPath[MAX_PATH];
|
||||
DWORD err = MPIU_Getenv( L"MSMPI_DUMP_PATH",
|
||||
dumpPath,
|
||||
_countof( dumpPath ) );
|
||||
if( err != NOERROR )
|
||||
{
|
||||
dumpPath[0] = '\0';
|
||||
}
|
||||
|
||||
HANDLE tempDumpFile = CreateTempDumpFile(
|
||||
GetCurrentProcess(),
|
||||
GetCurrentProcessId(),
|
||||
dumpType,
|
||||
dumpPath,
|
||||
&exrParam
|
||||
);
|
||||
|
||||
if( tempDumpFile != INVALID_HANDLE_VALUE )
|
||||
{
|
||||
CreateFinalDumpFile(
|
||||
tempDumpFile,
|
||||
env_to_int( L"PMI_RANK", -1, -1 ),
|
||||
dumpPath,
|
||||
env_to_int( L"CCP_JOBID", 0, 0 ),
|
||||
env_to_int( L"CCP_TASKID", 0, 0 ),
|
||||
env_to_int( L"CCP_TASKINSTANCEID", 0, 0 )
|
||||
);
|
||||
CloseHandle( tempDumpFile );
|
||||
}
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
|
||||
void CreateDumpFileIfConfigured(
|
||||
_In_ EXCEPTION_POINTERS* exp
|
||||
)
|
||||
{
|
||||
enum MSMPI_DUMP_MODE dumpMode = GetDumpMode();
|
||||
if (dumpMode != MsmpiDumpNone)
|
||||
{
|
||||
TakeDump(exp, dumpMode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This is the real routine for generating an error code. It takes
|
||||
* a va_list so that it can be called by any routine that accepts a
|
||||
* variable number of arguments.
|
||||
*/
|
||||
_Post_satisfies_( return != MPI_SUCCESS )
|
||||
MPI_RESULT
|
||||
MPIR_Err_create_code_valist(
|
||||
_In_ int lastcode,
|
||||
_In_ int fatal,
|
||||
_In_ int error_class,
|
||||
_Printf_format_string_ const char specific_msg[],
|
||||
_In_ va_list Argp
|
||||
)
|
||||
{
|
||||
int user_error_code = -1;
|
||||
int specific_idx;
|
||||
int ring_idx;
|
||||
long ring_idx_base;
|
||||
const char* specific_fmt;
|
||||
char* ring_msg;
|
||||
|
||||
/* Check that lastcode is valid */
|
||||
#if DBG
|
||||
MPIU_Assert(ErrcodeIsValid(lastcode));
|
||||
#endif //DBG
|
||||
MPIU_Assert(specific_msg != nullptr);
|
||||
|
||||
if( IsDebuggerPresent() )
|
||||
{
|
||||
DebugBreak();
|
||||
}
|
||||
|
||||
enum MSMPI_DUMP_MODE dumpMode = GetDumpMode();
|
||||
if( dumpMode != MsmpiDumpNone && lastcode == MPI_SUCCESS )
|
||||
{
|
||||
__try
|
||||
{
|
||||
RaiseException( 0, 0, 0, nullptr );
|
||||
}
|
||||
__except( TakeDump( GetExceptionInformation(), dumpMode ) )
|
||||
OACR_WARNING_SUPPRESS(EXCEPT_BLOCK_EMPTY,"mpicr: dump handler")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (error_class == MPI_ERR_OTHER)
|
||||
{
|
||||
if (ERROR_GET_CLASS(lastcode) != MPI_SUCCESS)
|
||||
{
|
||||
/* If the last class is more specific (and is valid), then pass it through */
|
||||
error_class = ERROR_GET_CLASS(lastcode);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle special case of MPI_ERR_IN_STATUS. According to the standard,
|
||||
the code must be equal to the class. See section 3.7.5.
|
||||
Information on the particular error is in the MPI_ERROR field
|
||||
of the status. */
|
||||
if (error_class == MPI_ERR_IN_STATUS)
|
||||
return MPI_ERR_IN_STATUS;
|
||||
|
||||
ring_idx_base = ::InterlockedIncrement(&error_ring_loc);
|
||||
|
||||
/* Get the next entry in the ring */
|
||||
ring_idx = ring_idx_base % _countof(ErrorRing);
|
||||
|
||||
ring_msg = ErrorRing[ring_idx].msg;
|
||||
|
||||
specific_idx = FindMessageIndex(specific_msg);
|
||||
specific_fmt = errors_map[specific_idx].fmt;
|
||||
|
||||
//
|
||||
// CompareString does not check for null terminating character
|
||||
// when length of string is given explicitly
|
||||
//
|
||||
int len = _countof("**user") - 1;
|
||||
if( MPIU_Strlen( errors_map[specific_idx].key ) >= static_cast<size_t>(len) &&
|
||||
CompareStringA( LOCALE_INVARIANT,
|
||||
0,
|
||||
errors_map[specific_idx].key,
|
||||
len,
|
||||
"**user",
|
||||
len ) == CSTR_EQUAL )
|
||||
{
|
||||
/* This is a special case. The format is ..., "**userxxx %d", intval);
|
||||
In this case we must save the user value because we store it explicitly in the ring.
|
||||
We do this here because we cannot both access the user error code and pass the argp
|
||||
to vsnprintf_mpi. */
|
||||
user_error_code = va_arg(Argp,int);
|
||||
ErrorRing[ring_idx].use_user_error_code = 1;
|
||||
ErrorRing[ring_idx].user_error_code = user_error_code;
|
||||
|
||||
// errors_map is generated by a perl script but since its test code isn't compiled
|
||||
// there is no opportunity to do specifier to type checking. Ideally, testerr.c would
|
||||
// be included in the project build so oacr could potentially find mismatches
|
||||
OACR_WARNING_SUPPRESS(PRINTF_FORMAT_STRING_PARAM_NEEDS_REVIEW, "format is determined at runtime");
|
||||
MPIU_Snprintf( ring_msg, MPIR_MAX_ERROR_LINE, specific_fmt, user_error_code );
|
||||
}
|
||||
else
|
||||
{
|
||||
OACR_WARNING_SUPPRESS(PRINTF_FORMAT_STRING_PARAM_NEEDS_REVIEW, "format is determined at runtime");
|
||||
MPIR_Err_vsnprintf_mpi( ring_msg, MPIR_MAX_ERROR_LINE, specific_fmt, Argp );
|
||||
|
||||
if (ERROR_IS_CODE(lastcode))
|
||||
{
|
||||
int last_ring_idx;
|
||||
|
||||
last_ring_idx = GET_RING_INDEX(lastcode);
|
||||
if (ErrorRing[last_ring_idx].id == lastcode)
|
||||
{
|
||||
if (ErrorRing[last_ring_idx].use_user_error_code)
|
||||
{
|
||||
ErrorRing[ring_idx].use_user_error_code = 1;
|
||||
ErrorRing[ring_idx].user_error_code = ErrorRing[last_ring_idx].user_error_code;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ring_msg[MPIR_MAX_ERROR_LINE] = '\0';
|
||||
|
||||
/* Set the previous code. */
|
||||
ErrorRing[ring_idx].prev_error = lastcode;
|
||||
ErrorRing[ring_idx].location[0] = '\0';
|
||||
|
||||
/* Make sure error_index doesn't get so large that it sets the dynamic bit. */
|
||||
int error_index = (ring_idx_base << ERROR_INDEX_SHIFT) & ERROR_INDEX_MASK;
|
||||
|
||||
int err_code = error_class | ERROR_COD_FLAG | error_index;
|
||||
if (fatal || ERROR_IS_FATAL(lastcode))
|
||||
{
|
||||
err_code |= ERROR_FATAL_FLAG;
|
||||
}
|
||||
|
||||
ErrorRing[ring_idx].id = err_code;
|
||||
__analysis_assume( err_code != MPI_SUCCESS );
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Accessor routines for the predefined messages. These can be
|
||||
* used by the other routines (such as MPI_Error_string) to
|
||||
* access the messages in this file, or the messages that may be
|
||||
* available through any message catalog facility
|
||||
*/
|
||||
C_ASSERT(_countof(class_to_index) == MPICH_ERR_LAST_CLASS + 1);
|
||||
|
||||
_Ret_z_
|
||||
static const char*
|
||||
get_class_msg(
|
||||
_In_ int error_class
|
||||
)
|
||||
{
|
||||
if (error_class >= 0 && error_class < _countof(class_to_index))
|
||||
{
|
||||
return errors_map[class_to_index[error_class]].fmt;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Unknown error class";
|
||||
}
|
||||
}
|
||||
|
||||
/* Given an error code, print the stack of messages corresponding to this
|
||||
error code. */
|
||||
static void
|
||||
MPIR_Err_print_stack_string(
|
||||
_In_ int errcode,
|
||||
_Out_writes_z_(maxlen) char *str,
|
||||
_In_ size_t maxlen
|
||||
)
|
||||
{
|
||||
size_t len;
|
||||
const char *str_orig = str;
|
||||
size_t max_location_len = 0;
|
||||
int tmp_errcode = errcode;
|
||||
int error_class;
|
||||
|
||||
/* make sure is not a dynamic error code or a simple error class */
|
||||
MPIU_Assert(!ERROR_IS_DYN(errcode));
|
||||
MPIU_Assert(ERROR_GET_CLASS(errcode) != errcode);
|
||||
MPIU_Assert(maxlen > 1);
|
||||
*str = '\0';
|
||||
|
||||
|
||||
/* Find the longest location string in the stack */
|
||||
while (ERROR_IS_CODE(tmp_errcode))
|
||||
{
|
||||
int ring_idx = GET_RING_INDEX(tmp_errcode);
|
||||
|
||||
if (ErrorRing[ring_idx].id != tmp_errcode)
|
||||
break;
|
||||
|
||||
len = MPIU_Strlen( ErrorRing[ring_idx].location,
|
||||
_countof(ErrorRing[ring_idx].location) );
|
||||
max_location_len = max(max_location_len, len);
|
||||
tmp_errcode = ErrorRing[ring_idx].prev_error;
|
||||
}
|
||||
|
||||
max_location_len += 2; /* add space for the ": " */
|
||||
|
||||
/* print the error stack */
|
||||
while (ERROR_IS_CODE(errcode))
|
||||
{
|
||||
size_t nchrs;
|
||||
|
||||
int ring_idx = GET_RING_INDEX(errcode);
|
||||
|
||||
if (ErrorRing[ring_idx].id != errcode)
|
||||
break;
|
||||
|
||||
len = MPIU_Snprintf(str, maxlen, "%s", ErrorRing[ring_idx].location);
|
||||
maxlen -= len;
|
||||
str += len;
|
||||
|
||||
nchrs = max_location_len -
|
||||
MPIU_Strlen( ErrorRing[ring_idx].location,
|
||||
_countof(ErrorRing[ring_idx].location) ) - 2;
|
||||
while (nchrs > 0 && maxlen > 0)
|
||||
{
|
||||
*str++ = '.';
|
||||
nchrs--;
|
||||
maxlen--;
|
||||
}
|
||||
|
||||
len = MPIU_Snprintf(str, maxlen, "%s\n", ErrorRing[ring_idx].msg);
|
||||
maxlen -= len;
|
||||
str += len;
|
||||
|
||||
errcode = ErrorRing[ring_idx].prev_error;
|
||||
}
|
||||
|
||||
/* FIXME: This is wrong. The only way that you can get here without
|
||||
errcode beign MPI_SUCCESS is if there is an error in the
|
||||
processing of the error codes. Dropping through into the next
|
||||
level of code (particularly when that code doesn't check for
|
||||
valid error codes!) is erroneous */
|
||||
if (errcode == MPI_SUCCESS)
|
||||
{
|
||||
goto fn_exit;
|
||||
}
|
||||
|
||||
error_class = ERROR_GET_CLASS(errcode);
|
||||
|
||||
if (error_class <= MPICH_ERR_LAST_CLASS)
|
||||
{
|
||||
len = MPIU_Snprintf(str, maxlen, "(unknown)(): %s\n", get_class_msg(error_class));
|
||||
maxlen -= len;
|
||||
str += len;
|
||||
}
|
||||
else
|
||||
{
|
||||
len = MPIU_Snprintf(str, maxlen,
|
||||
"Error code contains an invalid class (%d)\n",
|
||||
error_class);
|
||||
maxlen -= len;
|
||||
str += len;
|
||||
}
|
||||
|
||||
fn_exit:
|
||||
if (str_orig != str)
|
||||
{
|
||||
str--;
|
||||
*str = '\0'; /* erase the last \n */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MPIR_Err_get_string(
|
||||
_In_ int errorcode,
|
||||
_Out_writes_z_(length) char * msg,
|
||||
_In_ size_t length
|
||||
)
|
||||
{
|
||||
size_t len;
|
||||
size_t num_remaining = length;
|
||||
|
||||
MPIU_Assert(num_remaining > 0);
|
||||
|
||||
/* Convert the code to a string. The cases are:
|
||||
simple class. Find the corresponding string.
|
||||
<not done>
|
||||
if (user code)
|
||||
{
|
||||
go to code that extracts user error messages
|
||||
}
|
||||
else
|
||||
{
|
||||
is specific message code set and available? if so, use it
|
||||
else use generic code (lookup index in table of messages)
|
||||
}
|
||||
*/
|
||||
if (ERROR_IS_DYN(errorcode))
|
||||
{
|
||||
/* This is a dynamically created error code (e.g., with MPI_Err_add_class) */
|
||||
|
||||
/* If a dynamic error code was created, the function to convert
|
||||
them into strings has been set. Check to see that it was; this
|
||||
is a safeguard against a bogus error code */
|
||||
const char* s = nullptr;
|
||||
if (MPIR_Err_code_to_string)
|
||||
{
|
||||
/* FIXME: not internationalized */
|
||||
s = MPIR_Err_code_to_string(errorcode);
|
||||
if(s != nullptr)
|
||||
{
|
||||
MPIU_Strncpy(msg, s, num_remaining);
|
||||
}
|
||||
}
|
||||
|
||||
if(s == nullptr)
|
||||
{
|
||||
len = MPIU_Snprintf(msg, num_remaining, "Undefined dynamic error code (%d)", errorcode);
|
||||
msg[num_remaining-1] = '\0';
|
||||
}
|
||||
}
|
||||
else if (ERROR_GET_CLASS(errorcode) == errorcode)
|
||||
{
|
||||
MPIU_Strncpy(msg, get_class_msg( errorcode ), num_remaining);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* print the class message first */
|
||||
MPIU_Strncpy(msg, get_class_msg(ERROR_GET_CLASS(errorcode)), num_remaining);
|
||||
|
||||
msg[num_remaining - 1] = '\0';
|
||||
len = MPIU_Strlen( msg, num_remaining );
|
||||
msg += len;
|
||||
num_remaining -= len;
|
||||
|
||||
/* then print the stack or the last specific error message */
|
||||
MPIU_Strncpy(msg, ", error stack:\n", num_remaining);
|
||||
len = MPIU_Strlen( msg, num_remaining );
|
||||
msg += len;
|
||||
num_remaining -= len;
|
||||
MPIR_Err_print_stack_string(errorcode, msg, num_remaining);
|
||||
}
|
||||
}
|
||||
|
||||
_Ret_z_
|
||||
const char*
|
||||
get_error_string(
|
||||
_In_ int error
|
||||
)
|
||||
{
|
||||
wchar_t* wmsg;
|
||||
static char msg[1024];
|
||||
|
||||
int n;
|
||||
OACR_REVIEWED_CALL(
|
||||
mpicr,
|
||||
n = FormatMessageW(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS |
|
||||
FORMAT_MESSAGE_MAX_WIDTH_MASK, // dwFlags
|
||||
nullptr, // lpSource
|
||||
error, // dwMessageId,
|
||||
0, // dwLanguageId
|
||||
reinterpret_cast<LPWSTR>(&wmsg),// lpBuffer
|
||||
0, // nSize
|
||||
nullptr )); // Arguments
|
||||
|
||||
if( n != 0 )
|
||||
{
|
||||
n = WideCharToMultiByte(
|
||||
CP_UTF8,
|
||||
0,
|
||||
wmsg,
|
||||
-1,
|
||||
msg,
|
||||
sizeof(msg),
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
LocalFree( wmsg );
|
||||
}
|
||||
if( n == 0 )
|
||||
{
|
||||
msg[0] = '\0';
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Traces the MPI Error string and error class for the specified
|
||||
// mpi error code.
|
||||
//
|
||||
ULONG MpiTraceError(
|
||||
REGHANDLE RegHandle,
|
||||
PCEVENT_DESCRIPTOR Descriptor,
|
||||
int ErrorCode
|
||||
)
|
||||
{
|
||||
const ULONG EventDataCount = 2;
|
||||
EVENT_DATA_DESCRIPTOR EventData[ EventDataCount ];
|
||||
char message[ MPI_MAX_ERROR_STRING ];
|
||||
int error_class;
|
||||
|
||||
//make sure the string starts null terminated.
|
||||
message[0] = 0;
|
||||
|
||||
//
|
||||
// Get the error class
|
||||
//
|
||||
error_class = ERROR_GET_CLASS(ErrorCode);
|
||||
|
||||
MPIR_Err_get_string( ErrorCode, message, MPI_MAX_ERROR_STRING);
|
||||
|
||||
EventDataDescCreate(&EventData[0], &error_class, sizeof(error_class) );
|
||||
EventDataDescCreate(&EventData[1], message, (ULONG)strlen(message) + sizeof('\0') );
|
||||
|
||||
return EventWrite(RegHandle, Descriptor, EventDataCount, EventData);
|
||||
}
|
|
@ -0,0 +1,307 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
* Copyright (C) 1997 University of Chicago.
|
||||
* See COPYRIGHT notice in top-level directory.
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
#include "ex.h"
|
||||
#include <oacr.h>
|
||||
|
||||
_Success_(return==NO_ERROR)
|
||||
static
|
||||
int
|
||||
WINAPI
|
||||
ExpKeyZeroCompletionProcessor(
|
||||
_In_opt_ DWORD BytesTransfered,
|
||||
_In_ PVOID pOverlapped
|
||||
);
|
||||
|
||||
|
||||
#ifdef EXSINGLETONE
|
||||
//
|
||||
// The only completion port, supporting all events
|
||||
//
|
||||
static HANDLE s_port;
|
||||
#endif
|
||||
|
||||
//
|
||||
// The registered processors. This module supports up to 4 processors where
|
||||
// processor zero is pre-registered for overlapped operations completion.
|
||||
// the completion processor is registered by the completion key.
|
||||
//
|
||||
static ExCompletionProcessor s_processors[EX_KEY_MAX] = {
|
||||
|
||||
ExpKeyZeroCompletionProcessor,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr
|
||||
};
|
||||
|
||||
|
||||
static inline BOOL
|
||||
IsValidSet(
|
||||
_In_ ExSetHandle_t Set
|
||||
)
|
||||
{
|
||||
return (Set != nullptr && Set != INVALID_HANDLE_VALUE);
|
||||
}
|
||||
|
||||
_Success_(return != nullptr)
|
||||
_Ret_valid_
|
||||
ExSetHandle_t
|
||||
ExCreateSet(
|
||||
void
|
||||
)
|
||||
{
|
||||
ExSetHandle_t Set;
|
||||
Set = CreateIoCompletionPort(
|
||||
INVALID_HANDLE_VALUE, // FileHandle
|
||||
nullptr, // ExistingCompletionPort
|
||||
0, // CompletionKey
|
||||
MAXDWORD // NumberOfConcurrentThreads
|
||||
);
|
||||
|
||||
return Set;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ExCloseSet(
|
||||
_In_ _Post_invalid_ ExSetHandle_t Set
|
||||
)
|
||||
{
|
||||
MPIU_Assert(IsValidSet(Set));
|
||||
CloseHandle(Set);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ExRegisterCompletionProcessor(
|
||||
_In_ EX_PROCESSOR_KEYS Key,
|
||||
_In_ ExCompletionProcessor pfnCompletionProcessor
|
||||
)
|
||||
{
|
||||
MPIU_Assert(Key > 0);
|
||||
MPIU_Assert(Key < RTL_NUMBER_OF(s_processors));
|
||||
MPIU_Assert(s_processors[Key] == nullptr);
|
||||
s_processors[Key] = pfnCompletionProcessor;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ExUnregisterCompletionProcessor(
|
||||
_In_ EX_PROCESSOR_KEYS Key
|
||||
)
|
||||
{
|
||||
MPIU_Assert(Key > 0);
|
||||
MPIU_Assert(Key < RTL_NUMBER_OF(s_processors));
|
||||
MPIU_Assert(s_processors[Key] != nullptr);
|
||||
s_processors[Key] = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ExPostCompletion(
|
||||
_In_ ExSetHandle_t Set,
|
||||
_In_ EX_PROCESSOR_KEYS Key,
|
||||
_Inout_opt_ PVOID pOverlapped,
|
||||
_In_ DWORD BytesTransfered
|
||||
)
|
||||
{
|
||||
MPIU_Assert(IsValidSet(Set));
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if(PostQueuedCompletionStatus(Set, BytesTransfered, Key, (OVERLAPPED*)pOverlapped))
|
||||
return;
|
||||
|
||||
MPIU_Assert(GetLastError() == ERROR_NO_SYSTEM_RESOURCES);
|
||||
Sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ULONG
|
||||
ExGetPortValue(
|
||||
_In_ ExSetHandle_t Set
|
||||
)
|
||||
{
|
||||
MPIU_Assert(IsValidSet(Set));
|
||||
return HandleToUlong(Set);
|
||||
}
|
||||
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int
|
||||
ExInitialize(
|
||||
void
|
||||
)
|
||||
{
|
||||
#ifdef EXSINGLETONE
|
||||
MPIU_Assert(s_port == nullptr);
|
||||
s_port = CreateIoCompletionPort(
|
||||
INVALID_HANDLE_VALUE, // FileHandle
|
||||
nullptr, // ExistingCompletionPort
|
||||
0, // CompletionKey
|
||||
0 // NumberOfConcurrentThreads
|
||||
);
|
||||
|
||||
if(s_port != nullptr)
|
||||
return MPI_SUCCESS;
|
||||
|
||||
return MPI_ERR_INTERN;
|
||||
#endif
|
||||
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ExFinalize(
|
||||
void
|
||||
)
|
||||
{
|
||||
#ifdef EXSINGLETONE
|
||||
MPIU_Assert(s_port != nullptr);
|
||||
CloseHandle(s_port);
|
||||
s_port = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
_Success_(return==MPI_SUCCESS || return==MPI_ERR_PENDING)
|
||||
int
|
||||
ExProcessCompletions(
|
||||
_In_ ExSetHandle_t set,
|
||||
_In_ DWORD timeout,
|
||||
_In_opt_ bool interruptible
|
||||
)
|
||||
{
|
||||
MPIU_Assert(IsValidSet(set));
|
||||
|
||||
BOOL fSucc;
|
||||
DWORD bytesTransfered;
|
||||
ULONG_PTR key;
|
||||
OVERLAPPED* pOverlapped;
|
||||
for (;;)
|
||||
{
|
||||
fSucc = GetQueuedCompletionStatus(
|
||||
set,
|
||||
&bytesTransfered,
|
||||
&key,
|
||||
&pOverlapped,
|
||||
timeout
|
||||
);
|
||||
|
||||
if(!fSucc && pOverlapped == nullptr)
|
||||
{
|
||||
//
|
||||
// Return success on timeout per caller request. The Executive progress
|
||||
// engine will not wait for the async processing to complete
|
||||
//
|
||||
DWORD gle = GetLastError();
|
||||
if (gle == WAIT_TIMEOUT)
|
||||
{
|
||||
if( timeout == 0 )
|
||||
{
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
return HRESULT_FROM_WIN32(WAIT_TIMEOUT);
|
||||
}
|
||||
|
||||
//
|
||||
// Io Completion port internal error, try again
|
||||
//
|
||||
continue;
|
||||
}
|
||||
|
||||
if( key == EX_KEY_WAIT_INTERRUPT )
|
||||
{
|
||||
if( interruptible == false )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return MPI_ERR_PENDING;
|
||||
}
|
||||
|
||||
MPIU_Assert(key < RTL_NUMBER_OF(s_processors));
|
||||
MPIU_Assert(s_processors[key] != nullptr);
|
||||
|
||||
//
|
||||
// Call the completion processor and return the result.
|
||||
//
|
||||
return s_processors[key](bytesTransfered, pOverlapped);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Preregistered completion processor for Key-Zero
|
||||
//
|
||||
|
||||
_Success_(return==NO_ERROR)
|
||||
static
|
||||
int
|
||||
WINAPI
|
||||
ExpKeyZeroCompletionProcessor(
|
||||
_In_opt_ DWORD /*BytesTransfered*/,
|
||||
_In_ PVOID pOverlapped
|
||||
)
|
||||
{
|
||||
EXOVERLAPPED* pov = CONTAINING_RECORD(pOverlapped, EXOVERLAPPED, ov);
|
||||
return ExCompleteOverlapped(pov);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ExPostOverlapped(
|
||||
_In_ ExSetHandle_t Set,
|
||||
_Inout_ EXOVERLAPPED* pOverlapped
|
||||
)
|
||||
{
|
||||
MPIU_Assert(IsValidSet(Set));
|
||||
|
||||
ExPostCompletion(
|
||||
Set,
|
||||
EX_KEY_RESERVED, // Key,
|
||||
&pOverlapped->ov,
|
||||
0 // BytesTransfered
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ExAttachHandle(
|
||||
_In_ ExSetHandle_t Set,
|
||||
_In_ HANDLE Handle,
|
||||
_In_opt_ EX_PROCESSOR_KEYS Key
|
||||
)
|
||||
{
|
||||
MPIU_Assert(IsValidSet(Set));
|
||||
MPIU_Assert(s_processors[Key] != nullptr);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
HANDLE hPort;
|
||||
hPort = CreateIoCompletionPort(
|
||||
Handle, // FileHandle
|
||||
Set, // ExistingCompletionPort
|
||||
Key, // CompletionKey
|
||||
0 // NumberOfConcurrentThreads
|
||||
);
|
||||
|
||||
if(hPort != nullptr)
|
||||
{
|
||||
MPIU_Assert(hPort == Set);
|
||||
return;
|
||||
}
|
||||
|
||||
MPIU_Assert(GetLastError() == ERROR_NO_SYSTEM_RESOURCES);
|
||||
Sleep(10);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,461 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* (C) 2001 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
#ifndef EX_H
|
||||
#define EX_H
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// The Executive, a generic progress engine
|
||||
//
|
||||
// Overview:
|
||||
// The generic progress engine, the Executive, implements a simple asynchronous
|
||||
// processing model. In this model records indicating events get queued up for
|
||||
// processing. The Executive invokes the appropriate registered handler for the
|
||||
// event to take further action if required. The executive exits when a sequence
|
||||
// of events, representing a complete logical function is complete.
|
||||
//
|
||||
// This model is a producers-consumers model with a single events queue. The
|
||||
// events are being processed in the order they have been queued.
|
||||
// *** temporary extended to support multiple queues until the clients can ***
|
||||
// *** use a single event queue. (e.g., PMI client implementation) ***
|
||||
//
|
||||
// The function ExProcessCompletions is the heart of the consumers model. It
|
||||
// dequeues the events records and invokes the appropriate completion processor.
|
||||
// Multiple threads can call this function for processing. The Executive will
|
||||
// run as many concurrent threads as there are processors in the system. When
|
||||
// concurrent threads are running, the completion processors should be able to
|
||||
// handle the concurrency and out-of-order execution.
|
||||
//
|
||||
// The Executive pre-registers a completion processor for Key-Zero with a simple
|
||||
// handler signature. see description below.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
//
|
||||
// ExSetHandle_t *** temp extenssion ***
|
||||
//
|
||||
// Represents the set object
|
||||
//
|
||||
typedef HANDLE ExSetHandle_t;
|
||||
#define EX_INVALID_SET nullptr
|
||||
|
||||
//to get NTSTATUS
|
||||
#include <winternl.h>
|
||||
|
||||
|
||||
//
|
||||
// ExCreateSet *** temp extenssion ***
|
||||
//
|
||||
// Create the set object.
|
||||
// An EX_INVALID_SET value is returned for an out of memory condition.
|
||||
//
|
||||
_Success_(return != nullptr)
|
||||
_Ret_valid_
|
||||
ExSetHandle_t
|
||||
ExCreateSet(
|
||||
void
|
||||
);
|
||||
|
||||
//
|
||||
// ExCloseSet *** temp extenssion ***
|
||||
//
|
||||
// Close the set object.
|
||||
//
|
||||
void
|
||||
ExCloseSet(
|
||||
_In_ _Post_invalid_ ExSetHandle_t Set
|
||||
);
|
||||
|
||||
//
|
||||
// ExCompletionProcessor, function prototype
|
||||
//
|
||||
// The completion processor function is called by ExProcessCompletions function
|
||||
// to process a completion event. The completion processor indicates whether the
|
||||
// sequence of asynchronous events is complete or whether further processing is
|
||||
// required.
|
||||
//
|
||||
// Parameters:
|
||||
// BytesTransferred
|
||||
// A DWORD value posted to the completion port. Usually the number of bytes
|
||||
// transferred in this operation
|
||||
//
|
||||
// pOverlapped
|
||||
// A pointer value posted to the completion port. Usually a pointer to the
|
||||
// OVERLAPPED structure
|
||||
//
|
||||
// Return Value:
|
||||
// MPI error value indicating the result of the "logical" async function.
|
||||
// This value is meaningful only when the completion processor returns TRUE.
|
||||
//
|
||||
typedef
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int
|
||||
(WINAPI * ExCompletionProcessor)(
|
||||
DWORD BytesTransferred,
|
||||
PVOID pOverlapped
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Key values used when calling ExRegisterCompletionProcessor.
|
||||
//
|
||||
enum EX_PROCESSOR_KEYS
|
||||
{
|
||||
EX_KEY_WAIT_INTERRUPT = -1,
|
||||
EX_KEY_RESERVED = 0,
|
||||
EX_KEY_SHM_NOTIFY_CONNECTION,
|
||||
EX_KEY_SHM_NOTIFY_MESSAGE,
|
||||
EX_KEY_PROGRESS_WAKEUP,
|
||||
EX_KEY_ND,
|
||||
EX_KEY_CONNECT_REQUEST,
|
||||
EX_KEY_CONNECT_COMPLETE,
|
||||
EX_KEY_DEFER_CONNECT,
|
||||
EX_KEY_DEFER_WRITE,
|
||||
EX_KEY_MAX
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// ExRegisterCompletionProcessor
|
||||
//
|
||||
// Resister a completion processor for a specific Key.
|
||||
// N.B. Current implementation supports keys 0 - 3, where key 0 is reserved.
|
||||
//
|
||||
void
|
||||
ExRegisterCompletionProcessor(
|
||||
_In_ EX_PROCESSOR_KEYS Key,
|
||||
_In_ ExCompletionProcessor pfnCompletionProcessor
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// ExUnregisterCompletionProcessor
|
||||
//
|
||||
// Remove a registered completion processor
|
||||
//
|
||||
void
|
||||
ExUnregisterCompletionProcessor(
|
||||
_In_ EX_PROCESSOR_KEYS Key
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// ExPostCompletion
|
||||
//
|
||||
// Post an event completion to the completion queue. The appropriate
|
||||
// completion processor will be invoked by ExProcessCompletions thread
|
||||
// with the passed in parameters.
|
||||
//
|
||||
void
|
||||
ExPostCompletion(
|
||||
_In_ ExSetHandle_t Set,
|
||||
_In_ EX_PROCESSOR_KEYS Key,
|
||||
_Inout_opt_ PVOID pOverlapped,
|
||||
_In_ DWORD BytesTransferred
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// ExGetPortValue
|
||||
//
|
||||
// Returns the value of the completion queue handle
|
||||
//
|
||||
ULONG
|
||||
ExGetPortValue(
|
||||
_In_ ExSetHandle_t Set
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// ExProcessCompletions
|
||||
//
|
||||
// Process all completion event types by invoking the appropriate completion
|
||||
// processor function. This routine continues to process all events until an
|
||||
// asynchronous sequence is complete (function with several async stages).
|
||||
// If the caller indicated "no blocking" this routine will exit when no more
|
||||
// events to process are available, regardles of the completion processor
|
||||
// indication to continue.
|
||||
//
|
||||
// Parameters:
|
||||
// timeout - Milliseconds to wait for an event sequence to complete
|
||||
// interruptible - flag indicating whether the wait can be interrupted
|
||||
//
|
||||
// Return Value:
|
||||
// The result of the asynchronous function last to complete.
|
||||
// Returns MPI_ERR_PENDING if the wait was interrupted.
|
||||
// Returns MPI_SUCCESS if the wait timed out.
|
||||
//
|
||||
_Success_(return==MPI_SUCCESS || return==MPI_ERR_PENDING)
|
||||
int
|
||||
ExProcessCompletions(
|
||||
_In_ ExSetHandle_t set,
|
||||
_In_ DWORD timeout,
|
||||
_In_opt_ bool interruptible = false
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// ExInitialize
|
||||
//
|
||||
// Initialize the completion queue. This function can only be called once before
|
||||
// before Finialize.
|
||||
//
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int
|
||||
ExInitialize(
|
||||
void
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// ExFinitialize
|
||||
//
|
||||
// Close the completion queue progress engine. This function can only be called
|
||||
// once.
|
||||
//
|
||||
void
|
||||
ExFinalize(
|
||||
void
|
||||
);
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// The Executive Key-Zero completion processor
|
||||
//
|
||||
// Overview:
|
||||
// The Key-Zero completion processor enables the users of the Executive to
|
||||
// associate a different completion routine with each operation rather than
|
||||
// use a single completion processor per handle. The Key-Zero processor works
|
||||
// with user supplied OVERLAPPED structure. It cannot work with system generated
|
||||
// completion events (e.g., Job Object enets), or other external events.
|
||||
//
|
||||
// The Key-Zero processor uses the EXOVERLAPPED data structure which embeds the
|
||||
// user success and failure completion routines. When the Key-Zero completion
|
||||
// processor is invoked it calls the user success or failure routine base on
|
||||
// the result of the async operation.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// ExCompletionRoutine function prototype
|
||||
//
|
||||
// The ExCompletionRoutine callback routine is invoked by the built-in Key-Zero
|
||||
// completion processor. The information required for processing the event is
|
||||
// packed with the EXOVERLAPED structure and can be accessed with the Ex utility
|
||||
// functions. The callback routine returns the logical error value.
|
||||
//
|
||||
// Parameters:
|
||||
// pOverlapped
|
||||
// A pointer to an EXOVERLAPPED structure associated with the completed
|
||||
// operation. This pointer is used to extract the caller context with the
|
||||
// CONTAINING_RECORD macro.
|
||||
//
|
||||
// Return Value:
|
||||
// MPI error value indicating the result of the "logical" async function.
|
||||
//
|
||||
struct EXOVERLAPPED;
|
||||
|
||||
typedef
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int
|
||||
(WINAPI * ExCompletionRoutine)(
|
||||
_Inout_ struct EXOVERLAPPED* pOverlapped
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// struct EXOVERLAPPED
|
||||
//
|
||||
// The data structure used for Key-Zero completions processing. The pfnSuccess
|
||||
// and pfnFailure are set by the caller before calling an async operation.
|
||||
// The pfnSuccess is called if the async operation was successful.
|
||||
// The pfnFailure is called if the async operation was unsuccessful.
|
||||
//
|
||||
struct EXOVERLAPPED
|
||||
{
|
||||
|
||||
OVERLAPPED ov;
|
||||
ExCompletionRoutine pfnSuccess;
|
||||
ExCompletionRoutine pfnFailure;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// ExInitOverlapped
|
||||
//
|
||||
// Initialize the success & failure callback function fields
|
||||
// Rest the hEvent field of the OVERLAPPED, make it ready for use with the OS
|
||||
// overlapped API's.
|
||||
//
|
||||
static
|
||||
inline
|
||||
void
|
||||
ExInitOverlapped(
|
||||
_Inout_ EXOVERLAPPED* pOverlapped,
|
||||
_In_ ExCompletionRoutine pfnSuccess,
|
||||
_In_ ExCompletionRoutine pfnFailure
|
||||
)
|
||||
{
|
||||
pOverlapped->ov.hEvent = nullptr;
|
||||
pOverlapped->pfnSuccess = pfnSuccess;
|
||||
pOverlapped->pfnFailure = pfnFailure;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// ExPostOverlapped
|
||||
//
|
||||
// Post an EXOVERLAPPED completion to the completion queue to be invoked by
|
||||
// ExProcessCompletions.
|
||||
//
|
||||
void
|
||||
ExPostOverlapped(
|
||||
_In_ ExSetHandle_t Set,
|
||||
_Inout_ EXOVERLAPPED* pOverlapped
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// ExPostOverlappedResult
|
||||
//
|
||||
// Post an EXOVERLAPPED completion to the completion queue to be invoked by
|
||||
// ExProcessCompletions. Set the status and bytes transferred count.
|
||||
//
|
||||
static
|
||||
inline
|
||||
void
|
||||
ExPostOverlappedResult(
|
||||
_In_ ExSetHandle_t Set,
|
||||
_Inout_ EXOVERLAPPED* pOverlapped,
|
||||
_In_ HRESULT Status,
|
||||
_In_ DWORD BytesTransferred
|
||||
)
|
||||
{
|
||||
pOverlapped->ov.Internal = Status;
|
||||
pOverlapped->ov.InternalHigh = BytesTransferred;
|
||||
ExPostOverlapped(Set, pOverlapped);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// ExAttachHandle
|
||||
//
|
||||
// Associate an OS handle with the Executive completion queue. All asynchronous
|
||||
// operations using the attached handle are processed with the completion
|
||||
// processor associated with the provided Key. If no key value is specified,
|
||||
// the Key-Zero completion processor is used. Key-Zero completion processor
|
||||
// requires the use of EXOVERLAPPED data structure when calling an asynchronous
|
||||
// operation with that Handle.
|
||||
//
|
||||
void
|
||||
ExAttachHandle(
|
||||
_In_ ExSetHandle_t Set,
|
||||
_In_ HANDLE Handle,
|
||||
_In_opt_ EX_PROCESSOR_KEYS Key = EX_KEY_RESERVED
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// ExGetBytesTransferred
|
||||
//
|
||||
// Get the number of bytes transferred from the overlapped structure
|
||||
//
|
||||
static
|
||||
inline
|
||||
DWORD
|
||||
ExGetBytesTransferred(
|
||||
_In_ const EXOVERLAPPED* pOverlapped
|
||||
)
|
||||
{
|
||||
return (DWORD)pOverlapped->ov.InternalHigh;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// ExGetStatus
|
||||
//
|
||||
// Get the status return value from the overlapped structure
|
||||
//
|
||||
static
|
||||
inline
|
||||
NTSTATUS
|
||||
ExGetStatus(
|
||||
_In_ const EXOVERLAPPED* pOverlapped
|
||||
)
|
||||
{
|
||||
return (NTSTATUS)pOverlapped->ov.Internal;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// ExCallSuccess
|
||||
//
|
||||
// Set the completion status and bytes transferred and execute the EXOVERLAPPED
|
||||
// Success completion routine
|
||||
//
|
||||
static
|
||||
inline
|
||||
int
|
||||
ExCallSuccess(
|
||||
_Inout_ EXOVERLAPPED* pOverlapped,
|
||||
_In_ HRESULT Status,
|
||||
_In_ DWORD BytesTransferred
|
||||
)
|
||||
{
|
||||
pOverlapped->ov.Internal = Status;
|
||||
pOverlapped->ov.InternalHigh = BytesTransferred;
|
||||
return pOverlapped->pfnSuccess(pOverlapped);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// ExCallFailure
|
||||
//
|
||||
// Set the completion status and bytes transferred and execute the EXOVERLAPPED
|
||||
// Failure completion routine
|
||||
//
|
||||
static
|
||||
inline
|
||||
int
|
||||
ExCallFailure(
|
||||
_Inout_ EXOVERLAPPED* pOverlapped,
|
||||
_In_ HRESULT Status,
|
||||
_In_ DWORD BytesTransferred
|
||||
)
|
||||
{
|
||||
pOverlapped->ov.Internal = Status;
|
||||
pOverlapped->ov.InternalHigh = BytesTransferred;
|
||||
return pOverlapped->pfnFailure(pOverlapped);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// ExCompleteOverlapped
|
||||
//
|
||||
// Execute the EXOVERLAPPED success or failure completion routine based
|
||||
// on the overlapped status value.
|
||||
//
|
||||
static
|
||||
inline
|
||||
int
|
||||
ExCompleteOverlapped(
|
||||
_Inout_ EXOVERLAPPED* pOverlapped
|
||||
)
|
||||
{
|
||||
if(SUCCEEDED(ExGetStatus(pOverlapped)))
|
||||
return pOverlapped->pfnSuccess(pOverlapped);
|
||||
|
||||
return pOverlapped->pfnFailure(pOverlapped);
|
||||
}
|
||||
|
||||
#endif /* EX_H */
|
|
@ -0,0 +1,799 @@
|
|||
#! /usr/bin/perl
|
||||
# (Tested with -w; 10/5/04)
|
||||
#
|
||||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License.
|
||||
#
|
||||
# Find the parse.sub routine.
|
||||
my $maintdir = "maint";
|
||||
my $rootdir = ".";
|
||||
if ( ! -s "maint/parse.sub" ) {
|
||||
my $program = $0;
|
||||
$program =~ s/extracterrmsgs//;
|
||||
if (-s "$program/parse.sub") {
|
||||
$maintdir = $program;
|
||||
$rootdir = $program;
|
||||
$rootdir =~ s/\/maint\///g;
|
||||
$rootdir =~ s/\\maint\\//g;
|
||||
print "Rootdir = $rootdir\n" if $debug;
|
||||
}
|
||||
}
|
||||
require "$maintdir/parse.sub";
|
||||
|
||||
$debug = 0;
|
||||
$careful = 0; # Set careful to 1 to flag unused messages
|
||||
$carefulFilename = "";
|
||||
$showfiles = 0;
|
||||
$quiet = 0;
|
||||
$build_test_pgm = 1;
|
||||
|
||||
# Strict is used to control checking of error message strings.
|
||||
$gStrict = 0;
|
||||
if (defined($ENV{"DEBUG_STRICT"})) { $gStrict = 1; }
|
||||
|
||||
# Check for special args
|
||||
@files = ();
|
||||
%skipFiles = ();
|
||||
$outfile = "";
|
||||
$testfile = "errtest.c";
|
||||
$outpath = ".";
|
||||
$srcroot = $rootdir;
|
||||
|
||||
foreach $arg (@ARGV) {
|
||||
if ($arg =~ /^-showfiles/) { $showfiles = 1; }
|
||||
elsif( $arg =~ /-debug/) { $debug = 1; }
|
||||
elsif( $arg =~ /-quiet/) { $quiet = 1; }
|
||||
elsif( $arg =~ /-notest/) { $build_test_pgm = 0; }
|
||||
elsif( $arg =~ /-outfile=(.*)/) { $outfile = $1; }
|
||||
elsif( $arg =~ /-outpath=(.*)/) { $outpath = $1; }
|
||||
elsif( $arg =~ /-testfile=(.*)/) { $testfile = $1; }
|
||||
elsif( $arg =~ /-srcroot=(.*)/) { $srcroot = $1; }
|
||||
elsif( $arg =~ /-careful=(.*)/) {
|
||||
$careful = 1;
|
||||
$carefulFilename = $1;
|
||||
}
|
||||
elsif( $arg =~ /-careful/) { $careful = 1; }
|
||||
elsif( $arg =~ /-strict/) { $gStrict = 1; }
|
||||
elsif( $arg =~ /-skip=(.*)/) { $skipFiles{$1} = 1; }
|
||||
else {
|
||||
print "Adding $arg to files\n" if $debug;
|
||||
if (-d $arg) {
|
||||
# Add all .c files from directory $arg to the list of files
|
||||
# to process (this lets us shorten the arg list)
|
||||
@files = (@files, &ExpandDir( $arg ));
|
||||
}
|
||||
else {
|
||||
$files[$#files+1] = $arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
# End of argument processing
|
||||
|
||||
|
||||
# Setup the basic file for errnames - Now determined in ExpandDirs
|
||||
#@errnameFiles = ( "$srcroot/errnames.txt" );
|
||||
|
||||
if ($outfile ne "") {
|
||||
print STDOUT "Creating out file $outpath\\$outfile\n";
|
||||
$OUTFD = "MyOutFile";
|
||||
open( $OUTFD, ">$outpath\\$outfile" ) or die "Could not open $outpath\\$outfile\n";
|
||||
}
|
||||
else {
|
||||
$OUTFD = STDOUT;
|
||||
}
|
||||
# Setup before processing the files
|
||||
if ($build_test_pgm) {
|
||||
print STDOUT "Creating test file $outpath\\$testfile\n";
|
||||
open( TESTFD, ">$outpath\\$testfile" ) or die "Cannot create test program $outpath\\$testfile\n";
|
||||
print TESTFD "/* -*- Mode: C++; c-basic-offset:4 ; -*- */\
|
||||
/* \
|
||||
* (C) 2004 by Argonne National Laboratory.\
|
||||
* See COPYRIGHT in top-level directory.\
|
||||
*\
|
||||
* This file is automatically generated by maint/extracterrmsgs\
|
||||
* DO NOT EDIT\
|
||||
*/\n";
|
||||
print TESTFD "
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <oacr.h>
|
||||
#include <windows.h>
|
||||
#include \"mpi.h\"
|
||||
#include \"mpierror.h\"
|
||||
#include \"errcodes.h\"
|
||||
|
||||
#pragma warning(disable:4100) // unreferenced formal parameter
|
||||
|
||||
void MPID_Type_get_envelope(MPI_Datatype datatype, int* num_integers, int* num_addresses, int* num_datatypes, int* combiner)
|
||||
{
|
||||
*combiner = MPI_COMBINER_NAMED;
|
||||
}
|
||||
|
||||
typedef struct MPID_Comm MPID_Comm;
|
||||
|
||||
_Analysis_noreturn_
|
||||
int
|
||||
MPID_Abort(
|
||||
_Inout_opt_ MPID_Comm* comm,
|
||||
_In_ BOOL intern,
|
||||
_In_ int exit_code,
|
||||
_In_z_ const char* error_msg
|
||||
)
|
||||
{
|
||||
printf(\"MPID_Abort called. exit code (%d); msg '%s'\", exit_code, error_msg);
|
||||
exit(exit_code);
|
||||
}
|
||||
|
||||
_Success_(return>=0)
|
||||
int
|
||||
MPIU_Internal_error_printf(
|
||||
_In_z_ _Printf_format_string_params_(...) const char *str,
|
||||
...
|
||||
)
|
||||
{
|
||||
int n;
|
||||
va_list list;
|
||||
|
||||
va_start(list, str);
|
||||
n = vfprintf(stderr, str, list);
|
||||
va_end(list);
|
||||
|
||||
fflush(stderr);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void ChkMsg( int err, int msgclass, const char msg[] )
|
||||
{
|
||||
char errmsg[MPI_MAX_ERROR_STRING];
|
||||
|
||||
MPIR_Err_get_string( err, errmsg, MPI_MAX_ERROR_STRING );
|
||||
|
||||
printf( \"[0x%08x] [0x%08x] %2d %s\\n%s\\n\", err, MPIR_Err_get_user_error_code(err), msgclass, msg, errmsg );
|
||||
}
|
||||
\n\n";
|
||||
|
||||
print TESTFD "int __cdecl main(int argc, char **argv)\n";
|
||||
print TESTFD "{\n int err;\n\n";
|
||||
print TESTFD " printf(\"mpi_errno user_errno class error id string\\n\");\n";
|
||||
}
|
||||
|
||||
# Process the definitions
|
||||
foreach $file (@files) {
|
||||
print "$file\n" if $showfiles;
|
||||
&ProcessFile( $file );
|
||||
}
|
||||
|
||||
#
|
||||
# Create the hash %longnames that maps the short names to the long names,
|
||||
# $longnames{shortname} => longname, by reading the errnames.txt files
|
||||
foreach my $sourcefile (@errnameFiles) {
|
||||
#print STDERR "processing $sourcefile for error names\n";
|
||||
&ReadErrnamesFile( $sourcefile );
|
||||
}
|
||||
|
||||
# Create the output files from the input that we've read
|
||||
&CreateErrmsgsHeader( $OUTFD );
|
||||
&CreateErrMsgMapping( $OUTFD );
|
||||
|
||||
if ($build_test_pgm) {
|
||||
print TESTFD " printf(\"---------- end ----------\\n\");\n";
|
||||
print TESTFD "\n return 0;\n}\n";
|
||||
close TESTFD;
|
||||
}
|
||||
|
||||
#
|
||||
# Generate a list of unused keys
|
||||
if ($careful) {
|
||||
my $OUTFD = STDERR;
|
||||
if ($carefulFilename ne "") {
|
||||
$OUTFD = "ERRFD";
|
||||
open $OUTFD, ">$carefulFilename" or die "Cannot open $carefulFilename";
|
||||
}
|
||||
foreach $shortname (keys(%longnames)) {
|
||||
if (!defined($longnamesUsed{$shortname}) ||
|
||||
$longnamesUsed{$shortname} < 1) {
|
||||
$loc = $longnamesDefined{$shortname};
|
||||
print $OUTFD "Name $shortname is defined in $loc but never used\n";
|
||||
}
|
||||
}
|
||||
if ($carefulFilename ne "") {
|
||||
close $OUTFD;
|
||||
}
|
||||
}
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# ROUTINES
|
||||
# ----------------------------------------------------------------------------
|
||||
# From the data collected above, generate the file containing the error message
|
||||
# text.
|
||||
# This is a temporary routine; the exact output form will be defined later
|
||||
sub CreateErrmsgsHeader {
|
||||
$FD = $_[0];
|
||||
print $FD "/* -*- Mode: C; c-basic-offset:4 ; -*- */\
|
||||
/* \
|
||||
* (C) 2001 by Argonne National Laboratory.\
|
||||
* See COPYRIGHT in top-level directory.\
|
||||
*\
|
||||
* This file automatically created by extracterrmsgs\
|
||||
* DO NOT EDIT\
|
||||
*/\n";
|
||||
print $FD "typedef struct msgpair {\
|
||||
const char* key;
|
||||
const char* fmt;
|
||||
} msgpair;\n\n"
|
||||
}
|
||||
#
|
||||
# We also need a way to create the records
|
||||
# We then hash these on the first occurance (or precompute the hashes?)
|
||||
#
|
||||
# The error messages are output in the following form:
|
||||
# typedef struct {const char short[], const long[]} namemap;
|
||||
# Generic messages
|
||||
# static const char[] short1 = "";
|
||||
# static const char[] long1 = "";
|
||||
# ...
|
||||
# static const namemap[] = { {short1, long1}, {...} }
|
||||
#
|
||||
sub CreateErrMsgMapping {
|
||||
my $OUTFD = $_[0];
|
||||
|
||||
# Create a mapping of MPI error classes to the specific error
|
||||
# message by index into generic_err_msgs. This reads the file
|
||||
# baseerrnames, looks up the generic message, and maps the MPI error
|
||||
# class to the corresponding index.
|
||||
# We must do this here because we must ensure that all MPI error
|
||||
# classes have been added to the generic messages
|
||||
@class_msgs = ();
|
||||
open (FD, "<$srcroot/baseerrnames.txt" ) ||
|
||||
die "Could not open $srcroot/baseerrnames.txt\n";
|
||||
while (<FD>) {
|
||||
s/#.*$//;
|
||||
my ($mpiname,$num,$shortmsg) = split(/\s\s*/);
|
||||
if (!defined($shortmsg)) {
|
||||
# Incase there is no short message entry (!)
|
||||
$shortmsg = "";
|
||||
}
|
||||
if ($shortmsg ne "")
|
||||
{
|
||||
if ($shortmsg =~ /\%/)
|
||||
{
|
||||
print STDERR "$srcroot/baseerrnames.txt(1) : error : message $shortmsg in baseerrnames.txt contains format control\n";
|
||||
}
|
||||
|
||||
$specific_msgs{$shortmsg}++;
|
||||
$specific_loc{$shortmsg} = ":baseerrnames.txt(1)";
|
||||
|
||||
$class_msgs[$num] = "$shortmsg";
|
||||
}
|
||||
}
|
||||
close (FD);
|
||||
|
||||
$num = 0;
|
||||
# Now output the instance specific messages
|
||||
foreach $key (sort keys %specific_msgs)
|
||||
{
|
||||
$longvalue = "\"\0\"";
|
||||
|
||||
if (!defined($longnames{$key}))
|
||||
{
|
||||
print STDERR "$specific_loc{$key} : error : shortname $key for specific messages has no expansion\n";
|
||||
next;
|
||||
}
|
||||
else {
|
||||
# Keep track of which messages we have seen
|
||||
$longnamesUsed{$key} += 1;
|
||||
}
|
||||
|
||||
# Escape any naked quotes
|
||||
$longvalue =~ s/(?<!\\)\"/\\\"/;
|
||||
$longvalue = "\"" . $longnames{$key} . "\"";
|
||||
|
||||
print $OUTFD "extern const __declspec(selectany) char short_spc$num\[\] = \"$key\";\n";
|
||||
# print $OUTFD "static const char short_spc$num\[\] = $key;\n";
|
||||
print $OUTFD "extern const __declspec(selectany) char long_spc$num\[\] = $longvalue;\n";
|
||||
$short_to_num{$key} = $num;
|
||||
$num ++;
|
||||
}
|
||||
# Generate the mapping of short to long names
|
||||
|
||||
print $OUTFD "\n\nextern const __declspec(selectany) msgpair errors_map[] = {\n";
|
||||
for (my $i = 0; $i < $num ; $i ++) {
|
||||
print $OUTFD "{ short_spc$i, long_spc$i }";
|
||||
print $OUTFD "," if ($i < $num - 1);
|
||||
print $OUTFD "\n";
|
||||
}
|
||||
print $OUTFD "};\n\n";
|
||||
|
||||
print $OUTFD "extern const __declspec(selectany) int class_to_index[] = {\n";
|
||||
for (my $i=0; $i<=$#class_msgs; $i++) {
|
||||
print $OUTFD "$short_to_num{$class_msgs[$i]}";
|
||||
print $OUTFD "," if ($i < $#class_msgs);
|
||||
print $OUTFD "\n" if !(($i + 1) % 10);
|
||||
}
|
||||
print $OUTFD "};\n";
|
||||
}
|
||||
#
|
||||
# Add a call to test this message for the error message.
|
||||
# Handle both the generic and specific messages
|
||||
#
|
||||
sub AddTestCall {
|
||||
|
||||
my $genericArgLoc = $_[0];
|
||||
|
||||
my $last_errcode = "MPI_SUCCESS"; # $_[0];
|
||||
my $fatal_flag = "MPIR_ERR_RECOVERABLE"; # $_[1];
|
||||
my $fcname = "unknown"; # $_[2];
|
||||
my $linenum = "__LINE__"; # $_[3];
|
||||
my $errclass = "MPI_ERR_OTHER"; # $_[4];
|
||||
|
||||
my $specific_msg = $_[$genericArgLoc+1];
|
||||
if ($specific_msg =~ /(\".*\")/)
|
||||
{
|
||||
$specific_msg = $1;
|
||||
}
|
||||
|
||||
# Ensure that the last_errcode, class and fatal flag are specified. There are a few places where these are variables.
|
||||
if (!($last_errcode =~ /MPI_ERR_/) )
|
||||
{
|
||||
$last_errcode = "MPI_SUCCESS";
|
||||
}
|
||||
if (!($errclass =~ /MPI_ERR_/) )
|
||||
{
|
||||
$errclass = "MPI_ERR_OTHER";
|
||||
}
|
||||
if (!($fatal_flag =~ /MPIR_ERR_FATAL/) && !($fatal_flag =~ /MPIR_ERR_RECOVERABLE/))
|
||||
{
|
||||
$fatal_flag = "MPIR_ERR_FATAL";
|
||||
}
|
||||
|
||||
# Specific messages
|
||||
if (!defined($test_specific_msg{$specific_msg}))
|
||||
{
|
||||
$test_specific_msg{$specific_msg} = $filename;
|
||||
|
||||
print TESTFD " {\n";
|
||||
print TESTFD " /* $filename */\n";
|
||||
# Use types in the string to create the types with default
|
||||
# values
|
||||
my $format = $specific_msg;
|
||||
my $fullformat = $format;
|
||||
my $narg = 0;
|
||||
my @args = ();
|
||||
while ($format =~ /[^%]*%(.)(.*)/)
|
||||
{
|
||||
my $type = $1;
|
||||
$format = $2;
|
||||
$narg ++;
|
||||
if ($type eq "x")
|
||||
{
|
||||
print TESTFD " int i$narg = $narg;\n";
|
||||
$args[$#args+1] = "i$narg";
|
||||
}
|
||||
elsif ($type eq "d")
|
||||
{
|
||||
print TESTFD " int i$narg = $narg;\n";
|
||||
$args[$#args+1] = "i$narg";
|
||||
}
|
||||
elsif ($type eq "i")
|
||||
{
|
||||
print TESTFD " int i$narg = $narg;\n";
|
||||
$args[$#args+1] = "i$narg";
|
||||
}
|
||||
elsif ($type eq "t")
|
||||
{
|
||||
print TESTFD " int i$narg = $narg;\n";
|
||||
$args[$#args+1] = "i$narg";
|
||||
}
|
||||
elsif ($type eq "s")
|
||||
{
|
||||
print TESTFD " char s$narg\[\] = \"string$narg\";\n";
|
||||
$args[$#args+1] = "s$narg";
|
||||
}
|
||||
elsif ($type eq "p")
|
||||
{
|
||||
print TESTFD " char s$narg\[\] = \"pointer$narg\";\n";
|
||||
$args[$#args+1] = "s$narg";
|
||||
}
|
||||
elsif ($type eq "C")
|
||||
{
|
||||
print TESTFD " int i$narg = MPI_COMM_WORLD;\n";
|
||||
$args[$#args+1] = "i$narg";
|
||||
}
|
||||
elsif ($type eq "I")
|
||||
{
|
||||
print TESTFD " int i$narg = MPI_INFO_NULL;\n";
|
||||
$args[$#args+1] = "i$narg";
|
||||
}
|
||||
elsif ($type eq "D")
|
||||
{
|
||||
print TESTFD " int i$narg = MPI_INT;\n";
|
||||
$args[$#args+1] = "i$narg";
|
||||
}
|
||||
elsif ($type eq "F")
|
||||
{
|
||||
# This must be an MPI_File since that type may not
|
||||
# be an integer (it is a pointer at this time)
|
||||
print TESTFD " MPI_File i$narg = MPI_FILE_NULL;\n OACR_USE_PTR( i$narg );\n";
|
||||
$args[$#args+1] = "i$narg";
|
||||
}
|
||||
elsif ($type eq "W")
|
||||
{
|
||||
print TESTFD " int i$narg = MPI_WIN_NULL;\n";
|
||||
$args[$#args+1] = "i$narg";
|
||||
}
|
||||
elsif ($type eq "A")
|
||||
{
|
||||
print TESTFD " int i$narg = $narg;\n";
|
||||
$args[$#args+1] = "i$narg";
|
||||
}
|
||||
elsif ($type eq "G")
|
||||
{
|
||||
print TESTFD " int i$narg = MPI_GROUP_NULL;\n";
|
||||
$args[$#args+1] = "i$narg";
|
||||
}
|
||||
elsif ($type eq "O")
|
||||
{
|
||||
print TESTFD " int i$narg = MPI_SUM;\n";
|
||||
$args[$#args+1] = "i$narg";
|
||||
}
|
||||
elsif ($type eq "R")
|
||||
{
|
||||
print TESTFD " int i$narg = MPI_REQUEST_NULL;\n";
|
||||
$args[$#args+1] = "i$narg";
|
||||
}
|
||||
elsif ($type eq "E")
|
||||
{
|
||||
print TESTFD " int i$narg = MPI_ERRORS_RETURN;\n";
|
||||
$args[$#args+1] = "i$narg";
|
||||
}
|
||||
elsif ($type eq "g")
|
||||
{
|
||||
print TESTFD " GUID g$narg = \{ 0x4d36e96e, 0xe325, 0x11c3, \{ 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 \} \};\n";
|
||||
$args[$#args+1] = "g$narg";
|
||||
}
|
||||
elsif ($type eq "l")
|
||||
{
|
||||
print TESTFD " int i$narg = $narg;\n";
|
||||
$args[$#args+1] = "i$narg";
|
||||
}
|
||||
else
|
||||
{
|
||||
print STDERR "$filename : error : unrecognized format type $type for $fullformat\n";
|
||||
}
|
||||
}
|
||||
$actargs = $#_ - $genericArgLoc - 1;
|
||||
if ($actargs != $narg)
|
||||
{
|
||||
print STDERR "$filename : error : format $fullformat provides $narg arguments but call has $actargs\n";
|
||||
}
|
||||
print TESTFD " err = MPIR_Err_create_code($last_errcode, $fatal_flag, $errclass, $specific_msg";
|
||||
foreach my $arg (@args)
|
||||
{
|
||||
print TESTFD ", $arg";
|
||||
}
|
||||
print TESTFD ");\n";
|
||||
print TESTFD " ChkMsg( err, $errclass, $specific_msg );\n }\n";
|
||||
# ToDo: pass another string to ChkMsg that contains the
|
||||
# names of the variables, as a single string (comma separated).
|
||||
# This allows us to review the source of the values for the args.
|
||||
}
|
||||
}
|
||||
|
||||
# ==========================================================================
|
||||
# Read an errnames file. This allows us to distribute the errnames.txt
|
||||
# files in the relevant modules, rather than making them part of one
|
||||
# single master file.
|
||||
# This updates the global hashs longnames and longnamesDefined
|
||||
# ReadErrnamesFile( filename )
|
||||
# ==========================================================================
|
||||
sub ReadErrnamesFile {
|
||||
my $sourcefile = $_[0];
|
||||
|
||||
open( FD, "<$sourcefile" ) or return 0;
|
||||
my $linecount = 0;
|
||||
while (<FD>) {
|
||||
$linecount++;
|
||||
# Skip Comments
|
||||
if (/^\s*\#/) { next; }
|
||||
# Read entire error message (allow \ at end of line to continue)
|
||||
if (/^\s*(\*\*[^:]*):(.*)$/) {
|
||||
my $name = $1;
|
||||
my $repl = $2;
|
||||
$repl =~ s/\r*\n*$//g;
|
||||
while ($repl =~ /\\\s*$/) {
|
||||
# If there is a \\ at the end, read another.
|
||||
# Remove the \ at the end (an alternative is to turn
|
||||
# it into a \n (newline), but we may want to avoid
|
||||
# multiline messages
|
||||
$repl =~ s/\\\s*$//;
|
||||
my $inline = <FD>;
|
||||
$linecount++;
|
||||
$inline =~ s/^\s*//; # remove leading spaces
|
||||
$repl .= $inline;
|
||||
$repl =~ s/[\r\n]*$//g; # remove newlines
|
||||
}
|
||||
|
||||
# Check that the name and the replacement text at least
|
||||
# partially match as to format specifiers
|
||||
# (They should have exactly the same pattern, i.e.,
|
||||
# if the name has %d %x in is, the replacement should
|
||||
# have %d %x, in that order)
|
||||
my $namehasformat = ($name =~ /%/);
|
||||
my $replhasformat = ($repl =~ /%/);
|
||||
if ($namehasformat != $replhasformat) {
|
||||
print STDERR "$sourcefile($linecount) : error : format control usage in $name and $repl do not agree\n";
|
||||
}
|
||||
# if (!defined($longnames{"\"$name\""}))
|
||||
# {
|
||||
# $longnames{"\"$name\""} = $repl;
|
||||
# $longnamesDefined{"\"$name\""} = "$sourcefile:$linecount";
|
||||
# }
|
||||
# Check that the replacement text doesn't include a unquoted
|
||||
# double quote
|
||||
if ($repl =~ /(.)\"/) {
|
||||
my $prechar = $1;
|
||||
if ($1 ne "\\") {
|
||||
print STDERR "$sourcefile($linecount) : error : replacement text for $name contains an unescaped double quote: $repl\n";
|
||||
}
|
||||
}
|
||||
if (!defined($longnames{$name}))
|
||||
{
|
||||
$longnames{$name} = $repl;
|
||||
$longnamesDefined{$name} = "$sourcefile:$linecount";
|
||||
}
|
||||
else
|
||||
{
|
||||
print STDERR "$sourcefile($linecount) : warning : attempt to redefine $name. Duplicate ignored.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
close( FD );
|
||||
}
|
||||
|
||||
# ==========================================================================
|
||||
# Call this for each file
|
||||
# This reads a C source or header file and adds does the following:
|
||||
# adds any generic message short names encountered to the hash generic_msgs.
|
||||
# adds any specific message short names encounter to the hash specific_msgs.
|
||||
# adds the filename to the hash generic_loc{msg} as the value (: separated)
|
||||
# and the same for hash specific_loc{msg}.
|
||||
# The last two are used to provide better error reporting.
|
||||
#
|
||||
$filename = ""; # Make global so that other routines can echo filename
|
||||
sub ProcessFile
|
||||
{
|
||||
# Leave filename global for AddTest
|
||||
$filename = $_[0];
|
||||
my $linecount = 0;
|
||||
open (FD, "<$filename" ) or die "Could not open $filename\n";
|
||||
|
||||
while (<FD>) {
|
||||
$linecount++;
|
||||
|
||||
# Skip code that is marked as ignore (e.g., for
|
||||
# macros that are used to simplify the use of MPIR_Err_create_code
|
||||
# (such macros must also be recognized and processed)
|
||||
if (/\/\*\s+--BEGIN ERROR MACROS--\s+\*\//) {
|
||||
while (<FD>) {
|
||||
$linecount++;
|
||||
if (/\/\*\s+--END ERROR MACROS--\s+\*\//) { last; }
|
||||
}
|
||||
$remainder = "";
|
||||
next;
|
||||
}
|
||||
|
||||
# Next, remove any comments
|
||||
$_ = StripComments( FD, $_ );
|
||||
|
||||
# Skip the definition of the function
|
||||
if (/MPI_RESULT\s+MPI[OUR]_Err_create_code/) { $remainder = ""; next; }
|
||||
|
||||
# Match the known routines and macros.
|
||||
# Then check that the arguments match if there is a
|
||||
# specific string (number of args matches the number present)
|
||||
# (MPIU_ERR_FATAL_GET[0-4]?(cond,code,class,gmsg[,smsg,args])
|
||||
# Value is a quadruplet of:
|
||||
# 1. the count of args where the generic msg begins (starting from 0)
|
||||
# 2. location of __LINE__ (-1 for none)
|
||||
# 3. specific msg arg required (0 for no, > 0 for yes)
|
||||
# 4. only indirect message allowed
|
||||
#
|
||||
%KnownErrRoutines = ( 'MPIR_Err_create_code' => '3:-1:1:1',
|
||||
'MPIR_ERRTEST_VALID_HANDLE' => '4:-1:0:1',
|
||||
'MPIU_ERR_FATAL_GET' => '2:-1:0:1',
|
||||
'MPIU_ERR_GET' => '1:-1:0:1',
|
||||
'MPIU_ERR_CLASS_GET' => '2:-1:0:1',
|
||||
'MPIU_ERR_CREATE' => '1:-1:0:1',
|
||||
|
||||
'MPIU_E_ERR' => '0:-1:0:1',
|
||||
);
|
||||
|
||||
while (/(MPI[OUR]_E[A-Za-z0-9_]+)\s*(\(.*)$/) {
|
||||
my $routineName = $1;
|
||||
my $arglist = $2;
|
||||
if (!defined($KnownErrRoutines{$routineName})) {
|
||||
if($routineName =~ /[1-9]$/) {
|
||||
$routineNameN = substr($routineName, 0, $#routineName);
|
||||
if (!defined($KnownErrRoutines{$routineNameN})) {
|
||||
print "Skipping $routineName\n" if $debug;
|
||||
last;
|
||||
}
|
||||
print "Found $routineName, using $routineNameN definition\n" if $debug;
|
||||
$routineName = $routineNameN;
|
||||
}
|
||||
else {
|
||||
print "Skipping $routineName\n" if $debug;
|
||||
last;
|
||||
}
|
||||
}
|
||||
else {
|
||||
print "Found $routineName\n" if $debug;
|
||||
}
|
||||
|
||||
my ($genericArgLoc,$hasLine,$hasSpecific,$onlyIndirect) =
|
||||
split(/:/,$KnownErrRoutines{$routineName});
|
||||
|
||||
($leader, $remainder, @args ) = &GetSubArgs( FD, $arglist );
|
||||
# Discard leader
|
||||
if ($debug) {
|
||||
print "Line begins with $leader\n"; # Use $leader to keep -w happy
|
||||
foreach $arg (@args) {
|
||||
print "|$arg|\n";
|
||||
}
|
||||
}
|
||||
# Process the signature
|
||||
|
||||
# if signature does not match new function prototype, then skip it
|
||||
if ($#args < $genericArgLoc) {
|
||||
if (!defined($bad_syntax_in_file{$filename})) {
|
||||
$bad_syntax_in_file{$filename} = 1;
|
||||
print STDERR "$filename($linecount) : error : $routineName call with too few arguments\n";
|
||||
}
|
||||
next;
|
||||
}
|
||||
if ($hasLine >= 0 &&
|
||||
($args[$hasLine] ne "__LINE__" && $args[$hasLine] ne "line")) {
|
||||
if (!defined($bad_syntax_in_file{$filename})) {
|
||||
$bad_syntax_in_file{$filename} = 1;
|
||||
my $tmpi = $hasLine + 1;
|
||||
print STDERR "$filename($linecount) : error : Expected __LINE__ or line as ${tmpi}th argument of $routineName\n";
|
||||
}
|
||||
next;
|
||||
}
|
||||
|
||||
#my $last_errcode = $args[0];
|
||||
#my $fatal_flag = $args[1];
|
||||
#my $fcname = $args[2];
|
||||
#my $linenum = $args[3];
|
||||
#my $errclass = $args[4];
|
||||
my $specific_msg = $args[$genericArgLoc];
|
||||
|
||||
if ($specific_msg =~ /(\".*\")/)
|
||||
{
|
||||
$specific_msg = $1;
|
||||
}
|
||||
|
||||
# Check the generic and specific message arguments
|
||||
if ($specific_msg =~ /\s"/)
|
||||
{
|
||||
print STDERR "$filename($linecount) : warning : trailing blank in error key '$specific_msg'\n";
|
||||
}
|
||||
|
||||
if ($onlyIndirect && !($specific_msg =~ /^\"\*\*.+\"$/)) {
|
||||
|
||||
print STDERR "$filename($linecount) : error : error key '$specific_msg' has incorrect format\n";
|
||||
next;
|
||||
}
|
||||
|
||||
if ($specific_msg =~ /%/) {
|
||||
# Specific message includes format values. Check
|
||||
# for number and for valid strings if %s
|
||||
my $nargs = 0;
|
||||
my $tmpmsg = $specific_msg;
|
||||
my @stringLocs = ();
|
||||
while ($tmpmsg =~ /[^%]*%(.)(.*)/) {
|
||||
$tmpmsg = $2;
|
||||
my $followchar = $1;
|
||||
if ($followchar eq "s") {
|
||||
$stringLocs[$#stringLocs+1] = $nargs;
|
||||
}
|
||||
if ($followchar ne "%") {
|
||||
$nargs ++;
|
||||
}
|
||||
if (! ($followchar =~ /[%xsditpDCRWOEIGFAgl]/) ) {
|
||||
print STDERR "$filename($linecount) : error : Unrecognized format specifier in error key $specific_msg\n";
|
||||
}
|
||||
}
|
||||
if ($nargs != $#args - $genericArgLoc) {
|
||||
my $actargs = $#args - $genericArgLoc;
|
||||
print STDERR "$filename($linecount) : error : wrong number of arguments for instance error key $specific_msg; expected $nargs but found $actargs\n";
|
||||
}
|
||||
elsif ($#stringLocs >= 0 && $gStrict) {
|
||||
# Check for reasonable strings if strict checking requested
|
||||
for (my $i=0; $i<=$#stringLocs; $i++) {
|
||||
my $index = $stringLocs[$i];
|
||||
my $string = $args[$genericArgLoc+1+$index];
|
||||
if ($string =~ /\"/) {
|
||||
# Allow a few special cases:
|
||||
# Always: all uppercase and _, single word
|
||||
my $stringOk = 0;
|
||||
if ($string =~ /^\"[A-Z_]*\"$/) {
|
||||
$stringOk = 1;
|
||||
}
|
||||
elsif ($string =~ /^\"\w*\"$/) {
|
||||
if (1) { $stringOk = 1; }
|
||||
}
|
||||
if (!$stringOk) {
|
||||
print STDERR "$filename($linecount) : error : explicit string as argument to error key $specific_msg; explicit string is $string\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($build_test_pgm) {
|
||||
&AddTestCall( $genericArgLoc, @args )
|
||||
}
|
||||
|
||||
if ($specific_msg =~ /^\"(\*\*.*)\"/)
|
||||
{
|
||||
$specific_msg = $1;
|
||||
$specific_msgs{$specific_msg}++;
|
||||
$specific_loc{$specific_msg} .= ":$filename($linecount)";
|
||||
}
|
||||
}
|
||||
continue
|
||||
{
|
||||
$_ = $remainder;
|
||||
}
|
||||
}
|
||||
close FD;
|
||||
}
|
||||
|
||||
# Get all of the .c files from the named directory, including any subdirs
|
||||
# Also, add any errnames.txt files to the errnamesFiles arrays
|
||||
sub ExpandDir {
|
||||
my $dir = $_[0];
|
||||
my @otherdirs = ();
|
||||
my @files = ();
|
||||
opendir DIR, "$dir";
|
||||
while ($filename = readdir DIR) {
|
||||
if ($filename =~ /^\./ || $filename eq "CVS" || $filename eq $testfile) {
|
||||
next;
|
||||
}
|
||||
elsif (-d "$dir/$filename") {
|
||||
if( ($filename ne "objd") && ($filename ne "obj") ) {
|
||||
$otherdirs[$#otherdirs+1] = "$dir/$filename";
|
||||
}
|
||||
}
|
||||
elsif ($filename =~ /(.*\.[chi][xp]*)$/) {
|
||||
# Test for both Unix- and Windows-style directory separators
|
||||
if (!defined($skipFiles{"$dir/$filename"}) &&
|
||||
!defined($skipFiles{"$dir\\$filename"})) {
|
||||
$files[$#files + 1] = "$dir/$filename";
|
||||
}
|
||||
}
|
||||
elsif ($filename eq "errnames.txt") {
|
||||
$errnameFiles[$#errnameFiles+1] = "$dir/$filename";
|
||||
}
|
||||
}
|
||||
closedir DIR;
|
||||
# (almost) tail recurse on otherdirs (we've closed the directory handle,
|
||||
# so we don't need to worry about it anymore)
|
||||
foreach $dir (@otherdirs) {
|
||||
@files = (@files, &ExpandDir( $dir ) );
|
||||
}
|
||||
return @files;
|
||||
}
|
||||
#
|
||||
# Other todos:
|
||||
# It would be good to keep track of any .N MPI_ERR_xxx names in the structured
|
||||
# comment and match these against any MPI_ERR_yyy used in the code, emitting a
|
||||
# warning message for MPI_ERR_yyy values used in the code but not mentioned
|
||||
# in the header. This could even apply to routines that are not at the MPI
|
||||
# layer, forcing all routines to document all MPI error classes that they might
|
||||
# return (this is like requiring routines to document the exceptions that
|
||||
# they may throw).
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "hwtree.h"
|
||||
#include "util.h"
|
||||
|
||||
typedef SYSTEM_LOGICAL_PROCESSOR_INFORMATION SLPI;
|
||||
|
||||
|
||||
inline const SLPI* HwInfoGetEnd( const SLPI* pInfo, DWORD cb )
|
||||
{
|
||||
return (const SLPI*)((ULONG_PTR)pInfo + (ULONG_PTR)cb);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Get the full mask of all cores
|
||||
//
|
||||
UINT64
|
||||
HwInfoGetGroupMask(
|
||||
_In_ const SLPI* pSlpi,
|
||||
_In_ DWORD cb
|
||||
)
|
||||
{
|
||||
UINT64 mask = 0;
|
||||
for( const SLPI* pCurrent = pSlpi;
|
||||
pCurrent < HwInfoGetEnd(pSlpi, cb);
|
||||
pCurrent++
|
||||
)
|
||||
{
|
||||
if( pCurrent->Relationship == RelationProcessorCore )
|
||||
{
|
||||
mask |= static_cast<UINT64>(pCurrent->ProcessorMask);
|
||||
}
|
||||
}
|
||||
Assert(0 != mask);
|
||||
return mask;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Get the count of logical cores per physical core
|
||||
//
|
||||
UINT8
|
||||
HwInfoGetPcoreWidth(
|
||||
_In_ const SLPI* pSlpi,
|
||||
_In_ DWORD cb
|
||||
)
|
||||
{
|
||||
UINT8 c = 1;
|
||||
for( const SLPI* pCurrent = pSlpi;
|
||||
pCurrent < HwInfoGetEnd(pSlpi, cb);
|
||||
pCurrent++
|
||||
)
|
||||
{
|
||||
if( pCurrent->Relationship == RelationProcessorCore )
|
||||
{
|
||||
//
|
||||
// MSDN documents that if Flags == 1, HT is enabled.
|
||||
// so we need to count the bits used.
|
||||
//
|
||||
if( 1 == pCurrent->ProcessorCore.Flags )
|
||||
{
|
||||
c = CountBits( pCurrent->ProcessorMask );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Get the count of logical cores per numa node
|
||||
//
|
||||
UINT8
|
||||
HwInfoGetNumaWidth(
|
||||
_In_ const SLPI* pSlpi,
|
||||
_In_ DWORD cb
|
||||
)
|
||||
{
|
||||
UINT8 c = 0;
|
||||
for( const SLPI* pCurrent = pSlpi;
|
||||
pCurrent < HwInfoGetEnd(pSlpi, cb);
|
||||
pCurrent++
|
||||
)
|
||||
{
|
||||
if( pCurrent->Relationship == RelationNumaNode )
|
||||
{
|
||||
c = CountBits( pCurrent->ProcessorMask );
|
||||
break;
|
||||
}
|
||||
}
|
||||
Assert(0 != c);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Allocate the SLPI information for this machine.
|
||||
//
|
||||
// Parameters:
|
||||
// ppSlpi - pointer to recieve the allocate SLPI array
|
||||
// pcbSlpi - pointer to recieve the total buffer size.
|
||||
//
|
||||
HRESULT
|
||||
HwInfoGetSlpi(
|
||||
_Outptr_result_buffer_(*pcbSlpi) SLPI** ppSlpi,
|
||||
_Out_ UINT32* pcbSlpi
|
||||
)
|
||||
{
|
||||
SLPI* pSlpi;
|
||||
DWORD ntError;
|
||||
DWORD cb = 0;
|
||||
|
||||
BOOL bResult = ::GetLogicalProcessorInformation( nullptr, &cb );
|
||||
if( FALSE == bResult )
|
||||
{
|
||||
ntError = GetLastError();
|
||||
if( ntError != ERROR_INSUFFICIENT_BUFFER )
|
||||
{
|
||||
return HRESULT_FROM_WIN32(ntError);
|
||||
}
|
||||
}
|
||||
|
||||
pSlpi = static_cast<SLPI*>(malloc(cb));
|
||||
if( nullptr == pSlpi )
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
bResult = ::GetLogicalProcessorInformation( pSlpi, &cb );
|
||||
if( FALSE == bResult )
|
||||
{
|
||||
free(pSlpi);
|
||||
ntError = GetLastError();
|
||||
return HRESULT_FROM_WIN32(ntError);
|
||||
}
|
||||
|
||||
*ppSlpi = pSlpi;
|
||||
*pcbSlpi = cb;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Initialize the array of pInfos from the current machine using Win7 apis
|
||||
//
|
||||
// Parameters:
|
||||
// pInfo - HWINFO to initialize
|
||||
// pFilter - Option bit mask filter
|
||||
//
|
||||
HRESULT
|
||||
HwInfoInitializeWin6(
|
||||
_Out_ HWINFO* pInfo
|
||||
)
|
||||
{
|
||||
SLPI* pSlpi;
|
||||
UINT32 cbSlpi;
|
||||
HRESULT hr;
|
||||
|
||||
hr = HwInfoGetSlpi(&pSlpi, &cbSlpi );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
pInfo->Mask = HwInfoGetGroupMask(pSlpi,cbSlpi);
|
||||
pInfo->ActiveMask = pInfo->Mask;
|
||||
|
||||
pInfo->Group = 0;
|
||||
pInfo->GroupWidth = CountBits(pInfo->Mask);
|
||||
pInfo->NumaWidth = HwInfoGetNumaWidth(pSlpi,cbSlpi);
|
||||
pInfo->PcoreWidth = HwInfoGetPcoreWidth(pSlpi,cbSlpi);
|
||||
|
||||
Assert(pInfo->GroupWidth >= pInfo->NumaWidth);
|
||||
Assert(pInfo->NumaWidth >= pInfo->PcoreWidth);
|
||||
Assert(pInfo->PcoreWidth > 0 );
|
||||
|
||||
free(pSlpi);
|
||||
return S_OK;
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "hwtree.h"
|
||||
#include "util.h"
|
||||
#include "kernel32util.h"
|
||||
#include <oacr.h>
|
||||
#include<string.h>
|
||||
//
|
||||
// Summary:
|
||||
// Utility function to get the specificied processor relations using the existing buffer if possible.
|
||||
//
|
||||
// Parameters:
|
||||
// relation - the specific relation that we want.
|
||||
// ppSlpi - pointer to an existing buffer on input (optional)
|
||||
// pointer to new buffer if current buffer is null or too small
|
||||
// pcbSlpi - on input, points to the current size of the buffer
|
||||
// on output, contains the new alloc size or the size used if the
|
||||
// existing buffer is large enough.
|
||||
//
|
||||
static
|
||||
HRESULT
|
||||
HwInfoGetSlpiEx(
|
||||
_In_ LOGICAL_PROCESSOR_RELATIONSHIP relation,
|
||||
_Inout_ _Outptr_result_bytebuffer_to_(*pcbSlpi,*pcbSlpi) SLPIEX** ppSlpi,
|
||||
_Inout_ UINT32* pcbSlpi
|
||||
)
|
||||
{
|
||||
SLPIEX* pSlpi = *ppSlpi;
|
||||
DWORD cb = *pcbSlpi;
|
||||
DWORD ntError;
|
||||
BOOL bResult;
|
||||
for(;;)
|
||||
{
|
||||
Assert( nullptr != Kernel32::Methods.GetLogicalProcessorInformationEx );
|
||||
|
||||
bResult = Kernel32::Methods.GetLogicalProcessorInformationEx( relation, pSlpi, &cb );
|
||||
if( FALSE != bResult )
|
||||
{
|
||||
break;
|
||||
}
|
||||
ntError = GetLastError();
|
||||
if( nullptr != pSlpi )
|
||||
{
|
||||
//
|
||||
// ensure that we null out the input buffer if
|
||||
// and free the input buffer on error.
|
||||
// this prevents the caller from having to
|
||||
// free it on failure.
|
||||
//
|
||||
*ppSlpi = nullptr;
|
||||
free(pSlpi);
|
||||
}
|
||||
if( ntError != ERROR_INSUFFICIENT_BUFFER )
|
||||
{
|
||||
return HRESULT_FROM_WIN32(ntError);
|
||||
}
|
||||
|
||||
pSlpi = static_cast<SLPIEX*>( malloc( cb ) );
|
||||
if( nullptr == pSlpi )
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
*ppSlpi = pSlpi;
|
||||
*pcbSlpi = cb;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Initialize the array of pInfos from the current machine using Win7 apis
|
||||
//
|
||||
// Parameters:
|
||||
// pnInfos - On input, the count of elements in pInfos.
|
||||
// On output, the count of elements used in pInfos or size required if too small
|
||||
// pInfos - Array of HWINFO to populate
|
||||
//
|
||||
HRESULT
|
||||
HwInfoInitializeWin7(
|
||||
_Inout_ UINT32* pnInfos,
|
||||
_Out_writes_to_opt_(*pnInfos,*pnInfos) HWINFO pInfos[]
|
||||
)
|
||||
{
|
||||
SLPIEX* pSlpiEx = nullptr;
|
||||
UINT32 cbSlpiEx = 0;
|
||||
UINT32 cbSlpiExAlloc = 0;
|
||||
UINT8 numaWidth;
|
||||
UINT8 pcoreWidth = 1;
|
||||
HRESULT hr;
|
||||
|
||||
hr = HwInfoGetSlpiEx(RelationNumaNode,&pSlpiEx, &cbSlpiExAlloc );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
__analysis_assume(pSlpiEx != nullptr);
|
||||
|
||||
numaWidth = CountBits( pSlpiEx->NumaNode.GroupMask.Mask );
|
||||
|
||||
cbSlpiEx = cbSlpiExAlloc;
|
||||
hr = HwInfoGetSlpiEx( RelationProcessorCore, &pSlpiEx, &cbSlpiEx );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
//
|
||||
// If HT is enabled, then calculate the pcoreWidth to include the
|
||||
// logical cores it contains.
|
||||
//
|
||||
__analysis_assume(pSlpiEx != nullptr);
|
||||
if( 0 != (pSlpiEx->Processor.Flags & LTP_PC_SMT) )
|
||||
{
|
||||
pcoreWidth = CountBits( pSlpiEx->Processor.GroupMask[0].Mask );
|
||||
}
|
||||
|
||||
//
|
||||
// if the second call to HwInfoGetSlpiEx reallocated the buffer
|
||||
// we calculate the new alloc max based on previous and current size
|
||||
//
|
||||
cbSlpiExAlloc = max(cbSlpiExAlloc,cbSlpiEx);
|
||||
cbSlpiEx = cbSlpiExAlloc;
|
||||
hr = HwInfoGetSlpiEx(RelationGroup,&pSlpiEx, &cbSlpiEx );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
//
|
||||
// To make the data structures pack nicely, we have limited ourselves to
|
||||
// UINT8 worth of processor groups. There is no real world case where
|
||||
// the number of processor groups will exceed this limit.
|
||||
//
|
||||
__analysis_assume(pSlpiEx != nullptr);
|
||||
UINT8 nGroups = static_cast<UINT8>( pSlpiEx->Group.ActiveGroupCount );
|
||||
|
||||
//
|
||||
// This should be a very rare case where group count > 1
|
||||
// so I don't feel bad not pre-emptively checking the group count
|
||||
// before calculating the PCores and Numa widths.
|
||||
//
|
||||
if( nGroups > *pnInfos )
|
||||
{
|
||||
*pnInfos = nGroups;
|
||||
free(pSlpiEx);
|
||||
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
|
||||
|
||||
for( UINT8 i = 0; i < nGroups; i++ )
|
||||
{
|
||||
pInfos[i].Mask = pSlpiEx->Group.GroupInfo[i].ActiveProcessorMask;
|
||||
pInfos[i].ActiveMask = pInfos[i].Mask;
|
||||
|
||||
pInfos[i].Group = i;
|
||||
pInfos[i].GroupWidth = pSlpiEx->Group.GroupInfo[ i ].ActiveProcessorCount;
|
||||
pInfos[i].NumaWidth = numaWidth;
|
||||
pInfos[i].PcoreWidth = pcoreWidth;
|
||||
|
||||
Assert(pInfos[i].GroupWidth >= pInfos[i].NumaWidth);
|
||||
Assert(pInfos[i].NumaWidth >= pInfos[i].PcoreWidth);
|
||||
Assert(pInfos[i].PcoreWidth > 0 );
|
||||
}
|
||||
free(pSlpiEx);
|
||||
*pnInfos = nGroups;
|
||||
return S_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,401 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "hwtree.h"
|
||||
#include "stdio.h"
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Utility function to get a simple string for error message formatting.
|
||||
//
|
||||
inline const char* GetNodeTypeString(HWNODE_TYPE targetType)
|
||||
{
|
||||
switch( targetType )
|
||||
{
|
||||
case HWNODE_TYPE_MACHINE:
|
||||
return "M";
|
||||
case HWNODE_TYPE_GROUP:
|
||||
return "G";
|
||||
case HWNODE_TYPE_NUMA:
|
||||
return "N";
|
||||
case HWNODE_TYPE_PCORE:
|
||||
return "P";
|
||||
case HWNODE_TYPE_LCORE:
|
||||
return "L";
|
||||
default:
|
||||
Assert(0);
|
||||
return "Invalid";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FW delclare some local functions
|
||||
//
|
||||
static HRESULT
|
||||
HwLayoutProcessEnum(
|
||||
_In_ const HWLAYOUT* pLayout,
|
||||
_In_ const HWVIEW* pView,
|
||||
_In_ PVOID pData,
|
||||
_In_ FN_HwLayoutProcessCallback* pfn,
|
||||
_In_ HWLAYOUT_STATE* pState,
|
||||
_In_ UINT32 enumIndex
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Process the specified layout using the specified tree
|
||||
//
|
||||
// Parameters:
|
||||
// pLayout - Pointer to layout description
|
||||
// pView - Pointer to the view
|
||||
// minProc - Minimum number of processes to create
|
||||
// maxProc - Maximum number of processes to create
|
||||
// pData - Opaque data pointer to hand to callback
|
||||
// pfn - Callback function to invoke for each iteration
|
||||
//
|
||||
HRESULT
|
||||
HwLayoutProcess(
|
||||
_In_ const HWLAYOUT* pLayout,
|
||||
_In_ const HWVIEW* pView,
|
||||
_In_ UINT32 minProc,
|
||||
_In_ UINT32 maxProc,
|
||||
_In_ PVOID pData,
|
||||
_In_ FN_HwLayoutProcessCallback* pfn
|
||||
)
|
||||
{
|
||||
HRESULT hr;
|
||||
HWLAYOUT_STATE state;
|
||||
|
||||
state.MaxProc = maxProc;
|
||||
state.MinProc = minProc;
|
||||
state.ProcCount = 0;
|
||||
|
||||
for( UINT32 i = 0; i < pLayout->EnumCount; i++ )
|
||||
{
|
||||
state.Enums[i].Start = 0;
|
||||
state.Enums[i].Size = 0;
|
||||
state.Enums[i].Current = 0;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
hr = HwLayoutProcessEnum( pLayout, pView, pData, pfn, &state, 0 );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
if( S_FALSE == hr )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
} while( state.ProcCount < state.MinProc );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Process the target of each iteration.
|
||||
//
|
||||
// Parameters:
|
||||
// pLayout - Pointer to the current layout
|
||||
// pView - Pointer to the view where the location is set
|
||||
// pData - Pointer to the opaque data to pass to the callback
|
||||
// pfn - Callback function invoked for each iteration target
|
||||
// pState - Pointer to the current state of the iterations.
|
||||
//
|
||||
inline HRESULT
|
||||
HwLayoutProcessTarget(
|
||||
_In_ const HWLAYOUT* pLayout,
|
||||
_In_ const HWVIEW* pView,
|
||||
_In_ PVOID pData,
|
||||
_In_ FN_HwLayoutProcessCallback* pfn,
|
||||
_In_ HWLAYOUT_STATE* pState
|
||||
)
|
||||
{
|
||||
HRESULT hr;
|
||||
UINT32 location = pState->Enums[pLayout->EnumCount-1].Current;
|
||||
UINT32 count = pLayout->TargetCount;
|
||||
|
||||
if( 0 != pState->MaxProc )
|
||||
{
|
||||
count = min(count,pState->MaxProc - pState->ProcCount);
|
||||
}
|
||||
|
||||
if( pView == nullptr)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
while( pView->Nodes[location].Type > pLayout->TargetType )
|
||||
{
|
||||
location = pView->Nodes[location].Parent;
|
||||
}
|
||||
|
||||
Assert( 0 != location );
|
||||
|
||||
hr = pfn( pLayout, pState, pView, location, pData, &count );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
pState->ProcCount += count;
|
||||
|
||||
if( S_FALSE == hr )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
if( 0 != pState->MaxProc && pState->ProcCount >= pState->MaxProc )
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Lookup the count of elements for a give type within the scope of the current layout
|
||||
//
|
||||
// Parameters:
|
||||
// pLayout - The layout to use to scope the returned size
|
||||
// pState - The state of the layout enumeration
|
||||
// enumIndex - The current layout enumeration being processed
|
||||
// pView - The view to use to resolve the size
|
||||
// type - The type of node we need a count for
|
||||
//
|
||||
static UINT32
|
||||
HwLayoutResolveWellknownExpression(
|
||||
_In_ const HWLAYOUT* pLayout,
|
||||
_In_ const HWLAYOUT_STATE* pState,
|
||||
_In_ UINT32 enumIndex,
|
||||
_In_ const HWVIEW* pView,
|
||||
_In_ HWNODE_TYPE type
|
||||
)
|
||||
{
|
||||
Assert( type >= HWNODE_TYPE_MACHINE );
|
||||
Assert( pLayout->Enums[enumIndex].Type >= type );
|
||||
|
||||
//
|
||||
// First find the Enumerator in the layout that provides the
|
||||
// scope we need resolve the wellknown value.
|
||||
//
|
||||
while( enumIndex > 0 && pLayout->Enums[enumIndex].Type > type )
|
||||
{
|
||||
enumIndex--;
|
||||
}
|
||||
|
||||
//
|
||||
// If expression matches an enumerator value, just return the size
|
||||
// of that exact match.
|
||||
//
|
||||
if( pLayout->Enums[enumIndex].Type == type )
|
||||
{
|
||||
return pState->Enums[enumIndex].Size;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Else, we must be closer to the root of the tree with the
|
||||
// currently selected enumerator, so continue to walk the span
|
||||
// of the tree until we reach the correct depth, and return the width
|
||||
// of that range.
|
||||
//
|
||||
UINT32 start = pState->Enums[enumIndex].Current;
|
||||
UINT32 end = start;
|
||||
|
||||
do
|
||||
{
|
||||
start = pView->Nodes[start].FirstChild;
|
||||
end = pView->Nodes[end].LastChild;
|
||||
|
||||
}while( pView->Nodes[start].Type < type );
|
||||
|
||||
return end - start + 1;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Resolve the HWENUM_EXPR value to the resulting UINT32
|
||||
//
|
||||
// Parameters:
|
||||
// pLayout - The layout to use to scope the returned size
|
||||
// pState - The state of the layout enumeration
|
||||
// enumIndex - The current layout enumeration being processed
|
||||
// pView - The view to use to resolve the size
|
||||
// pExpression - The expression to resolve
|
||||
//
|
||||
inline UINT32
|
||||
HwLayoutResolveExpression(
|
||||
_In_ const HWLAYOUT* pLayout,
|
||||
_In_ const HWLAYOUT_STATE* pState,
|
||||
_In_ UINT32 enumIndex,
|
||||
_In_ const HWVIEW* pView,
|
||||
_In_ const HWENUM_EXPR* pExpression
|
||||
)
|
||||
{
|
||||
if( 0 == pExpression->Flags )
|
||||
{
|
||||
return pExpression->Left;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT32 left = pExpression->Left;
|
||||
UINT32 right = pExpression->Right;
|
||||
|
||||
if( 0 != ( pExpression->Flags & HWENUM_EXPR_WELLKNOWN_LEFT ) )
|
||||
{
|
||||
left = HwLayoutResolveWellknownExpression(
|
||||
pLayout,
|
||||
pState,
|
||||
enumIndex,
|
||||
pView,
|
||||
static_cast<HWNODE_TYPE>(left)
|
||||
);
|
||||
}
|
||||
if( 0 == ( pExpression->Flags & HWENUM_EXPR_DIVIDE_BY_RIGHT ) )
|
||||
{
|
||||
return left;
|
||||
}
|
||||
|
||||
if( 0 != ( pExpression->Flags & HWENUM_EXPR_WELLKNOWN_RIGHT ) )
|
||||
{
|
||||
right = HwLayoutResolveWellknownExpression(
|
||||
pLayout,
|
||||
pState,
|
||||
enumIndex,
|
||||
pView,
|
||||
static_cast<HWNODE_TYPE>(right)
|
||||
);
|
||||
}
|
||||
|
||||
Assert(0 != right);
|
||||
|
||||
return left / right;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline UINT32 HwLayoutResolveExpressionAndRoundUp(
|
||||
_In_ const HWLAYOUT* pLayout,
|
||||
_In_ const HWLAYOUT_STATE* pState,
|
||||
_In_ UINT32 enumIndex,
|
||||
_In_ const HWVIEW* pView,
|
||||
_In_ const HWENUM_EXPR* pExpression
|
||||
)
|
||||
{
|
||||
UINT32 i = HwLayoutResolveExpression(pLayout,pState,enumIndex,pView,pExpression);
|
||||
if( i == 0 )
|
||||
{
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Run the chain of enumerations recursively
|
||||
//
|
||||
// Parameters:
|
||||
// pLayout - Pointer to the current layout
|
||||
// pView - Pointer to the view where the location is set
|
||||
// pData - Pointer to the opaque data to pass to the callback
|
||||
// pfn - Callback function invoked for each iteration target
|
||||
// pState - Pointer to the current state of the iterations.
|
||||
// enumIndex - The index of the current enumation level.
|
||||
//
|
||||
static HRESULT
|
||||
HwLayoutProcessEnum(
|
||||
_In_ const HWLAYOUT* pLayout,
|
||||
_In_ const HWVIEW* pView,
|
||||
_In_ PVOID pData,
|
||||
_In_ FN_HwLayoutProcessCallback* pfn,
|
||||
_In_ HWLAYOUT_STATE* pState,
|
||||
_In_ UINT32 enumIndex
|
||||
)
|
||||
{
|
||||
HRESULT hr;
|
||||
if( enumIndex == pLayout->EnumCount )
|
||||
{
|
||||
return HwLayoutProcessTarget( pLayout, pView, pData, pfn, pState );
|
||||
}
|
||||
|
||||
HWENUM_STATE* pEnumState = &pState->Enums[ enumIndex ];
|
||||
const HWENUM* pEnum = &pLayout->Enums[ enumIndex ];
|
||||
|
||||
//
|
||||
// Work out the start and count of elements in the list
|
||||
//
|
||||
if( 0 != enumIndex )
|
||||
{
|
||||
UINT32 end = pState->Enums[enumIndex-1].Current;
|
||||
pEnumState->Start = end;
|
||||
|
||||
Assert(pView != nullptr);
|
||||
|
||||
while( pView->Nodes[end].Type != pEnum->Type )
|
||||
{
|
||||
Assert( pView->Nodes[pEnumState->Start].Type == pView->Nodes[end].Type );
|
||||
|
||||
pEnumState->Start = pView->Nodes[pEnumState->Start].FirstChild;
|
||||
end = pView->Nodes[end].LastChild;
|
||||
}
|
||||
pEnumState->Size = (end - pEnumState->Start) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
pEnumState->Start = pView->Strides[pEnum->Type];
|
||||
pEnumState->Size = pView->Counts[pEnum->Type];
|
||||
}
|
||||
|
||||
//
|
||||
// There are cases where you can scope the values of an expression and get
|
||||
// a resulting 0 from the divide operation. This can happen when the Left side of the expression
|
||||
// results in a value < the right. For example, the pattern "MNL{1,0,N/2}" on boxes where there is only 1 numa node.
|
||||
// We round these value up to 1 to ensure that we place at least a single item..
|
||||
//
|
||||
UINT32 offset = HwLayoutResolveExpression( pLayout, pState, enumIndex, pView, &pEnum->Offset );
|
||||
UINT32 count = HwLayoutResolveExpressionAndRoundUp( pLayout, pState, enumIndex, pView, &pEnum->Count );
|
||||
UINT32 stride = HwLayoutResolveExpressionAndRoundUp( pLayout, pState, enumIndex, pView, &pEnum->Stride );
|
||||
UINT32 repeatCount = HwLayoutResolveExpressionAndRoundUp( pLayout, pState, enumIndex, pView, &pEnum->RepeatCount );
|
||||
UINT32 repeatOffset = HwLayoutResolveExpression( pLayout, pState, enumIndex, pView, &pEnum->RepeatOffset );
|
||||
|
||||
Assert(repeatCount>0);
|
||||
Assert(count>0);
|
||||
Assert(stride>0);
|
||||
|
||||
pEnumState->Current = pEnumState->Start + ( offset % pEnumState->Size );
|
||||
|
||||
do
|
||||
{
|
||||
for( UINT32 i = 0; i < count; i++ )
|
||||
{
|
||||
hr = HwLayoutProcessEnum( pLayout, pView, pData, pfn, pState, enumIndex + 1 );
|
||||
if( FAILED( hr ) || S_FALSE == hr )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
pEnumState->Current = pEnumState->Start + ((pEnumState->Current - pEnumState->Start + stride) % pEnumState->Size);
|
||||
}
|
||||
|
||||
pEnumState->Current = pEnumState->Start + ((pEnumState->Current - pEnumState->Start + repeatOffset) % pEnumState->Size);
|
||||
|
||||
repeatCount--;
|
||||
|
||||
} while( repeatCount > 0 );
|
||||
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "hwtree.h"
|
||||
#include "util.h"
|
||||
#include "kernel32util.h"
|
||||
|
||||
HRESULT
|
||||
HwInfoInitializeWin6(
|
||||
_Out_ HWINFO* pInfo
|
||||
);
|
||||
|
||||
|
||||
HRESULT
|
||||
HwInfoInitializeWin7(
|
||||
_Inout_ UINT32* pnInfos,
|
||||
_Out_writes_to_opt_(*pnInfos,*pnInfos) HWINFO pInfos[]
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Initialize HWINFO array from the local logical processor information.
|
||||
//
|
||||
// Parameters:
|
||||
// pnInfos - On input, max size of pInfos
|
||||
// on output, size used.
|
||||
// if return code is HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)
|
||||
// the required count will be written here.
|
||||
// pInfos - pointer to buffer to fill with values
|
||||
// pFilters - (optional) pointer to array of affinity filters
|
||||
// must be same length as pInfos when specified.
|
||||
//
|
||||
HRESULT
|
||||
HwInfoInitialize(
|
||||
_Inout_ UINT32* pnInfos,
|
||||
_Out_writes_to_opt_(*pnInfos,*pnInfos) HWINFO pInfos[]
|
||||
)
|
||||
{
|
||||
if( FALSE != g_IsWin7OrGreater )
|
||||
{
|
||||
return HwInfoInitializeWin7(pnInfos,pInfos);
|
||||
}
|
||||
else
|
||||
{
|
||||
if( *pnInfos < 1 )
|
||||
{
|
||||
*pnInfos = 1;
|
||||
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
Assert(pInfos != nullptr);
|
||||
HRESULT hr = HwInfoInitializeWin6(pInfos);
|
||||
if( SUCCEEDED( hr ) )
|
||||
{
|
||||
*pnInfos = 1;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Initialize the local HWSUMMARY information
|
||||
//
|
||||
// Parameters:
|
||||
// pcbSummary - On input, size of pSummary buffer
|
||||
// on output, size used.
|
||||
// if return code is HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)
|
||||
// the required count will be written here.
|
||||
// pSummary - The summary information to initialize.
|
||||
//
|
||||
HRESULT
|
||||
HwSummaryInitialize(
|
||||
_Inout_ UINT32* pcbSummary,
|
||||
_Inout_updates_bytes_to_(*pcbSummary, *pcbSummary) HWSUMMARY* pSummary
|
||||
)
|
||||
{
|
||||
HRESULT hr;
|
||||
UINT32 nInfos = 0;
|
||||
UINT32 cb;
|
||||
|
||||
hr = HwInfoInitialize( &nInfos, nullptr );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
if( HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
cb = sizeof(*pSummary) - sizeof(pSummary->Infos) +
|
||||
(sizeof(pSummary->Infos[0]) * nInfos);
|
||||
|
||||
if( *pcbSummary < cb )
|
||||
{
|
||||
*pcbSummary = cb;
|
||||
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
|
||||
Assert(pSummary != nullptr);
|
||||
|
||||
pSummary->Size = cb;
|
||||
pSummary->Count = nInfos;
|
||||
|
||||
hr = HwInfoInitialize( &nInfos, pSummary->Infos );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (!(g_IsWin7OrGreater && nInfos > 1))
|
||||
{
|
||||
KAFFINITY sysMask;
|
||||
union
|
||||
{
|
||||
KAFFINITY procMask;
|
||||
UINT64 procMask64;
|
||||
};
|
||||
procMask64 = 0;
|
||||
if( FALSE == ::GetProcessAffinityMask( ::GetCurrentProcess(), &procMask, &sysMask ) )
|
||||
{
|
||||
return HRESULT_FROM_WIN32( ::GetLastError() );
|
||||
}
|
||||
HwSummaryFilter( pSummary, &procMask64 );
|
||||
}
|
||||
|
||||
*pcbSummary = cb;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,575 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "hwtree.h"
|
||||
#include "util.h"
|
||||
|
||||
//
|
||||
// List of masks index by count - 1 of sequential bits set starting at bit 0.
|
||||
//
|
||||
static const UINT64 WidthMasks[] =
|
||||
{
|
||||
0x0000000000000001L,0x0000000000000003L,0x0000000000000007L,0x000000000000000FL,
|
||||
0x000000000000001FL,0x000000000000003FL,0x000000000000007FL,0x00000000000000FFL,
|
||||
0x00000000000001FFL,0x00000000000003FFL,0x00000000000007FFL,0x0000000000000FFFL,
|
||||
0x0000000000001FFFL,0x0000000000003FFFL,0x0000000000007FFFL,0x000000000000FFFFL,
|
||||
0x000000000001FFFFL,0x000000000003FFFFL,0x000000000007FFFFL,0x00000000000FFFFFL,
|
||||
0x00000000001FFFFFL,0x00000000003FFFFFL,0x00000000007FFFFFL,0x0000000000FFFFFFL,
|
||||
0x0000000001FFFFFFL,0x0000000003FFFFFFL,0x0000000007FFFFFFL,0x000000000FFFFFFFL,
|
||||
0x000000001FFFFFFFL,0x000000003FFFFFFFL,0x000000007FFFFFFFL,0x00000000FFFFFFFFL,
|
||||
0x00000001FFFFFFFFL,0x00000003FFFFFFFFL,0x00000007FFFFFFFFL,0x0000000FFFFFFFFFL,
|
||||
0x0000001FFFFFFFFFL,0x0000003FFFFFFFFFL,0x0000007FFFFFFFFFL,0x000000FFFFFFFFFFL,
|
||||
0x000001FFFFFFFFFFL,0x000003FFFFFFFFFFL,0x000007FFFFFFFFFFL,0x00000FFFFFFFFFFFL,
|
||||
0x00001FFFFFFFFFFFL,0x00003FFFFFFFFFFFL,0x00007FFFFFFFFFFFL,0x0000FFFFFFFFFFFFL,
|
||||
0x0001FFFFFFFFFFFFL,0x0003FFFFFFFFFFFFL,0x0007FFFFFFFFFFFFL,0x000FFFFFFFFFFFFFL,
|
||||
0x001FFFFFFFFFFFFFL,0x003FFFFFFFFFFFFFL,0x007FFFFFFFFFFFFFL,0x00FFFFFFFFFFFFFFL,
|
||||
0x01FFFFFFFFFFFFFFL,0x03FFFFFFFFFFFFFFL,0x07FFFFFFFFFFFFFFL,0x0FFFFFFFFFFFFFFFL,
|
||||
0x1FFFFFFFFFFFFFFFL,0x3FFFFFFFFFFFFFFFL,0x7FFFFFFFFFFFFFFFL,0xFFFFFFFFFFFFFFFFL,
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Utility function to initialize the specified node within the tree.
|
||||
//
|
||||
// Parameters:
|
||||
// pTree - pointer to the tree to manipulate
|
||||
// index - index of the node within the tree
|
||||
// type - the type to set on the node
|
||||
// parent - the parent ID of the node
|
||||
// previous - the previous node
|
||||
//
|
||||
static void
|
||||
HwTreeInitializeNode(
|
||||
_Inout_ HWTREE* pTree,
|
||||
_In_ UINT32 index,
|
||||
_In_ HWNODE_TYPE type,
|
||||
_In_ UINT32 parent,
|
||||
_In_ UINT32 previous
|
||||
)
|
||||
{
|
||||
pTree->Nodes[index].Type = type;
|
||||
pTree->Nodes[index].Parent = parent;
|
||||
pTree->Nodes[index].FirstChild = HWNODEID_NONE;
|
||||
pTree->Nodes[index].LastChild = HWNODEID_NONE;
|
||||
pTree->Nodes[index].NextSibling = HWNODEID_NONE;
|
||||
pTree->Nodes[index].PrevSibling = previous;
|
||||
|
||||
pTree->Nodes[parent].LastChild = index;
|
||||
|
||||
if( previous == HWNODEID_NONE ||
|
||||
pTree->Nodes[previous].Parent != parent )
|
||||
{
|
||||
pTree->Nodes[parent].FirstChild = index;
|
||||
}
|
||||
else
|
||||
{
|
||||
pTree->Nodes[previous].NextSibling = index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Utility function to initialize the specified node within the tree with affinity data.
|
||||
//
|
||||
// Parameters:
|
||||
// pTree - pointer to the tree to manipulate
|
||||
// index - index of the node within the tree
|
||||
// type - the type to set on the node
|
||||
// parent - the parent ID of the node
|
||||
// previous - the previous node
|
||||
// group - the processor group to set in the affinity value
|
||||
// mask - the affinity mask to set
|
||||
//
|
||||
static void
|
||||
HwTreeInitializeAffinityNode(
|
||||
_Inout_ HWTREE* pTree,
|
||||
_In_ UINT32 index,
|
||||
_In_ HWNODE_TYPE type,
|
||||
_In_ UINT32 parent,
|
||||
_In_ UINT32 previous,
|
||||
_In_ UINT16 group,
|
||||
_In_ UINT64 mask
|
||||
)
|
||||
{
|
||||
HwTreeInitializeNode(pTree, index, type, parent, previous);
|
||||
pTree->Nodes[index].Affinity.GroupId = group;
|
||||
pTree->Nodes[index].Affinity.Mask = mask;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Utility function to initialize the specified machine node
|
||||
//
|
||||
// Parameters:
|
||||
// pTree - pointer to the tree to manipulate
|
||||
// index - index of the node within the tree
|
||||
// type - the type to set on the node
|
||||
// parent - the parent ID of the node
|
||||
// previous - the previous node
|
||||
// hostId - the hostid of the machine node
|
||||
//
|
||||
static void
|
||||
HwTreeInitializeMachineNode(
|
||||
_Inout_ HWTREE* pTree,
|
||||
_In_ UINT32 index,
|
||||
_In_ HWNODE_TYPE type,
|
||||
_In_ UINT32 parent,
|
||||
_In_ UINT32 previous,
|
||||
_In_ int hostId
|
||||
)
|
||||
{
|
||||
HwTreeInitializeNode(pTree, index, type, parent, previous);
|
||||
pTree->Nodes[index].HostId = hostId;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Initialize all logical core elements in the tree.
|
||||
//
|
||||
// Parameter:
|
||||
// pTree - pointer to the tree to populate
|
||||
// pStrides - pointer to the current strides of each level in the tree
|
||||
// pEnds - pointer to the current ends of each level in the tree
|
||||
// group - the processor group that this core belongs to.
|
||||
// pcoreMask - the processor mask for the parent physical core
|
||||
//
|
||||
static HRESULT
|
||||
HwTreeInitializeLCores(
|
||||
_Inout_ HWTREE* pTree,
|
||||
_Inout_updates_(HWNODE_MAX_DEPTH) UINT32 pStrides[],
|
||||
_In_reads_(HWNODE_MAX_DEPTH) const UINT32 pEnds[],
|
||||
_In_ UINT16 group,
|
||||
_In_ UINT64 pcoreMask
|
||||
)
|
||||
{
|
||||
UINT32 last = HWNODEID_NONE;
|
||||
UINT64 fullMask = pcoreMask;
|
||||
|
||||
//
|
||||
// Get the lowest set bit from pcoreMask (the first logical core)
|
||||
//
|
||||
UINT64 mask = ((~pcoreMask << 1 ) | 1) & pcoreMask;
|
||||
|
||||
while( 0 != fullMask )
|
||||
{
|
||||
Assert(mask & pcoreMask);
|
||||
|
||||
if( pStrides[HWNODE_TYPE_LCORE] >= pEnds[HWNODE_TYPE_LCORE] )
|
||||
{
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
HwTreeInitializeAffinityNode(
|
||||
pTree,
|
||||
pStrides[HWNODE_TYPE_LCORE],
|
||||
HWNODE_TYPE_LCORE,
|
||||
pStrides[HWNODE_TYPE_PCORE],
|
||||
last,
|
||||
group,
|
||||
mask
|
||||
);
|
||||
|
||||
last = pStrides[HWNODE_TYPE_LCORE];
|
||||
pStrides[HWNODE_TYPE_LCORE]++;
|
||||
pTree->Counts[HWNODE_TYPE_LCORE]++;
|
||||
|
||||
//
|
||||
// Remove mask from the remaining bits
|
||||
//
|
||||
fullMask &= (~mask);
|
||||
|
||||
//
|
||||
// Move to the next bit
|
||||
//
|
||||
mask <<= 1;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Initialize all physical core elements in the tree.
|
||||
//
|
||||
// Parameter:
|
||||
// pTree - pointer to the tree to populate
|
||||
// pStrides - pointer to the current strides of each level in the tree
|
||||
// pEnds - pointer to the current ends of each level in the tree
|
||||
// numaMask - the processor mask for the parent numa node
|
||||
// pInfo - pointer to the HWINFO for the current processor group
|
||||
//
|
||||
static HRESULT
|
||||
HwTreeInitializePcores(
|
||||
_Inout_ HWTREE* pTree,
|
||||
_Inout_updates_(HWNODE_MAX_DEPTH) UINT32 pStrides[],
|
||||
_In_reads_(HWNODE_MAX_DEPTH) const UINT32 pEnds[],
|
||||
UINT64 numaMask,
|
||||
const HWINFO* pInfo
|
||||
)
|
||||
{
|
||||
HRESULT hr;
|
||||
UINT32 last = HWNODEID_NONE;
|
||||
UINT64 fullMask = numaMask;
|
||||
|
||||
//
|
||||
// Get the lowest N bits from numaMask where N is PCoreWidth (the first physical core)
|
||||
//
|
||||
Assert(pInfo->PcoreWidth>0);
|
||||
UINT64 mask = ((~numaMask << pInfo->PcoreWidth ) | WidthMasks[pInfo->PcoreWidth-1]) & numaMask;
|
||||
|
||||
while( 0 != fullMask )
|
||||
{
|
||||
Assert( mask & numaMask );
|
||||
|
||||
if( pStrides[HWNODE_TYPE_PCORE] >= pEnds[HWNODE_TYPE_PCORE] )
|
||||
{
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
HwTreeInitializeAffinityNode(
|
||||
pTree,
|
||||
pStrides[HWNODE_TYPE_PCORE],
|
||||
HWNODE_TYPE_PCORE,
|
||||
pStrides[HWNODE_TYPE_NUMA],
|
||||
last,
|
||||
pInfo->Group,
|
||||
mask
|
||||
);
|
||||
|
||||
hr = HwTreeInitializeLCores( pTree, pStrides, pEnds, pInfo->Group, mask );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
last = pStrides[HWNODE_TYPE_PCORE];
|
||||
pStrides[HWNODE_TYPE_PCORE]++;
|
||||
pTree->Counts[HWNODE_TYPE_PCORE]++;
|
||||
|
||||
//
|
||||
// Remove mask from the remaining bits
|
||||
//
|
||||
fullMask &= (~mask);
|
||||
|
||||
//
|
||||
// Move to the next physical core
|
||||
//
|
||||
mask <<= pInfo->PcoreWidth;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Initialize all numa elements in the tree.
|
||||
//
|
||||
// Parameter:
|
||||
// pTree - pointer to the tree to populate
|
||||
// pStrides - pointer to the current strides of each level in the tree
|
||||
// pEnds - pointer to the current ends of each level in the tree
|
||||
// pInfo - pointer to the HWINFO for the current processor group
|
||||
//
|
||||
static HRESULT
|
||||
HwTreeInitializeNuma(
|
||||
_Inout_ HWTREE* pTree,
|
||||
_Inout_updates_(HWNODE_MAX_DEPTH) UINT32 pStrides[],
|
||||
_In_reads_(HWNODE_MAX_DEPTH) const UINT32 pEnds[],
|
||||
_In_ const HWINFO* pInfo
|
||||
)
|
||||
{
|
||||
HRESULT hr;
|
||||
UINT32 last = HWNODEID_NONE;
|
||||
UINT64 fullMask = pInfo->Mask;
|
||||
|
||||
//
|
||||
// Get the lowest N bits from group mask where N is NumaWidth (the numa node)
|
||||
//
|
||||
Assert(pInfo->NumaWidth>0);
|
||||
UINT64 mask = ((~pInfo->Mask << pInfo->NumaWidth ) | WidthMasks[pInfo->NumaWidth-1]) & pInfo->Mask;
|
||||
|
||||
while( 0 != fullMask )
|
||||
{
|
||||
Assert( mask & pInfo->Mask );
|
||||
|
||||
if( pStrides[HWNODE_TYPE_NUMA] >= pEnds[HWNODE_TYPE_NUMA] )
|
||||
{
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
HwTreeInitializeAffinityNode(
|
||||
pTree,
|
||||
pStrides[HWNODE_TYPE_NUMA],
|
||||
HWNODE_TYPE_NUMA,
|
||||
pStrides[HWNODE_TYPE_GROUP],
|
||||
last,
|
||||
pInfo->Group,
|
||||
mask
|
||||
);
|
||||
|
||||
hr = HwTreeInitializePcores(pTree, pStrides, pEnds, mask, pInfo);
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
last = pStrides[HWNODE_TYPE_NUMA];
|
||||
pStrides[HWNODE_TYPE_NUMA]++;
|
||||
pTree->Counts[HWNODE_TYPE_NUMA]++;
|
||||
|
||||
//
|
||||
// Remove mask from the remaining bits
|
||||
//
|
||||
fullMask &= (~mask);
|
||||
|
||||
//
|
||||
// Move to the next numa node
|
||||
//
|
||||
mask <<= pInfo->NumaWidth;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Initialize all Group and Machine element in the tree.
|
||||
//
|
||||
// Parameter:
|
||||
// pTree - pointer to the tree to populate
|
||||
// pStrides - pointer to the current strides of each level in the tree
|
||||
// pEnds - pointer to the current ends of each level in the tree
|
||||
// pSummary - Pointer to machine's summary
|
||||
//
|
||||
static HRESULT
|
||||
HwTreeInitializeGroups(
|
||||
_Inout_ HWTREE* pTree,
|
||||
_Inout_updates_(HWNODE_MAX_DEPTH) UINT32 pStrides[],
|
||||
_In_reads_(HWNODE_MAX_DEPTH) const UINT32 pEnds[],
|
||||
_In_ const HWSUMMARY* pSummary
|
||||
|
||||
)
|
||||
{
|
||||
UINT32 lastMachine = HWNODEID_NONE;
|
||||
UINT32 lastGroup = HWNODEID_NONE;
|
||||
HRESULT hr;
|
||||
|
||||
if(pSummary == nullptr)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if( pStrides[HWNODE_TYPE_MACHINE] >= pEnds[HWNODE_TYPE_MACHINE] )
|
||||
{
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
HwTreeInitializeMachineNode(
|
||||
pTree,
|
||||
pStrides[HWNODE_TYPE_MACHINE],
|
||||
HWNODE_TYPE_MACHINE,
|
||||
HWNODEID_WORLD,
|
||||
lastMachine,
|
||||
HWMACHINEID_SELF
|
||||
);
|
||||
lastGroup = HWNODEID_NONE;
|
||||
|
||||
for( UINT32 i = 0; i < pSummary->Count; i++ )
|
||||
{
|
||||
if( pStrides[HWNODE_TYPE_GROUP] >= pEnds[HWNODE_TYPE_GROUP] )
|
||||
{
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
HwTreeInitializeAffinityNode(
|
||||
pTree,
|
||||
pStrides[HWNODE_TYPE_GROUP],
|
||||
HWNODE_TYPE_GROUP,
|
||||
pStrides[HWNODE_TYPE_MACHINE],
|
||||
lastGroup,
|
||||
pSummary->Infos[i].Group,
|
||||
pSummary->Infos[i].Mask
|
||||
);
|
||||
|
||||
hr = HwTreeInitializeNuma( pTree, pStrides, pEnds, &pSummary->Infos[i] );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
lastGroup = pStrides[HWNODE_TYPE_GROUP];
|
||||
pStrides[HWNODE_TYPE_GROUP]++;
|
||||
pTree->Counts[HWNODE_TYPE_GROUP]++;
|
||||
}
|
||||
|
||||
lastMachine = pStrides[HWNODE_TYPE_MACHINE];
|
||||
pStrides[HWNODE_TYPE_MACHINE]++;
|
||||
pTree->Counts[HWNODE_TYPE_MACHINE]++;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Calculate the size of the tree required for the specified HWINFO array
|
||||
//
|
||||
// Parameters:
|
||||
// pSummary - Pointer to a machine's summary information.
|
||||
// pCounts - Pointer to array of UINT32 for holding the counts of each level in the tree.
|
||||
//
|
||||
// Returns:
|
||||
// Total node code for full tree.
|
||||
//
|
||||
_Success_(return > 0)
|
||||
static UINT32
|
||||
HwTreeCalculateNodeCounts(
|
||||
_In_opt_ const HWSUMMARY* pSummary,
|
||||
_Out_writes_(HWNODE_MAX_DEPTH) UINT32 pCounts[]
|
||||
)
|
||||
{
|
||||
if(pSummary == nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
pCounts[HWNODE_TYPE_MACHINE] = 0;
|
||||
pCounts[HWNODE_TYPE_GROUP] = 0;
|
||||
pCounts[HWNODE_TYPE_NUMA] = 0;
|
||||
pCounts[HWNODE_TYPE_PCORE] = 0;
|
||||
pCounts[HWNODE_TYPE_LCORE] = 0;
|
||||
|
||||
|
||||
pCounts[HWNODE_TYPE_MACHINE]++;
|
||||
//one for every group
|
||||
pCounts[HWNODE_TYPE_GROUP] += pSummary->Count;
|
||||
|
||||
for( UINT32 i = 0; i < pSummary->Count; i++ )
|
||||
{
|
||||
|
||||
pCounts[HWNODE_TYPE_NUMA] += pSummary->Infos[i].GroupWidth / pSummary->Infos[i].NumaWidth;
|
||||
|
||||
//
|
||||
// 1 for each pcore
|
||||
//
|
||||
pCounts[HWNODE_TYPE_PCORE] += pSummary->Infos[i].GroupWidth / pSummary->Infos[i].PcoreWidth;
|
||||
|
||||
//
|
||||
// 1 for each lcore
|
||||
//
|
||||
pCounts[HWNODE_TYPE_LCORE] += pSummary->Infos[i].GroupWidth;
|
||||
}
|
||||
|
||||
//
|
||||
// Include 1 extra for the WORLD node.
|
||||
//
|
||||
return 1 +
|
||||
pCounts[HWNODE_TYPE_MACHINE] +
|
||||
pCounts[HWNODE_TYPE_GROUP] +
|
||||
pCounts[HWNODE_TYPE_NUMA] +
|
||||
pCounts[HWNODE_TYPE_PCORE] +
|
||||
pCounts[HWNODE_TYPE_LCORE];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Initialize hardware tree representing all machines.
|
||||
//
|
||||
// Parameters:
|
||||
// pcbTree - On input, current size of pTree
|
||||
// On output, the size of the buffer used.
|
||||
// if return code is HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)
|
||||
// the required size will be written here.
|
||||
// pTree - pointer to HWTREE buffer
|
||||
// pSummary - Pointer to a machine's summary information.
|
||||
//
|
||||
// NOTE:
|
||||
// The memory is sequentially allocated, and can be marshalled with memcpy.
|
||||
//
|
||||
HRESULT
|
||||
HwTreeInitialize(
|
||||
_Inout_ UINT32* pcbTree,
|
||||
_Inout_updates_to_(*pcbTree,*pcbTree) HWTREE* pTree,
|
||||
_In_ const HWSUMMARY* pSummary
|
||||
)
|
||||
{
|
||||
HRESULT hr;
|
||||
UINT32 cb;
|
||||
UINT32 nNodes;
|
||||
UINT32 strides[HWNODE_MAX_DEPTH];
|
||||
UINT32 ends[HWNODE_MAX_DEPTH];
|
||||
|
||||
//
|
||||
// Count total nodes + 1 for world
|
||||
//
|
||||
nNodes = HwTreeCalculateNodeCounts( pSummary, ends );
|
||||
|
||||
//
|
||||
// There must be at least 1 node for each level in the tree.
|
||||
//
|
||||
Assert( nNodes >= HWNODE_MAX_DEPTH );
|
||||
|
||||
cb = sizeof(*pTree) - sizeof(pTree->Nodes) + (sizeof(pTree->Nodes[0]) * nNodes);
|
||||
|
||||
if( *pcbTree < cb )
|
||||
{
|
||||
*pcbTree = cb;
|
||||
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
|
||||
//
|
||||
// Update the stride table.
|
||||
//
|
||||
strides[HWNODE_TYPE_MACHINE]= 1;
|
||||
strides[HWNODE_TYPE_GROUP] = strides[HWNODE_TYPE_MACHINE] + ends[HWNODE_TYPE_MACHINE];
|
||||
strides[HWNODE_TYPE_NUMA] = strides[HWNODE_TYPE_GROUP] + ends[HWNODE_TYPE_GROUP];
|
||||
strides[HWNODE_TYPE_PCORE] = strides[HWNODE_TYPE_NUMA] + ends[HWNODE_TYPE_NUMA];
|
||||
strides[HWNODE_TYPE_LCORE] = strides[HWNODE_TYPE_PCORE] + ends[HWNODE_TYPE_PCORE];
|
||||
|
||||
pTree->Strides[HWNODE_TYPE_MACHINE] = strides[HWNODE_TYPE_MACHINE];
|
||||
pTree->Strides[HWNODE_TYPE_GROUP] = strides[HWNODE_TYPE_GROUP];
|
||||
pTree->Strides[HWNODE_TYPE_NUMA] = strides[HWNODE_TYPE_NUMA];
|
||||
pTree->Strides[HWNODE_TYPE_PCORE] = strides[HWNODE_TYPE_PCORE];
|
||||
pTree->Strides[HWNODE_TYPE_LCORE] = strides[HWNODE_TYPE_LCORE];
|
||||
|
||||
pTree->Counts[HWNODE_TYPE_MACHINE] = 0;
|
||||
pTree->Counts[HWNODE_TYPE_GROUP] = 0;
|
||||
pTree->Counts[HWNODE_TYPE_NUMA] = 0;
|
||||
pTree->Counts[HWNODE_TYPE_PCORE] = 0;
|
||||
pTree->Counts[HWNODE_TYPE_LCORE] = 0;
|
||||
|
||||
//
|
||||
// update the "ends" to be offset from the strides so we don't
|
||||
// have to track the start of the chain through the iteration.
|
||||
//
|
||||
ends[HWNODE_TYPE_MACHINE] += strides[HWNODE_TYPE_MACHINE];
|
||||
ends[HWNODE_TYPE_GROUP] += strides[HWNODE_TYPE_GROUP];
|
||||
ends[HWNODE_TYPE_NUMA] += strides[HWNODE_TYPE_NUMA];
|
||||
ends[HWNODE_TYPE_PCORE] += strides[HWNODE_TYPE_PCORE];
|
||||
ends[HWNODE_TYPE_LCORE] += strides[HWNODE_TYPE_LCORE];
|
||||
|
||||
|
||||
pTree->Nodes[HWNODEID_WORLD].Type = HWNODE_TYPE_WORLD;
|
||||
pTree->Nodes[HWNODEID_WORLD].Parent = HWNODEID_NONE;
|
||||
pTree->Nodes[HWNODEID_WORLD].FirstChild = HWNODEID_NONE;
|
||||
pTree->Nodes[HWNODEID_WORLD].LastChild = HWNODEID_NONE;
|
||||
pTree->Nodes[HWNODEID_WORLD].NextSibling = HWNODEID_NONE;
|
||||
pTree->Nodes[HWNODEID_WORLD].PrevSibling = HWNODEID_NONE;
|
||||
|
||||
|
||||
hr = HwTreeInitializeGroups(pTree, strides, ends, pSummary);
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
*pcbTree = cb;
|
||||
return S_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,470 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <oacr.h>
|
||||
#include "hwtree_common.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// The maximum depth of the tree
|
||||
//
|
||||
#define HWNODE_MAX_DEPTH ((UINT32)HWNODE_TYPE_MAX)
|
||||
|
||||
|
||||
//
|
||||
// Fixed width field for holding affinity information.
|
||||
//
|
||||
// Fields:
|
||||
// Mask - 64bit mask of processors with in the specified processor group.
|
||||
// GroupId - The processor group id that the affinity mask applies to.
|
||||
// Padding - padding to show wasted space.
|
||||
//
|
||||
typedef struct _HWAFFINITY
|
||||
{
|
||||
UINT64 Mask;
|
||||
UINT16 GroupId;
|
||||
UINT16 Padding[3];
|
||||
|
||||
} HWAFFINITY;
|
||||
|
||||
|
||||
#define HWNODEID_WORLD ((UINT32)0)
|
||||
#define HWNODEID_NONE ((UINT32)MAXDWORD)
|
||||
#define HWMACHINEID_SELF ((UINT32)1)
|
||||
|
||||
//
|
||||
// Definition of basic tree node
|
||||
//
|
||||
// Fields:
|
||||
// Type - The type of data within the node.
|
||||
// Parent - Index of the parent element
|
||||
// FirstChild - Index of this nodes first child
|
||||
// LastChild - Index of this nodes last child
|
||||
// NextSibling - Index of this nodes next sibling
|
||||
// PrevSibling - Index of this nodes previous sibling
|
||||
//
|
||||
typedef struct HWNODEHEADER
|
||||
{
|
||||
HWNODE_TYPE Type;
|
||||
UINT32 Parent;
|
||||
UINT32 FirstChild;
|
||||
UINT32 LastChild;
|
||||
UINT32 NextSibling;
|
||||
UINT32 PrevSibling;
|
||||
|
||||
} HWNODEHEADER;
|
||||
|
||||
|
||||
//
|
||||
// Definition of a node in the HWTREE.
|
||||
//
|
||||
// Fields:
|
||||
// Affinity - Specifies the affinity information represented by the node
|
||||
// Valid only when Type > HWNODE_TYPE_MACHINE
|
||||
// HostId - Specifies the identifier for the machine in the tree.
|
||||
// Valid only when Type == HWNODE_TYPE_MACHINE
|
||||
//
|
||||
typedef struct _HWNODE
|
||||
: public HWNODEHEADER
|
||||
{
|
||||
union
|
||||
{
|
||||
HWAFFINITY Affinity;
|
||||
int HostId;
|
||||
};
|
||||
|
||||
} HWNODE;
|
||||
|
||||
|
||||
//
|
||||
// Definition of a node in the HWVIEW.
|
||||
//
|
||||
// Fields:
|
||||
// NodeId - Specifies node id in the original tree.
|
||||
//
|
||||
typedef struct _HWVIEWNODE
|
||||
: public HWNODEHEADER
|
||||
{
|
||||
UINT32 NodeId;
|
||||
|
||||
} HWVIEWNODE;
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Data structure representing the a single machine hardware tree.
|
||||
//
|
||||
// Fields:
|
||||
// Counts - The total counts of each depth in the tree
|
||||
// Strides - The stride offset to the start of each level in the tree
|
||||
// Nodes - This list of HWNODE structures that make up the tree.
|
||||
//
|
||||
typedef struct _HWTREE
|
||||
{
|
||||
UINT32 Counts[HWNODE_MAX_DEPTH];
|
||||
UINT32 Strides[HWNODE_MAX_DEPTH];
|
||||
HWNODE Nodes[ANYSIZE_ARRAY];
|
||||
|
||||
} HWTREE;
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Structure that represents a portion of the tree within a HWTREE
|
||||
//
|
||||
// Fields:
|
||||
// Counts - The total counts of each depth in the tree
|
||||
// Strides - The stride offset to the start of each level in the tree
|
||||
// Nodes - This list of HWVIEWNODE structures that make up the tree.
|
||||
//
|
||||
typedef struct _HWVIEW
|
||||
{
|
||||
const HWTREE* Tree;
|
||||
UINT32 Counts[HWNODE_MAX_DEPTH];
|
||||
UINT32 Strides[HWNODE_MAX_DEPTH];
|
||||
HWVIEWNODE Nodes[ANYSIZE_ARRAY];
|
||||
|
||||
} HWVIEW;
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Summary of the local information on an individual processor group
|
||||
//
|
||||
// Fields:
|
||||
// Mask - The entire bitmask for the group
|
||||
// ActiveMask - The active bitmask for the group after filter
|
||||
// Group - the processor group id
|
||||
// We only use UINT8 worth of groups. There is no
|
||||
// real world scenario where this will not work, and
|
||||
// using this size makes the structure pack cleanly.
|
||||
// GroupWidth - The number of logical cores for this group
|
||||
// NumaWidth - the number of logical cores per numa node
|
||||
// PcoreWidth - the number of logical cores per physical core
|
||||
// Padding - Pad.
|
||||
//
|
||||
typedef struct _HWINFO
|
||||
{
|
||||
UINT64 Mask;
|
||||
UINT64 ActiveMask;
|
||||
UINT8 Group;
|
||||
UINT8 GroupWidth;
|
||||
UINT8 NumaWidth;
|
||||
UINT8 PcoreWidth;
|
||||
UINT32 Padding;
|
||||
|
||||
} HWINFO;
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Hosts the logical processor information for the processor groups on a machine.
|
||||
//
|
||||
// Fields:
|
||||
// Size - The total size of the buffer
|
||||
// Count - The count of elements in Infos
|
||||
// Infos - The array of HWINFO, one for each Processor Group
|
||||
//
|
||||
typedef struct _HWSUMMARY
|
||||
{
|
||||
UINT32 Size;
|
||||
UINT32 Count;
|
||||
HWINFO Infos[ANYSIZE_ARRAY];
|
||||
|
||||
} HWSUMMARY;
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Hosts the summary information for a local machine.
|
||||
//
|
||||
// Fields:
|
||||
// Next - The pointer to the next machine in the chain
|
||||
// Summary - Pointer to the summary information for the machine
|
||||
// HostId - The unique id assigned to the machine.
|
||||
//
|
||||
typedef struct _HWMACHINEINFO
|
||||
{
|
||||
struct _HWMACHINEINFO* Next;
|
||||
HWSUMMARY* Summary;
|
||||
int HostId;
|
||||
|
||||
} HWMACHINEINFO;
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Represents an exprssion parsed from the LAYOUT format string
|
||||
//
|
||||
// Fields:
|
||||
// Left - The left side of the expression
|
||||
// Right - The right side of the expression
|
||||
// Flags - The flags to indicate how to interpret Left and Right fields.
|
||||
// HWENUM_EXPR_WELLKNOWN_LEFT - means that left must be resolved
|
||||
// HWENUM_EXPR_DIVIDE_BY_RIGHT - means that right is present
|
||||
// HWENUM_EXPR_WELLKNOWN_RIGHT - means that right must be resolved
|
||||
// If no flags are set, Left is a constant value.
|
||||
//
|
||||
typedef struct _HWENUM_EXPR
|
||||
{
|
||||
UINT32 Left;
|
||||
UINT32 Right;
|
||||
UINT32 Flags;
|
||||
|
||||
} HWENUM_EXPR;
|
||||
|
||||
|
||||
#define HWENUM_EXPR_WELLKNOWN_LEFT 0x1
|
||||
#define HWENUM_EXPR_DIVIDE_BY_RIGHT 0x2
|
||||
#define HWENUM_EXPR_WELLKNOWN_RIGHT 0x4
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Represents the settings for an individual enumeration in an HWTREE
|
||||
//
|
||||
// Fields:
|
||||
// Type - The depth in the HWTREE to target
|
||||
// Offset - The offset from the start to use
|
||||
// Count - The count of steps.
|
||||
// Stride - The stride to use for each step
|
||||
// RepeatCount - The number of times repeat all steps.
|
||||
// RepeatOffset - The size to step the offset each repeat.
|
||||
//
|
||||
typedef struct _HWENUM
|
||||
{
|
||||
HWNODE_TYPE Type;
|
||||
HWENUM_EXPR Offset;
|
||||
HWENUM_EXPR Count;
|
||||
HWENUM_EXPR Stride;
|
||||
HWENUM_EXPR RepeatCount;
|
||||
HWENUM_EXPR RepeatOffset;
|
||||
|
||||
} HWENUM;
|
||||
|
||||
|
||||
#define HWLAYOUT_ENUM_MAX (HWNODE_MAX_DEPTH)
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Represents the layout information of the processes.
|
||||
//
|
||||
// Fields:
|
||||
// TargetType - The affinity target type
|
||||
// TargetCount - The count of processes to create on each target
|
||||
// EnumCount - The count of enumeration items specified
|
||||
// Must be <= HWLAYOUT_ENUM_MAX.
|
||||
// Enums - The array of enumeration items.
|
||||
//
|
||||
typedef struct _HWLAYOUT
|
||||
{
|
||||
HWNODE_TYPE TargetType;
|
||||
UINT32 TargetCount;
|
||||
UINT32 EnumCount;
|
||||
HWENUM Enums[HWLAYOUT_ENUM_MAX];
|
||||
|
||||
} HWLAYOUT;
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Holds the iteration state during the processing of an HWENUM
|
||||
//
|
||||
// Fields:
|
||||
// Start - The start value for the full list
|
||||
// Size - The count of elements for the full list
|
||||
// Current - The current offset in the full list
|
||||
// This is used for deriving the size of child HWENUM's
|
||||
//
|
||||
typedef struct _HWENUM_STATE
|
||||
{
|
||||
UINT32 Start;
|
||||
UINT32 Size;
|
||||
UINT32 Current;
|
||||
|
||||
} HWENUM_STATE;
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Holds the processing state of an HWLAYOUT
|
||||
//
|
||||
// Fields:
|
||||
// MinProc - The number of process that must be created.
|
||||
// MaxProc - The maximum number of processes to create.
|
||||
// ProcCount - The total number of processes created.
|
||||
// Enums - Array of states corresponding to the HWENUM in the layout
|
||||
// For example, item 0 represents the state for HWENUM 0 in the layout.
|
||||
//
|
||||
typedef struct _HWLAYOUT_STATE
|
||||
{
|
||||
UINT32 MinProc;
|
||||
UINT32 MaxProc;
|
||||
UINT32 ProcCount;
|
||||
HWENUM_STATE Enums[HWLAYOUT_ENUM_MAX];
|
||||
|
||||
} HWLAYOUT_STATE;
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Callback function invoked for each set of processes created during layout.
|
||||
//
|
||||
// Paramters:
|
||||
// pLayout - Pointer to the requested layout information.
|
||||
// pState - Pointer to the layout iteration state information.
|
||||
// pView - The view to use to get the location information.
|
||||
// location - The location within the view to assign the item.
|
||||
// pData - Opaque data passed from entry to callback functions.
|
||||
// pCount - On input, specifies the count of the processes to created.
|
||||
// On output, specifies the number of processes created.
|
||||
//
|
||||
// NOTE: Return S_FALSE to terminate process creation immediately.
|
||||
//
|
||||
typedef HRESULT ( __stdcall FN_HwLayoutProcessCallback) (
|
||||
__in const HWLAYOUT* pLayout,
|
||||
__in const HWLAYOUT_STATE* pState,
|
||||
__in const HWVIEW* pView,
|
||||
__in UINT32 location,
|
||||
__in PVOID pData,
|
||||
__inout UINT32* pCount
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Initialize hardware tree representing all machines.
|
||||
//
|
||||
// Parameters:
|
||||
// pcbTree - On input, current size of pTree
|
||||
// On output, the size of the buffer used.
|
||||
// if return code is HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)
|
||||
// the required size will be written here.
|
||||
// pTree - pointer to HWTREE buffer
|
||||
// pSummary - pointer to a machine's summary information.
|
||||
//
|
||||
// NOTE:
|
||||
// The memory is sequentially allocated, and can be marshalled with memcpy.
|
||||
//
|
||||
HRESULT
|
||||
HwTreeInitialize(
|
||||
_Inout_ UINT32* pcbTree,
|
||||
_Inout_updates_to_(*pcbTree,*pcbTree) HWTREE* pTree,
|
||||
_In_ const HWSUMMARY* pSummary
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Find the node id for the specified machine
|
||||
//
|
||||
// Parameters:
|
||||
// pTree - The tree to search for the machine node.
|
||||
// pInfo - The HostId field is used as the search key.
|
||||
//
|
||||
// Returns:
|
||||
// HWNODEID_NONE - if not found
|
||||
//
|
||||
inline UINT32
|
||||
HwTreeFindMachineNodeId(
|
||||
_In_ const HWTREE* pTree,
|
||||
_In_ const HWMACHINEINFO* pInfo
|
||||
)
|
||||
{
|
||||
UINT32 stride;
|
||||
for( UINT32 i = 0; i < pTree->Counts[HWNODE_TYPE_MACHINE]; i++ )
|
||||
{
|
||||
stride = i + pTree->Strides[HWNODE_TYPE_MACHINE];
|
||||
if( pTree->Nodes[ stride ].HostId == pInfo->HostId )
|
||||
{
|
||||
return stride;
|
||||
}
|
||||
}
|
||||
return HWNODEID_NONE;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Initialize the local HWSUMMARY information
|
||||
//
|
||||
// Parameters:
|
||||
// pcbSummary - On input, size of pSummary buffer
|
||||
// on output, size used.
|
||||
// if return code is HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)
|
||||
// the required count will be written here.
|
||||
// pSummary - The summary information to initialize.
|
||||
//
|
||||
HRESULT
|
||||
HwSummaryInitialize(
|
||||
_Inout_ UINT32* pcbSummary,
|
||||
_Inout_updates_bytes_to_(*pcbSummary, *pcbSummary) HWSUMMARY* pSummary
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Filter out the processor information in each processor group.
|
||||
//
|
||||
// Parameters:
|
||||
// pSummary - The summary information to filter.
|
||||
// pFilters - The core filters to apply
|
||||
//
|
||||
inline void
|
||||
HwSummaryFilter(
|
||||
_Inout_ HWSUMMARY* pSummary,
|
||||
_In_reads_(pSummary->Count) const UINT64 pFilters[]
|
||||
)
|
||||
{
|
||||
for( UINT32 i = 0; i < pSummary->Count; i++ )
|
||||
{
|
||||
pSummary->Infos[i].ActiveMask &= pFilters[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Initialize a HWVIEW from an HWTREE
|
||||
//
|
||||
// Parameters:
|
||||
// pcbView - On input, current size of pView
|
||||
// On output, the size of the buffer used.
|
||||
// if return code is HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)
|
||||
// the required size will be written here.
|
||||
// pView - pointer to HWVIEW buffer
|
||||
// pTree - Pointer to tree to base view on
|
||||
// pSummary - Pointer to a summary of machine.
|
||||
//
|
||||
HRESULT
|
||||
HwViewInitialize(
|
||||
_Inout_ UINT32* pcbView,
|
||||
_Out_writes_to_(*pcbView,*pcbView) HWVIEW* pView,
|
||||
_In_ const HWTREE* pTree,
|
||||
_In_ const HWSUMMARY* pSummary
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Process the specified layout using the specified tree
|
||||
//
|
||||
// Parameters:
|
||||
// pLayout - Pointer to layout description
|
||||
// pView - Pointer to the view
|
||||
// minProc - Minimum number of processes to create
|
||||
// maxProc - Maximum number of processes to create
|
||||
// pData - Opaque data pointer to hand to callback
|
||||
// pfn - Callback function to invoke for each iteration
|
||||
//
|
||||
HRESULT
|
||||
HwLayoutProcess(
|
||||
_In_ const HWLAYOUT* pLayout,
|
||||
_In_ const HWVIEW* pView,
|
||||
_In_ UINT32 minProc,
|
||||
_In_ UINT32 maxProc,
|
||||
_In_ PVOID pData,
|
||||
_In_ FN_HwLayoutProcessCallback* pfn
|
||||
);
|
||||
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// Represents the node types in the tree. Each value
|
||||
// corrisponds to depth in the HW tree.
|
||||
//
|
||||
typedef enum _HWNODE_TYPE
|
||||
{
|
||||
HWNODE_TYPE_WORLD = -1,
|
||||
HWNODE_TYPE_MACHINE = 0,
|
||||
HWNODE_TYPE_GROUP = 1,
|
||||
HWNODE_TYPE_NUMA = 2,
|
||||
HWNODE_TYPE_PCORE = 3,
|
||||
HWNODE_TYPE_LCORE = 4,
|
||||
|
||||
HWNODE_TYPE_MAX,
|
||||
|
||||
} HWNODE_TYPE;
|
||||
|
||||
|
||||
enum SMPD_AFFINITY_PLACEMENT
|
||||
{
|
||||
SMPD_AFFINITY_DISABLED = 0,
|
||||
SMPD_AFFINITY_SPREAD = 1,
|
||||
SMPD_AFFINITY_SEQUENTIAL = 2,
|
||||
SMPD_AFFINITY_BALANCED = 3,
|
||||
SMPD_AFFINITY_DEFAULT = SMPD_AFFINITY_SPREAD,
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef struct _AffinityOptions
|
||||
{
|
||||
BOOL isSet;
|
||||
BOOL isExplicit;
|
||||
BOOL isAuto;
|
||||
enum SMPD_AFFINITY_PLACEMENT placement;
|
||||
HWNODE_TYPE target;
|
||||
HWNODE_TYPE stride;
|
||||
INT affinityTableStyle;
|
||||
INT hwTableStyle;
|
||||
} AffinityOptions;
|
|
@ -0,0 +1,292 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "hwtree.h"
|
||||
#include "util.h"
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Utility function to initialize the specified node within the view.
|
||||
//
|
||||
// Parameters:
|
||||
// pView - pointer to the view to manipulate
|
||||
// index - index of the node with in the tree
|
||||
// type - the type to set on the node
|
||||
// parent - the parent ID of the node
|
||||
// previous - the previous node
|
||||
// treeNodeId - id of the node in the original tree
|
||||
//
|
||||
static void
|
||||
HwViewInitializeNode(
|
||||
_Inout_ HWVIEW* pView,
|
||||
_In_ UINT32 index,
|
||||
_In_ HWNODE_TYPE type,
|
||||
_In_ UINT32 parent,
|
||||
_In_ UINT32 previous,
|
||||
_In_ UINT32 treeNodeId
|
||||
)
|
||||
{
|
||||
pView->Nodes[index].Type = type;
|
||||
pView->Nodes[index].Parent = parent;
|
||||
pView->Nodes[index].FirstChild = HWNODEID_NONE;
|
||||
pView->Nodes[index].LastChild = HWNODEID_NONE;
|
||||
pView->Nodes[index].NextSibling = HWNODEID_NONE;
|
||||
pView->Nodes[index].PrevSibling = previous;
|
||||
|
||||
pView->Nodes[parent].LastChild = index;
|
||||
|
||||
if( previous == HWNODEID_NONE ||
|
||||
pView->Nodes[previous].Parent != parent )
|
||||
{
|
||||
pView->Nodes[parent].FirstChild = index;
|
||||
}
|
||||
else
|
||||
{
|
||||
pView->Nodes[previous].NextSibling = index;
|
||||
}
|
||||
|
||||
pView->Nodes[index].NodeId = treeNodeId;
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Initialize the subtree elements of the view
|
||||
//
|
||||
// Parameters:
|
||||
// pView - pointer to the view to initialize
|
||||
// pStrides - array of offsets for each level in the view
|
||||
// pEnds - array of end offsets for each level in the view
|
||||
// parentId - the node id of the parent to add children for
|
||||
//
|
||||
static HRESULT
|
||||
HwViewInitializeSubTree(
|
||||
_Inout_ HWVIEW* pView,
|
||||
_Inout_updates_(HWNODE_MAX_DEPTH) UINT32 pStrides[],
|
||||
_Inout_updates_(HWNODE_MAX_DEPTH) UINT32 pEnds[],
|
||||
_In_ UINT32 parentId,
|
||||
_In_ const HWSUMMARY* pSummary
|
||||
)
|
||||
{
|
||||
UINT32 last = HWNODEID_NONE;
|
||||
UINT32 current = pView->Tree->Nodes[parentId].FirstChild;
|
||||
UINT32 end = pView->Tree->Nodes[parentId].LastChild;
|
||||
|
||||
HWNODE_TYPE depth = pView->Tree->Nodes[current].Type;
|
||||
|
||||
Assert(depth >= HWNODE_TYPE_GROUP);
|
||||
Assert( nullptr != pSummary );
|
||||
|
||||
while( current <= end )
|
||||
{
|
||||
if( pStrides[depth] >= pEnds[depth] )
|
||||
{
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
//
|
||||
// Verify that the current element has not been filtered by the HWSUMMARY.
|
||||
//
|
||||
Assert( pSummary->Count >= (UINT32)pView->Tree->Nodes[ current ].Affinity.GroupId );
|
||||
if( 0 == ( pView->Tree->Nodes[current].Affinity.Mask & pSummary->Infos[pView->Tree->Nodes[ current ].Affinity.GroupId].ActiveMask ) )
|
||||
{
|
||||
current++;
|
||||
continue;
|
||||
}
|
||||
|
||||
HwViewInitializeNode(
|
||||
pView,
|
||||
pStrides[depth],
|
||||
depth,
|
||||
pStrides[depth - 1],
|
||||
last,
|
||||
current
|
||||
);
|
||||
|
||||
if( depth + 1 < HWNODE_MAX_DEPTH )
|
||||
{
|
||||
HRESULT hr = HwViewInitializeSubTree( pView, pStrides, pEnds, current, pSummary );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
last = pStrides[depth];
|
||||
pStrides[depth]++;
|
||||
pView->Counts[depth]++;
|
||||
current++;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Utility function to collect the node counts for each depth and the total count
|
||||
// for the specified set of machines in the tree.
|
||||
//
|
||||
// Paramters:
|
||||
// pTree - pointer to the tree to scan
|
||||
// pMachines - The linked list of machine information
|
||||
// pCounts - array to recieve the counts at each depth
|
||||
//
|
||||
// Returns:
|
||||
// The total number of nodes required in the View
|
||||
//
|
||||
static UINT32
|
||||
HwViewCalculateCountNodes(
|
||||
_In_ const HWTREE* pTree,
|
||||
_Out_writes_(HWNODE_MAX_DEPTH) UINT32 pCounts[]
|
||||
)
|
||||
{
|
||||
pCounts[HWNODE_TYPE_MACHINE] = 0;
|
||||
pCounts[HWNODE_TYPE_GROUP] = 0;
|
||||
pCounts[HWNODE_TYPE_NUMA] = 0;
|
||||
pCounts[HWNODE_TYPE_PCORE] = 0;
|
||||
pCounts[HWNODE_TYPE_LCORE] = 0;
|
||||
|
||||
UINT32 first;
|
||||
UINT32 last;
|
||||
UINT32 depth;
|
||||
UINT32 machineId;
|
||||
|
||||
machineId = HWMACHINEID_SELF;
|
||||
|
||||
Assert(machineId >= pTree->Strides[HWNODE_TYPE_MACHINE] );
|
||||
Assert(machineId < pTree->Strides[HWNODE_TYPE_MACHINE] + pTree->Counts[HWNODE_TYPE_MACHINE] );
|
||||
Assert(pTree->Nodes[machineId].Type == HWNODE_TYPE_MACHINE);
|
||||
|
||||
depth = static_cast<UINT32>( HWNODE_TYPE_GROUP );
|
||||
first = pTree->Nodes[machineId].FirstChild;
|
||||
last = pTree->Nodes[machineId].LastChild;
|
||||
|
||||
do
|
||||
{
|
||||
Assert( first != HWNODEID_NONE );
|
||||
Assert( last != HWNODEID_NONE );
|
||||
|
||||
pCounts[depth] += last - first + 1;
|
||||
first = pTree->Nodes[first].FirstChild;
|
||||
last = pTree->Nodes[last].LastChild;
|
||||
|
||||
} while( ++depth < HWNODE_MAX_DEPTH );
|
||||
|
||||
pCounts[HWNODE_TYPE_MACHINE]++;
|
||||
|
||||
//
|
||||
// Include 1 extra for the WORLD node.
|
||||
//
|
||||
return 1 +
|
||||
pCounts[HWNODE_TYPE_MACHINE] +
|
||||
pCounts[HWNODE_TYPE_GROUP] +
|
||||
pCounts[HWNODE_TYPE_NUMA] +
|
||||
pCounts[HWNODE_TYPE_PCORE] +
|
||||
pCounts[HWNODE_TYPE_LCORE];
|
||||
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Initialize a HWVIEW from an HWTREE
|
||||
//
|
||||
// Parameters:
|
||||
// pcbView - On input, current size of pView
|
||||
// On output, the size of the buffer used.
|
||||
// if return code is HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)
|
||||
// the required size will be written here.
|
||||
// pView - pointer to HWVIEW buffer
|
||||
// pTree - Pointer to tree to base view on
|
||||
// pMachines - The linked list of machine information
|
||||
//
|
||||
HRESULT
|
||||
HwViewInitialize(
|
||||
_Inout_ UINT32* pcbView,
|
||||
_Out_writes_to_(*pcbView,*pcbView) HWVIEW* pView,
|
||||
_In_ const HWTREE* pTree,
|
||||
_In_ const HWSUMMARY* pSummary
|
||||
)
|
||||
{
|
||||
UINT32 machineId;
|
||||
UINT32 strides[HWNODE_MAX_DEPTH];
|
||||
UINT32 ends[HWNODE_MAX_DEPTH];
|
||||
UINT32 last = HWNODEID_NONE;
|
||||
|
||||
UINT32 nNodes = HwViewCalculateCountNodes( pTree, ends );
|
||||
|
||||
UINT32 cb = sizeof(*pView) - sizeof(pView->Nodes) + ( sizeof(pView->Nodes[0]) * nNodes );
|
||||
if( cb > *pcbView )
|
||||
{
|
||||
*pcbView = cb;
|
||||
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
|
||||
//
|
||||
// Update the stride table.
|
||||
//
|
||||
strides[HWNODE_TYPE_MACHINE]= 1;
|
||||
strides[HWNODE_TYPE_GROUP] = strides[HWNODE_TYPE_MACHINE] + ends[HWNODE_TYPE_MACHINE];
|
||||
strides[HWNODE_TYPE_NUMA] = strides[HWNODE_TYPE_GROUP] + ends[HWNODE_TYPE_GROUP];
|
||||
strides[HWNODE_TYPE_PCORE] = strides[HWNODE_TYPE_NUMA] + ends[HWNODE_TYPE_NUMA];
|
||||
strides[HWNODE_TYPE_LCORE] = strides[HWNODE_TYPE_PCORE] + ends[HWNODE_TYPE_PCORE];
|
||||
|
||||
pView->Strides[HWNODE_TYPE_MACHINE] = strides[HWNODE_TYPE_MACHINE];
|
||||
pView->Strides[HWNODE_TYPE_GROUP] = strides[HWNODE_TYPE_GROUP];
|
||||
pView->Strides[HWNODE_TYPE_NUMA] = strides[HWNODE_TYPE_NUMA];
|
||||
pView->Strides[HWNODE_TYPE_PCORE] = strides[HWNODE_TYPE_PCORE];
|
||||
pView->Strides[HWNODE_TYPE_LCORE] = strides[HWNODE_TYPE_LCORE];
|
||||
|
||||
pView->Counts[HWNODE_TYPE_MACHINE] = 0;
|
||||
pView->Counts[HWNODE_TYPE_GROUP] = 0;
|
||||
pView->Counts[HWNODE_TYPE_NUMA] = 0;
|
||||
pView->Counts[HWNODE_TYPE_PCORE] = 0;
|
||||
pView->Counts[HWNODE_TYPE_LCORE] = 0;
|
||||
|
||||
//
|
||||
// update the "ends" to be offset from the strides so we don't
|
||||
// have to track the start of the chain through the iteration.
|
||||
//
|
||||
ends[HWNODE_TYPE_MACHINE] += strides[HWNODE_TYPE_MACHINE];
|
||||
ends[HWNODE_TYPE_GROUP] += strides[HWNODE_TYPE_GROUP];
|
||||
ends[HWNODE_TYPE_NUMA] += strides[HWNODE_TYPE_NUMA];
|
||||
ends[HWNODE_TYPE_PCORE] += strides[HWNODE_TYPE_PCORE];
|
||||
ends[HWNODE_TYPE_LCORE] += strides[HWNODE_TYPE_LCORE];
|
||||
|
||||
pView->Nodes[HWNODEID_WORLD].Type = HWNODE_TYPE_WORLD;
|
||||
pView->Nodes[HWNODEID_WORLD].Parent = HWNODEID_NONE;
|
||||
pView->Nodes[HWNODEID_WORLD].NextSibling = HWNODEID_NONE;
|
||||
pView->Nodes[HWNODEID_WORLD].FirstChild = HWNODEID_NONE;
|
||||
pView->Nodes[HWNODEID_WORLD].PrevSibling = HWNODEID_NONE;
|
||||
pView->Nodes[HWNODEID_WORLD].LastChild = HWNODEID_NONE;
|
||||
|
||||
pView->Tree = pTree;
|
||||
|
||||
if( strides[HWNODE_TYPE_MACHINE] >= ends[HWNODE_TYPE_MACHINE] )
|
||||
{
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
machineId = HWMACHINEID_SELF;
|
||||
|
||||
HwViewInitializeNode(
|
||||
pView,
|
||||
strides[HWNODE_TYPE_MACHINE],
|
||||
HWNODE_TYPE_MACHINE,
|
||||
HWNODEID_WORLD,
|
||||
last,
|
||||
machineId
|
||||
);
|
||||
|
||||
|
||||
HRESULT hr = HwViewInitializeSubTree(pView, strides, ends, machineId, pSummary);
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
last = strides[HWNODE_TYPE_MACHINE];
|
||||
strides[HWNODE_TYPE_MACHINE]++;
|
||||
pView->Counts[HWNODE_TYPE_MACHINE]++;
|
||||
|
||||
*pcbView = cb;
|
||||
return S_OK;
|
||||
}
|
|
@ -0,0 +1,237 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "shlobj.h"
|
||||
#include "Shlwapi.h"
|
||||
#include "mpistr.h"
|
||||
|
||||
//
|
||||
// A global shared memory for IPC. Allows ipc among different users on the same computer,
|
||||
// with no specific previlige like SeCrateGlobalPrevilige. Processes communicate over
|
||||
// a temporary, i.e no disk flush, delete-on-close file mapped view.
|
||||
//
|
||||
|
||||
class GlobalShmRegion
|
||||
{
|
||||
private:
|
||||
BOOL isReadOnly;
|
||||
HANDLE file;
|
||||
HANDLE fileMap;
|
||||
void* pView;
|
||||
WCHAR fullRegionName[MAX_PATH];
|
||||
|
||||
//
|
||||
// Non-copyable
|
||||
//
|
||||
GlobalShmRegion(const GlobalShmRegion&);
|
||||
GlobalShmRegion& operator = (const GlobalShmRegion&);
|
||||
|
||||
HRESULT CreateFullRegionName(_In_z_ PCWSTR regionName)
|
||||
{
|
||||
//
|
||||
// The file system directory that contains application data for all users
|
||||
//
|
||||
HRESULT result = SHGetFolderPathW(nullptr, CSIDL_COMMON_APPDATA, nullptr, 0, fullRegionName);
|
||||
if(result != S_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// SHGetFolderPathW returns full path without a trailing backslash.
|
||||
//
|
||||
size_t fullPathLen = MPIU_Strlen(fullRegionName) + 1 + MPIU_Strlen(regionName);
|
||||
if (fullPathLen >= _countof(fullRegionName))
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
OACR_WARNING_SUPPRESS(UNSAFE_STRING_FUNCTION, "Buffer length is already checked.");
|
||||
BOOL appended = PathAppendW(fullRegionName, regionName);
|
||||
return appended ? S_OK : E_FAIL;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
GlobalShmRegion():
|
||||
isReadOnly(FALSE),
|
||||
file(INVALID_HANDLE_VALUE),
|
||||
fileMap(nullptr),
|
||||
pView(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
~GlobalShmRegion()
|
||||
{
|
||||
if(pView != nullptr)
|
||||
{
|
||||
UnmapViewOfFile(pView);
|
||||
}
|
||||
if(fileMap != nullptr)
|
||||
{
|
||||
CloseHandle(fileMap);
|
||||
}
|
||||
if(file != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DWORD Open(_In_z_ PCWSTR regionName)
|
||||
{
|
||||
if(pView != nullptr)
|
||||
{
|
||||
return ERROR_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
isReadOnly = TRUE;
|
||||
|
||||
HRESULT result = CreateFullRegionName(regionName);
|
||||
if(result != S_OK)
|
||||
{
|
||||
return ERROR_INVALID_NAME;
|
||||
}
|
||||
|
||||
file = CreateFileW(
|
||||
fullRegionName,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
|
||||
nullptr,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_TEMPORARY,
|
||||
nullptr
|
||||
);
|
||||
|
||||
if(file == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
fileMap = CreateFileMappingW(file, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||
|
||||
if(fileMap ==nullptr)
|
||||
{
|
||||
CloseHandle(file);
|
||||
file = nullptr;
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
pView = MapViewOfFile(
|
||||
fileMap,
|
||||
FILE_MAP_READ,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
);
|
||||
if( pView == nullptr )
|
||||
{
|
||||
CloseHandle(file);
|
||||
CloseHandle(fileMap);
|
||||
file = nullptr;
|
||||
fileMap = nullptr;
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
DWORD Create(_In_z_ PCWSTR regionName, UINT32 regionSize)
|
||||
{
|
||||
if(pView != nullptr)
|
||||
{
|
||||
return ERROR_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
isReadOnly = FALSE;
|
||||
|
||||
HRESULT result = CreateFullRegionName(regionName);
|
||||
if(result != S_OK)
|
||||
{
|
||||
return ERROR_INVALID_NAME;
|
||||
}
|
||||
|
||||
SECURITY_ATTRIBUTES security;
|
||||
ZeroMemory(&security, sizeof(security));
|
||||
security.nLength = sizeof(security);
|
||||
ConvertStringSecurityDescriptorToSecurityDescriptorW(
|
||||
L"D:(A;;GA;;;WD)",
|
||||
SDDL_REVISION_1,
|
||||
&security.lpSecurityDescriptor,
|
||||
NULL);
|
||||
|
||||
file = CreateFileW(
|
||||
fullRegionName,
|
||||
GENERIC_READ|GENERIC_WRITE,
|
||||
FILE_SHARE_READ,
|
||||
&security,
|
||||
CREATE_NEW,
|
||||
FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
|
||||
NULL
|
||||
);
|
||||
|
||||
LocalFree(security.lpSecurityDescriptor);
|
||||
|
||||
if(file == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
fileMap = CreateFileMappingW(
|
||||
file,
|
||||
nullptr,
|
||||
PAGE_READWRITE,
|
||||
0,
|
||||
regionSize,
|
||||
nullptr
|
||||
);
|
||||
|
||||
if( fileMap == nullptr )
|
||||
{
|
||||
CloseHandle(file);
|
||||
file = nullptr;
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
pView = MapViewOfFile(
|
||||
fileMap,
|
||||
FILE_MAP_WRITE,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
if(pView != nullptr)
|
||||
{
|
||||
ZeroMemory(pView, regionSize);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
CloseHandle(file);
|
||||
CloseHandle(fileMap);
|
||||
file = nullptr;
|
||||
fileMap = nullptr;
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
|
||||
const void* ReadPtr() const
|
||||
{
|
||||
return pView;
|
||||
}
|
||||
|
||||
|
||||
void* WritePtr()
|
||||
{
|
||||
if(isReadOnly)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return pView;
|
||||
}
|
||||
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "kernel32util.h"
|
||||
#include "util.h"
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Global to indicate if we should use Win7+ features.
|
||||
//
|
||||
// NOTE:
|
||||
// This is not static so we can manipulate this bit from unit tests
|
||||
//
|
||||
BOOL g_IsWin7OrGreater = CheckOSVersion(6,1);
|
||||
BOOL g_IsWin8OrGreater = CheckOSVersion(6,2);
|
||||
|
||||
Kernel32 Kernel32::Methods;
|
|
@ -0,0 +1,170 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
#include <oacr.h>
|
||||
#include <assert.h>
|
||||
//
|
||||
// Make some shorter names.
|
||||
//
|
||||
typedef SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX SLPIEX;
|
||||
|
||||
|
||||
typedef _Success_(return==TRUE) BOOL ( WINAPI FN_GetLogicalProcessorInformationEx )(
|
||||
_In_ LOGICAL_PROCESSOR_RELATIONSHIP relationshipType,
|
||||
_Out_writes_to_opt_(*pReturnedLength,*pReturnedLength) PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX pBuffer,
|
||||
_Inout_ PDWORD pReturnedLength
|
||||
);
|
||||
|
||||
|
||||
typedef _Success_(return==TRUE) BOOL ( WINAPI FN_GetLogicalProcessorInformationEx )(
|
||||
_In_ LOGICAL_PROCESSOR_RELATIONSHIP relationshipType,
|
||||
_Out_writes_to_opt_(*pReturnedLength,*pReturnedLength) PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX pBuffer,
|
||||
_Inout_ PDWORD pReturnedLength
|
||||
);
|
||||
|
||||
typedef _Success_(return==TRUE) BOOL ( WINAPI FN_SetThreadGroupAffinity)(
|
||||
_In_ HANDLE hThread,
|
||||
_In_ const GROUP_AFFINITY *GroupAffinity,
|
||||
_Out_opt_ PGROUP_AFFINITY PreviousGroupAffinity
|
||||
);
|
||||
|
||||
typedef _Success_(return==TRUE) BOOL (WINAPI FN_GetNumaNodeProcessorMaskEx) (
|
||||
_In_ USHORT Node,
|
||||
_Out_ PGROUP_AFFINITY ProcessorMask
|
||||
);
|
||||
|
||||
typedef _Success_(return==TRUE) BOOL (WINAPI FN_GetProcessGroupAffinity) (
|
||||
_In_ HANDLE hProcess,
|
||||
_Inout_ PUSHORT GroupCount,
|
||||
_Out_writes_to_(*GroupCount,*GroupCount) PUSHORT GroupArray
|
||||
);
|
||||
|
||||
|
||||
typedef _Success_(return == TRUE) BOOL (WINAPI FN_InitializeProcThreadAttributeList) (
|
||||
_In_opt_ LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
|
||||
_In_ DWORD dwAttributeCount,
|
||||
_In_ DWORD dwFlags,
|
||||
_Inout_ PSIZE_T lpSize
|
||||
);
|
||||
|
||||
|
||||
typedef _Success_(return == TRUE) BOOL(WINAPI FN_UpdateProcThreadAttribute) (
|
||||
_In_ LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
|
||||
_In_ DWORD dwFlags,
|
||||
_In_ DWORD_PTR Attribute,
|
||||
_In_ PVOID lpValue,
|
||||
_In_ SIZE_T cbSize,
|
||||
_In_opt_ PVOID lpPreviousValue,
|
||||
_In_opt_ PSIZE_T lpReturnSize
|
||||
);
|
||||
|
||||
|
||||
typedef _Success_(return==TRUE) BOOL (WINAPI FN_WaitOnAddress)(
|
||||
_In_ VOID volatile *Address,
|
||||
_In_ PVOID CompareAddress,
|
||||
_In_ SIZE_T AddressSize,
|
||||
_In_opt_ DWORD dwMilliseconds
|
||||
);
|
||||
|
||||
|
||||
typedef VOID (WINAPI FN_WakeByAddressAll)(
|
||||
_In_ PVOID Address
|
||||
);
|
||||
|
||||
|
||||
extern BOOL g_IsWin7OrGreater;
|
||||
extern BOOL g_IsWin8OrGreater;
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Singleton class to load and GetProcAddress
|
||||
//
|
||||
struct Kernel32
|
||||
{
|
||||
static Kernel32 Methods;
|
||||
|
||||
FN_GetLogicalProcessorInformationEx* GetLogicalProcessorInformationEx;
|
||||
FN_SetThreadGroupAffinity* SetThreadGroupAffinity;
|
||||
FN_GetNumaNodeProcessorMaskEx* GetNumaNodeProcessorMaskEx;
|
||||
FN_GetProcessGroupAffinity* GetProcessGroupAffinity;
|
||||
FN_InitializeProcThreadAttributeList* InitializeProcThreadAttributeList;
|
||||
FN_UpdateProcThreadAttribute* UpdateProcThreadAttribute;
|
||||
FN_WaitOnAddress* WaitOnAddress;
|
||||
FN_WakeByAddressAll* WakeByAddressAll;
|
||||
|
||||
|
||||
private:
|
||||
Kernel32()
|
||||
{
|
||||
HMODULE kernel32 = ::GetModuleHandleW(L"kernel32");
|
||||
if(kernel32 != nullptr)
|
||||
{
|
||||
GetLogicalProcessorInformationEx = reinterpret_cast<FN_GetLogicalProcessorInformationEx*>(
|
||||
::GetProcAddress(
|
||||
kernel32,
|
||||
"GetLogicalProcessorInformationEx"
|
||||
) );
|
||||
SetThreadGroupAffinity = reinterpret_cast<FN_SetThreadGroupAffinity*>(
|
||||
::GetProcAddress(
|
||||
kernel32,
|
||||
"SetThreadGroupAffinity"
|
||||
) );
|
||||
GetNumaNodeProcessorMaskEx = reinterpret_cast<FN_GetNumaNodeProcessorMaskEx*>(
|
||||
::GetProcAddress(
|
||||
kernel32,
|
||||
"GetNumaNodeProcessorMaskEx"
|
||||
) );
|
||||
GetProcessGroupAffinity = reinterpret_cast<FN_GetProcessGroupAffinity*>(
|
||||
::GetProcAddress(
|
||||
kernel32,
|
||||
"GetProcessGroupAffinity"
|
||||
) );
|
||||
InitializeProcThreadAttributeList = reinterpret_cast<FN_InitializeProcThreadAttributeList*>(
|
||||
::GetProcAddress(
|
||||
kernel32,
|
||||
"InitializeProcThreadAttributeList"
|
||||
) );
|
||||
UpdateProcThreadAttribute = reinterpret_cast<FN_UpdateProcThreadAttribute*>(
|
||||
::GetProcAddress(
|
||||
kernel32,
|
||||
"UpdateProcThreadAttribute"
|
||||
) );
|
||||
}
|
||||
|
||||
assert(!g_IsWin7OrGreater || GetLogicalProcessorInformationEx != nullptr);
|
||||
assert(!g_IsWin7OrGreater || SetThreadGroupAffinity != nullptr);
|
||||
assert(!g_IsWin7OrGreater || GetNumaNodeProcessorMaskEx != nullptr);
|
||||
assert(!g_IsWin7OrGreater || GetProcessGroupAffinity != nullptr);
|
||||
assert(!g_IsWin7OrGreater || InitializeProcThreadAttributeList != nullptr);
|
||||
assert(!g_IsWin7OrGreater || UpdateProcThreadAttribute != nullptr);
|
||||
|
||||
if (g_IsWin8OrGreater)
|
||||
{
|
||||
HMODULE kernelBase = ::GetModuleHandleW(L"kernelbase");
|
||||
if(kernelBase != nullptr)
|
||||
{
|
||||
WakeByAddressAll = reinterpret_cast<FN_WakeByAddressAll*>(
|
||||
::GetProcAddress(
|
||||
kernelBase,
|
||||
"WakeByAddressAll"
|
||||
));
|
||||
|
||||
WaitOnAddress = reinterpret_cast<FN_WaitOnAddress*>(
|
||||
::GetProcAddress(
|
||||
kernelBase,
|
||||
"WaitOnAddress"
|
||||
));
|
||||
}
|
||||
|
||||
assert(WakeByAddressAll != nullptr);
|
||||
assert(WaitOnAddress != nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
WakeByAddressAll = nullptr;
|
||||
WaitOnAddress = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,97 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<Import Project="$(SrcRoot)\mpi.props" />
|
||||
|
||||
<PropertyGroup Label="Globals">
|
||||
<TargetName>mpicommon</TargetName>
|
||||
<ProjectGuid>{990e2ef8-f801-4101-a7b5-2d561fb6667b}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Configuration">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<IntDirSharingDetected>None</IntDirSharingDetected>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>$(IntDir)\pch_hdr.src</PrecompiledHeaderOutputFile>
|
||||
<AdditionalIncludeDirectories>
|
||||
%(AdditionalIncludeDirectories);
|
||||
$(MPI_SRC_ROOT)\common\$(O);
|
||||
</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ClCompile Include=".\argstr.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
|
||||
<ClCompile Include=".\dbg_printf.cpp" />
|
||||
<ClCompile Include=".\dump.cpp" />
|
||||
<ClCompile Include=".\errutil.cpp" />
|
||||
<ClCompile Include=".\ex.cpp" />
|
||||
<ClCompile Include=".\hwinfowin6.cpp" />
|
||||
<ClCompile Include=".\hwinfowin7.cpp" />
|
||||
<ClCompile Include=".\hwlayout.cpp" />
|
||||
<ClCompile Include=".\hwsummary.cpp" />
|
||||
<ClCompile Include=".\hwtree.cpp" />
|
||||
<ClCompile Include=".\hwview.cpp" />
|
||||
<ClCompile Include=".\kernel32util.cpp" />
|
||||
<ClCompile Include=".\msgprint.cpp" />
|
||||
<ClCompile Include=".\mpilock.cpp" />
|
||||
<ClCompile Include=".\mpistr.cpp" />
|
||||
<ClCompile Include=".\parsing.cpp" />
|
||||
<ClCompile Include=".\sock.cpp" />
|
||||
<ClCompile Include=".\util.cpp" />
|
||||
<ClCompile Include=".\svcutils.cpp" />
|
||||
<ClCompile Include=".\rpcutil.cpp" />
|
||||
<ClCompile Include=".\mpiutil.cpp" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<PostBuildEvent>
|
||||
<Command>robocopy .\ $(BinariesBuildTypeArchDirectory)\$(MPI_BIN_DESTINATION) mpitrace.man
|
||||
set rc=%errorlevel%
|
||||
if not %rc%==1 exit %rce% else exit 0</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="traceManifest.vcxproj">
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Note that the input of this target is not just extracterrmsgs/errnames but rather
|
||||
all of the core code base's C/CPP files. To ensure correct rebuild, we
|
||||
will need to manually build this target if there are additional error messages -->
|
||||
<Target Name="GenerateMPIErrorFiles"
|
||||
BeforeTargets="BeforeClCompile"
|
||||
Inputs="$(MPI_SRC_ROOT)\common\extracterrmsgs;$(MPI_SRC_ROOT)\common\errnames.txt"
|
||||
Outputs="$(O)\defmsg.h">
|
||||
<PropertyGroup>
|
||||
<FileToSkip Condition="'$(BuildArchitecture)'=='amd64'">$(BaseIntermediateOutputPath)i386\errtest.c</FileToSkip>
|
||||
<FileToSkip Condition="'$(BuildArchitecture)'=='i386'">$(BaseIntermediateOutputPath)amd64\errtest.c</FileToSkip>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<DirectoriesToParse Include="$(MPI_SRC_ROOT)\common"/>
|
||||
<DirectoriesToParse Include="$(MPI_SRC_ROOT)\msmpi"/>
|
||||
<DirectoriesToParse Include="$(MPI_SRC_ROOT)\pmilib"/>
|
||||
<DirectoriesToParse Include="$(MPI_SRC_ROOT)\mpiexec"/>
|
||||
<DirectoriesToParse Include="$(MPI_SRC_ROOT)\smpd"/>
|
||||
<DirectoriesToParse Include="$(SrcRoot)\launchSvc"/>
|
||||
</ItemGroup>
|
||||
<Exec ConsoleToMsBuild="true"
|
||||
IgnoreExitCode="true"
|
||||
Command="perl $(MPI_SRC_ROOT)\common\extracterrmsgs -skip=$(FileToSkip) -outpath=$(O) -outfile=defmsg.h -testfile=errtest.c @(DirectoriesToParse,' ')"/>
|
||||
</Target>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,191 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
*
|
||||
* (C) 2001 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
#if !defined(MPITYPEDEFS_H_INCLUDED)
|
||||
#define MPITYPEDEFS_H_INCLUDED
|
||||
|
||||
/* Define if addresses are larger than Fortran integers */
|
||||
#ifdef _WIN64
|
||||
#define HAVE_AINT_LARGER_THAN_FINT
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have `alloca', as a function or macro. */
|
||||
#define HAVE_ALLOCA 1
|
||||
|
||||
/* Define if debugger support is included */
|
||||
/* #undef HAVE_DEBUGGER_SUPPORT */
|
||||
|
||||
/* Define if F90 type routines available */
|
||||
/* #undef HAVE_F90_TYPE_ROUTINES */
|
||||
|
||||
/* Define if Fortran is supported */
|
||||
/* Defined as a compiler directive, see mpich2sources.inc */
|
||||
/* #undef HAVE_FORTRAN_BINDING */
|
||||
|
||||
/* Controls byte alignment of structures (for aligning allocated structures)
|
||||
*/
|
||||
#define HAVE_MAX_STRUCT_ALIGNMENT 8
|
||||
|
||||
/* Define if a name publishing service is available */
|
||||
#define HAVE_NAMEPUB_SERVICE 1
|
||||
|
||||
/* Define if the Fortran types are not available in C */
|
||||
/* #undef HAVE_NO_FORTRAN_MPI_TYPES_IN_C */
|
||||
|
||||
/* Define as the name of the debugger support library */
|
||||
/* #undef MPICH_INFODLL_LOC */
|
||||
|
||||
/* Level of thread support selected at compile time */
|
||||
#ifdef MPICH_MULTITHREADED
|
||||
#define MPICH_THREAD_LEVEL MPI_THREAD_MULTIPLE
|
||||
#else
|
||||
#define MPICH_THREAD_LEVEL MPI_THREAD_SERIALIZED
|
||||
#endif
|
||||
|
||||
/* C type to use for MPI_INTEGER16 */
|
||||
/* #undef MPIR_INTEGER16_CTYPE */
|
||||
|
||||
/* C type to use for MPI_REAL2 */
|
||||
/* #undef MPIR_REAL2_CTYPE */
|
||||
|
||||
/* C type to use for MPI_REAL16 */
|
||||
/* #undef MPIR_REAL16_CTYPE */
|
||||
|
||||
/* C99 types available for MPI_C_XXX */
|
||||
/* #undef MPIR_C99_TYPES */
|
||||
|
||||
/* Define if alloca should be used if available */
|
||||
/* #undef USE_ALLOCA */
|
||||
|
||||
/* Define to use ='s and spaces in the string utilities. */
|
||||
#define USE_HUMAN_READABLE_TOKENS 1
|
||||
|
||||
/* if C does not support restrict */
|
||||
#define restrict
|
||||
|
||||
/* The following are defined as a compiler directive, see mpich2sources.inc */
|
||||
/* Added here to make it easier to search for the define */
|
||||
/*
|
||||
#define USE_MPI_FOR_NMPI
|
||||
#define HAVE_FORTRAN_BINDING
|
||||
#define MPIDI_CH3_HAS_NO_DYNAMIC_PROCESS
|
||||
*/
|
||||
|
||||
|
||||
#ifndef EXTERN_C
|
||||
#if defined(__cplusplus)
|
||||
#define EXTERN_C extern "C"
|
||||
#else
|
||||
#define EXTERN_C extern
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _PREFIX_
|
||||
EXTERN_C void __pfx_assert(bool, const char*);
|
||||
#undef __analysis_assert
|
||||
#define __analysis_assert(expr) __pfx_assert(expr, "")
|
||||
#else
|
||||
#ifndef __analysis_assert
|
||||
#define __analysis_assert(expr)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _PREFIX_
|
||||
EXTERN_C void __pfx_assume(bool, const char*);
|
||||
#undef __analysis_assume
|
||||
#define __analysis_assume(expr) __pfx_assume(expr, "")
|
||||
#elif _PREFAST_
|
||||
#undef __analysis_assume
|
||||
#define __analysis_assume(expr) __assume(expr)
|
||||
#else
|
||||
#ifndef __analysis_assume
|
||||
#define __analysis_assume(expr)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __midl
|
||||
typedef int MPI_RESULT;
|
||||
#else
|
||||
typedef _Check_return_ _Return_type_success_(return == MPI_SUCCESS) int MPI_RESULT;
|
||||
#endif
|
||||
|
||||
|
||||
/* Set to a type that can express the size of a send/receive buffer */
|
||||
typedef unsigned int MPIU_Bsize_t;
|
||||
#define MPIU_BSIZE_MAX UINT_MAX
|
||||
|
||||
typedef MPIU_Bsize_t MPIDI_msg_sz_t;
|
||||
#define MPIDI_MSG_SZ_MAX MPIU_BSIZE_MAX
|
||||
|
||||
|
||||
/* Use the MPIU_PtrToXXX macros to convert pointers to and from integer types */
|
||||
|
||||
/* The Microsoft compiler will not allow casting of different sized types
|
||||
* without
|
||||
* printing a compiler warning. Using these macros allows compiler specific
|
||||
* type casting and avoids the warning output. These macros should only be used
|
||||
* in code that can handle loss of bits.
|
||||
*/
|
||||
|
||||
/* PtrToInt converts a pointer to a int type, truncating bits if necessary */
|
||||
#define MPIU_PtrToInt PtrToInt
|
||||
|
||||
/* PtrToAint converts a pointer to an MPI_Aint type, truncating bits if necessary */
|
||||
#define MPIU_PtrToAint(a) ((MPI_Aint)(INT_PTR) (a) )
|
||||
|
||||
/* IntToPtr converts a int to a pointer type, extending bits if necessary */
|
||||
#define MPIU_IntToPtr IntToPtr
|
||||
|
||||
|
||||
//
|
||||
// Constant used to define the maximum number of characters in the hostname
|
||||
// string placed into the PMI KVS when publishing our node id.
|
||||
//
|
||||
#if (!defined MAXHOSTNAMELEN) && (!defined MAX_HOSTNAME_LEN)
|
||||
#define MAX_HOSTNAME_LEN 256
|
||||
#elif !defined MAX_HOSTNAME_LEN
|
||||
#define MAX_HOSTNAME_LEN MAXHOSTNAMELEN
|
||||
#endif
|
||||
|
||||
#define MSMPI_VER_MAJOR( _v ) (_v >> 24)
|
||||
#define MSMPI_VER_MINOR( _v ) ((_v >> 16) & 0xFF)
|
||||
#define MSMPI_VER_BUILD( _v ) (_v & 0xFFFF)
|
||||
#if MSMPI_IS_RTM
|
||||
#define MSMPI_BUILD_LABEL L""
|
||||
#else
|
||||
#define MSMPI_BUILD_LABEL L" [PRE-RELEASE]"
|
||||
#endif
|
||||
|
||||
//
|
||||
// This is the maximum length of an environment variable according
|
||||
// to platform specification.
|
||||
//
|
||||
#define MAX_ENV_LENGTH 32767
|
||||
|
||||
#define MSMPI_MAX_RANKS 32768
|
||||
|
||||
#define MSMPI_MAX_TRANSFER_SIZE INT_MAX
|
||||
|
||||
//
|
||||
// Maximum number of connection retires in case of errors. Applies to both sockets and ND.
|
||||
//
|
||||
#define MSMPI_DEFAULT_CONNECT_RETRIES 5
|
||||
|
||||
//
|
||||
// This string identifies the service_name in spn construction
|
||||
//
|
||||
#define MSMPI_SPN_SERVICE_NAME L"msmpi"
|
||||
|
||||
//
|
||||
// Cast definition to help flag places we use potentially truncate but shouldn't.
|
||||
//
|
||||
#define fixme_cast static_cast
|
||||
|
||||
#endif /* !defined(MPITYPEDEFS_H_INCLUDED) */
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef MPIDUMP_H_INCLUDED
|
||||
#define MPIDUMP_H_INCLUDED
|
||||
|
||||
#include <dbghelp.h>
|
||||
|
||||
//
|
||||
// Constants used to control dump file generation.
|
||||
//
|
||||
enum MSMPI_DUMP_MODE
|
||||
{
|
||||
MsmpiDumpNone = 0,
|
||||
MsmpiDumpMini,
|
||||
MsmpiDumpAllMini,
|
||||
MsmpiDumpFull,
|
||||
MsmpiDumpAllFull,
|
||||
MsmpiDumpMaximumValue
|
||||
};
|
||||
|
||||
|
||||
MSMPI_DUMP_MODE GetDumpMode();
|
||||
|
||||
|
||||
void
|
||||
CreateFinalDumpFile(
|
||||
_In_ HANDLE tempFileHandle,
|
||||
_In_ int rank,
|
||||
_In_z_ const wchar_t* dumpPath,
|
||||
_In_ int jobid,
|
||||
_In_ int taskid,
|
||||
_In_ int taskinstid
|
||||
);
|
||||
|
||||
|
||||
HANDLE
|
||||
CreateTempDumpFile(
|
||||
__in HANDLE hProcess,
|
||||
__in DWORD pid,
|
||||
__in MINIDUMP_TYPE dumpType,
|
||||
__in const wchar_t* dumpPath,
|
||||
__in_opt MINIDUMP_EXCEPTION_INFORMATION* pExrParam
|
||||
);
|
||||
|
||||
#endif // MPIDUMP_H_INCLUDED
|
|
@ -0,0 +1,293 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
* (C) 2001 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// IMPORTANT NOTE: All MPI*_Err_* functions must have return value and function name
|
||||
// on the SAME LINE or the error string parser will FAIL.
|
||||
//
|
||||
|
||||
#ifndef MPIERROR_H_INCLUDED
|
||||
#define MPIERROR_H_INCLUDED
|
||||
|
||||
/* Error severity */
|
||||
#define MPIR_ERR_FATAL 1
|
||||
#define MPIR_ERR_RECOVERABLE 0
|
||||
|
||||
/*
|
||||
This file contains the definitions of the error code fields
|
||||
|
||||
An error code is organized as:
|
||||
|
||||
3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
|
||||
1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
||||
+-+-+-----------------------------------------+-+-+-------------+
|
||||
|0|D| Error Code Index |C|F| Class |
|
||||
+-+-+-----------------------------------------+-+-+-------------+
|
||||
|
||||
Class: [0-6]
|
||||
The MPI error class (including dynamically defined classes).
|
||||
|
||||
Fatal: [7]
|
||||
Set if the error is fatal and should not be returned to the user.
|
||||
|
||||
Code: [8]
|
||||
Set for error Codes (vs error class). Note that 0 is a valid value for the Error Code Index.
|
||||
|
||||
Index: [9-28]
|
||||
The Error Code Index assigned at error code creation. The lower 7 bits are used as an index to
|
||||
the ErrorRing to find the error message. The rest of this field bits help verifing that the
|
||||
ErrorRing entry is assinged to that error.
|
||||
|
||||
Dyanmic: [30]
|
||||
Set if this is a dynamically created error code (using the routines to add error classes and
|
||||
codes at runtime). This *must* be the top bit so that MPI_ERR_LASTCODE and MPI_LASTUSEDCODE
|
||||
can be set properly. (MPI_ERR_LASTCODE must be the largest valid error *code* from the
|
||||
predefined codes.
|
||||
The standard text is poorly worded here, but users will expect to be able to perform
|
||||
(errcode <= MPI_ERR_LASTCODE). See Section 8.5 in the MPI-2 standard for MPI_LASTUSEDCODE.
|
||||
|
||||
0: [31]
|
||||
Error codes must be positive integers, so we lose one bit (if they aren't positive, the
|
||||
comparisons agains MPI_ERR_LASTCODE and the value of the attribute MPI_LASTUSEDCODE will fail).
|
||||
*/
|
||||
|
||||
|
||||
#define ERROR_CLASS_MASK 0x0000007f
|
||||
#define ERROR_CLASS_SIZE 128
|
||||
|
||||
#define ERROR_FATAL_FLAG 0x00000080
|
||||
#define ERROR_COD_FLAG 0x00000100
|
||||
|
||||
#define ERROR_INDEX_MASK 0x3FFFFE00
|
||||
#define ERROR_INDEX_SHIFT 9
|
||||
|
||||
#define ERROR_DYN_FLAG 0x40000000
|
||||
|
||||
#define ERROR_DINDEX_MASK 0x003FFE00
|
||||
#define ERROR_DINDEX_SHIFT 9
|
||||
#define ERROR_DINDEX_SIZE 8192
|
||||
|
||||
/* shorthand macros */
|
||||
#define ERROR_GET_CLASS(code) (code & ERROR_CLASS_MASK)
|
||||
#define ERROR_GET_INDEX(code) ((code & ERROR_INDEX_MASK) >> ERROR_INDEX_SHIFT)
|
||||
|
||||
#define ERROR_IS_FATAL(code) ((code & ERROR_FATAL_FLAG) != 0)
|
||||
#define ERROR_IS_CODE(code) ((code & ERROR_COD_FLAG) != 0)
|
||||
#define ERROR_IS_DYN(code) ((code & ERROR_DYN_FLAG) != 0)
|
||||
|
||||
|
||||
/* FIXME:
|
||||
* The following description is out of date and should not be used
|
||||
*/
|
||||
/*@
|
||||
MPIR_Err_create_code - Create an error code and associated message
|
||||
to report an error
|
||||
|
||||
Input Parameters:
|
||||
+ lastcode - Previous error code (see notes)
|
||||
. severity - Indicates severity of error
|
||||
. class - Error class
|
||||
. instance_msg - A message containing printf-style formatting commands
|
||||
that, when combined with the instance_parameters, specify an error
|
||||
message containing instance-specific data.
|
||||
- instance_parameters - The remaining parameters. These must match
|
||||
the formatting commands in 'instance_msg'.
|
||||
|
||||
Notes:
|
||||
A typical use is:
|
||||
.vb
|
||||
mpi_errno = MPIR_Err_create_code( mpi_errno, MPIR_ERR_RECOVERABLE, MPI_ERR_RANK, "Invalid rank %d", rank );
|
||||
.ve
|
||||
|
||||
Predefined message may also be used. Any message that uses the
|
||||
prefix '"**"' will be looked up in a table. This allows standardized
|
||||
messages to be used for a message that is used in several different locations
|
||||
in the code. For example, the name '"**rank"' might be used instead of
|
||||
'"Invalid Rank"'; this would also allow the message to be made more
|
||||
specific and useful, such as
|
||||
.vb
|
||||
Invalid rank provided. The rank must be between 0 and the 1 less than
|
||||
the size of the communicator in this call.
|
||||
.ve
|
||||
This interface is compatible with the 'gettext' interface for
|
||||
internationalization, in the sense that the 'generic_msg' and 'instance_msg'
|
||||
may be used as arguments to 'gettext' to return a string in the appropriate
|
||||
language; the implementation of 'MPID_Err_create_code' can then convert
|
||||
this text into the appropriate code value.
|
||||
|
||||
The current set of formatting commands is undocumented and will change.
|
||||
You may safely use '%d' and '%s' (though only use '%s' for names of
|
||||
objects, not text messages, as using '%s' for a message breaks support for
|
||||
internationalization.
|
||||
|
||||
This interface allows error messages to be chained together. The first
|
||||
argument is the last error code; if there is no previous error code,
|
||||
use 'MPI_SUCCESS'.
|
||||
|
||||
Module:
|
||||
Error
|
||||
|
||||
@*/
|
||||
_Post_satisfies_( return != MPI_SUCCESS )
|
||||
MPI_RESULT MPIR_Err_create_code(
|
||||
_In_ int lastcode,
|
||||
_In_ int fatal,
|
||||
_In_ int error_class,
|
||||
_In_z_ const char specific_msg[],
|
||||
...
|
||||
);
|
||||
|
||||
_Post_satisfies_( return != MPI_SUCCESS )
|
||||
MPI_RESULT MPIR_Err_create_code_valist(
|
||||
_In_ int lastcode,
|
||||
_In_ int fatal,
|
||||
_In_ int error_class,
|
||||
_In_z_ const char specific_msg[],
|
||||
_In_ va_list Argp
|
||||
);
|
||||
|
||||
void MPIR_Err_preOrPostInit( void );
|
||||
|
||||
|
||||
/*@
|
||||
MPID_Err_get_string - Get the message string that corresponds to an error
|
||||
class or code
|
||||
|
||||
Input Parameter:
|
||||
+ code - An error class or code. If a code, it must have been created by
|
||||
'MPID_Err_create_code'.
|
||||
- msg_len - Length of 'msg'.
|
||||
|
||||
Output Parameter:
|
||||
. msg - A null-terminated text string of length (including the null) of no
|
||||
more than 'msg_len'.
|
||||
|
||||
Return value:
|
||||
Zero on success. Non-zero returns indicate either (a) 'msg_len' is too
|
||||
small for the message or (b) the value of 'code' is neither a valid
|
||||
error class or code.
|
||||
|
||||
Notes:
|
||||
This routine is used to implement 'MPI_ERROR_STRING'.
|
||||
|
||||
Module:
|
||||
Error
|
||||
|
||||
Question:
|
||||
What values should be used for the error returns? Should they be
|
||||
valid error codes?
|
||||
|
||||
How do we get a good value for 'MPI_MAX_ERROR_STRING' for 'mpi.h'?
|
||||
See 'errgetmsg' for one idea.
|
||||
|
||||
@*/
|
||||
|
||||
void MPIR_Err_get_string(
|
||||
_In_ int errorcode,
|
||||
_Out_writes_z_(length) char * msg,
|
||||
_In_ size_t length
|
||||
);
|
||||
|
||||
|
||||
/* Prototypes for internal routines for the errhandling module */
|
||||
MPI_RESULT
|
||||
MPIR_Err_set_msg(
|
||||
_In_ int code,
|
||||
_In_z_ const char * msg_string
|
||||
);
|
||||
|
||||
int MPIR_Err_add_class( void );
|
||||
int MPIR_Err_add_code( int );
|
||||
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int MPIR_Err_vsnprintf_mpi(
|
||||
_Out_writes_z_(maxlen) char* str,
|
||||
_In_ size_t maxlen,
|
||||
_Printf_format_string_ const char* fmt,
|
||||
_In_ va_list list
|
||||
);
|
||||
|
||||
_Post_satisfies_( return != MPI_SUCCESS )
|
||||
int MPIR_Err_get_user_error_code(
|
||||
_In_ int errcode
|
||||
);
|
||||
|
||||
typedef _Ret_z_ const char* (*MPIR_Err_to_string_fn)(int code);
|
||||
|
||||
void MPIR_Err_set_dynerr_fn(
|
||||
_In_ MPIR_Err_to_string_fn fn
|
||||
);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Standardized error checking macros. These provide the correct tests for
|
||||
* common tests. These set err with the encoded error value.
|
||||
*/
|
||||
|
||||
/* The following are placeholders. We haven't decided yet whether these
|
||||
should take a handle or pointer, or if they should take a handle and return
|
||||
a pointer if the handle is valid. These need to be rationalized with the
|
||||
MPID_xxx_valid_ptr and MPID_xxx_get_ptr.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#define MPIU_ERR_FAIL(err_) \
|
||||
err_
|
||||
|
||||
#define ON_ERROR_FAIL(err_) \
|
||||
if((err_) != MPI_SUCCESS) { goto fn_fail; }
|
||||
|
||||
#define MPIU_ERR_NOMEM() \
|
||||
MPIU_ERR_CREATE(MPI_ERR_OTHER, "**nomem")
|
||||
|
||||
/*
|
||||
* Standardized error setting and checking macros
|
||||
* These are intended to simplify the insertion of standardized error
|
||||
* checks
|
||||
*
|
||||
*/
|
||||
/* --BEGIN ERROR MACROS-- */
|
||||
|
||||
/* If you add any macros to this list, make sure that you update
|
||||
maint/extracterrmsgs to handle the additional macros (see the hash
|
||||
KnownErrRoutines in that script) */
|
||||
#define MPIU_ERR_TYPE_GET(err_, fatal_, class_, fmt_, ...) \
|
||||
MPIR_Err_create_code(err_, fatal_, class_, fmt_, __VA_ARGS__)
|
||||
|
||||
/* Get fatal error code */
|
||||
#define MPIU_ERR_FATAL_GET(err_, class_, fmt_, ...) \
|
||||
MPIU_ERR_TYPE_GET(err_, MPIR_ERR_FATAL, class_, fmt_, __VA_ARGS__)
|
||||
|
||||
/* Get recoverable error code */
|
||||
#define MPIU_ERR_GET(err_, fmt_, ...) \
|
||||
MPIU_ERR_TYPE_GET(*&err_, MPIR_ERR_RECOVERABLE, MPI_ERR_OTHER, fmt_, __VA_ARGS__)
|
||||
|
||||
/* Get recov error code with class */
|
||||
#define MPIU_ERR_CLASS_GET(err_, class_, fmt_, ...) \
|
||||
MPIU_ERR_TYPE_GET(*&err_, MPIR_ERR_RECOVERABLE, class_, fmt_, __VA_ARGS__)
|
||||
|
||||
/* Create a new recoverable error code */
|
||||
#define MPIU_ERR_CREATE(class_, fmt_, ...) \
|
||||
MPIU_ERR_TYPE_GET( MPI_SUCCESS, MPIR_ERR_RECOVERABLE, class_, fmt_, __VA_ARGS__ )
|
||||
|
||||
/* --END ERROR MACROS-- */
|
||||
|
||||
_Ret_z_
|
||||
const char*
|
||||
get_error_string(
|
||||
_In_ int error
|
||||
);
|
||||
|
||||
void CreateDumpFileIfConfigured(
|
||||
_In_ EXCEPTION_POINTERS* exp
|
||||
);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,635 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
*
|
||||
* (C) 2001 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
#ifndef MPIHANDLE_H_INCLUDED
|
||||
#define MPIHANDLE_H_INCLUDED
|
||||
|
||||
#include "MpiLock.h"
|
||||
|
||||
/*TDSOverview.tex
|
||||
|
||||
MPI has a number of data structures, most of which are represented by
|
||||
an opaque handle in an MPI program. In the MPICH implementation of MPI,
|
||||
these handles are represented
|
||||
as integers; this makes implementation of the C/Fortran handle transfer
|
||||
calls (part of MPI-2) easy.
|
||||
|
||||
MPID objects (again with the possible exception of 'MPI_Request's)
|
||||
are allocated by a common set of object allocation functions.
|
||||
These are
|
||||
.vb
|
||||
void *MPIU_Handle_obj_create( MPIU_Object_alloc_t *objmem )
|
||||
void MPIU_Handle_obj_destroy( MPIU_Object_alloc_t *objmem, void *object )
|
||||
.ve
|
||||
where 'objmem' is a pointer to a memory allocation object that knows
|
||||
enough to allocate objects, including the
|
||||
size of the object and the location of preallocated memory, as well
|
||||
as the type of memory allocator. By providing the routines to allocate and
|
||||
free the memory, we make it easy to use the same interface to allocate both
|
||||
local and shared memory for objects (always using the same kind for each
|
||||
type of object).
|
||||
|
||||
The names create/destroy were chosen because they are different from
|
||||
new/delete (C++ operations) and malloc/free.
|
||||
Any name choice will have some conflicts with other uses, of course.
|
||||
|
||||
Reference Counts:
|
||||
Many MPI objects have reference count semantics.
|
||||
The semantics of MPI require that many objects that have been freed by the
|
||||
user
|
||||
(e.g., with 'MPI_Type_free' or 'MPI_Comm_free') remain valid until all
|
||||
pending
|
||||
references to that object (e.g., by an 'MPI_Irecv') are complete. There
|
||||
are several ways to implement this; MPICH uses `reference counts` in the
|
||||
objects. To support the 'MPI_THREAD_MULTIPLE' level of thread-safety, these
|
||||
reference counts must be accessed and updated atomically.
|
||||
A reference count for
|
||||
`any` object can be incremented (atomically)
|
||||
with 'MPIU_Object_add_ref(objptr)'
|
||||
and decremented with 'MPIU_Object_release_ref(objptr,newval_ptr)'.
|
||||
These have been designed so that then can be implemented as inlined
|
||||
macros rather than function calls, even in the multithreaded case, and
|
||||
can use special processor instructions that guarantee atomicity to
|
||||
avoid thread locks.
|
||||
The decrement routine sets the value pointed at by 'inuse_ptr' to 0 if
|
||||
the postdecrement value of the reference counter is zero, and to a non-zero
|
||||
value otherwise. If this value is zero, then the routine that decremented
|
||||
the
|
||||
reference count should free the object. This may be as simple as
|
||||
calling 'MPIU_Handle_obj_destroy' (for simple objects with no other allocated
|
||||
storage) or may require calling a separate routine to destroy the object.
|
||||
Because MPI uses 'MPI_xxx_free' to both decrement the reference count and
|
||||
free the object if the reference count is zero, we avoid the use of 'free'
|
||||
in the MPID routines.
|
||||
|
||||
The 'inuse_ptr' approach is used rather than requiring the post-decrement
|
||||
value because, for reference-count semantics, all that is necessary is
|
||||
to know when the reference count reaches zero, and this can sometimes
|
||||
be implemented more cheaply that requiring the post-decrement value (e.g.,
|
||||
on IA32, there is an instruction for this operation).
|
||||
|
||||
Question:
|
||||
Should we state that this is a macro so that we can use a register for
|
||||
the output value? That avoids a store. Alternately, have the macro
|
||||
return the value as if it was a function?
|
||||
|
||||
Structure Definitions:
|
||||
The structure definitions in this document define `only` that part of
|
||||
a structure that may be used by code that is making use of the ADI.
|
||||
Thus, some structures, such as 'MPID_Comm', have many defined fields;
|
||||
these are used to support MPI routines such as 'MPI_Comm_size' and
|
||||
'MPI_Comm_remote_group'. Other structures may have few or no defined
|
||||
members; these structures have no fields used outside of the ADI.
|
||||
In C++ terms, all members of these structures are 'private'.
|
||||
|
||||
For the initial implementation, we expect that the structure definitions
|
||||
will be designed for the multimethod device. However, all items that are
|
||||
specific to a particular device (including the multi-method device)
|
||||
will be placed at the end of the structure;
|
||||
the document will clearly identify the members that all implementations
|
||||
will provide. This simplifies much of the code in both the ADI and the
|
||||
implementation of the MPI routines because structure member can be directly
|
||||
accessed rather than using some macro or C++ style method interface.
|
||||
|
||||
T*/
|
||||
|
||||
|
||||
/*TOpaqOverview.tex
|
||||
MPI Opaque Objects:
|
||||
|
||||
MPI Opaque objects such as 'MPI_Comm' or 'MPI_Datatype' are specified by
|
||||
integers (in the MPICH2 implementation); the MPI standard calls these
|
||||
handles.
|
||||
Out of range values are invalid; the value 0 is reserved.
|
||||
For most (with the possible exception of
|
||||
'MPI_Request' for performance reasons) MPI Opaque objects, the integer
|
||||
encodes both the kind of object (allowing runtime tests to detect a datatype
|
||||
passed where a communicator is expected) and important properties of the
|
||||
object. Even the 'MPI_xxx_NULL' values should be encoded so that
|
||||
different null handles can be distinguished. The details of the encoding
|
||||
of the handles is covered in more detail in the MPICH2 Design Document.
|
||||
For the most part, the ADI uses pointers to the underlying structures
|
||||
rather than the handles themselves. However, each structure contains an
|
||||
'handle' field that is the corresponding integer handle for the MPI object.
|
||||
|
||||
MPID objects (objects used within the implementation of MPI) are not opaque.
|
||||
|
||||
T*/
|
||||
|
||||
/* Known MPI object types. These are used for both the error handlers
|
||||
and for the handles. This is a 4 bit value. 0 is reserved for so
|
||||
that all-zero handles can be flagged as an error. */
|
||||
/*E
|
||||
MPID_Object_kind - Object kind (communicator, window, or file)
|
||||
|
||||
Notes:
|
||||
This enum is used by keyvals and errhandlers to indicate the type of
|
||||
object for which MPI opaque types the data is valid. These are defined
|
||||
as bits to allow future expansion to the case where an object is value for
|
||||
multiple types (for example, we may want a universal error handler for
|
||||
errors return). This is also used to indicate the type of MPI object a
|
||||
MPI handle represents. It is an enum because only this applies only the
|
||||
the MPI and internal MPICH2 objects.
|
||||
|
||||
The 'MPID_PROCGROUP' kind is used to manage process groups (different
|
||||
from MPI Groups) that are used to keep track of collections of
|
||||
processes (each 'MPID_PROCGROUP' corresponds to a group of processes
|
||||
that define an 'MPI_COMM_WORLD'. This becomes important only
|
||||
when MPI-2 dynamic process features are supported. 'MPID_VCONN' is
|
||||
a virtual connection; while this is not part of the overall ADI3
|
||||
design, an object that manages connections to other processes is
|
||||
a common need, and 'MPID_VCONN' may be used for that.
|
||||
|
||||
Module:
|
||||
Attribute-DS
|
||||
E*/
|
||||
|
||||
|
||||
//
|
||||
// Handle values are 32 bit values laid out as follows:
|
||||
//
|
||||
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
|
||||
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
||||
// +---+-------+---------------------------------------------------+
|
||||
// |Typ| Kind | Index |
|
||||
// +---+-------+---------------------------------------------------+
|
||||
//
|
||||
//
|
||||
// Handles of type HANDLE_TYPE_INDIRECT are laid out as follows:
|
||||
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
|
||||
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
||||
// +---+-------+-------------------+-------------------------------+
|
||||
// |Typ| Kind | Block | Index |
|
||||
// +---+-------+-------------------+-------------------------------+
|
||||
//
|
||||
// where
|
||||
//
|
||||
// Typ - is the handle type:
|
||||
//
|
||||
#define HANDLE_TYPE_INVALID 0x0
|
||||
#define HANDLE_TYPE_BUILTIN 0x1
|
||||
#define HANDLE_TYPE_DIRECT 0x2
|
||||
#define HANDLE_TYPE_INDIRECT 0x3
|
||||
|
||||
#define HANDLE_TYPE_MASK 0xc0000000
|
||||
#define HANDLE_TYPE_SHIFT 30
|
||||
#define HANDLE_GET_TYPE(a) (((a) & HANDLE_TYPE_MASK)>>HANDLE_TYPE_SHIFT)
|
||||
#define HANDLE_SET_TYPE(a,kind) ((a)|((kind)<<HANDLE_TYPE_SHIFT))
|
||||
|
||||
#define HANDLE_IS_VALID(a) (HANDLE_GET_TYPE(a) != HANDLE_TYPE_INVALID)
|
||||
#define HANDLE_IS_BUILTIN(a) (HANDLE_GET_TYPE(a) == HANDLE_TYPE_BUILTIN)
|
||||
|
||||
//
|
||||
// Kind - is the kind of MPI object:
|
||||
//
|
||||
typedef enum MPID_Object_kind
|
||||
{
|
||||
MPID_COMM = 0x1,
|
||||
MPID_GROUP = 0x2,
|
||||
MPID_DATATYPE = 0x3,
|
||||
MPID_FILE = 0x4, /* This is not used */
|
||||
MPID_ERRHANDLER = 0x5,
|
||||
MPID_OP = 0x6,
|
||||
MPID_INFO = 0x7,
|
||||
MPID_WIN = 0x8,
|
||||
MPID_KEYVAL = 0x9,
|
||||
MPID_ATTR = 0xa,
|
||||
MPID_REQUEST = 0xb,
|
||||
MPID_MESSAGE = 0xc,
|
||||
MPID_VCONN = 0xd,
|
||||
MPID_GREQ_CLASS = 0xf,
|
||||
MPID_OBJECT_KIND_MAX
|
||||
|
||||
} MPID_Object_kind;
|
||||
|
||||
extern const char* MPID_Object_kind_names[MPID_OBJECT_KIND_MAX];
|
||||
|
||||
#define HANDLE_MPI_KIND_SHIFT 26
|
||||
#define HANDLE_GET_MPI_KIND(a) ( ((a) & 0x3c000000) >> HANDLE_MPI_KIND_SHIFT )
|
||||
#define HANDLE_SET_MPI_KIND(a,kind) ( ((a) & 0xc3ffffff) | ((kind) << HANDLE_MPI_KIND_SHIFT) )
|
||||
|
||||
//
|
||||
// Block - for indirect handles only, the index of the indirect block to
|
||||
// which the Index applies
|
||||
//
|
||||
#define HANDLE_INDIRECT_SHIFT 16
|
||||
#define HANDLE_INDIRECT_BLOCK(a) (((a)& 0x03FF0000) >> HANDLE_INDIRECT_SHIFT)
|
||||
/* Handle block is between 1 and 1024 *elements* */
|
||||
#define HANDLE_BLOCK_SIZE 256
|
||||
C_ASSERT(HANDLE_BLOCK_SIZE <= 1024);
|
||||
|
||||
//
|
||||
// Index - Index of the object. For indirect handles, the index is relative ot the block.
|
||||
//
|
||||
#define HANDLE_INDIRECT_INDEX(a) ((a) & 0x0000FFFF)
|
||||
#define HANDLE_BLOCK_INDEX_SIZE 1024
|
||||
C_ASSERT(HANDLE_BLOCK_SIZE < 65536);
|
||||
|
||||
#define HANDLE_INDEX_MASK 0x03FFFFFF
|
||||
#define HANDLE_DIRECT_INDEX(a) ((a) & HANDLE_INDEX_MASK)
|
||||
|
||||
#define HANDLE_BUILTIN_INDEX(a) ((a) & 0x000000FF)
|
||||
|
||||
/* ALL objects have the handle as the first value. */
|
||||
/* Inactive (unused and stored on the appropriate avail list) objects
|
||||
have MPIU_Handle_common as the head */
|
||||
typedef struct MPIU_Handle_common
|
||||
{
|
||||
int handle;
|
||||
volatile long ref_count;
|
||||
struct MPIU_Handle_common *next; /* Free handles use this field to point to the next
|
||||
free object */
|
||||
|
||||
} MPIU_Handle_common;
|
||||
|
||||
/* All *active* (in use) objects have the handle as the first value; objects
|
||||
with referene counts have the reference count as the second value.
|
||||
See MPIU_Object_add_ref and MPIU_Object_release_ref. */
|
||||
typedef struct MPIU_Handle_head
|
||||
{
|
||||
int handle;
|
||||
volatile long ref_count;
|
||||
|
||||
} MPIU_Handle_head;
|
||||
|
||||
/* This type contains all of the data, except for the direct array,
|
||||
used by the object allocators. */
|
||||
typedef struct MPIU_Object_alloc_t
|
||||
{
|
||||
MPIU_Handle_common *avail; /* Next available object */
|
||||
int initialized; /* */
|
||||
void *(*indirect)[]; /* Pointer to indirect object blocks */
|
||||
int indirect_size; /* Number of allocated indirect blocks */
|
||||
MPID_Object_kind kind; /* Kind of object this is for */
|
||||
int size; /* Size of an individual object */
|
||||
void *direct; /* Pointer to direct block, used
|
||||
for allocation */
|
||||
int direct_size; /* Size of direct block */
|
||||
|
||||
MPI_RWLOCK alloc_lock;
|
||||
|
||||
#if DBG
|
||||
int num_alloc; /* Number of objects out of the pool. */
|
||||
volatile long num_user_alloc; /* Number of objects out of the pool owned by the client. */
|
||||
volatile long num_user_msg_alloc; /* Number of objects out of the pool of kind MPID_MESSAGE owned by the client. */
|
||||
#endif
|
||||
|
||||
} MPIU_Object_alloc_t;
|
||||
|
||||
|
||||
_Success_(return!=nullptr)
|
||||
_Ret_valid_
|
||||
void* MPIU_Handle_obj_alloc(
|
||||
_In_ MPIU_Object_alloc_t* objmem
|
||||
);
|
||||
|
||||
void MPIU_Handle_obj_free(
|
||||
_In_ MPIU_Object_alloc_t* objmem,
|
||||
_In_ _Post_ptr_invalid_ void* obj
|
||||
);
|
||||
|
||||
_Success_(return!=nullptr)
|
||||
void* MPIU_Handle_get_ptr_indirect(
|
||||
_In_ int handle,
|
||||
_In_ MPIU_Object_alloc_t* objmem
|
||||
);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* mpiobjref.h */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
/*M
|
||||
MPIU_Object_add_ref - Increment the reference count for an MPI object
|
||||
|
||||
Synopsis:
|
||||
.vb
|
||||
MPIU_Object_add_ref( MPIU_Object *ptr )
|
||||
.ve
|
||||
|
||||
Input Parameter:
|
||||
. ptr - Pointer to the object.
|
||||
|
||||
Notes:
|
||||
In an unthreaded implementation, this function will usually be implemented
|
||||
as a single-statement macro. In an 'MPI_THREAD_MULTIPLE' implementation,
|
||||
this routine must implement an atomic increment operation, using, for
|
||||
example, a lock on datatypes or special assembly code such as
|
||||
.vb
|
||||
try-again:
|
||||
load-link refcount-address to r2
|
||||
add 1 to r2
|
||||
store-conditional r2 to refcount-address
|
||||
if failed branch to try-again:
|
||||
.ve
|
||||
on RISC architectures or
|
||||
.vb
|
||||
lock
|
||||
inc refcount-address or
|
||||
.ve
|
||||
on IA32; "lock" is a special opcode prefix that forces atomicity. This
|
||||
is not a separate instruction; however, the GNU assembler expects opcode
|
||||
prefixes on a separate line.
|
||||
|
||||
Module:
|
||||
MPID_CORE
|
||||
|
||||
Question:
|
||||
This accesses the 'ref_count' member of all MPID objects. Currently,
|
||||
that member is typed as 'volatile int'. However, for a purely polling,
|
||||
thread-funnelled application, the 'volatile' is unnecessary. Should
|
||||
MPID objects use a 'typedef' for the 'ref_count' that can be defined
|
||||
as 'volatile' only when needed? For now, the answer is no; there isn''t
|
||||
enough to be gained in that case.
|
||||
M*/
|
||||
|
||||
/*M
|
||||
MPIU_Object_release_ref - Decrement the reference count for an MPI object
|
||||
|
||||
Synopsis:
|
||||
.vb
|
||||
MPIU_Object_release_ref( MPIU_Object *ptr, int *inuse_ptr )
|
||||
.ve
|
||||
|
||||
Input Parameter:
|
||||
. objptr - Pointer to the object.
|
||||
|
||||
Output Parameter:
|
||||
. inuse_ptr - Pointer to the value of the reference count after decrementing.
|
||||
This value is either zero or non-zero. See below for details.
|
||||
|
||||
Notes:
|
||||
In an unthreaded implementation, this function will usually be implemented
|
||||
as a single-statement macro. In an 'MPI_THREAD_MULTIPLE' implementation,
|
||||
this routine must implement an atomic decrement operation, using, for
|
||||
example, a lock on datatypes or special assembly code such as
|
||||
.vb
|
||||
try-again:
|
||||
load-link refcount-address to r2
|
||||
sub 1 to r2
|
||||
store-conditional r2 to refcount-address
|
||||
if failed branch to try-again:
|
||||
store r2 to newval_ptr
|
||||
.ve
|
||||
on RISC architectures or
|
||||
.vb
|
||||
lock
|
||||
dec refcount-address
|
||||
if zf store 0 to newval_ptr else store 1 to newval_ptr
|
||||
.ve
|
||||
on IA32; "lock" is a special opcode prefix that forces atomicity. This
|
||||
is not a separate instruction; however, the GNU assembler expects opcode
|
||||
prefixes on a separate line. 'zf' is the zero flag; this is set if the
|
||||
result of the operation is zero. Implementing a full decrement-and-fetch
|
||||
would require more code and the compare and swap instruction.
|
||||
|
||||
Once the reference count is decremented to zero, it is an error to
|
||||
change it. A correct MPI program will never do that, but an incorrect one
|
||||
(particularly a multithreaded program with a race condition) might.
|
||||
|
||||
The following code is `invalid`\:
|
||||
.vb
|
||||
MPID_Object_release_ref( datatype_ptr );
|
||||
if (datatype_ptr->ref_count == 0) MPID_Datatype_free( datatype_ptr );
|
||||
.ve
|
||||
In a multi-threaded implementation, the value of 'datatype_ptr->ref_count'
|
||||
may have been changed by another thread, resulting in both threads calling
|
||||
'MPID_Datatype_free'. Instead, use
|
||||
.vb
|
||||
MPID_Object_release_ref( datatype_ptr, &inUse );
|
||||
if (!inuse)
|
||||
MPID_Datatype_free( datatype_ptr );
|
||||
.ve
|
||||
|
||||
Module:
|
||||
MPID_CORE
|
||||
M*/
|
||||
|
||||
/* The MPIU_DBG... statements are macros that vanish unless
|
||||
--enable-g=log is selected. MPIU_HANDLE_CHECK_REFCOUNT is
|
||||
defined above, and adds an additional sanity check for the refcounts
|
||||
*/
|
||||
template<typename T>
|
||||
__forceinline void MPIU_Object_set_ref(_In_ T* objptr, _In_ long val)
|
||||
{
|
||||
::InterlockedExchange(&objptr->ref_count, val);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
__forceinline void MPIU_Object_add_ref(_In_ T* objptr)
|
||||
{
|
||||
::InterlockedIncrement(&objptr->ref_count);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
__forceinline void MPIU_Object_release_ref(_In_ T* objptr, _Out_ BOOL* inuse_ptr)
|
||||
{
|
||||
*inuse_ptr = ::InterlockedDecrement(&objptr->ref_count);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* mpiobjref.h */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* Convert Handles to objects for MPI types that have predefined objects */
|
||||
/* Question. Should this do ptr=0 first, particularly if doing --enable-strict
|
||||
complication? */
|
||||
#define MPID_Getb_ptr(kind,a,bmsk,ptr) \
|
||||
{ \
|
||||
switch (HANDLE_GET_TYPE(a)) { \
|
||||
case HANDLE_TYPE_BUILTIN: \
|
||||
ptr=MPID_##kind##_builtin+((a)&(bmsk)); \
|
||||
__analysis_assume(ptr != nullptr); \
|
||||
break; \
|
||||
case HANDLE_TYPE_DIRECT: \
|
||||
ptr=MPID_##kind##_direct+HANDLE_DIRECT_INDEX(a); \
|
||||
__analysis_assume(ptr != nullptr); \
|
||||
break; \
|
||||
case HANDLE_TYPE_INDIRECT: \
|
||||
ptr=((MPID_##kind*) \
|
||||
MPIU_Handle_get_ptr_indirect(a,&MPID_##kind##_mem)); \
|
||||
__analysis_assume(ptr != nullptr); \
|
||||
break; \
|
||||
case HANDLE_TYPE_INVALID: \
|
||||
default: \
|
||||
ptr=0; \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define MPID_Getb_ptr_valid(kind,a,bmsk,ptr) \
|
||||
{ \
|
||||
switch (HANDLE_GET_TYPE(a)) { \
|
||||
case HANDLE_TYPE_BUILTIN: \
|
||||
ptr=MPID_##kind##_builtin+((a)&(bmsk)); \
|
||||
__analysis_assume(ptr != nullptr); \
|
||||
break; \
|
||||
case HANDLE_TYPE_DIRECT: \
|
||||
ptr=MPID_##kind##_direct+HANDLE_DIRECT_INDEX(a); \
|
||||
__analysis_assume(ptr != nullptr); \
|
||||
break; \
|
||||
case HANDLE_TYPE_INDIRECT: \
|
||||
ptr=((MPID_##kind*) \
|
||||
MPIU_Handle_get_ptr_indirect(a,&MPID_##kind##_mem)); \
|
||||
__analysis_assume(ptr != nullptr); \
|
||||
break; \
|
||||
case HANDLE_TYPE_INVALID: \
|
||||
default: \
|
||||
MPID_Abort(nullptr, TRUE, 0, "Invalid Handle type for " #kind);\
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
/* Convert handles to objects for MPI types that do _not_ have any predefined
|
||||
objects */
|
||||
/* Question. Should this do ptr=0 first, particularly if doing --enable-strict
|
||||
complication? */
|
||||
#define MPID_Get_ptr(kind,a,ptr) \
|
||||
{ \
|
||||
switch (HANDLE_GET_TYPE(a)) { \
|
||||
case HANDLE_TYPE_DIRECT: \
|
||||
ptr=MPID_##kind##_direct+HANDLE_DIRECT_INDEX(a); \
|
||||
__analysis_assume(ptr != nullptr); \
|
||||
break; \
|
||||
case HANDLE_TYPE_INDIRECT: \
|
||||
ptr=((MPID_##kind*) \
|
||||
MPIU_Handle_get_ptr_indirect(a,&MPID_##kind##_mem)); \
|
||||
__analysis_assume(ptr != nullptr); \
|
||||
break; \
|
||||
case HANDLE_TYPE_INVALID: \
|
||||
case HANDLE_TYPE_BUILTIN: \
|
||||
default: \
|
||||
ptr=0; \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define MPID_Get_ptr_valid(kind,a,ptr) \
|
||||
{ \
|
||||
switch (HANDLE_GET_TYPE(a)) { \
|
||||
case HANDLE_TYPE_DIRECT: \
|
||||
ptr=MPID_##kind##_direct+HANDLE_DIRECT_INDEX(a); \
|
||||
__analysis_assume(ptr != nullptr); \
|
||||
break; \
|
||||
case HANDLE_TYPE_INDIRECT: \
|
||||
ptr=((MPID_##kind*) \
|
||||
MPIU_Handle_get_ptr_indirect(a,&MPID_##kind##_mem)); \
|
||||
__analysis_assume(ptr != nullptr); \
|
||||
break; \
|
||||
case HANDLE_TYPE_INVALID: \
|
||||
case HANDLE_TYPE_BUILTIN: \
|
||||
default: \
|
||||
MPID_Abort(nullptr, TRUE, 0, "Invalid Handle type for " #kind);\
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* FIXME: the masks should be defined with the handle definitions instead
|
||||
of inserted here as literals */
|
||||
#define MPID_Group_get_ptr(a,ptr) MPID_Getb_ptr(Group,a,0x03ffffff,ptr)
|
||||
#define MPID_File_get_ptr(a,ptr) MPID_Get_ptr(File,a,ptr)
|
||||
#define MPID_Errhandler_get_ptr(a,ptr) MPID_Getb_ptr(Errhandler,a,0x3,ptr)
|
||||
#define MPID_Op_get_ptr(a,ptr) MPID_Getb_ptr(Op,a,0x000000ff,ptr)
|
||||
#define MPID_Info_get_ptr(a,ptr) MPID_Get_ptr(Info,a,ptr)
|
||||
#define MPID_Win_get_ptr(a,ptr) MPID_Get_ptr(Win,a,ptr)
|
||||
#define MPID_Request_get_ptr(a,ptr) MPID_Get_ptr(Request,a,ptr)
|
||||
|
||||
|
||||
#define MPID_Group_get_ptr_valid(a,ptr) MPID_Getb_ptr_valid(Group,a,0x03ffffff,ptr)
|
||||
#define MPID_File_get_ptr_valid(a,ptr) MPID_Get_ptr_valid(File,a,ptr)
|
||||
#define MPID_Errhandler_get_ptr_valid(a,ptr) MPID_Getb_ptr_valid(Errhandler,a,0x3,ptr)
|
||||
#define MPID_Op_get_ptr_valid(a,ptr) MPID_Getb_ptr_valid(Op,a,0x000000ff,ptr)
|
||||
#define MPID_Info_get_ptr_valid(a,ptr) MPID_Get_ptr_valid(Info,a,ptr)
|
||||
#define MPID_Win_get_ptr_valid(a,ptr) MPID_Get_ptr_valid(Win,a,ptr)
|
||||
#define MPID_Request_get_ptr_valid(a,ptr) MPID_Get_ptr_valid(Request,a,ptr)
|
||||
|
||||
|
||||
|
||||
/* Keyvals have a special format. This is roughly MPID_Get_ptrb, but
|
||||
the handle index is in a smaller bit field. In addition,
|
||||
there is no storage for the builtin keyvals.
|
||||
For the indirect case, we mask off the part of the keyval that is
|
||||
in the bits normally used for the indirect block index.
|
||||
*/
|
||||
#define MPID_Keyval_get_ptr(a,ptr) \
|
||||
{ \
|
||||
switch (HANDLE_GET_TYPE(a)) { \
|
||||
case HANDLE_TYPE_BUILTIN: \
|
||||
ptr=0; \
|
||||
break; \
|
||||
case HANDLE_TYPE_DIRECT: \
|
||||
ptr=MPID_Keyval_direct+((a)&0x3fffff); \
|
||||
break; \
|
||||
case HANDLE_TYPE_INDIRECT: \
|
||||
ptr=((MPID_Keyval*) \
|
||||
MPIU_Handle_get_ptr_indirect((a)&0xfc3fffff,&MPID_Keyval_mem)); \
|
||||
break; \
|
||||
case HANDLE_TYPE_INVALID: \
|
||||
default: \
|
||||
ptr=0; \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define MPID_Keyval_get_ptr_valid(a,ptr) \
|
||||
{ \
|
||||
switch (HANDLE_GET_TYPE(a)) { \
|
||||
case HANDLE_TYPE_DIRECT: \
|
||||
ptr=MPID_Keyval_direct+((a)&0x3fffff); \
|
||||
break; \
|
||||
case HANDLE_TYPE_INDIRECT: \
|
||||
ptr=((MPID_Keyval*) \
|
||||
MPIU_Handle_get_ptr_indirect((a)&0xfc3fffff,&MPID_Keyval_mem)); \
|
||||
break; \
|
||||
case HANDLE_TYPE_BUILTIN: \
|
||||
case HANDLE_TYPE_INVALID: \
|
||||
default: \
|
||||
MPID_Abort(nullptr, TRUE, 0, "Invalid Handle type for Keyval"); \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
template<typename T> bool SetName( _Inout_ T* obj, _In_z_ const char* name )
|
||||
{
|
||||
if( obj->name == obj->GetDefaultName() )
|
||||
{
|
||||
char* tempName = static_cast<char*>(MPIU_Malloc( MPI_MAX_OBJECT_NAME ));
|
||||
if( tempName == nullptr )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
obj->name = tempName;
|
||||
}
|
||||
MPIU_Strncpy( const_cast<char*>(obj->name), name, MPI_MAX_OBJECT_NAME );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template<typename T> void CleanupName( _Inout_ T* obj )
|
||||
{
|
||||
if( obj->name != obj->GetDefaultName() && obj->name != nullptr )
|
||||
{
|
||||
MPIU_Free( const_cast<char*>(obj->name) );
|
||||
obj->name = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename T> void InitName( _Inout_ T* obj )
|
||||
{
|
||||
obj->name = obj->GetDefaultName();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* MPIHANDLE_H_INCLUDED */
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
* (C) 2001 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
#ifndef MPIIOV_H_INCLUDED
|
||||
#define MPIIOV_H_INCLUDED
|
||||
|
||||
/* IOVs */
|
||||
/* The basic channel interface uses IOVs */
|
||||
typedef WSABUF MPID_IOV;
|
||||
typedef char iovsendbuf_t;
|
||||
typedef char iovrecvbuf_t;
|
||||
|
||||
/* FIXME: How is IOV_LIMIT chosen? */
|
||||
#define MPID_IOV_LIMIT 16
|
||||
|
||||
static inline unsigned iov_size(_In_reads_(n_iov) const MPID_IOV* iov, int n_iov)
|
||||
{
|
||||
unsigned total = 0;
|
||||
while(n_iov--)
|
||||
{
|
||||
total += iov->len;
|
||||
iov++;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,104 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
*
|
||||
* (C) 2001 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
#ifndef MPIMEM_H_INCLUDED
|
||||
#define MPIMEM_H_INCLUDED
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* mpimem.h */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/*D
|
||||
Memory - Memory Management Routines
|
||||
|
||||
Rules for memory management:
|
||||
|
||||
MPICH explicity prohibits the appearence of 'malloc', 'free',
|
||||
'calloc', 'realloc', or 'strdup' in any code implementing a device or
|
||||
MPI call (of course, users may use any of these calls in their code).
|
||||
Instead, you must use 'MPIU_Malloc' etc.; if these are defined
|
||||
as 'malloc', that is allowed, but an explicit use of 'malloc' instead of
|
||||
'MPIU_Malloc' in the source code is not allowed. This restriction is
|
||||
made to simplify the use of portable tools to test for memory leaks,
|
||||
overwrites, and other consistency checks.
|
||||
|
||||
Most memory should be allocated at the time that 'MPID_Init' is
|
||||
called and released with 'MPID_Finalize' is called. If at all possible,
|
||||
no other MPID routine should fail because memory could not be allocated
|
||||
(for example, because the user has allocated large arrays after 'MPI_Init').
|
||||
|
||||
The implementation of the MPI routines will strive to avoid memory allocation
|
||||
as well; however, operations such as 'MPI_Type_index' that create a new
|
||||
data type that reflects data that must be copied from an array of arbitrary
|
||||
size will have to allocate memory (and can fail; note that there is an
|
||||
MPI error class for out-of-memory).
|
||||
|
||||
Question:
|
||||
Do we want to have an aligned allocation routine? E.g., one that
|
||||
aligns memory on a cache-line.
|
||||
D*/
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* No memory tracing; just use native functions */
|
||||
void* MPIU_Malloc( _In_ SIZE_T size );
|
||||
|
||||
void* MPIU_Calloc( _In_ SIZE_T elements, _In_ SIZE_T size );
|
||||
|
||||
void MPIU_Free( _In_opt_ _Post_ptr_invalid_ void* pMem );
|
||||
|
||||
void* MPIU_Realloc( _In_ void* pMem, _In_ SIZE_T size );
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
//
|
||||
// C++ operator new/delete overload.
|
||||
//
|
||||
// Normal operator new: pInt = new int;
|
||||
//
|
||||
void* __cdecl operator new( size_t size );
|
||||
|
||||
//
|
||||
// Placement new: pInt = new( ptr ) int;
|
||||
//
|
||||
void* __cdecl operator new( size_t /*size*/, _In_/*count_(size)*/ void* pMem );
|
||||
|
||||
//
|
||||
// Array new: pInt = new int[10];
|
||||
//
|
||||
void* __cdecl operator new[]( size_t size );
|
||||
|
||||
//
|
||||
// Placement array new: pInt = new( ptr ) int[10];
|
||||
//
|
||||
void* __cdecl operator new[]( size_t /*size*/, _In_/*count_(size)*/ void* pMem );
|
||||
|
||||
//
|
||||
// Normal operator delete: delete pInt;
|
||||
//
|
||||
void __cdecl operator delete( _In_opt_ _Post_ptr_invalid_ void* pObj );
|
||||
|
||||
//
|
||||
// Array delete: delete[] pInt;
|
||||
//
|
||||
void __cdecl operator delete[]( _In_opt_ _Post_ptr_invalid_ void* pObj );
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
#define MPIU_Malloc_obj(type_) \
|
||||
(type_*)MPIU_Malloc(sizeof(type_))
|
||||
|
||||
#define MPIU_Malloc_objn(count_, type_) \
|
||||
(type_*)MPIU_Malloc((count_)*sizeof(type_))
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* end of mpimem.h */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "mpimem.h"
|
||||
|
||||
|
||||
__forceinline void* __cdecl operator new( size_t size )
|
||||
{
|
||||
return MPIU_Malloc( size );
|
||||
}
|
||||
|
||||
|
||||
__forceinline void* __cdecl operator new( size_t /*size*/, _In_ void* pMem )
|
||||
{
|
||||
return pMem;
|
||||
}
|
||||
|
||||
|
||||
__forceinline void* __cdecl operator new[]( size_t size )
|
||||
{
|
||||
return MPIU_Malloc( size );
|
||||
}
|
||||
|
||||
|
||||
__forceinline void* __cdecl operator new[]( size_t /*size*/, _In_ void* pMem )
|
||||
{
|
||||
return pMem;
|
||||
}
|
||||
|
||||
|
||||
__forceinline void __cdecl operator delete( _In_opt_ _Post_ptr_invalid_ void* pObj )
|
||||
{
|
||||
MPIU_Free( pObj );
|
||||
}
|
||||
|
||||
|
||||
__forceinline void __cdecl operator delete( _In_opt_ void* /*pObj*/, _In_ void* /*pMem*/ )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
__forceinline void __cdecl operator delete[]( _In_opt_ _Post_ptr_invalid_ void* pObj )
|
||||
{
|
||||
MPIU_Free( pObj );
|
||||
}
|
||||
|
||||
|
||||
__forceinline void __cdecl operator delete[]( _In_opt_ void* /*pObj*/, _In_ void* /*pMem*/ )
|
||||
{
|
||||
}
|
|
@ -0,0 +1,749 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
* (C) 2001 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#if !defined(MPIDU_SOCK_H_INCLUDED)
|
||||
#define MPIDU_SOCK_H_INCLUDED
|
||||
|
||||
#include "mpidef.h"
|
||||
#include "ex.h"
|
||||
|
||||
|
||||
#define MPIDU_SOCK_INVALID_SOCK NULL
|
||||
#define MPIDU_SOCK_INFINITE_TIME INFINITE
|
||||
|
||||
typedef SOCKET MPIDU_SOCK_NATIVE_FD;
|
||||
|
||||
|
||||
//
|
||||
// Allocated per request
|
||||
//
|
||||
typedef struct sock_read_context
|
||||
{
|
||||
WSABUF tmpiov;
|
||||
WSABUF *iov;
|
||||
MPIU_Bsize_t total;
|
||||
MPIU_Bsize_t min_recv;
|
||||
int iovlen;
|
||||
|
||||
} sock_read_context;
|
||||
|
||||
|
||||
typedef struct sock_write_context
|
||||
{
|
||||
WSABUF tmpiov;
|
||||
WSABUF *iov;
|
||||
MPIU_Bsize_t total;
|
||||
int iovlen;
|
||||
|
||||
} sock_write_context;
|
||||
|
||||
|
||||
struct sock_state_t;
|
||||
|
||||
|
||||
typedef struct sock_accept_context
|
||||
{
|
||||
sock_state_t* accept_state;
|
||||
char accept_buffer[sizeof(struct sockaddr_in)*2+32];
|
||||
|
||||
} sock_accept_context;
|
||||
|
||||
|
||||
#define SOCKI_DESCRIPTION_LENGTH 256
|
||||
typedef struct sock_connect_context
|
||||
{
|
||||
HANDLE retry_timer;
|
||||
const char* cur_host;
|
||||
int error;
|
||||
int port;
|
||||
int retry_count;
|
||||
char host_description[SOCKI_DESCRIPTION_LENGTH];
|
||||
|
||||
} sock_connect_context;
|
||||
|
||||
|
||||
typedef struct sock_close_context
|
||||
{
|
||||
int closectx;
|
||||
|
||||
} sock_close_context;
|
||||
|
||||
|
||||
typedef struct sock_overlapped_s
|
||||
{
|
||||
EXOVERLAPPED exov;
|
||||
sock_state_t* sock;
|
||||
|
||||
union
|
||||
{
|
||||
sock_read_context read;
|
||||
sock_write_context write;
|
||||
sock_accept_context accept;
|
||||
sock_connect_context connect;
|
||||
sock_close_context close;
|
||||
};
|
||||
|
||||
} sock_overlapped_t;
|
||||
|
||||
|
||||
typedef void (*sock_close_routine)(
|
||||
_Inout_ sock_state_t* sock,
|
||||
_Inout_ sock_overlapped_t* pov
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Allocated per socket
|
||||
//
|
||||
typedef struct sock_connect_state_t
|
||||
{
|
||||
sock_overlapped_t* pov;
|
||||
|
||||
} sock_connect_state_t;
|
||||
|
||||
|
||||
typedef struct sock_state_t
|
||||
{
|
||||
sock_close_routine pfnClose;
|
||||
SOCKET sock;
|
||||
ExSetHandle_t set;
|
||||
int closing;
|
||||
sock_connect_state_t connect;
|
||||
|
||||
} sock_state_t;
|
||||
|
||||
|
||||
typedef struct MPIDU_Sock_context_t
|
||||
{
|
||||
|
||||
//
|
||||
// Caller Executive overlapped.
|
||||
// * The success/failure callback functions will be invoked on Scok async
|
||||
// operation completion when MPIDU_Sock_wait is called.
|
||||
// * The total number of bytes transfered in a successful read/write
|
||||
// operation is in uov.ov.InernalHigh field of the OVERLAPPED strcture.
|
||||
// * The Sock MPI error value is in uov.ov.Internal
|
||||
//
|
||||
EXOVERLAPPED uov;
|
||||
|
||||
//
|
||||
// Sock private context
|
||||
//
|
||||
sock_overlapped_t sov;
|
||||
|
||||
} MPIDU_Sock_context_t;
|
||||
|
||||
|
||||
//
|
||||
// Parses the netmask from a given environment variable.
|
||||
//
|
||||
HRESULT ParseNetmask( _In_z_ PCWSTR szNetmaskEnv, _Out_ IN_ADDR* pAddr, _Out_ IN_ADDR* pMask );
|
||||
|
||||
|
||||
/*@
|
||||
MPIDU_Sock_init - initialize the Sock communication library
|
||||
|
||||
Return value: MPI error code
|
||||
. MPI_SUCCESS - initialization completed successfully
|
||||
|
||||
Notes:
|
||||
The Sock module may be initialized multiple times. The implementation should perform reference counting if necessary.
|
||||
|
||||
Module:
|
||||
Utility-Sock
|
||||
@*/
|
||||
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int MPIDU_Sock_init(void);
|
||||
|
||||
|
||||
/*@
|
||||
MPIDU_Sock_finalize - shutdown the Sock communication library
|
||||
|
||||
Return value: MPI error code
|
||||
. MPI_SUCCESS - shutdown completed successfully
|
||||
|
||||
Notes:
|
||||
<BRT> What are the semantics of finalize? Is it responsible for releasing any resources (socks and sock sets) that the calling
|
||||
code(s) leaked? Should it block until all OS resources are released?
|
||||
|
||||
Module:
|
||||
Utility-Sock
|
||||
@*/
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int MPIDU_Sock_finalize(void);
|
||||
|
||||
|
||||
/*@
|
||||
MPIDU_Sock_get_host_description - obtain a description of the host's
|
||||
communication capabilities
|
||||
|
||||
Input Parameters:
|
||||
. host_description - character array in which the function can store a string
|
||||
describing the communication capabilities of the host
|
||||
- len - length of the character array
|
||||
|
||||
Return value: MPI error code
|
||||
. MPI_SUCCESS - description successfully obtained and placed in host_description
|
||||
|
||||
Notes:
|
||||
The host description string returned by the function is defined by the
|
||||
implementation and should not be interpreted by the
|
||||
application. This string is to be supplied to MPIDU_Sock_post_connect() when
|
||||
one wishes to form a connection with this host.
|
||||
|
||||
Module:
|
||||
Utility-Sock
|
||||
@*/
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int
|
||||
MPIDU_Sock_get_host_description(
|
||||
_Out_writes_z_(len) char* host_description,
|
||||
_In_ int len
|
||||
);
|
||||
|
||||
/*@
|
||||
MPIDU_Sock_hostname_to_host_description - convert a host name to a description of the host's communication capabilities
|
||||
|
||||
Input Parameters:
|
||||
+ hostname - host name string
|
||||
. host_description - character array in which the function can store a string describing the communication capabilities of the host
|
||||
- len - length of host_description
|
||||
|
||||
Return value: MPI error code
|
||||
. MPI_SUCCESS - description successfully obtained and placed in host_description
|
||||
|
||||
Notes:
|
||||
The host description string returned by the function is defined by the implementation and should not be interpreted by the
|
||||
application. This string is to be supplied to MPIDU_Sock_post_connect() when one wishes to form a connection with the host
|
||||
specified by hostname.
|
||||
|
||||
Module:
|
||||
Utility-Sock
|
||||
@*/
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int
|
||||
MPIDU_Sock_hostname_to_host_description(
|
||||
_In_z_ const char* hostname,
|
||||
_Out_writes_z_(len) char* host_description,
|
||||
_In_ int len
|
||||
);
|
||||
|
||||
|
||||
/*@
|
||||
MPIDU_Sock_create_native_fd - create a new native socket descriptor/handle
|
||||
|
||||
Output Parameter:
|
||||
. fd - pointer to the new socket handle
|
||||
|
||||
Return value: MPI error code
|
||||
. MPI_SUCCESS - new sock set successfully create
|
||||
|
||||
Notes:
|
||||
|
||||
Module:
|
||||
Utility-Sock
|
||||
@*/
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int
|
||||
MPIDU_Sock_create_native_fd(
|
||||
_Out_ MPIDU_SOCK_NATIVE_FD* fd
|
||||
);
|
||||
|
||||
|
||||
/*@
|
||||
MPIDU_Sock_native_to_sock - convert a native file descriptor/handle to a sock object
|
||||
|
||||
Input Parameters:
|
||||
+ set - sock set to which the new sock should be added
|
||||
. fd - native file descriptor
|
||||
|
||||
Output Parameter:
|
||||
. sock - new sock object
|
||||
|
||||
Return value: MPI error code
|
||||
. MPI_SUCCESS - sock successfully created
|
||||
|
||||
Notes:
|
||||
The constraints on which file descriptors/handles may be converted to a sock object are defined by the implementation.
|
||||
It is possible, however, that the conversion of an inappropriate descriptor/handle may complete successfully but the
|
||||
sock object may not function properly.
|
||||
|
||||
Thread safety:
|
||||
The addition of a new sock object to the sock set may occur while other threads are performing operations on the same sock set.
|
||||
Thread safety of simultaneously operations on the same sock set must be guaranteed by the Sock implementation.
|
||||
|
||||
@*/
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int
|
||||
MPIDU_Sock_native_to_sock(
|
||||
_In_ ExSetHandle_t set,
|
||||
_In_ MPIDU_SOCK_NATIVE_FD fd,
|
||||
_Outptr_ sock_state_t **ppSock
|
||||
);
|
||||
|
||||
|
||||
/*@
|
||||
MPIDU_Sock_listen - establish a listener sock
|
||||
|
||||
Input Parameters:
|
||||
+ set - sock set to which the listening sock should be added
|
||||
- port - desired port (or zero if a specific port is not desired)
|
||||
|
||||
Output Parameters:
|
||||
+ port - port assigned to the listener
|
||||
- sock - new listener sock
|
||||
|
||||
Return value: MPI error code
|
||||
. MPI_SUCCESS - listener sock successfully established
|
||||
|
||||
Notes:
|
||||
Use the established listener socket to call MPIDU_Sock_post_accept
|
||||
|
||||
The environment variable MPICH_PORTRANGE=min:max may be used to restrict the ports mpich processes listen on.
|
||||
|
||||
Thread safety:
|
||||
The addition of the listener sock object to the sock set may occur while other threads are performing operations on the same sock
|
||||
set. Thread safety of simultaneously operations on the same sock set must be guaranteed by the Sock implementation.
|
||||
|
||||
Module:
|
||||
Utility-Sock
|
||||
@*/
|
||||
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int
|
||||
MPIDU_Sock_listen(
|
||||
_In_ ExSetHandle_t set,
|
||||
_In_ unsigned long addr,
|
||||
_Inout_ int *port,
|
||||
_Outptr_ sock_state_t **ppSock
|
||||
);
|
||||
|
||||
|
||||
/*@
|
||||
MPIDU_Sock_post_accept - request that a new connection would be accepted
|
||||
|
||||
Input Parameters:
|
||||
+ listener_sock - listener sock object from which to obtain the new connection
|
||||
- pov - user context associated with the accept request
|
||||
|
||||
Output Parameter:
|
||||
. pSock - sock object for the new connection
|
||||
|
||||
Return value: MPI error code
|
||||
. MPI_SUCCESS - new connection successfully established and associated with new sock objecta
|
||||
|
||||
Notes:
|
||||
In the event of a connection failure, MPIDU_Sock_post_accept() may fail to acquire and return a new sock despite any
|
||||
MPIDU_SOCK_OP_ACCEPT event notification. On the other hand, MPIDU_Sock_post_accept() may return a sock for which the underlying
|
||||
connection has already failed. (The Sock implementation may be unaware of the failure until read/write operations are performed.)
|
||||
|
||||
Thread safety:
|
||||
The addition of the new sock object to the sock set may occur while other threads are performing operations on the same sock set.
|
||||
Thread safety of simultaneously operations on the same sock set must be guaranteed by the Sock implementation.
|
||||
|
||||
Module:
|
||||
Utility-Sock
|
||||
@*/
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int
|
||||
MPIDU_Sock_post_accept(
|
||||
_In_ sock_state_t *listener_sock,
|
||||
_Outptr_ sock_state_t **ppSock,
|
||||
_In_ MPIDU_Sock_context_t* psc
|
||||
);
|
||||
|
||||
|
||||
/*@
|
||||
MPIDU_Sock_post_connect - request that a new connection be formed
|
||||
|
||||
Input Parameters:
|
||||
+ set - sock set to which the new sock object should be added
|
||||
. host_description - string containing the communication capabilities of the listening host
|
||||
+ port - port number of listener sock on the listening host
|
||||
. pov - user context associated with the connect request
|
||||
|
||||
Output Parameter:
|
||||
. sock - new sock object associated with the connection request
|
||||
|
||||
Return value: MPI error code
|
||||
. MPI_SUCCESS - request to form new connection successfully posted
|
||||
|
||||
Notes:
|
||||
The host description of the listening host is supplied MPIDU_Sock_get_host_description(). The intention is that the description
|
||||
contain an enumeration of interface information so that the MPIDU_Sock_connect() can try each of the interfaces until it succeeds
|
||||
in forming a connection. Having a complete set of interface information also allows a particular interface be used selected by the
|
||||
user at runtime using the MPICH_NETMASK. <BRT> The name of the environment variable seems wrong. Perhaps MPICH_INTERFACE? We
|
||||
should ask the Systems group.
|
||||
|
||||
Thread safety:
|
||||
The addition of the new sock object to the sock set may occur while other threads are performing operations on the same sock set.
|
||||
Thread safety of simultaneously operations on the same sock set must be guaranteed by the Sock implementation.
|
||||
|
||||
Module:
|
||||
Utility-Sock
|
||||
@*/
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int
|
||||
MPIDU_Sock_post_connect(
|
||||
_In_ ExSetHandle_t set,
|
||||
_In_z_ const char* host_description,
|
||||
_In_ int port,
|
||||
_Outptr_ sock_state_t** ppSock,
|
||||
_In_ int usemask,
|
||||
_Inout_ MPIDU_Sock_context_t* psc
|
||||
);
|
||||
|
||||
|
||||
/*@
|
||||
MPIDU_Sock_post_close - request that an existing connection be closed
|
||||
|
||||
Input Parameter:
|
||||
. sock - sock object to be closed
|
||||
- pov - user context associated with the close request
|
||||
|
||||
Return value: MPI error code
|
||||
. MPI_SUCCESS - request to close the connection was successfully posted
|
||||
|
||||
Notes:
|
||||
If any other operations are posted on the specified sock, they will be terminated. An appropriate event will be generated for each
|
||||
terminated operation. All such events will be delivered by MPIDU_Sock_wait() prior to the delivery of the MPIDU_SOCK_OP_CLOSE
|
||||
event.
|
||||
|
||||
The sock object is destroyed just prior to the MPIDU_SOCK_OP_CLOSE event being returned by MPIDU_Sock_wait(). Any oustanding
|
||||
references to the sock object held by the application should be considered invalid and not used again.
|
||||
|
||||
Thread safety:
|
||||
MPIDU_Sock_post_close() may be called while another thread is calling or blocking in MPIDU_Sock_wait() specifying the same sock set
|
||||
to which this sock belongs. If another thread is blocking MPIDU_Sock_wait() and the close operation causes the sock set to become
|
||||
empty, then MPIDU_Sock_wait() will return with an error.
|
||||
|
||||
Calling any of the immediate or post routines during or after the call to MPIDU_Sock_post_close() is consider an application error.
|
||||
The result of doing so is undefined. The application should coordinate the closing of a sock with the activities of other threads
|
||||
to ensure that simultaneous calls do not occur.
|
||||
|
||||
Module:
|
||||
Utility-Sock
|
||||
@*/
|
||||
|
||||
void
|
||||
MPIDU_Sock_post_close(
|
||||
_Inout_ sock_state_t *sock,
|
||||
_Inout_ MPIDU_Sock_context_t* psc
|
||||
);
|
||||
|
||||
/*@
|
||||
MPIDU_Sock_post_read - request that data be read from a sock
|
||||
|
||||
Input Parameters:
|
||||
+ sock - sock object from which data is to be read
|
||||
. buf - buffer into which the data should be placed
|
||||
. len - number of bytes to read
|
||||
. minbr - the async operation can return with number of bytes read greater or
|
||||
equal to minbr (min bar) before the entire buffer is read.
|
||||
. pov - user context associated with the read request
|
||||
|
||||
Return value: MPI error code
|
||||
. MPI_SUCCESS - request to read was successfully posted
|
||||
|
||||
Notes:
|
||||
Only one read operation may be posted at a time. Furthermore, an immediate read may not be performed while a posted write is
|
||||
outstanding. This is considered to be an application error, and the results of doing so are undefined.
|
||||
|
||||
If MPIDU_Sock_post_close() is called before the posted read operation completes, the read operation will be terminated.
|
||||
|
||||
Thread safety:
|
||||
MPIDU_Sock_post_read() may be called while another thread is attempting to perform an immediate write or post a write operation on
|
||||
the same sock. MPIDU_Sock_post_read() may also be called while another thread is calling or blocking in MPIDU_Sock_wait() on the
|
||||
same sock set to which the specified sock belongs.
|
||||
|
||||
MPIDU_Sock_post_write() may not be called while another thread is performing an immediate read on the same sock. This is
|
||||
considered to be an application error, and the results of doing so are undefined.
|
||||
|
||||
Calling MPIDU_Sock_post_read() during or after the call to MPIDU_Sock_post_close() is consider an application error. The result of
|
||||
doing so is undefined. The application should coordinate the closing of a sock with the activities of other threads to ensure that
|
||||
one thread is not attempting to post a new operation while another thread is attempting to close the sock.
|
||||
|
||||
Module:
|
||||
Utility-Sock
|
||||
@*/
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int
|
||||
MPIDU_Sock_post_read(
|
||||
_Inout_ sock_state_t *sock,
|
||||
_Out_writes_bytes_(len) void * buf,
|
||||
_In_ MPIU_Bsize_t len,
|
||||
_In_ MPIU_Bsize_t minbr,
|
||||
_Inout_ MPIDU_Sock_context_t* psc
|
||||
);
|
||||
|
||||
/*@
|
||||
MPIDU_Sock_post_readv - request that a vector of data be read from a sock
|
||||
|
||||
Input Parameters:
|
||||
+ sock - sock object from which the data is to read
|
||||
. iov - I/O vector describing buffers into which the data is placed
|
||||
. iov_n - number of elements in I/O vector (must be 1 currently)
|
||||
. minbr - the async operation can return with number of bytes read greater or
|
||||
equal to minbr (min bar) before the entire buffer is read.
|
||||
. pov - user context associated with the readv request
|
||||
|
||||
Return value: MPI error code
|
||||
. MPI_SUCCESS - request to read was successfully posted
|
||||
|
||||
Notes:
|
||||
Only one read operation may be posted at a time. Furthermore, an immediate read may not be performed while a posted write is
|
||||
outstanding. This is considered to be an application error, and the results of doing so are undefined.
|
||||
|
||||
If MPIDU_Sock_post_close() is called before the posted read operation completes, the read operation will be terminated.
|
||||
|
||||
Thread safety:
|
||||
MPIDU_Sock_post_readv() may be called while another thread is attempting to perform an immediate write or post a write operation on
|
||||
the same sock. MPIDU_Sock_post_readv() may also be called while another thread is calling or blocking in MPIDU_Sock_wait() on the
|
||||
same sock set to which the specified sock belongs.
|
||||
|
||||
MPIDU_Sock_post_readv() may not be called while another thread is performing an immediate read on the same sock. This is
|
||||
considered to be an application error, and the results of doing so are undefined.
|
||||
|
||||
Calling MPIDU_Sock_post_readv() during or after the call to MPIDU_Sock_post_close() is consider an application error. The result
|
||||
of doing so is undefined. The application should coordinate the closing of a sock with the activities of other threads to ensure
|
||||
that one thread is not attempting to post a new operation while another thread is attempting to close the sock.
|
||||
|
||||
Module:
|
||||
Utility-Sock
|
||||
@*/
|
||||
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int
|
||||
MPIDU_Sock_post_readv(
|
||||
_Inout_ sock_state_t *sock,
|
||||
_In_reads_(iov_n)WSABUF * iov,
|
||||
_In_ int iov_n,
|
||||
_In_ MPIU_Bsize_t minbr,
|
||||
_Inout_ MPIDU_Sock_context_t* psc
|
||||
);
|
||||
|
||||
/*@
|
||||
MPIDU_Sock_post_write - request that data be written to a sock
|
||||
|
||||
Input Parameters:
|
||||
+ sock - sock object which the data is to be written
|
||||
. buf - buffer containing the data
|
||||
. len - number of bytes to write
|
||||
. pov - user context associated with the write request
|
||||
|
||||
Return value: MPI error code
|
||||
. MPI_SUCCESS - request to write was successfully posted
|
||||
|
||||
Notes:
|
||||
Only one write operation may be posted at a time. Furthermore, an immediate write may not be performed while a posted write is
|
||||
outstanding. This is considered to be an application error, and the results of doing so are undefined.
|
||||
|
||||
If MPIDU_Sock_post_close() is called before the posted write operation completes, the write operation will be terminated.
|
||||
|
||||
Thread safety:
|
||||
MPIDU_Sock_post_write() may be called while another thread is attempting to perform an immediate read or post a read operation on
|
||||
the same sock. MPIDU_Sock_post_write() may also be called while another thread is calling or blocking in MPIDU_Sock_wait() on the
|
||||
same sock set to which the specified sock belongs.
|
||||
|
||||
MPIDU_Sock_post_write() may not be called while another thread is performing an immediate write on the same sock. This is
|
||||
considered to be an application error, and the results of doing so are undefined.
|
||||
|
||||
Calling MPIDU_Sock_post_write() during or after the call to MPIDU_Sock_post_close() is consider an application error. The result
|
||||
of doing so is undefined. The application should coordinate the closing of a sock with the activities of other threads to ensure
|
||||
that one thread is not attempting to post a new operation while another thread is attempting to close the sock. <BRT> Do we really
|
||||
need this flexibility?
|
||||
|
||||
Module:
|
||||
Utility-Sock
|
||||
@*/
|
||||
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int
|
||||
MPIDU_Sock_post_write(
|
||||
_Inout_ sock_state_t *sock,
|
||||
_In_reads_bytes_(min) const void* buf,
|
||||
_In_ MPIU_Bsize_t min,
|
||||
_Inout_ MPIDU_Sock_context_t* psc
|
||||
);
|
||||
|
||||
/*@
|
||||
MPIDU_Sock_post_writev - request that a vector of data be written to a sock
|
||||
|
||||
Input Parameters:
|
||||
+ sock - sock object which the data is to be written
|
||||
. iov - I/O vector describing buffers of data to be written
|
||||
. iov_n - number of elements in I/O vector
|
||||
. pov - user context associated with the writev request
|
||||
|
||||
Return value: MPI error code
|
||||
. MPI_SUCCESS - request to write was successfully posted
|
||||
|
||||
Notes:
|
||||
Only one write operation may be posted at a time. Furthermore, an immediate write may not be performed while a posted write is
|
||||
outstanding. This is considered to be an application error, and the results of doing so are undefined.
|
||||
|
||||
If MPIDU_Sock_post_close() is called before the posted write operation completes, the write operation will be terminated.
|
||||
|
||||
Thread safety:
|
||||
MPIDU_Sock_post_writev() may be called while another thread is attempting to perform an immediate read or post a read operation on
|
||||
the same sock. MPIDU_Sock_post_writev() may also be called while another thread is calling or blocking in MPIDU_Sock_wait() on the
|
||||
same sock set to which the specified sock belongs.
|
||||
|
||||
MPIDU_Sock_post_writev() may not be called while another thread is performing an immediate write on the same sock. This is
|
||||
considered to be an application error, and the results of doing so are undefined.
|
||||
|
||||
Calling MPIDU_Sock_post_writev() during or after the call to MPIDU_Sock_post_close() is consider an application error. The result
|
||||
of doing so is undefined. The application should coordinate the closing of a sock with the activities of other threads to ensure
|
||||
that one thread is not attempting to post a new operation while another thread is attempting to close the sock.
|
||||
|
||||
Module:
|
||||
Utility-Sock
|
||||
@*/
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int
|
||||
MPIDU_Sock_post_writev(
|
||||
_Inout_ sock_state_t *sock,
|
||||
_In_reads_(iov_n) WSABUF* iov,
|
||||
_In_ int iov_n,
|
||||
_Inout_ MPIDU_Sock_context_t* psc
|
||||
);
|
||||
|
||||
/*@
|
||||
MPIDU_Sock_close - perform an immediate hard close
|
||||
|
||||
Input Parameter:
|
||||
. sock - sock object to be closed
|
||||
|
||||
Return value: none
|
||||
|
||||
Notes:
|
||||
If any other operations are posted on the specified sock, they will be terminated. An appropriate event will be generated for each
|
||||
terminated operation. All such events will be delivered by MPIDU_Sock_wait(). No MPIDU_SOCK_OP_CLOSE is generated.
|
||||
event.
|
||||
|
||||
The sock object is destroyed immediately. Any oustanding references to the sock object held by the application should be considered
|
||||
invalid and not used again.
|
||||
|
||||
Thread safety:
|
||||
MPIDU_Sock_close() may be called while another thread is calling or blocking in MPIDU_Sock_wait() specifying the same sock set
|
||||
to which this sock belongs. If another thread is blocking MPIDU_Sock_wait() and the close operation causes the sock set to become
|
||||
empty, then MPIDU_Sock_wait() will return with an error.
|
||||
|
||||
Calling any of the immediate or post routines during or after the call to MPIDU_Sock_post_close() is consider an application error.
|
||||
The result of doing so is undefined. The application should coordinate the closing of a sock with the activities of other threads
|
||||
to ensure that simultaneous calls do not occur.
|
||||
|
||||
Module:
|
||||
Utility-Sock
|
||||
@*/
|
||||
|
||||
void
|
||||
MPIDU_Sock_close(
|
||||
_In_ _Post_invalid_ sock_state_t *sock
|
||||
);
|
||||
|
||||
|
||||
/*@
|
||||
MPIDU_Sock_writev - perform an immediate vector write
|
||||
|
||||
Input Parameters:
|
||||
+ sock - sock object to which data is to be written
|
||||
. iov - I/O vector describing buffers of data to be written
|
||||
- iov_n - number of elements in I/O vector
|
||||
|
||||
Output Parameter:
|
||||
. num_written - actual number of bytes written
|
||||
|
||||
Return value: MPI error code
|
||||
. MPI_SUCCESS - no error encountered during the write operation
|
||||
|
||||
Notes:
|
||||
An immediate write may not be performed while a posted write is outstanding on the same sock. This is considered to be an
|
||||
application error, and the results of doing so are undefined.
|
||||
|
||||
Thread safety:
|
||||
MPIDU_Sock_write() may be called while another thread is attempting to perform an immediate read or post a read operation on the
|
||||
same sock. MPIDU_Sock_write() may also be called while another thread is calling or blocking in MPIDU_Sock_wait() on the same sock
|
||||
set to which the specified sock belongs.
|
||||
|
||||
A immediate write may not be performed if another thread is performing an immediate write on the same sock. This is considered to
|
||||
be an application error, and the results of doing so are undefined.
|
||||
|
||||
Calling MPIDU_Sock_write() during or after the call to MPIDU_Sock_post_close() is consider to be an application error. The result
|
||||
of doing so is undefined. The application should coordinate the closing of a sock with the activities of other threads to ensure
|
||||
that one thread is not attempting to perform an immediate write while another thread is attempting to close the sock.
|
||||
|
||||
Module:
|
||||
Utility-Sock
|
||||
@*/
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int
|
||||
MPIDU_Sock_writev(
|
||||
_In_ const sock_state_t * const sock,
|
||||
_In_reads_(iov_n) WSABUF * iov,
|
||||
_In_ int iov_n,
|
||||
_Out_ MPIU_Bsize_t * num_written
|
||||
);
|
||||
|
||||
|
||||
/*@r
|
||||
MPIDU_Sock_get_sock_id - get an integer identifier for a sock object
|
||||
|
||||
Input Parameter:
|
||||
. sock - sock object
|
||||
|
||||
Return value: an integer that uniquely identifies the sock object
|
||||
|
||||
Notes:
|
||||
The integer is unique relative to all other open sock objects in the local process. The integer may later be reused for a
|
||||
different sock once the current object is closed and destroyed.
|
||||
|
||||
This function does not return an error code. Passing in an invalid sock object has undefined results (garbage in, garbage out).
|
||||
|
||||
Module:
|
||||
Utility-Sock
|
||||
@*/
|
||||
|
||||
_Success_(return >=0)
|
||||
int
|
||||
MPIDU_Sock_get_sock_id(
|
||||
_In_ const sock_state_t * const sock
|
||||
);
|
||||
|
||||
/*@
|
||||
MPIDU_Sock_keepalive - enable connection keep-alive protocol
|
||||
|
||||
Input Parameter:
|
||||
. sock - sock object
|
||||
|
||||
Return value: an MPI error code
|
||||
|
||||
Module:
|
||||
Utility-Sock
|
||||
@*/
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int
|
||||
MPIDU_Sock_keepalive(
|
||||
_In_ const sock_state_t * const sock
|
||||
);
|
||||
|
||||
//
|
||||
// Utility function to retrieve the ip address string associated with a socket.
|
||||
// This is the address the socket is connected to on the remote host.
|
||||
//
|
||||
_Success_(*pPort != 0)
|
||||
void
|
||||
get_sock_peer_address(
|
||||
_In_ _Pre_satisfies_(0 != pSock->sock) sock_state_t* pSock,
|
||||
_Out_writes_bytes_(addrLen) char* pAddr,
|
||||
_In_ int addrLen,
|
||||
_Out_ int* pPort
|
||||
);
|
||||
|
||||
#endif /* !defined(MPIDU_SOCK_H_INCLUDED) */
|
|
@ -0,0 +1,445 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
|
||||
/*
|
||||
* This file contains "safe" versions of the various string and printf
|
||||
* operations.
|
||||
*/
|
||||
|
||||
_Success_(return >= 0 && return <= cchDest)
|
||||
int
|
||||
MPIU_Snprintf(
|
||||
_Null_terminated_ _Out_writes_to_(cchDest, return) char* dest,
|
||||
_In_ size_t cchDest,
|
||||
_Printf_format_string_ const char* format,
|
||||
...
|
||||
)
|
||||
{
|
||||
size_t len;
|
||||
va_list args;
|
||||
va_start( args, format );
|
||||
|
||||
OACR_WARNING_SUPPRESS(USE_WIDE_API, "SMPD uses only ANSI character set.");
|
||||
HRESULT hr = StringCchVPrintfExA(
|
||||
dest,
|
||||
cchDest,
|
||||
nullptr,
|
||||
&len,
|
||||
0,
|
||||
format,
|
||||
args
|
||||
);
|
||||
|
||||
va_end( args );
|
||||
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return static_cast<int>(cchDest - len);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Overloaded function for wide characters
|
||||
//
|
||||
_Success_(return >= 0 && return <= cchDest)
|
||||
int
|
||||
MPIU_Snprintf(
|
||||
_Null_terminated_ _Out_writes_to_(cchDest, return) wchar_t* dest,
|
||||
_In_ size_t cchDest,
|
||||
_Printf_format_string_ const wchar_t* format,
|
||||
...
|
||||
)
|
||||
{
|
||||
size_t len;
|
||||
va_list args;
|
||||
va_start( args, format );
|
||||
|
||||
HRESULT hr = StringCchVPrintfExW(
|
||||
dest,
|
||||
cchDest,
|
||||
nullptr,
|
||||
&len,
|
||||
0,
|
||||
format,
|
||||
args
|
||||
);
|
||||
|
||||
va_end( args );
|
||||
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return static_cast<int>(cchDest - len);
|
||||
}
|
||||
|
||||
|
||||
_Success_(return >= 0 && return <= cchDest)
|
||||
int
|
||||
MPIU_Vsnprintf(
|
||||
_Null_terminated_ _Out_writes_to_(cchDest, return) char* dest,
|
||||
_In_ size_t cchDest,
|
||||
_Printf_format_string_ const char* format,
|
||||
_In_ va_list args
|
||||
)
|
||||
{
|
||||
size_t len;
|
||||
OACR_WARNING_SUPPRESS(USE_WIDE_API, "MSMPI uses only ANSI character set.");
|
||||
HRESULT hr = StringCchVPrintfExA(
|
||||
dest,
|
||||
cchDest,
|
||||
nullptr,
|
||||
&len,
|
||||
0,
|
||||
format,
|
||||
args
|
||||
);
|
||||
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return static_cast<int>(cchDest - len);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Overloaded function for wide characters
|
||||
//
|
||||
_Success_(return >= 0 && return <= cchDest)
|
||||
int
|
||||
MPIU_Vsnprintf(
|
||||
_Null_terminated_ _Out_writes_to_(cchDest, return) wchar_t* dest,
|
||||
_In_ size_t cchDest,
|
||||
_Printf_format_string_ const wchar_t* format,
|
||||
_In_ va_list args
|
||||
)
|
||||
{
|
||||
size_t len;
|
||||
HRESULT hr = StringCchVPrintfExW(
|
||||
dest,
|
||||
cchDest,
|
||||
nullptr,
|
||||
&len,
|
||||
0,
|
||||
format,
|
||||
args
|
||||
);
|
||||
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return static_cast<int>(cchDest - len);
|
||||
}
|
||||
|
||||
|
||||
_Success_(return == 0)
|
||||
int
|
||||
MPIU_Strcpy(
|
||||
_Out_writes_z_(cchDest) char* dest,
|
||||
_In_ size_t cchDest,
|
||||
_In_z_ const char* src )
|
||||
{
|
||||
OACR_WARNING_SUPPRESS(USE_WIDE_API, "MSMPI uses only ANSI character set.");
|
||||
HRESULT hr = StringCchCopyA( dest, cchDest, src );
|
||||
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return static_cast<int>( hr );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
_Success_(return == 0)
|
||||
int
|
||||
MPIU_Strcpy(
|
||||
_Out_writes_z_(cchDest) wchar_t* dest,
|
||||
_In_ size_t cchDest,
|
||||
_In_z_ const wchar_t* src )
|
||||
{
|
||||
HRESULT hr = StringCchCopyW( dest, cchDest, src );
|
||||
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return static_cast<int>( hr );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MPIU_Strnapp(
|
||||
_Out_writes_z_(n) char* dst,
|
||||
_In_z_ const char* src,
|
||||
_In_ size_t n )
|
||||
{
|
||||
OACR_WARNING_SUPPRESS(USE_WIDE_API, "MSMPI uses only ANSI character set.");
|
||||
OACR_WARNING_SUPPRESS(HRESULT_NOT_CHECKED, "Ignoring return value.");
|
||||
StringCchCatA( dst, n, src );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MPIU_Strnapp(
|
||||
_Out_writes_z_(n) wchar_t* dst,
|
||||
_In_z_ const wchar_t* src,
|
||||
_In_ size_t n)
|
||||
{
|
||||
OACR_WARNING_SUPPRESS(HRESULT_NOT_CHECKED, "Ignoring return value.");
|
||||
StringCchCatW(dst, n, src);
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
MPIU_Strlen(
|
||||
_In_ PCSTR src,
|
||||
_In_ size_t cchMax
|
||||
)
|
||||
{
|
||||
size_t len;
|
||||
OACR_WARNING_SUPPRESS(USE_WIDE_API, "MSMPI uses only ANSI character set.");
|
||||
HRESULT hr = StringCchLengthA( src, cchMax, &len );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return SIZE_MAX;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
MPIU_Strlen(
|
||||
_In_ PCWSTR src,
|
||||
_In_ size_t cchMax
|
||||
)
|
||||
{
|
||||
size_t len;
|
||||
HRESULT hr = StringCchLengthW( src, cchMax, &len );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return SIZE_MAX;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
_Ret_valid_ _Null_terminated_
|
||||
_Success_(return != nullptr)
|
||||
wchar_t*
|
||||
MPIU_Strdup(
|
||||
_In_z_ const wchar_t* str
|
||||
)
|
||||
{
|
||||
size_t maxlen = MPIU_Strlen( str );
|
||||
if( maxlen == SIZE_MAX )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//
|
||||
// Need one extra for the null terminating character
|
||||
//
|
||||
maxlen++;
|
||||
wchar_t* s = static_cast<wchar_t*>( MPIU_Malloc( sizeof(wchar_t) * maxlen ) );
|
||||
if( s != nullptr )
|
||||
{
|
||||
CopyMemory( s, str, maxlen * sizeof(wchar_t) );
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
_Ret_valid_ _Null_terminated_
|
||||
_Success_(return != nullptr)
|
||||
char*
|
||||
MPIU_Strdup(
|
||||
_In_z_ const char* str
|
||||
)
|
||||
{
|
||||
size_t maxlen = MPIU_Strlen( str );
|
||||
if( maxlen == SIZE_MAX )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//
|
||||
// Need one extra for the null terminating character
|
||||
//
|
||||
maxlen++;
|
||||
char* s = static_cast<char*>( MPIU_Malloc( sizeof(char) * maxlen ) );
|
||||
if( s != nullptr )
|
||||
{
|
||||
CopyMemory( s, str, maxlen );
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
_Success_(return==NO_ERROR)
|
||||
DWORD
|
||||
MPIU_Getenv(
|
||||
_In_z_ PCSTR name,
|
||||
_Out_writes_z_(cchBuffer) PSTR buffer,
|
||||
_In_ DWORD cchBuffer
|
||||
)
|
||||
{
|
||||
OACR_WARNING_SUPPRESS( USE_WIDE_API, "MS MPI uses ANSI char set" );
|
||||
DWORD cchRet = GetEnvironmentVariableA( name, buffer, cchBuffer );
|
||||
if( cchRet == 0 )
|
||||
{
|
||||
//
|
||||
// There can be errors other than ERROR_ENVVAR_NOT_FOUND.
|
||||
// We treat them all as if the env var does not exist.
|
||||
//
|
||||
return ERROR_ENVVAR_NOT_FOUND;
|
||||
}
|
||||
else if( cchRet >= cchBuffer )
|
||||
{
|
||||
return ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
_Success_(return==NO_ERROR)
|
||||
DWORD
|
||||
MPIU_Getenv(
|
||||
_In_z_ PCWSTR name,
|
||||
_Out_writes_z_(cchBuffer) PWSTR buffer,
|
||||
_In_ DWORD cchBuffer
|
||||
)
|
||||
{
|
||||
DWORD cchRet = GetEnvironmentVariableW( name, buffer, cchBuffer );
|
||||
if( cchRet == 0 )
|
||||
{
|
||||
//
|
||||
// There can be errors other than ERROR_ENVVAR_NOT_FOUND.
|
||||
// We treat them all as if the env var does not exist.
|
||||
//
|
||||
return ERROR_ENVVAR_NOT_FOUND;
|
||||
}
|
||||
else if( cchRet >= cchBuffer )
|
||||
{
|
||||
return ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Callee will need to call delete[] to free the memory allocated
|
||||
// for wname_ptr if the function succeeds.
|
||||
//
|
||||
_Success_(return == NOERROR)
|
||||
DWORD
|
||||
MPIU_MultiByteToWideChar(
|
||||
_In_z_ const char* name,
|
||||
_Outptr_result_z_ wchar_t** wname_ptr
|
||||
)
|
||||
{
|
||||
int len = MultiByteToWideChar(
|
||||
CP_UTF8,
|
||||
MB_ERR_INVALID_CHARS,
|
||||
name,
|
||||
-1,
|
||||
NULL,
|
||||
0
|
||||
);
|
||||
if( len == 0 )
|
||||
{
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
wchar_t* wname = new wchar_t[len];
|
||||
if( wname == NULL )
|
||||
{
|
||||
return ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
len = MultiByteToWideChar(
|
||||
CP_UTF8,
|
||||
MB_ERR_INVALID_CHARS,
|
||||
name,
|
||||
-1,
|
||||
wname,
|
||||
len
|
||||
);
|
||||
if( len == 0 )
|
||||
{
|
||||
delete[] wname;
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
*wname_ptr = wname;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Callee will need to call delete[] to free the memory allocated
|
||||
// for outputStr if the function succeeds.
|
||||
//
|
||||
_Success_(return == NOERROR)
|
||||
DWORD
|
||||
MPIU_WideCharToMultiByte(
|
||||
_In_z_ const wchar_t* str,
|
||||
_Outptr_result_z_ char** outputStr
|
||||
)
|
||||
{
|
||||
int len = WideCharToMultiByte(
|
||||
CP_UTF8,
|
||||
WC_ERR_INVALID_CHARS,
|
||||
str,
|
||||
-1,
|
||||
nullptr,
|
||||
0,
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
if( len == 0 )
|
||||
{
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
char* tmpStr = new char[len];
|
||||
if( tmpStr == nullptr )
|
||||
{
|
||||
return ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
len = WideCharToMultiByte(
|
||||
CP_UTF8,
|
||||
WC_ERR_INVALID_CHARS,
|
||||
str,
|
||||
-1,
|
||||
tmpStr,
|
||||
len,
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
if( len == 0 )
|
||||
{
|
||||
delete[] tmpStr;
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
*outputStr = tmpStr;
|
||||
return NOERROR;
|
||||
}
|
|
@ -0,0 +1,366 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <strsafe.h>
|
||||
#include <oacr.h>
|
||||
|
||||
|
||||
/*@ MPIU_Strncpy - Copy a string with buffer size. Force null termination
|
||||
|
||||
Input Parameters:
|
||||
. dst - String to copy into
|
||||
+ src - String to copy
|
||||
- n - 'dst' buffer size in chars (including null char)
|
||||
|
||||
Return value:
|
||||
pointer to the end terminating null char
|
||||
|
||||
Notes:
|
||||
This routine is the routine that you wish 'strncpy' was. In copying
|
||||
'src' to 'dst', it stops when either the end of 'src' (the
|
||||
null character) is seen or the maximum length 'n is reached.
|
||||
Unlike 'strncpy', it does not add enough nulls to 'dst' after
|
||||
copying 'src' in order to move precisely 'n' characters.
|
||||
This routine is safer than strncpy; it always null terminates the dst
|
||||
string. (except when the dst size is zero)
|
||||
|
||||
MPIU_Strncpy is implemented inline to help the compiler optimize
|
||||
per use instance.
|
||||
|
||||
Module:
|
||||
Utility
|
||||
@*/
|
||||
_Ret_z_
|
||||
_Success_(return!=nullptr)
|
||||
static inline char*
|
||||
MPIU_Strncpy(
|
||||
_Out_writes_z_(n) char* dst,
|
||||
_In_z_ const char* src,
|
||||
_In_ size_t n
|
||||
)
|
||||
{
|
||||
char* end;
|
||||
OACR_WARNING_SUPPRESS(USE_WIDE_API, "MSMPI uses only ANSI character set.");
|
||||
HRESULT hr = StringCchCopyExA( dst, n, src, &end, nullptr, 0 );
|
||||
if( hr == STRSAFE_E_INVALID_PARAMETER )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
_Ret_z_
|
||||
_Success_(return!=nullptr)
|
||||
static inline wchar_t*
|
||||
MPIU_Strncpy(
|
||||
_Out_writes_z_(n) wchar_t* dst,
|
||||
_In_z_ const wchar_t* src,
|
||||
_In_ size_t n
|
||||
)
|
||||
{
|
||||
wchar_t* end;
|
||||
HRESULT hr = StringCchCopyExW( dst, n, src, &end, nullptr, 0 );
|
||||
if( hr == STRSAFE_E_INVALID_PARAMETER )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// This is a convenient wrapper for StringCchCopyA
|
||||
//
|
||||
// Return: 0 if success, other errors if failure
|
||||
//
|
||||
_Success_(return == 0)
|
||||
int
|
||||
MPIU_Strcpy(
|
||||
_Out_writes_z_(cchDest) char* dest,
|
||||
_In_ size_t cchDest,
|
||||
_In_z_ const char* src
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// This is a convenient wrapper for StringCchCopyW
|
||||
//
|
||||
// Return: 0 if success, other errors if failure
|
||||
//
|
||||
_Success_(return == 0)
|
||||
int
|
||||
MPIU_Strcpy(
|
||||
_Out_writes_z_(cchDest) wchar_t* dest,
|
||||
_In_ size_t cchDest,
|
||||
_In_z_ const wchar_t* src
|
||||
);
|
||||
|
||||
|
||||
/*@ MPIU_Szncpy - Copy a string into a fixed sized buffer; force null termination
|
||||
|
||||
MPIU_Szncpy is a helper macro provided for copying into fixed sized char arrays.
|
||||
The macro computes the size (char count) of the dst array. Usage example,
|
||||
|
||||
char buffer[333];
|
||||
...
|
||||
-* copy max 333 chars into buffer; buffer will be null terminated. *-
|
||||
MPIU_Szncpy(buffer, str);
|
||||
|
||||
@*/
|
||||
#define MPIU_Szncpy(dst, src) MPIU_Strncpy(dst, src, _countof(dst))
|
||||
|
||||
|
||||
/*@ MPIU_Strnapp - Append to a string with buffer size. Force null termination
|
||||
|
||||
Input Parameters:
|
||||
. dst - String to copy into
|
||||
+ src - String to append
|
||||
- n - 'dst' buffer size in chars (including null char)
|
||||
|
||||
Output Parameter:
|
||||
pointer to the end terminating null char
|
||||
|
||||
Notes:
|
||||
This routine is similar to 'strncat' except that the 'n' argument
|
||||
is the maximum total length of 'dst', rather than the maximum
|
||||
number of characters to move from 'src'. Thus, this routine is
|
||||
easier to use when the declared size of 'src' is known.
|
||||
|
||||
MPIU_Strnapp is implemented inline to help the compiler optimize
|
||||
per use instance.
|
||||
|
||||
Module:
|
||||
Utility
|
||||
@*/
|
||||
void MPIU_Strnapp(
|
||||
_Out_writes_z_(n) char *dst,
|
||||
_In_z_ const char *src,
|
||||
_In_ size_t n);
|
||||
|
||||
|
||||
void MPIU_Strnapp(
|
||||
_Out_writes_z_(n) wchar_t *dst,
|
||||
_In_z_ const wchar_t *src,
|
||||
_In_ size_t n);
|
||||
|
||||
|
||||
/*@ MPIU_Sznapp - Append a string into a fixed sized buffer; force null termination
|
||||
|
||||
MPIU_Sznapp is a helper macro provided for appending into fixed sized char arrays.
|
||||
The macro computes the size (char count) of the dst array. Usage example,
|
||||
|
||||
char buffer[333] = "Initial string";
|
||||
...
|
||||
-* copy max 333 chars into buffer; buffer will be null terminated. *-
|
||||
MPIU_Sznapp(buffer, str);
|
||||
|
||||
@*/
|
||||
#define MPIU_Sznapp(dst, src) MPIU_Strnapp(dst, src, _countof(dst))
|
||||
|
||||
|
||||
size_t MPIU_Strlen(
|
||||
_In_ PCSTR src,
|
||||
_In_ size_t cchMax = STRSAFE_MAX_CCH );
|
||||
|
||||
|
||||
size_t MPIU_Strlen(
|
||||
_In_ PCWSTR src,
|
||||
_In_ size_t cchMax = STRSAFE_MAX_CCH );
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* FIXME - The string routines do not belong in the memory header file */
|
||||
/* FIXME - The string error code such be MPICH2-usable error codes */
|
||||
#define MPIU_STR_SUCCESS 0
|
||||
#define MPIU_STR_FAIL -1
|
||||
#define MPIU_STR_NOMEM 1
|
||||
|
||||
/* FIXME: TRUE/FALSE definitions should either not be used or be
|
||||
used consistently. These also do not belong in the mpimem header file. */
|
||||
#define MPIU_TRUE 1
|
||||
#define MPIU_FALSE 0
|
||||
|
||||
/* FIXME: Global types like this need to be discussed and agreed to */
|
||||
typedef int MPIU_BOOL;
|
||||
|
||||
/* FIXME: These should be scoped to only the routines that need them */
|
||||
#ifdef USE_HUMAN_READABLE_TOKENS
|
||||
|
||||
#define MPIU_STR_QUOTE_CHAR '\"'
|
||||
#define MPIU_STR_QUOTE_STR "\""
|
||||
#define MPIU_STR_DELIM_CHAR '='
|
||||
#define MPIU_STR_DELIM_STR "="
|
||||
#define MPIU_STR_ESCAPE_CHAR '\\'
|
||||
#define MPIU_STR_SEPAR_CHAR ' '
|
||||
#define MPIU_STR_SEPAR_STR " "
|
||||
|
||||
#else
|
||||
|
||||
#define MPIU_STR_QUOTE_CHAR '\"'
|
||||
#define MPIU_STR_QUOTE_STR "\""
|
||||
#define MPIU_STR_DELIM_CHAR '#'
|
||||
#define MPIU_STR_DELIM_STR "#"
|
||||
#define MPIU_STR_ESCAPE_CHAR '\\'
|
||||
#define MPIU_STR_SEPAR_CHAR '$'
|
||||
#define MPIU_STR_SEPAR_STR "$"
|
||||
|
||||
#endif
|
||||
|
||||
_Success_(return == MPIU_STR_SUCCESS)
|
||||
int
|
||||
MPIU_Str_get_string_arg(
|
||||
_In_opt_z_ const char* str,
|
||||
_In_opt_z_ const char* key,
|
||||
_Out_writes_z_(val_len) char* val,
|
||||
_In_ size_t val_len
|
||||
);
|
||||
|
||||
|
||||
_Success_(return == MPIU_STR_SUCCESS)
|
||||
int
|
||||
MPIU_Str_get_int_arg(
|
||||
_In_z_ const char *str,
|
||||
_In_z_ const char *flag,
|
||||
_Out_ int *val_ptr
|
||||
);
|
||||
|
||||
|
||||
_Success_(return == MPIU_STR_SUCCESS)
|
||||
int
|
||||
MPIU_Str_add_string_arg(
|
||||
_Inout_ _Outptr_result_buffer_(*maxlen_ptr) PSTR*str_ptr,
|
||||
_Inout_ int *maxlen_ptr,
|
||||
_In_z_ const char *flag,
|
||||
_In_z_ const char *val
|
||||
);
|
||||
|
||||
|
||||
_Success_(return == MPIU_STR_SUCCESS)
|
||||
int
|
||||
MPIU_Str_add_int_arg(
|
||||
_Inout_ _Outptr_result_buffer_(*maxlen_ptr) PSTR*str_ptr,
|
||||
_Inout_ int *maxlen_ptr,
|
||||
_In_z_ const char *flag,
|
||||
_In_ int val
|
||||
);
|
||||
|
||||
|
||||
_Success_(return == MPIU_STR_SUCCESS)
|
||||
int
|
||||
MPIU_Str_add_string(
|
||||
_Inout_ _Outptr_result_buffer_(*maxlen_ptr) PSTR*str_ptr,
|
||||
_Inout_ int *maxlen_ptr,
|
||||
_In_z_ const char *val
|
||||
);
|
||||
|
||||
|
||||
_Success_(return == 0)
|
||||
int
|
||||
MPIU_Str_get_string(
|
||||
_Inout_ _Outptr_result_maybenull_z_ PCSTR* str_ptr,
|
||||
_Out_writes_z_(val_len)char *val,
|
||||
_In_ size_t val_len
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Provide a fallback snprintf for systems that do not have one
|
||||
//
|
||||
_Success_(return >= 0 && return <= cchDest)
|
||||
int
|
||||
MPIU_Snprintf(
|
||||
_Null_terminated_ _Out_writes_to_(cchDest, return) char* dest,
|
||||
_In_ size_t cchDest,
|
||||
_Printf_format_string_ const char* format,
|
||||
...
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Overloaded function for wide characters
|
||||
//
|
||||
_Success_(return >= 0 && return <= cchDest)
|
||||
int
|
||||
MPIU_Snprintf(
|
||||
_Null_terminated_ _Out_writes_to_(cchDest, return) wchar_t* dest,
|
||||
_In_ size_t cchDest,
|
||||
_Printf_format_string_ const wchar_t* format,
|
||||
...
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Provide vsnprintf functionality by using strsafe's StringCchVPrintfEx
|
||||
//
|
||||
_Success_(return >= 0 && return <= cchDest)
|
||||
int
|
||||
MPIU_Vsnprintf(
|
||||
_Null_terminated_ _Out_writes_to_(cchDest,return)char* dest,
|
||||
_In_ size_t cchDest,
|
||||
_Printf_format_string_ const char* format,
|
||||
_In_ va_list args
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Overloaded function for wide characters
|
||||
// Provide vsnprintf functionality by using strsafe's StringCchVPrintfEx
|
||||
//
|
||||
_Success_(return >= 0 && return <= cchDest)
|
||||
int
|
||||
MPIU_Vsnprintf(
|
||||
_Null_terminated_ _Out_writes_to_(cchDest, return) wchar_t* dest,
|
||||
_In_ size_t cchDest,
|
||||
_Printf_format_string_ const wchar_t* format,
|
||||
_In_ va_list args
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Provide _strdup functionality
|
||||
//
|
||||
_Ret_valid_ _Null_terminated_
|
||||
_Success_(return != nullptr)
|
||||
char*
|
||||
MPIU_Strdup(
|
||||
_In_z_ const char* str
|
||||
);
|
||||
|
||||
|
||||
_Ret_valid_ _Null_terminated_
|
||||
_Success_(return != nullptr)
|
||||
wchar_t*
|
||||
MPIU_Strdup(
|
||||
_In_z_ const wchar_t* str
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Callee will need to call delete[] to free the memory allocated
|
||||
// for wname_ptr if the function succeeds.
|
||||
//
|
||||
_Success_(return == NOERROR)
|
||||
DWORD
|
||||
MPIU_MultiByteToWideChar(
|
||||
_In_z_ const char* name,
|
||||
_Outptr_result_z_ wchar_t** wname_ptr
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Callee will need to call delete[] to free the memory allocated
|
||||
// for outputStr if the function succeeds.
|
||||
//
|
||||
_Success_(return == NOERROR)
|
||||
DWORD
|
||||
MPIU_WideCharToMultiByte(
|
||||
_In_z_ const wchar_t* str,
|
||||
_Outptr_result_z_ char** outputStr
|
||||
);
|
|
@ -0,0 +1,185 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
#include <wmistr.h>
|
||||
#include <evntrace.h>
|
||||
#include "evntprov.h"
|
||||
|
||||
#ifndef _In_reads_
|
||||
# define _In_reads_(max_count)
|
||||
#endif
|
||||
|
||||
//
|
||||
//Enums to identify call sites.
|
||||
//
|
||||
|
||||
//used for events in ch3u_nd_adapter.cpp
|
||||
enum AdapterInit{
|
||||
AdapterInitOpen = 1,
|
||||
AdapterInitQuery,
|
||||
AdapterInitCQDepth,
|
||||
AdapterInitInitiatorQDepth,
|
||||
AdapterInitRecvQDepth,
|
||||
AdapterInitCreateOverlapped
|
||||
};
|
||||
|
||||
enum AdapterListen{
|
||||
AdapterListenCreateListener = 1,
|
||||
AdapterListenBind,
|
||||
AdapterListenGetLocalAddress,
|
||||
AdapterListenListen
|
||||
};
|
||||
|
||||
enum AdapterGetConnectionRequest{
|
||||
GetConnectionRequestCreateConnector = 1,
|
||||
GetConnectionRequestGetConnectionRequest
|
||||
};
|
||||
|
||||
enum AdapterCreateConector{
|
||||
AdapterCreateConectorCreateConnector = 1,
|
||||
AdapterCreateConectorBind
|
||||
};
|
||||
|
||||
enum AdapterGetConnSucceeded{
|
||||
AdapterGetConnSucceededInvalidBufferSize = 1,
|
||||
AdapterGetConnSucceededAbortOrInvalid,
|
||||
AdapterGetConnSucceededReject,
|
||||
AdapterGetConnSucceededMismatchedVersion,
|
||||
AdapterGetConnSucceededPGFind,
|
||||
AdapterGetConnSucceededRank,
|
||||
AdapterGetConnSucceededHeadToHeadReject,
|
||||
AdapterGetConnSucceededHeadToHeadShutdown,
|
||||
AdapterGetConnSucceededAdapterShutdown,
|
||||
AdapterGetConnSucceededDefaultReject,
|
||||
AdapterGetConnSucceededSuccess
|
||||
};
|
||||
|
||||
//used for events in ch3u_nd_endpoint.cpp
|
||||
enum Endpoint{
|
||||
EndpointCompleteConnectBufferSize = 1,
|
||||
EndpointCompleteConnectDefault,
|
||||
EndpointCompleteConnectPending,
|
||||
EndpointConnReqFailedPassive,
|
||||
EndpointConnReqFailedCanceled,
|
||||
EndpointConnReqFailedFailed,
|
||||
EndpointConnCompleted,
|
||||
EndpointConnFailedRetry,
|
||||
EndpointConnFailedFail,
|
||||
EndpointAcceptPending,
|
||||
EndpointPrepostReceivesFailed,
|
||||
EndpointAcceptCompleted,
|
||||
EndpointAcceptFailedAbortedOrTimeout,
|
||||
EndpointAcceptFailedFailed,
|
||||
EndpointDisconnect,
|
||||
EndpointConnect,
|
||||
EndpointAccept,
|
||||
EndpointHandleTimeoutConnectTimeout,
|
||||
EndpointCompleteConnectAbortedOrInvalid,
|
||||
EndpointCompleteConnectCompleteConnect,
|
||||
EndpointHandleTimeoutConnect
|
||||
};
|
||||
|
||||
//used for events in ch3u_nd_env.cpp
|
||||
enum EnvironmentListen{
|
||||
EnvironmentListenNoNDv2Providers = 1,
|
||||
EnvironmentListenQueryAddressListForSizeFailed,
|
||||
EnvironmentListenQueryAddressListFailed
|
||||
};
|
||||
|
||||
enum EnvironmentConnect{
|
||||
EnvironmentConnectGetAddrsFromBc = 1,
|
||||
EnvironmentConnectNoLocalNoRemoteForce,
|
||||
EnvironmentConnectNoLocalForce,
|
||||
EnvironmentConnectNoLocalNoFallback,
|
||||
EnvironmentConnectNoLocalNoFallbackForce,
|
||||
EnvironmentConnectNoRemoteForce,
|
||||
EnvironmentConnectNoRemoteNoFallback,
|
||||
EnvironmentConnectNoPathForce,
|
||||
EnvironmentConnectNoPathNoFallback,
|
||||
EnvironmentConnectNoLocalFallback,
|
||||
EnvironmentConnectNoRemoteFallback,
|
||||
EnvironmentConnectNoPathFallback
|
||||
};
|
||||
|
||||
//used for events in ch3_progress_connect.cpp
|
||||
enum Shm_connect{
|
||||
Shm_connectConnectQueueName = 1,
|
||||
Shm_connectConnectQueueAttach,
|
||||
Shm_connectWriteQueue,
|
||||
Shm_connectNotifyConnect
|
||||
};
|
||||
|
||||
enum Shm_accept{
|
||||
Shm_acceptQueueAttach = 1,
|
||||
Shm_acceptMismatchedVersion,
|
||||
Shm_acceptPGFind,
|
||||
Shm_acceptRank,
|
||||
Shm_acceptGetConnStringFailed,
|
||||
Shm_acceptGetStringArgFailed,
|
||||
Shm_acceptBootstrapQueueAttach
|
||||
};
|
||||
|
||||
//used for events in ch3_progress_sock.c
|
||||
enum RecvOpenRequestSucceeded{
|
||||
RecvOpenRequestSucceededUnexpectedControl = 1,
|
||||
RecvOpenRequestSucceededMismatchedVersion,
|
||||
RecvOpenRequestSucceededInternal,
|
||||
RecvOpenRequestSucceededSuccess
|
||||
};
|
||||
|
||||
//used for events in sock.c
|
||||
enum ConnectFailedEnum{
|
||||
ConnectFailedEnumAbortedBeforeTimeout = 1,
|
||||
ConnectFailedEnumTimeout,
|
||||
ConnectFailedEnumAbortedClosing,
|
||||
ConnectFailedEnumRefused,
|
||||
ConnectFailedEnumError,
|
||||
ConnectFailedEnumExhausted,
|
||||
ConnectFailedEnumFail
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Mpi specific wrappers around trace functions
|
||||
//
|
||||
ULONG MpiTraceError(
|
||||
REGHANDLE RegHandle,
|
||||
PCEVENT_DESCRIPTOR EventDescriptor,
|
||||
int ErrorCode
|
||||
);
|
||||
|
||||
|
||||
#define SENTINEL_MASK ((ULONG_PTR)0x01)
|
||||
|
||||
#define IS_SENTINEL(p_) (0 == (((ULONG_PTR)p_) & (~SENTINEL_MASK)))
|
||||
|
||||
#define SENTINEL_SAFE_SIZE(p_) (IS_SENTINEL(p_)?0:sizeof(*p_))
|
||||
|
||||
#define SENTINEL_SAFE_COUNT(p_,c_) (IS_SENTINEL(p_)?0:c_)
|
||||
|
||||
//
|
||||
// This is a generated header.
|
||||
//
|
||||
#include "MpiTraceEvents.h"
|
||||
|
||||
|
||||
#ifndef MAX_TRACE_ARRAY_VALUE_COUNT
|
||||
#define MAX_TRACE_ARRAY_VALUE_COUNT 1
|
||||
#endif
|
||||
|
||||
#ifndef TraceArrayLength
|
||||
#define TraceArrayLength(_c_) ((BYTE)(_c_<=MAX_TRACE_ARRAY_VALUE_COUNT?_c_:MAX_TRACE_ARRAY_VALUE_COUNT))
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// Conditional trace macros. They will only trace if enabled. The generated header
|
||||
// contains the macros and values we use for these tests. See that header for more deatils.
|
||||
//
|
||||
|
||||
#define TraceError(_fn_,_errorcode_) \
|
||||
MCGEN_ENABLE_CHECK(MICROSOFT_HPC_MPI_PROVIDER_Context, EVENT_Error_##_fn_) ?\
|
||||
MpiTraceError(Microsoft_HPC_MPIHandle, &EVENT_Error_##_fn_,_errorcode_) \
|
||||
: ERROR_SUCCESS
|
||||
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,227 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
|
||||
#include "precomp.h"
|
||||
#include "winsock2.h"
|
||||
|
||||
BOOL
|
||||
env_is_on_ex(
|
||||
_In_z_ const wchar_t* name,
|
||||
_In_opt_z_ const wchar_t* deprecatedName,
|
||||
_In_ BOOL defval
|
||||
)
|
||||
{
|
||||
wchar_t env[5];
|
||||
|
||||
DWORD err = MPIU_Getenv( name, env, _countof(env) );
|
||||
if( err == ERROR_ENVVAR_NOT_FOUND && deprecatedName != nullptr )
|
||||
{
|
||||
err = MPIU_Getenv( deprecatedName, env, _countof(env) );
|
||||
}
|
||||
|
||||
if( err != NOERROR )
|
||||
{
|
||||
return defval;
|
||||
}
|
||||
|
||||
if( CompareStringW( LOCALE_INVARIANT,
|
||||
0,
|
||||
env,
|
||||
-1,
|
||||
L"1",
|
||||
-1 ) == CSTR_EQUAL )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if( CompareStringW( LOCALE_INVARIANT,
|
||||
NORM_IGNORECASE,
|
||||
env,
|
||||
-1,
|
||||
L"on",
|
||||
-1 ) == CSTR_EQUAL ||
|
||||
CompareStringW( LOCALE_INVARIANT,
|
||||
NORM_IGNORECASE,
|
||||
env,
|
||||
-1,
|
||||
L"yes",
|
||||
-1 ) == CSTR_EQUAL ||
|
||||
CompareStringW( LOCALE_INVARIANT,
|
||||
NORM_IGNORECASE,
|
||||
env,
|
||||
-1,
|
||||
L"true",
|
||||
-1 ) == CSTR_EQUAL )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
env_to_int_ex(
|
||||
_In_z_ const wchar_t* name,
|
||||
_In_opt_z_ const wchar_t* deprecatedName,
|
||||
_In_ int defval,
|
||||
_In_ int minval
|
||||
)
|
||||
{
|
||||
wchar_t val[12];
|
||||
DWORD err = MPIU_Getenv( name, val, _countof(val) );
|
||||
if( err == ERROR_ENVVAR_NOT_FOUND && deprecatedName != nullptr )
|
||||
{
|
||||
err = MPIU_Getenv( deprecatedName, val, _countof(val) );
|
||||
}
|
||||
|
||||
if( err != NOERROR )
|
||||
{
|
||||
return defval;
|
||||
}
|
||||
|
||||
defval = _wtoi(val);
|
||||
if(defval < minval)
|
||||
{
|
||||
return minval;
|
||||
}
|
||||
|
||||
return defval;
|
||||
}
|
||||
|
||||
|
||||
_Success_(return == TRUE)
|
||||
BOOL
|
||||
env_to_range_ex(
|
||||
_In_z_ const wchar_t* name,
|
||||
_In_opt_z_ const wchar_t* deprecatedName,
|
||||
_In_ int minval,
|
||||
_In_ int maxval,
|
||||
_In_ bool allowSingleValue,
|
||||
_Out_ int* low,
|
||||
_Out_ int* high
|
||||
)
|
||||
{
|
||||
//
|
||||
// We need a string big enough to be able to store
|
||||
// -INT_MAX : INT_MAX. 64 should be plenty
|
||||
//
|
||||
wchar_t range[64];
|
||||
wchar_t* next_token = nullptr;
|
||||
DWORD err = MPIU_Getenv( name, range, _countof(range) );
|
||||
if( err == ERROR_ENVVAR_NOT_FOUND && deprecatedName != nullptr )
|
||||
{
|
||||
err = MPIU_Getenv( deprecatedName, range, _countof(range) );
|
||||
}
|
||||
|
||||
if( err != NOERROR )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const wchar_t* pCur;
|
||||
|
||||
//
|
||||
// tokenize min,max OR min:max OR min..max
|
||||
//
|
||||
pCur = wcstok_s( range, L",.:", &next_token );
|
||||
if( pCur == nullptr )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int tmpLow = _wtoi( pCur );
|
||||
if( tmpLow < minval )
|
||||
{
|
||||
tmpLow = minval;
|
||||
}
|
||||
|
||||
int tmpHigh;
|
||||
pCur = wcstok_s( nullptr, L",.:", &next_token );
|
||||
if( pCur != nullptr )
|
||||
{
|
||||
tmpHigh = _wtoi( pCur );
|
||||
if( tmpHigh > maxval )
|
||||
{
|
||||
tmpHigh = maxval;
|
||||
}
|
||||
}
|
||||
else if( allowSingleValue )
|
||||
{
|
||||
tmpHigh = tmpLow;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if( tmpHigh < tmpLow )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*low = tmpLow;
|
||||
*high = tmpHigh;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
#define MAX_TCP_PORT 65535
|
||||
|
||||
int
|
||||
FindNextOpenPort(
|
||||
int startPort
|
||||
)
|
||||
{
|
||||
if( startPort > MAX_TCP_PORT )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
WSADATA wsaData;
|
||||
int ret = WSAStartup( MAKEWORD(2,0), &wsaData );
|
||||
if( ret != 0 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
SOCKET server;
|
||||
SOCKADDR_IN sockAddr;
|
||||
int port = startPort;
|
||||
|
||||
sockAddr.sin_family = AF_INET;
|
||||
sockAddr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
server = socket( AF_INET, SOCK_STREAM, 0 );
|
||||
if( server == INVALID_SOCKET )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
sockAddr.sin_port = htons( static_cast<unsigned short>( port ) );
|
||||
if( bind( server,
|
||||
reinterpret_cast<const SOCKADDR*>( &sockAddr ),
|
||||
sizeof( sockAddr ) ) == SOCKET_ERROR )
|
||||
{
|
||||
++port;
|
||||
if( port > MAX_TCP_PORT )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Found an open port
|
||||
//
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
closesocket( server );
|
||||
WSACleanup();
|
||||
return port;
|
||||
}
|
|
@ -0,0 +1,360 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
*
|
||||
* (C) 2001 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
#if !defined(MPIUTIL_H_INCLUDED)
|
||||
#define MPIUTIL_H_INCLUDED
|
||||
#include <oacr.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
/*
|
||||
* Debuging function and macros
|
||||
*/
|
||||
void MPIU_dbg_preinit(void);
|
||||
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int MPIU_dbg_init(
|
||||
_In_ unsigned int rank,
|
||||
_In_ unsigned int world_size
|
||||
);
|
||||
|
||||
void
|
||||
MPIU_dbg_printf(
|
||||
_Printf_format_string_ const char *str,
|
||||
...
|
||||
);
|
||||
|
||||
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int
|
||||
MPIU_Parse_rank_range(
|
||||
_In_ unsigned int rank,
|
||||
_In_z_ const char* range,
|
||||
_In_ unsigned int world_size,
|
||||
_Out_ bool* isWithinRange,
|
||||
_Out_writes_(world_size) unsigned int* total_unique_ranks
|
||||
);
|
||||
|
||||
struct MPID_Comm;
|
||||
|
||||
|
||||
/*@
|
||||
MPID_Abort - Abort at least the processes in the specified communicator.
|
||||
|
||||
Input Parameters:
|
||||
+ comm - Communicator of processes to abort
|
||||
. intern - indicates if the abort is internal or by the application.
|
||||
. exit_code - Exit code to return to the calling environment. See notes.
|
||||
- error_msg - error message (not optional)
|
||||
|
||||
Return value:
|
||||
'MPI_SUCCESS' or an MPI error code. Normally, this routine should not
|
||||
return, since the calling process must be a member of the communicator.
|
||||
However, under some circumstances, the 'MPID_Abort' might fail; in this
|
||||
case, returning an error indication is appropriate.
|
||||
|
||||
Notes:
|
||||
|
||||
In a fault-tolerant MPI implementation, this operation should abort `only`
|
||||
the processes in the specified communicator. Any communicator that shares
|
||||
processes with the aborted communicator becomes invalid. For more
|
||||
details, see (paper not yet written on fault-tolerant MPI).
|
||||
|
||||
In particular, if the communicator is 'MPI_COMM_SELF', only the calling
|
||||
process should be aborted.
|
||||
|
||||
The 'exit_code' is the exit code that this particular process will
|
||||
attempt to provide to the 'mpiexec' or other program invocation
|
||||
environment. See 'mpiexec' for a discussion of how exit codes from
|
||||
many processes may be combined.
|
||||
|
||||
If the error_msg field is non-nullptr this string will be used as the message
|
||||
with the abort output. Otherwise, the output message will be base on the
|
||||
error message associated with the mpi_errno.
|
||||
|
||||
An external agent that is aborting processes can invoke this with either
|
||||
'MPI_COMM_WORLD' or 'MPI_COMM_SELF'. For example, if the process manager
|
||||
wishes to abort a group of processes, it should cause 'MPID_Abort' to
|
||||
be invoked with 'MPI_COMM_SELF' on each process in the group.
|
||||
|
||||
Question:
|
||||
An alternative design is to provide an 'MPID_Group' instead of a
|
||||
communicator. This would allow a process manager to ask the ADI
|
||||
to kill an entire group of processes without needing a communicator.
|
||||
However, the implementation of 'MPID_Abort' will either do this by
|
||||
communicating with other processes or by requesting the process manager
|
||||
to kill the processes. That brings up this question: should
|
||||
'MPID_Abort' use 'PMI' to kill processes? Should it be required to
|
||||
notify the process manager? What about persistent resources (such
|
||||
as SYSV segments or forked processes)?
|
||||
|
||||
This suggests that for any persistent resource, an exit handler be
|
||||
defined. These would be executed by 'MPID_Abort' or 'MPID_Finalize'.
|
||||
See the implementation of 'MPI_Finalize' for an example of exit callbacks.
|
||||
In addition, code that registered persistent resources could use persistent
|
||||
storage (i.e., a file) to record that information, allowing cleanup
|
||||
utilities (such as 'mpiexec') to remove any resources left after the
|
||||
process exits.
|
||||
|
||||
'MPI_Finalize' requires that attributes on 'MPI_COMM_SELF' be deleted
|
||||
before anything else happens; this allows libraries to attach end-of-job
|
||||
actions to 'MPI_Finalize'. It is valuable to have a similar
|
||||
capability on 'MPI_Abort', with the caveat that 'MPI_Abort' may not
|
||||
guarantee that the run-on-abort routines were called. This provides a
|
||||
consistent way for the MPICH implementation to handle freeing any
|
||||
persistent resources. However, such callbacks must be limited since
|
||||
communication may not be possible once 'MPI_Abort' is called. Further,
|
||||
any callbacks must guarantee that they have finite termination.
|
||||
|
||||
One possible extension would be to allow `users` to add actions to be
|
||||
run when 'MPI_Abort' is called, perhaps through a special attribute value
|
||||
applied to 'MPI_COMM_SELF'. Note that is is incorrect to call the delete
|
||||
functions for the normal attributes on 'MPI_COMM_SELF' because MPI
|
||||
only specifies that those are run on 'MPI_Finalize' (i.e., normal
|
||||
termination).
|
||||
|
||||
Module:
|
||||
MPID_CORE
|
||||
@*/
|
||||
_Analysis_noreturn_
|
||||
DECLSPEC_NORETURN
|
||||
int MPID_Abort(
|
||||
_Inout_opt_ MPID_Comm* comm,
|
||||
_In_ BOOL intern,
|
||||
_In_ int exit_code,
|
||||
_In_z_ const char* error_msg
|
||||
);
|
||||
|
||||
_Success_(return>=0)
|
||||
int
|
||||
MPIU_Internal_error_printf(
|
||||
_Printf_format_string_ const char *str,
|
||||
...
|
||||
);
|
||||
|
||||
_Success_(return>=0)
|
||||
int
|
||||
MPIU_Error_printf(
|
||||
_Printf_format_string_ const char *str,
|
||||
...
|
||||
);
|
||||
|
||||
|
||||
static inline void MPIU_Debug_break(void)
|
||||
{
|
||||
//
|
||||
// Debug break without giving a chance to any exception handler to ignore the break
|
||||
//
|
||||
__try
|
||||
{
|
||||
__debugbreak();
|
||||
}
|
||||
__except(UnhandledExceptionFilter(GetExceptionInformation()))
|
||||
OACR_WARNING_SUPPRESS(EXCEPT_BLOCK_EMPTY,"lucasm: debug break handler")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define ASSERT(a_) MPIU_Assert(a_)
|
||||
#define VERIFY(a_) MPIU_Assertp(a_)
|
||||
|
||||
/*
|
||||
* MPIU_Assert()
|
||||
*
|
||||
* Similar to assert() except that it performs an MPID_Abort() when the
|
||||
* assertion fails. Also, for Windows, it doesn't popup a
|
||||
* mesage box on a remote machine.
|
||||
*
|
||||
* MPIU_AssertDecl may be used to include declarations only needed
|
||||
* when MPIU_Assert is non-null (e.g., when assertions are enabled)
|
||||
*/
|
||||
|
||||
#if DBG
|
||||
|
||||
#define MPIU_DebugBuildCode(a_) a_
|
||||
#define MPIU_Assert(a_) \
|
||||
(void) ((!!(a_)) || \
|
||||
(MPIU_Internal_error_printf("Assertion failed in %s(%d): %s\n", __FILE__, __LINE__, #a_), 0) || \
|
||||
(MPIU_Debug_break(), 0) || \
|
||||
(MPID_Abort(nullptr, TRUE, 0, "assertion failed")) \
|
||||
); __analysis_assume(a_)
|
||||
|
||||
#define MPIU_Assertp(a_) MPIU_Assert(a_)
|
||||
|
||||
#else
|
||||
|
||||
#define MPIU_Assert(a_) __analysis_assume(a_)
|
||||
#define MPIU_DebugBuildCode(a_)
|
||||
|
||||
/*
|
||||
* MPIU_Assertp()
|
||||
*
|
||||
* Similar to MPIU_Assert() except that these assertions persist regardless of
|
||||
* DBG. MPIU_Assertp() may be used for error checking in prototype code, although
|
||||
* it should be converted real error checking and reporting once the prototype
|
||||
* becomes part of the official and supported code base.
|
||||
*/
|
||||
#define MPIU_Assertp(a_) \
|
||||
(void) ((!!(a_)) || \
|
||||
(MPIU_Internal_error_printf("Assertion failed in %s(%d): %s\n", __FILE__, __LINE__, #a_), 0) || \
|
||||
(MPID_Abort(nullptr, TRUE, 0, "assertion failed")) \
|
||||
); __analysis_assume(a_)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*@ env_is_on - Check if an environment variable is in the 'on' state
|
||||
|
||||
Return value:
|
||||
'def' if the env var is not set
|
||||
1 if the env var is set to 'on'
|
||||
0 if the env var is set not to to 'on'
|
||||
|
||||
@*/
|
||||
BOOL
|
||||
env_is_on_ex(
|
||||
_In_z_ const wchar_t* name,
|
||||
_In_opt_z_ const wchar_t* deprecatedName,
|
||||
_In_ BOOL defval
|
||||
);
|
||||
|
||||
|
||||
int
|
||||
env_to_int_ex(
|
||||
_In_z_ const wchar_t* name,
|
||||
_In_opt_z_ const wchar_t* deprecatedName,
|
||||
_In_ int defval,
|
||||
_In_ int minval
|
||||
);
|
||||
|
||||
|
||||
_Success_(return == TRUE)
|
||||
BOOL
|
||||
env_to_range_ex(
|
||||
_In_z_ const wchar_t* name,
|
||||
_In_opt_z_ const wchar_t* deprecatedName,
|
||||
_In_ int minval,
|
||||
_In_ int maxval,
|
||||
_In_ bool allowSingleValue,
|
||||
_Out_ int* low,
|
||||
_Out_ int* high
|
||||
);
|
||||
|
||||
|
||||
inline BOOL
|
||||
env_is_on(
|
||||
_In_z_ const wchar_t* name,
|
||||
_In_ BOOL defval
|
||||
)
|
||||
{
|
||||
return env_is_on_ex(name, nullptr, defval);
|
||||
}
|
||||
|
||||
|
||||
inline int
|
||||
env_to_int(
|
||||
_In_z_ const wchar_t *name,
|
||||
_In_ int defval,
|
||||
_In_ int minval
|
||||
)
|
||||
{
|
||||
return env_to_int_ex(name, nullptr, defval, minval);
|
||||
}
|
||||
|
||||
|
||||
_Success_(return == TRUE)
|
||||
inline BOOL
|
||||
env_to_range(
|
||||
_In_z_ const wchar_t* name,
|
||||
_In_ int minval,
|
||||
_In_ int maxval,
|
||||
_In_ bool allowSingleValue,
|
||||
_Out_ int* low,
|
||||
_Out_ int* high
|
||||
)
|
||||
{
|
||||
return env_to_range_ex( name, nullptr, minval, maxval, allowSingleValue, low, high );
|
||||
}
|
||||
|
||||
|
||||
_Success_(return == NO_ERROR)
|
||||
DWORD
|
||||
MPIU_Getenv(
|
||||
_In_z_ PCSTR name,
|
||||
_Out_writes_z_(cchBuffer)PSTR buffer,
|
||||
_In_ DWORD cchBuffer
|
||||
);
|
||||
|
||||
|
||||
_Success_(return == NO_ERROR)
|
||||
DWORD
|
||||
MPIU_Getenv(
|
||||
_In_z_ PCWSTR name,
|
||||
_Out_writes_z_(cchBuffer)PWSTR buffer,
|
||||
_In_ DWORD cchBuffer
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Max string representation of GUID with hyphens, no braces
|
||||
//
|
||||
#define GUID_STRING_LENGTH 36
|
||||
|
||||
static inline void
|
||||
GuidToStr(
|
||||
_In_ const GUID& guid,
|
||||
_Out_writes_z_(cchBuffer) char* buffer,
|
||||
_In_range_(>,GUID_STRING_LENGTH) size_t cchBuffer
|
||||
)
|
||||
{
|
||||
MPIU_Assert( cchBuffer > GUID_STRING_LENGTH );
|
||||
|
||||
OACR_WARNING_SUPPRESS(HRESULT_NOT_CHECKED, "Ignore return value, we have an existing assert for buffer size");
|
||||
OACR_WARNING_SUPPRESS(USE_WIDE_API, "MS MPI uses ANSI character set.");
|
||||
(void) StringCchPrintfA(
|
||||
buffer,
|
||||
cchBuffer,
|
||||
"%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
|
||||
guid.Data1, guid.Data2, guid.Data3,
|
||||
guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
|
||||
guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
GuidToStr(
|
||||
_In_ const GUID& guid,
|
||||
_Out_writes_z_(cchBuffer) wchar_t* buffer,
|
||||
_In_range_(>,GUID_STRING_LENGTH) size_t cchBuffer
|
||||
)
|
||||
{
|
||||
MPIU_Assert( cchBuffer > GUID_STRING_LENGTH );
|
||||
|
||||
OACR_WARNING_SUPPRESS(HRESULT_NOT_CHECKED, "Ignore return value, we have an existing assert for buffer size");
|
||||
(void) StringCchPrintfW(
|
||||
buffer,
|
||||
cchBuffer,
|
||||
L"%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
|
||||
guid.Data1, guid.Data2, guid.Data3,
|
||||
guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
|
||||
guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary: Given a starting port, find an open TCP port that can be
|
||||
// used for listening
|
||||
//
|
||||
int
|
||||
FindNextOpenPort(
|
||||
int startPort
|
||||
);
|
||||
|
||||
#endif /* !defined(MPIUTIL_H_INCLUDED) */
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
* (C) 2001 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
_Success_(return>=0)
|
||||
int
|
||||
MPIU_Error_printf(
|
||||
_Printf_format_string_ const char *str,
|
||||
...
|
||||
)
|
||||
{
|
||||
int n;
|
||||
va_list list;
|
||||
|
||||
va_start(list, str);
|
||||
n = vfprintf(stderr, str, list);
|
||||
va_end(list);
|
||||
|
||||
fflush(stderr);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
_Success_(return>=0)
|
||||
int
|
||||
MPIU_Internal_error_printf(
|
||||
_Printf_format_string_ const char *str,
|
||||
...
|
||||
)
|
||||
{
|
||||
int n;
|
||||
va_list list;
|
||||
|
||||
va_start(list, str);
|
||||
n = vfprintf(stderr, str, list);
|
||||
va_end(list);
|
||||
|
||||
fflush(stderr);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
#! /usr/bin/perl
|
||||
#
|
||||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License.
|
||||
#
|
||||
# File of useful routines use to process the MPI source files. This is
|
||||
# included by routines that process parameters and error messages, along with
|
||||
# tools to check for proper usage (such as system routines and preprocessor
|
||||
# tests).
|
||||
|
||||
#
|
||||
# GetBalancedParen( FD, curline )
|
||||
# Returns a balanced parenthesis string, starting at curline. Reads from FD
|
||||
# if necessary. Skips any comments.
|
||||
# Returns the pair (leading, result, remainder)
|
||||
# Leading is anything before the opening paren. If no opening paren in the
|
||||
# line, returns the current line as "leading"
|
||||
# Newlines are removed.
|
||||
sub GetBalancedParen {
|
||||
my $paren_count = 1;
|
||||
my $result = "";
|
||||
my $count = 0;
|
||||
my $leading = "";
|
||||
my $maxcount = 200;
|
||||
$FD = $_[0];
|
||||
$curline = $_[1];
|
||||
# Remove escaped newlines
|
||||
$curline =~ s/\\$//;
|
||||
|
||||
if ($curline =~ /^([^\(]*)\((.*)$/) {
|
||||
$leading = $1;
|
||||
$curline = $2;
|
||||
$result = "(";
|
||||
print "Found open paren\n" if $debug;
|
||||
}
|
||||
else {
|
||||
$leading = $curline;
|
||||
return ($leading, "", "" );
|
||||
}
|
||||
|
||||
while ($count < $maxcount && $paren_count > 0) {
|
||||
if ($curline =~ /^([^\(\)]*\()(.*$)/) {
|
||||
# Found an opening paren
|
||||
$result .= $1;
|
||||
$curline = $2;
|
||||
$paren_count++;
|
||||
print "Found open paren\n" if $debug;
|
||||
}
|
||||
elsif ($curline =~ /^([^\(\)]*\))(.*$)/) {
|
||||
# Found a closing paren
|
||||
$result .= $1;
|
||||
$curline = $2;
|
||||
$paren_count--;
|
||||
print "Found close paren\n" if $debug;
|
||||
}
|
||||
else {
|
||||
# Need to read a new line
|
||||
$result .= $curline;
|
||||
$curline = <$FD>;
|
||||
$curline =~ s/[\r]*\n//;
|
||||
# Remove escaped newlines
|
||||
$curline =~ s/\\$//;
|
||||
}
|
||||
$count ++;
|
||||
}
|
||||
return ($leading, $result, $curline);
|
||||
}
|
||||
|
||||
# Like get balanced paren, but for a string. Simpler because it does not need
|
||||
# to handle balanced text.
|
||||
sub GetString {
|
||||
my $result = "";
|
||||
my $count = 0;
|
||||
my $leading = "";
|
||||
my $maxcount = 200;
|
||||
$FD = $_[0];
|
||||
$curline = $_[1];
|
||||
|
||||
if ($curline =~ /^([^\"]*)\"(.*)$/) {
|
||||
$leading = $1;
|
||||
$curline = $2;
|
||||
$result = "\"";
|
||||
print "Found quote\n" if $debug;
|
||||
}
|
||||
else {
|
||||
$leading = $curline;
|
||||
return ($leading, "", "" );
|
||||
}
|
||||
|
||||
while ($count < $maxcount) {
|
||||
if ($curline =~ /^([^\"]*\\\")(.*$)/) {
|
||||
# Found an escaped quote
|
||||
$result .= $1;
|
||||
$curline = $2;
|
||||
print "Found escaped quote\n" if $debug;
|
||||
}
|
||||
elsif ($curline =~ /^([^\"]*\")(.*$)/) {
|
||||
# Found the closing quote
|
||||
$result .= $1;
|
||||
$curline = $2;
|
||||
print "Found closing quote\n" if $debug;
|
||||
last;
|
||||
}
|
||||
else {
|
||||
# Need to read a new line
|
||||
$result .= $curline;
|
||||
$curline = <$FD>;
|
||||
$curline =~ s/[\r]*\n//;
|
||||
}
|
||||
$count ++;
|
||||
}
|
||||
return ($leading, $result, $curline);
|
||||
}
|
||||
#
|
||||
# GetSubArgs( FD, curline ) returns an array of the arguments of a routine.
|
||||
# Specifically, it converts (a,b,c) into an array containing "a", "b", and "c".
|
||||
# The special feature of this is that any commas that are within balanced
|
||||
# parenthesis are included within their argument.
|
||||
# Actually returns
|
||||
# (leader, remainder, (@args) )
|
||||
# in this order so the last values are always all of the args
|
||||
# so you don't need to know
|
||||
sub GetSubArgs {
|
||||
my @args = ();
|
||||
my $curline;
|
||||
my ($outer, $leader, $remainder, $arg);
|
||||
|
||||
$FD = $_[0];
|
||||
$curline = $_[1];
|
||||
# Remove any embedded newlines
|
||||
$curline =~ s/[\r\n]//g;
|
||||
|
||||
$curline =~ /^\(/ || die "No initial paren";
|
||||
($leader, $outer, $remainder ) = &GetBalancedParen( $FD, $curline );
|
||||
|
||||
|
||||
# Strip off the first and last parens
|
||||
# Because of the greedy algorithm, the \s before the closing paren
|
||||
# won't be used. To avoid problems with empty arguments, we remove
|
||||
# those blanks separately
|
||||
$outer =~ /^\s*\(\s*(.*)\s*\)\s*$/;
|
||||
$outer = $1;
|
||||
if ($outer =~ /(.*)\s+$/) { $outer = $1; }
|
||||
print "Line to tokenize is $outer\n" if $debug;
|
||||
$arg = "";
|
||||
while ($outer ne "") {
|
||||
if ($outer =~ /^([^,\(\"]*)\s*,\s*(.*$)/) {
|
||||
# simple arg
|
||||
$arg .= $1;
|
||||
$args[$#args+1] = $arg;
|
||||
print "Found simple arg $arg (remainder $2)\n" if $debug;
|
||||
$outer = $2;
|
||||
$arg = "";
|
||||
}
|
||||
elsif ($outer =~ /^([^,\"]*)\((.*$)/) {
|
||||
# arg with ()
|
||||
($startarg,$bal,$outer) = &GetBalancedParen( $FD, $outer );
|
||||
$arg = $arg . $startarg . $bal;
|
||||
# Rest of code will catch the rest
|
||||
}
|
||||
elsif ($outer =~ /^([^,\(]*)\"(.*$)/) {
|
||||
# arg with ""
|
||||
($startarg,$string,$outer) = &GetString( $FD, $outer );
|
||||
print "string is $string\n" if $debug;
|
||||
$arg = $arg . $startarg . $string;
|
||||
# Rest of code will catch the rest
|
||||
}
|
||||
else {
|
||||
# no comma
|
||||
print "Adding |$outer| to arg $arg\n" if $debug;
|
||||
$arg .= $outer;
|
||||
$outer = "";
|
||||
}
|
||||
}
|
||||
if ($arg ne "") {
|
||||
$args[$#args+1] = $arg;
|
||||
}
|
||||
print "Number of args is 1+$#args\n" if $debug;
|
||||
return ($leader, $remainder, @args );
|
||||
}
|
||||
|
||||
# remainder = StripComments( FD, inputline )
|
||||
# removes comments from a line and returns the line. Read more if necessary
|
||||
# Places the comment into $comment_line;
|
||||
# The external "cxx_header" adds // to the comments stripped
|
||||
|
||||
# Set a default value for cxx_header
|
||||
if (!defined($cxx_header)) {
|
||||
$cxx_header = 1;
|
||||
}
|
||||
|
||||
sub StripComments {
|
||||
my $FD = $_[0];
|
||||
my $curline = $_[1];
|
||||
my $remainder = "";
|
||||
$comment_line = "";
|
||||
if ($cxx_header == 1 && $curline =~ /(\/\/.*)/) {
|
||||
$comment_line = $1;
|
||||
$curline =~ s/\/\/.*//;
|
||||
print "Removed C++ comment, now is $curline\n" if $debug;
|
||||
return $curline;
|
||||
}
|
||||
while ($curline =~ /\/\*/) {
|
||||
print "Curline = $curline\n" if $debug;
|
||||
if ($curline =~ /(\/\*.*?\*\/)/s) {
|
||||
$comment_line = $1;
|
||||
$curline =~ s/\/\*.*?\*\///s;
|
||||
print "Removed comment, now is $curline\n" if $debug;
|
||||
# Keep looking for comments incase the line has multiple
|
||||
# comments
|
||||
}
|
||||
else {
|
||||
# Keep collecting until we find the end of the comment
|
||||
if (eof($FD)) {
|
||||
print STDOUT "Unterminated comment found$errsrc!\n";
|
||||
my $line = $curline;
|
||||
if ($line =~ /(.*)\n/) { $line = "$1"; }
|
||||
print STDOUT "Comment begins with $line\n";
|
||||
return $curline;
|
||||
}
|
||||
$curline .= <$FD>;
|
||||
}
|
||||
}
|
||||
return $curline;
|
||||
}
|
||||
|
||||
# Since this is a required package, indicate that we are successful.
|
||||
return 1;
|
|
@ -0,0 +1,159 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "precomp.h"
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
_Ret_z_
|
||||
static const char*
|
||||
find_digits(
|
||||
_In_z_ const char* p
|
||||
)
|
||||
{
|
||||
while(!isdigit(static_cast<unsigned char>(*p)))
|
||||
{
|
||||
if(*p == '\0')
|
||||
return p;
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
_Ret_z_
|
||||
static const char*
|
||||
skip_digits(
|
||||
_In_z_ const char* p
|
||||
)
|
||||
{
|
||||
while(isdigit(static_cast<unsigned char>(*p)))
|
||||
{
|
||||
p++;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
//
|
||||
// Given the range of ranks a,b,d-f,x-z in which separators are any character
|
||||
// except '-', this function checks whether the given rank belongs to this range
|
||||
//
|
||||
// Input:
|
||||
// rank - the rank to check for inclusion
|
||||
// range - the string containing the range of ranks
|
||||
// world_size - the size of MPI_COMM_WORLD
|
||||
//
|
||||
// Output
|
||||
// isWithinRange - true if the rank belongs to this range
|
||||
// total_unique_ranks - the number of unique ranks in the list
|
||||
//
|
||||
// Return: MPI_SUCCESS if the call succeeded, error otherwise.
|
||||
//
|
||||
//
|
||||
_Success_(return==MPI_SUCCESS)
|
||||
int
|
||||
MPIU_Parse_rank_range(
|
||||
_In_ unsigned int rank,
|
||||
_In_z_ const char* range,
|
||||
_In_ unsigned int world_size,
|
||||
_Out_ bool* isWithinRange,
|
||||
_Out_writes_(world_size) unsigned int* total_unique_ranks
|
||||
)
|
||||
{
|
||||
MPIU_Assert( range != nullptr );
|
||||
|
||||
if( CompareStringA( LOCALE_INVARIANT,
|
||||
0,
|
||||
range,
|
||||
-1,
|
||||
"all",
|
||||
-1 ) == CSTR_EQUAL ||
|
||||
CompareStringA( LOCALE_INVARIANT,
|
||||
0,
|
||||
range,
|
||||
-1,
|
||||
"*",
|
||||
-1 ) == CSTR_EQUAL )
|
||||
{
|
||||
*isWithinRange = true;
|
||||
*total_unique_ranks = world_size;
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// The first character has to be a digit
|
||||
//
|
||||
if( !isdigit( static_cast<unsigned char>( range[0] ) ) )
|
||||
{
|
||||
return MPIU_ERR_CREATE( MPI_ERR_OTHER, "**invalidrange %s", range );
|
||||
}
|
||||
|
||||
bool *ranks = new bool[world_size]();
|
||||
|
||||
if (ranks == nullptr)
|
||||
{
|
||||
return MPIU_ERR_NOMEM();
|
||||
}
|
||||
|
||||
for (unsigned int i=0; i < world_size; i++ )
|
||||
{
|
||||
ranks[i] = false;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
unsigned int total = 0;
|
||||
for( const char* curPos = find_digits( range );
|
||||
*curPos != '\0';
|
||||
curPos = find_digits( curPos ) )
|
||||
{
|
||||
unsigned int low = atoi( curPos );
|
||||
unsigned int high = low;
|
||||
|
||||
curPos = skip_digits( curPos );
|
||||
|
||||
if( *curPos == '-' )
|
||||
{
|
||||
//
|
||||
// Anything not a digit and not '-' is a valid separator
|
||||
//
|
||||
curPos ++;
|
||||
if ( isdigit( static_cast<unsigned char>( *curPos ) ) )
|
||||
{
|
||||
high = atoi( curPos );
|
||||
}
|
||||
}
|
||||
|
||||
for ( unsigned int i = low; i <= high; i++ )
|
||||
{
|
||||
if ( i >= world_size )
|
||||
{
|
||||
delete [] ranks;
|
||||
return MPIU_ERR_CREATE(MPI_ERR_OTHER, "**rank %d %d", i, world_size );
|
||||
}
|
||||
if ( ranks[i] == true )
|
||||
{
|
||||
delete [] ranks;
|
||||
return MPIU_ERR_CREATE(MPI_ERR_OTHER, "**rangedup %s %d", range, i);
|
||||
}
|
||||
ranks[i] = true;
|
||||
total++;
|
||||
}
|
||||
|
||||
if ( rank >= low && rank <= high )
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
curPos = skip_digits( curPos );
|
||||
}
|
||||
|
||||
*total_unique_ranks = total;
|
||||
*isWithinRange = found;
|
||||
|
||||
delete [] ranks;
|
||||
return MPI_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <winsock2.h>
|
||||
#include <mpi.h>
|
||||
#include "assertutil.h"
|
||||
#include "mpidef.h"
|
||||
#include "mpierror.h"
|
||||
#include "mpiutil.h"
|
||||
#include "mpimem.h"
|
||||
#include "mpistr.h"
|
||||
#include <sddl.h>
|
|
@ -0,0 +1,426 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "rpc.h"
|
||||
#include "rpcutil.h"
|
||||
#include "ntdsapi.h"
|
||||
|
||||
#define SECURITY_WIN32
|
||||
#include "security.h"
|
||||
|
||||
extern "C"
|
||||
void __RPC_FAR *
|
||||
__RPC_USER MIDL_user_allocate(
|
||||
size_t cBytes
|
||||
)
|
||||
{
|
||||
return malloc( cBytes );
|
||||
}
|
||||
|
||||
|
||||
extern "C"
|
||||
void __RPC_USER
|
||||
MIDL_user_free(
|
||||
void* pBuffer
|
||||
)
|
||||
{
|
||||
free( pBuffer );
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Start the RPC server
|
||||
//
|
||||
// In:
|
||||
// pProtSeq : The protocol sequence
|
||||
// pEndpoint : The endpoint (port). If null, we use dynamic port
|
||||
// rpcInterface : The RPC interface handle
|
||||
// pSecurityCallbackFn: The security callback function
|
||||
// maxConcurrentCalls : Number of concurrent client calls that the server will accept
|
||||
// localOnly : If true, use only LRPC for the server
|
||||
//
|
||||
// Out:
|
||||
// pPort : The TCP port that the RPC server is accepting calls on
|
||||
// pLrpcEndpoint : The LRPC port that the RPC server is accepting calls on
|
||||
//
|
||||
// Return:
|
||||
// NOERROR on success, other errors otherwise
|
||||
//
|
||||
_Success_(return == NOERROR)
|
||||
RPC_STATUS
|
||||
StartRpcServer(
|
||||
_In_z_ PCWSTR pProtSeq,
|
||||
_In_opt_z_ PCWSTR pEndpoint,
|
||||
_In_ RPC_IF_HANDLE rpcInterface,
|
||||
_In_opt_ RPC_IF_CALLBACK_FN* pSecurityCallbackFn,
|
||||
_Out_opt_ UINT16* pPort,
|
||||
_Out_opt_ GUID* pLrpcEndpoint,
|
||||
_In_ UINT maxConcurrentCalls,
|
||||
_In_ bool localOnly
|
||||
)
|
||||
{
|
||||
RPC_STATUS status = RPC_S_OK;
|
||||
|
||||
GUID lrpcEp = {0};
|
||||
if( pLrpcEndpoint != nullptr )
|
||||
{
|
||||
//
|
||||
// Enable listening on LRPC.
|
||||
// We generate a GUID to use as endpoint for LRPC.
|
||||
//
|
||||
status = UuidCreate( &lrpcEp );
|
||||
if( status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY )
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
wchar_t guidStr[37];
|
||||
GuidToStr( lrpcEp, guidStr, _countof(guidStr) );
|
||||
|
||||
wchar_t protSeq[] = L"ncalrpc";
|
||||
status = RpcServerUseProtseqEpW(
|
||||
protSeq,
|
||||
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
|
||||
guidStr,
|
||||
nullptr
|
||||
);
|
||||
if( status != RPC_S_OK )
|
||||
{
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if( localOnly == false )
|
||||
{
|
||||
//
|
||||
// Dynamic and static endpoints are setup through different RPC APIs
|
||||
//
|
||||
if( pEndpoint == nullptr )
|
||||
{
|
||||
//
|
||||
// Specify that we will be using TCP socket with dynamic endpoint
|
||||
//
|
||||
status = RpcServerUseProtseqW(
|
||||
const_cast<wchar_t*>( pProtSeq ),
|
||||
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
|
||||
nullptr
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Specify that we will be using TCP socket with static endpoint
|
||||
//
|
||||
status = RpcServerUseProtseqEpW(
|
||||
const_cast<wchar_t*>( pProtSeq ),
|
||||
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
|
||||
const_cast<wchar_t*>( pEndpoint ),
|
||||
nullptr
|
||||
);
|
||||
}
|
||||
|
||||
if( status != RPC_S_OK )
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
wchar_t computerName[MAX_COMPUTERNAME_LENGTH + 1];
|
||||
DWORD len = _countof(computerName);
|
||||
if( GetComputerNameW( computerName, &len ) == 0 )
|
||||
{
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
wchar_t spn[MAX_PATH+1];
|
||||
len = _countof(spn);
|
||||
|
||||
status = DsMakeSpnW(
|
||||
MSMPI_SPN_SERVICE_NAME,
|
||||
computerName,
|
||||
nullptr,
|
||||
0,
|
||||
nullptr,
|
||||
&len,
|
||||
spn );
|
||||
if( status != ERROR_SUCCESS )
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
#if !defined(MSMPI_NO_SEC)
|
||||
status = RpcServerRegisterAuthInfoW( spn,
|
||||
RPC_C_AUTHN_GSS_NEGOTIATE,
|
||||
nullptr,
|
||||
nullptr );
|
||||
if( status != RPC_S_OK )
|
||||
{
|
||||
return status;
|
||||
}
|
||||
#else
|
||||
pSecurityCallbackFn = nullptr;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT( pLrpcEndpoint != nullptr && pPort == nullptr );
|
||||
pSecurityCallbackFn = nullptr;
|
||||
}
|
||||
|
||||
//
|
||||
// Register the interface and start the server
|
||||
//
|
||||
status = RpcServerRegisterIfEx( rpcInterface,
|
||||
nullptr,
|
||||
nullptr,
|
||||
RPC_IF_AUTOLISTEN,
|
||||
maxConcurrentCalls,
|
||||
pSecurityCallbackFn );
|
||||
if( status != RPC_S_OK )
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
if( pPort == nullptr )
|
||||
{
|
||||
if( pLrpcEndpoint != nullptr )
|
||||
{
|
||||
*pLrpcEndpoint = lrpcEp;
|
||||
}
|
||||
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Extract the dynamic port that the server is using
|
||||
//
|
||||
RPC_BINDING_VECTOR* pBindingVector;
|
||||
|
||||
//
|
||||
// Get the server binding handle vector. This vector has information
|
||||
// about the server bindings (which includes the port)
|
||||
//
|
||||
status = RpcServerInqBindings( &pBindingVector );
|
||||
if( status != RPC_S_OK )
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
wchar_t* bindingStr;
|
||||
wchar_t* endpointStr;
|
||||
wchar_t* protSeqStr;
|
||||
bool found = false;
|
||||
for( unsigned i = 0; i < pBindingVector->Count; ++i )
|
||||
{
|
||||
status = RpcBindingToStringBindingW(
|
||||
pBindingVector->BindingH[i],
|
||||
reinterpret_cast<RPC_WSTR*>( &bindingStr ) );
|
||||
|
||||
if( status != RPC_S_OK )
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the port
|
||||
//
|
||||
status = RpcStringBindingParseW(
|
||||
bindingStr,
|
||||
nullptr,
|
||||
&protSeqStr,
|
||||
nullptr,
|
||||
&endpointStr,
|
||||
nullptr
|
||||
);
|
||||
RpcStringFreeW( &bindingStr );
|
||||
if( status != RPC_S_OK )
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
if( CompareStringW( LOCALE_INVARIANT,
|
||||
0,
|
||||
protSeqStr,
|
||||
-1,
|
||||
L"ncacn_ip_tcp",
|
||||
-1 ) == CSTR_EQUAL )
|
||||
{
|
||||
*pPort = static_cast<UINT16>(_wtoi( endpointStr ));
|
||||
found = true;
|
||||
|
||||
if( env_is_on(L"MPIEXEC_USE_NP", FALSE) )
|
||||
{
|
||||
wchar_t npEndpoint[64];
|
||||
MPIU_Snprintf(
|
||||
npEndpoint,
|
||||
_countof( npEndpoint ),
|
||||
L"\\pipe\\msmpi\\smpd\\%s",
|
||||
endpointStr );
|
||||
|
||||
status = RpcServerUseProtseqEpW(
|
||||
reinterpret_cast<RPC_WSTR>( L"ncacn_np" ),
|
||||
0,
|
||||
reinterpret_cast<RPC_WSTR>( npEndpoint ),
|
||||
NULL );
|
||||
}
|
||||
RpcStringFreeW( &endpointStr );
|
||||
RpcStringFreeW( &protSeqStr );
|
||||
break;
|
||||
}
|
||||
|
||||
RpcStringFreeW( &endpointStr );
|
||||
RpcStringFreeW( &protSeqStr );
|
||||
}
|
||||
|
||||
RpcBindingVectorFree( &pBindingVector );
|
||||
|
||||
ASSERT( found == true );
|
||||
if( pLrpcEndpoint != nullptr )
|
||||
{
|
||||
*pLrpcEndpoint = lrpcEp;
|
||||
}
|
||||
|
||||
if( status != RPC_S_OK )
|
||||
{
|
||||
return status;
|
||||
}
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Stop this RPC server
|
||||
//
|
||||
// In:
|
||||
// rpcInterface : The RPC interface handle
|
||||
//
|
||||
RPC_STATUS
|
||||
StopRpcServer(
|
||||
_In_ RPC_IF_HANDLE rpcInterface
|
||||
)
|
||||
{
|
||||
return RpcServerUnregisterIf( rpcInterface, nullptr, FALSE );
|
||||
}
|
||||
|
||||
|
||||
_Success_(return == NOERROR)
|
||||
RPC_STATUS
|
||||
CreateRpcBinding(
|
||||
_In_ PCWSTR pProtSeq,
|
||||
_In_opt_z_ PCWSTR pHostName,
|
||||
_In_ PCWSTR pEndpoint,
|
||||
_In_ UINT AuthnLevel,
|
||||
_In_ UINT AuthnSvc,
|
||||
_In_opt_ RPC_AUTH_IDENTITY_HANDLE pAuthIdentity,
|
||||
_Out_ handle_t* phBinding
|
||||
)
|
||||
{
|
||||
PWSTR bindingStr;
|
||||
RPC_STATUS status = RpcStringBindingComposeW(
|
||||
nullptr,
|
||||
const_cast<wchar_t*>(pProtSeq),
|
||||
const_cast<wchar_t*>(pHostName),
|
||||
const_cast<wchar_t*>(pEndpoint),
|
||||
nullptr,
|
||||
&bindingStr
|
||||
);
|
||||
if( status != RPC_S_OK )
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
handle_t hBinding;
|
||||
status = RpcBindingFromStringBindingW(
|
||||
bindingStr,
|
||||
&hBinding
|
||||
);
|
||||
RpcStringFreeW( &bindingStr );
|
||||
if( status != RPC_S_OK )
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
#if !defined(MSMPI_NO_SEC)
|
||||
wchar_t* pSpn = nullptr;
|
||||
wchar_t spn[MAX_PATH+1];
|
||||
|
||||
SEC_WINNT_AUTH_IDENTITY_EXW secAuth;
|
||||
if( AuthnSvc == RPC_C_AUTHN_GSS_NEGOTIATE &&
|
||||
pAuthIdentity == nullptr )
|
||||
{
|
||||
DWORD len = _countof(spn);
|
||||
status = DsMakeSpnW(
|
||||
MSMPI_SPN_SERVICE_NAME,
|
||||
pHostName,
|
||||
nullptr,
|
||||
0,
|
||||
nullptr,
|
||||
&len,
|
||||
spn );
|
||||
if( status != ERROR_SUCCESS )
|
||||
{
|
||||
if( status == ERROR_INVALID_PARAMETER )
|
||||
{
|
||||
//
|
||||
// This should only happen because the host is an IP
|
||||
// address and not a proper name. Kerberos requires
|
||||
// names which means we will have to disable Kerberos
|
||||
// to authenticate.
|
||||
//
|
||||
InitializeAuthIdentity(
|
||||
disableKerbStr,
|
||||
_countof(DISABLE_KERB_STR) - 1,
|
||||
&secAuth );
|
||||
pAuthIdentity = &secAuth;
|
||||
}
|
||||
else
|
||||
{
|
||||
RpcBindingFree( &hBinding );
|
||||
return status;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pSpn = spn;
|
||||
}
|
||||
}
|
||||
|
||||
status = RpcBindingSetAuthInfoW(
|
||||
hBinding,
|
||||
pSpn,
|
||||
AuthnLevel,
|
||||
AuthnSvc,
|
||||
pAuthIdentity,
|
||||
0 );
|
||||
if( status != RPC_S_OK )
|
||||
{
|
||||
RpcBindingFree( &hBinding );
|
||||
return status;
|
||||
}
|
||||
#else
|
||||
UNREFERENCED_PARAMETER(AuthnLevel);
|
||||
UNREFERENCED_PARAMETER(AuthnSvc);
|
||||
UNREFERENCED_PARAMETER(pAuthIdentity);
|
||||
#endif
|
||||
|
||||
*phBinding = hBinding;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InitializeAuthIdentity(
|
||||
_In_ PWSTR packageStr,
|
||||
_In_ DWORD packageLen,
|
||||
_Out_ SEC_WINNT_AUTH_IDENTITY_EXW* pSecAuth
|
||||
)
|
||||
{
|
||||
ZeroMemory( pSecAuth, sizeof(*pSecAuth) );
|
||||
pSecAuth->Version = SEC_WINNT_AUTH_IDENTITY_VERSION;
|
||||
pSecAuth->Length = sizeof(*pSecAuth);
|
||||
pSecAuth->PackageList = packageStr;
|
||||
pSecAuth->PackageListLength = packageLen;
|
||||
pSecAuth->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
#include "rpc.h"
|
||||
|
||||
#ifndef SECURITY_WIN32
|
||||
#define SECURITY_WIN32
|
||||
#endif
|
||||
|
||||
#include <security.h>
|
||||
|
||||
#define DISABLE_KERB_STR L"!Kerberos"
|
||||
__declspec(selectany) extern wchar_t disableKerbStr[] = DISABLE_KERB_STR;
|
||||
|
||||
_Success_(return == NOERROR)
|
||||
RPC_STATUS
|
||||
StartRpcServer(
|
||||
_In_z_ PCWSTR pProtSeq,
|
||||
_In_opt_z_ PCWSTR pEndpoint,
|
||||
_In_ RPC_IF_HANDLE rpcInterface,
|
||||
_In_opt_ RPC_IF_CALLBACK_FN* pSecurityCallbackFn,
|
||||
_Out_opt_ UINT16* pPort,
|
||||
_Out_opt_ GUID* pLrpcEndpoint,
|
||||
_In_ UINT maxConcurrentCalls = RPC_C_LISTEN_MAX_CALLS_DEFAULT,
|
||||
_In_ bool localOnly = false
|
||||
);
|
||||
|
||||
|
||||
RPC_STATUS
|
||||
StopRpcServer(
|
||||
_In_ RPC_IF_HANDLE rpcInterface
|
||||
);
|
||||
|
||||
|
||||
_Success_(return == NOERROR)
|
||||
RPC_STATUS
|
||||
CreateRpcBinding(
|
||||
_In_z_ PCWSTR pProtSeq,
|
||||
_In_opt_z_ PCWSTR pHostName,
|
||||
_In_z_ PCWSTR pEndpoint,
|
||||
_In_ UINT AuthnLevel,
|
||||
_In_ UINT AuthnSvc,
|
||||
_In_opt_ RPC_AUTH_IDENTITY_HANDLE pAuthIdentity,
|
||||
_Out_ handle_t* phBinding
|
||||
);
|
||||
|
||||
|
||||
void
|
||||
InitializeAuthIdentity(
|
||||
_In_ PWSTR packageStr,
|
||||
_In_ DWORD packageLen,
|
||||
_Out_ SEC_WINNT_AUTH_IDENTITY_EXW* pSecAuth
|
||||
);
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{A697D69E-7F67-457F-9194-267C73C5B8CF}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<Import Project="$(SrcRoot)\mpi.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<ConfigurationType>None</ConfigurationType>
|
||||
<PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>
|
||||
<IntDirSharingDetected>None</IntDirSharingDetected>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
||||
<ItemGroup>
|
||||
<MessageCompile Include="$(MPI_SRC_ROOT)\common\mpitrace.man">
|
||||
<GeneratedHeaderPath>true</GeneratedHeaderPath>
|
||||
<HeaderFilePath>$(MPI_SRC_ROOT)\common\$(O)</HeaderFilePath>
|
||||
<GeneratedRCAndMessagesPath>true</GeneratedRCAndMessagesPath>
|
||||
<RCFilePath>$(MPI_SRC_ROOT)\common\$(O)</RCFilePath>
|
||||
<GeneratedFilesBaseName>MpiTraceEvents</GeneratedFilesBaseName>
|
||||
<GenerateUserModeLoggingMacros>true</GenerateUserModeLoggingMacros>
|
||||
<PrefixMacroName>Trace</PrefixMacroName>
|
||||
<RemoveCharsFromSymbolName>EVENT_</RemoveCharsFromSymbolName>
|
||||
</MessageCompile>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
|
@ -0,0 +1,171 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Ensure that the OS version is greater than or equal to the specified version.
|
||||
//
|
||||
// Parameters:
|
||||
// major - Windows major version
|
||||
// minor - Windows minor version
|
||||
//
|
||||
_Success_(return!=FALSE)
|
||||
BOOL
|
||||
CheckOSVersion(
|
||||
_In_ DWORD major,
|
||||
_In_ DWORD minor
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Check if the smpd instance is running on azure and if so,
|
||||
// return the logical name of the node
|
||||
//
|
||||
// Input:
|
||||
// szBuffer: the size of the name buffer
|
||||
//
|
||||
// Output:
|
||||
// buffer : store the logical name. If null, name is not returned
|
||||
//
|
||||
// Return:
|
||||
// true if the node is on azure
|
||||
// false if the node is not on azure, or if the size of the buffer is
|
||||
// too small
|
||||
//
|
||||
//
|
||||
bool get_azure_node_logical_name(
|
||||
_Out_opt_z_cap_(szBuffer) wchar_t* buffer,
|
||||
_In_ DWORD szBuffer
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// We use a looping count means because the 99% case, the
|
||||
// bits will all be sequential in the low 32bits of the
|
||||
// value. Most uses will be to count 2 to 8 bits, so the
|
||||
// loop will be less overall overhead for the 99% case.
|
||||
//
|
||||
template<typename T>
|
||||
inline UINT8 CountBits( T value )
|
||||
{
|
||||
UINT8 c = 0;
|
||||
while( value != 0 )
|
||||
{
|
||||
c += static_cast<UINT8>(value & 1);
|
||||
value >>= 1;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
inline ULONG PowerOf2Floor( _In_range_(>, 0) ULONG value )
|
||||
{
|
||||
MPIU_Assert( value != 0 );
|
||||
|
||||
ULONG msb;
|
||||
_BitScanReverse( &msb, value );
|
||||
|
||||
return 1 << msb;
|
||||
}
|
||||
|
||||
|
||||
inline bool IsPowerOf2( _In_range_(>, 0) ULONG value )
|
||||
{
|
||||
MPIU_Assert( value != 0 );
|
||||
|
||||
return ((value & (value - 1)) == 0);
|
||||
}
|
||||
|
||||
|
||||
#define POWER_OF_2_CEILING_LIMIT 0x80000000
|
||||
inline ULONG PowerOf2Ceiling( _In_range_(1, POWER_OF_2_CEILING_LIMIT) ULONG value )
|
||||
{
|
||||
MPIU_Assert( value != 0 && value <= POWER_OF_2_CEILING_LIMIT );
|
||||
|
||||
if( IsPowerOf2( value ) )
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
ULONG msb;
|
||||
_BitScanReverse( &msb, value );
|
||||
|
||||
return 2 << msb;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Returns the size of the binomial subtree with root 'rank' in a tree of 'size'
|
||||
// total nodes.
|
||||
//
|
||||
inline
|
||||
unsigned
|
||||
TreeSize(
|
||||
_In_range_(0, size - 1) unsigned rank,
|
||||
_In_range_(>, 0) unsigned size
|
||||
)
|
||||
{
|
||||
MPIU_Assert( size > 0 );
|
||||
MPIU_Assert( rank < size );
|
||||
|
||||
ULONG k;
|
||||
if( _BitScanForward( &k, rank ) == 0 )
|
||||
{
|
||||
MPIU_Assert( rank == 0 );
|
||||
return size;
|
||||
}
|
||||
|
||||
k = 1 << k;
|
||||
return k < size - rank ? k : size - rank;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Returns the number of children in the biniomial subtree with root 'rank' in
|
||||
// a tree of 'size' total nodes.
|
||||
//
|
||||
inline
|
||||
unsigned
|
||||
ChildCount(
|
||||
_In_range_(0, size - 1) unsigned rank,
|
||||
_In_range_(>, 0) unsigned size
|
||||
)
|
||||
{
|
||||
MPIU_Assert( size > 0 );
|
||||
MPIU_Assert( rank < size );
|
||||
|
||||
unsigned treeSize = TreeSize( rank, size );
|
||||
MPIU_Assert(treeSize > 0);
|
||||
|
||||
ULONG msb;
|
||||
_BitScanReverse( &msb, treeSize );
|
||||
|
||||
return IsPowerOf2( treeSize ) ? msb : msb + 1;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Returns max value in an array
|
||||
//
|
||||
inline
|
||||
int
|
||||
MaxElement(
|
||||
_In_reads_(size) const int cnts[],
|
||||
_In_range_(>, 0) unsigned size
|
||||
)
|
||||
{
|
||||
MPIU_Assert(size > 0);
|
||||
|
||||
int maxElement = cnts[0];
|
||||
for (unsigned i = 1; i < size; ++i)
|
||||
{
|
||||
if (cnts[i] > maxElement)
|
||||
{
|
||||
maxElement = cnts[i];
|
||||
}
|
||||
}
|
||||
return maxElement;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectFile Include="$(MSBuildThisFileDirectory)common\mpicommon.vcxproj" />
|
||||
<ProjectFile Include="$(MSBuildThisFileDirectory)common\traceManifest.vcxproj" />
|
||||
<ProjectFile Include="$(MSBuildThisFileDirectory)mpiexec\mpiexec.vcxproj" />
|
||||
<ProjectFile Include="$(MSBuildThisFileDirectory)msmpi\dirs.proj" />
|
||||
<ProjectFile Include="$(MSBuildThisFileDirectory)pmilib\dirs.proj" />
|
||||
<ProjectFile Include="$(MSBuildThisFileDirectory)smpd\smpd.vcxproj" />
|
||||
<ProjectFile Include="$(MSBuildThisFileDirectory)stub\mpistub.vcxproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="$(TraversalTargets)" Condition=" '$(CBTModulesRestored)' == 'true' " />
|
||||
</Project>
|
|
@ -0,0 +1,160 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "mpiexec.h"
|
||||
#include "PmiDbgImpl.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
__declspec(dllexport) MPIR_PROCDESC* MPIR_Proctable;
|
||||
__declspec(dllexport) int MPIR_Proctable_size;
|
||||
__declspec(dllexport) volatile int MPIR_debug_state = 0;
|
||||
__declspec(dllexport) volatile int MPIR_being_debugged = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// FW define the callback functions.
|
||||
//
|
||||
static FN_PmiDbgControl MpiexecPmiDbgControlBeforeCreateProcesses;
|
||||
|
||||
|
||||
//
|
||||
// Define the notification events in Mpiexec
|
||||
//
|
||||
const PMIDBG_NOTIFICATION MpiexecNotifyInitialize =
|
||||
{
|
||||
PMIDBG_NOTIFY_INITIALIZE,
|
||||
NULL
|
||||
};
|
||||
|
||||
const PMIDBG_NOTIFICATION MpiexecNotifyFinalize =
|
||||
{
|
||||
PMIDBG_NOTIFY_FINALIZE,
|
||||
NULL
|
||||
};
|
||||
|
||||
const PMIDBG_NOTIFICATION MpiexecNotifyBeforeCreateProcesses =
|
||||
{
|
||||
PMIDBG_NOTIFY_BEFORE_CREATE_PROCESSES,
|
||||
MpiexecPmiDbgControlBeforeCreateProcesses
|
||||
};
|
||||
|
||||
|
||||
const PMIDBG_NOTIFICATION MpiexecNotifyAfterCreateProcesses =
|
||||
{
|
||||
PMIDBG_NOTIFY_AFTER_CREATE_PROCESSES,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static HRESULT __stdcall
|
||||
MpiexecPmiDbgControlBeforeCreateProcesses(
|
||||
__in PMIDBG_OPCODE_TYPE type,
|
||||
__in void* pData,
|
||||
__inout_bcount(cbBuffer) void* pBuffer,
|
||||
__in SIZE_T cbBuffer
|
||||
)
|
||||
{
|
||||
va_list args = reinterpret_cast<va_list>(pData);
|
||||
smpd_global_t* pSmpdProcess = va_arg(args,smpd_global_t*);
|
||||
smpd_host_t* pHosts = va_arg(args,smpd_host_t*);
|
||||
switch(type)
|
||||
{
|
||||
case PMIDBG_OPCODE_GET_WORLD_SIZE:
|
||||
{
|
||||
if( cbBuffer < sizeof(pSmpdProcess->nproc) )
|
||||
{
|
||||
return HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
|
||||
}
|
||||
*(reinterpret_cast<unsigned int*>(pBuffer)) = static_cast<unsigned int>( pSmpdProcess->nproc );
|
||||
}
|
||||
break;
|
||||
case PMIDBG_OPCODE_ENUM_WORLD_NODES:
|
||||
{
|
||||
PMIDBG_ENUM_WORLD_NODES* pEnum;
|
||||
smpd_host_t* pEntry;
|
||||
|
||||
if( cbBuffer < sizeof(*pEnum) )
|
||||
{
|
||||
return HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
|
||||
}
|
||||
|
||||
pEnum = static_cast<PMIDBG_ENUM_WORLD_NODES*>( pBuffer );
|
||||
|
||||
//
|
||||
// If they pass in a list that is already at the end, we error
|
||||
//
|
||||
if( pEnum->Context == PMIDBG_ENUM_END )
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if( pEnum->Context == PMIDBG_ENUM_BEGIN )
|
||||
{
|
||||
//
|
||||
// If they are requesting the begin
|
||||
//
|
||||
pEntry = pHosts;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Else use the context value passed in
|
||||
// NOTE: PMIDBG_ENUM_BEGIN == 0, so null is not possible
|
||||
//
|
||||
pEntry = static_cast<smpd_host_t*>(
|
||||
reinterpret_cast<smpd_host_t*>( pEnum->Context )->Next);
|
||||
}
|
||||
|
||||
if( NULL == pEntry )
|
||||
{
|
||||
pEnum->Context = PMIDBG_ENUM_END;
|
||||
}
|
||||
else
|
||||
{
|
||||
pEnum->Context = reinterpret_cast<LONG_PTR>( pEntry );
|
||||
MPIU_WideCharToMultiByte( pEntry->name, &pEntry->nameA );
|
||||
|
||||
pEnum->Hostname = pEntry->nameA;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PMIDBG_OPCODE_GET_PROCSIZE_ADDR:
|
||||
{
|
||||
if( cbBuffer < sizeof(&MPIR_Proctable_size) )
|
||||
{
|
||||
return HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
|
||||
}
|
||||
*(reinterpret_cast<int**>(pBuffer)) = &MPIR_Proctable_size;
|
||||
}
|
||||
break;
|
||||
case PMIDBG_OPCODE_GET_PROCTABLE_ADDR:
|
||||
{
|
||||
if( cbBuffer < sizeof(MPIR_Proctable) )
|
||||
{
|
||||
return HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
|
||||
}
|
||||
*(reinterpret_cast<MPIR_PROCDESC***>(pBuffer)) = &MPIR_Proctable;
|
||||
}
|
||||
break;
|
||||
case PMIDBG_OPCODE_GET_DEBUG_MODE:
|
||||
{
|
||||
if( cbBuffer < sizeof(MPIDBG_DBG_MODE) )
|
||||
{
|
||||
return HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
|
||||
}
|
||||
if( MPIR_being_debugged == 1 )
|
||||
{
|
||||
*(reinterpret_cast<MPIDBG_DBG_MODE*>(pBuffer)) = MPIDBG_DBG_LAUNCH;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(reinterpret_cast<MPIDBG_DBG_MODE*>(pBuffer)) = MPIDBG_DBG_ATTACH;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
|
@ -0,0 +1,209 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
* (C) 2001 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#include "smpd.h"
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
//
|
||||
// configfile_size
|
||||
//
|
||||
// Calculate the configfile size to allocate by adding 3 chars for each line len for the block
|
||||
// seperator " : ".
|
||||
// Zero is returned in indicate an error and errno is set to the error value.
|
||||
//
|
||||
static size_t configfile_size(FILE* fin)
|
||||
{
|
||||
size_t size = 0;
|
||||
wchar_t buffer[128];
|
||||
|
||||
while(fgetws(buffer, _countof(buffer), fin))
|
||||
{
|
||||
//
|
||||
// fgetws skips over NULL characters: it is unsafe to use strlen to get the number
|
||||
// of bytes read, since the user may erroneously supply a binary file.
|
||||
//
|
||||
size += _countof(buffer) + 3;
|
||||
}
|
||||
|
||||
if(ferror(fin))
|
||||
return 0;
|
||||
|
||||
if(fseek(fin, 0, SEEK_SET) != 0)
|
||||
return 0;
|
||||
|
||||
return size + 3;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// read_configfile
|
||||
//
|
||||
// Read the complete configfile into a buffer ( ':' seperated) and return the buffer.
|
||||
// NULL is returned in indicate an error and errno is set to the error value.
|
||||
//
|
||||
static wchar_t* read_configfile(FILE* fin)
|
||||
{
|
||||
size_t size = configfile_size(fin);
|
||||
if(size == 0)
|
||||
return NULL;
|
||||
|
||||
if(size > INT_MAX)
|
||||
{
|
||||
_set_errno(E2BIG);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wchar_t* cmdline = static_cast<wchar_t*>( malloc( size * sizeof(wchar_t) ) );
|
||||
if(cmdline == NULL)
|
||||
{
|
||||
_set_errno(ENOMEM);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wchar_t* line = cmdline;
|
||||
int concat = 0;
|
||||
while(fgetws(line, (int)(size), fin))
|
||||
{
|
||||
ASSERT(size > 1);
|
||||
|
||||
wchar_t* p = const_cast<wchar_t*>(skip_ws(line));
|
||||
|
||||
//
|
||||
// On comment, read the next line to the same buffer location.
|
||||
// Comment lines do not terminate concatenation, allowing commenting out parts
|
||||
// of a long block
|
||||
//
|
||||
if(*p == L'#')
|
||||
continue;
|
||||
|
||||
//
|
||||
// On whitespace lines, read the next line to the same buffer location.
|
||||
// Note that whitespace lines terminate line concatenation, and append the block
|
||||
// end sequence " : ".
|
||||
//
|
||||
if(*p == L'\0')
|
||||
{
|
||||
if(!concat)
|
||||
continue;
|
||||
|
||||
p = line - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
//
|
||||
// Trim whitespace at the the end of the line (remove CR or LF characters).
|
||||
// N.B. The line contain at least one non whitespace character; thus this code
|
||||
// will not underflow the line.
|
||||
//
|
||||
p += MPIU_Strlen( p ) - 1;
|
||||
while( iswspace(*p) )
|
||||
{
|
||||
p--;
|
||||
}
|
||||
|
||||
size -= p - line;
|
||||
line = p;
|
||||
|
||||
//
|
||||
// Line break marker; read the next line into the same location
|
||||
//
|
||||
if(*p == L'\\')
|
||||
{
|
||||
concat = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
concat = 0;
|
||||
*++p = L' ';
|
||||
*++p = L':';
|
||||
*++p = L' ';
|
||||
++p;
|
||||
|
||||
size -= p - line;
|
||||
line = p;
|
||||
}
|
||||
|
||||
if(ferror(fin))
|
||||
{
|
||||
free(cmdline);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if((line - cmdline > 3) && *(line - 2) == ':')
|
||||
{
|
||||
line -= 3;
|
||||
}
|
||||
|
||||
*line = L'\0';
|
||||
|
||||
return cmdline;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// smpd_get_argv_from_file
|
||||
//
|
||||
// Read the entire config file and set argv.
|
||||
// NULL is returned to indicate success; Error string is returned to indicate error.
|
||||
//
|
||||
_Success_( return == NULL )
|
||||
_Ret_maybenull_
|
||||
PCWSTR
|
||||
smpd_get_argv_from_file(
|
||||
_In_ PCWSTR filename,
|
||||
_Outptr_ wchar_t ***argvp
|
||||
)
|
||||
{
|
||||
FILE* fin = _wfopen(filename, L"r");
|
||||
if(fin == NULL)
|
||||
{
|
||||
const wchar_t* res = _wcserror(errno);
|
||||
_Analysis_assume_( res != nullptr );
|
||||
return res;
|
||||
}
|
||||
|
||||
wchar_t* cmdline = read_configfile(fin);
|
||||
|
||||
fclose(fin);
|
||||
|
||||
if (cmdline == nullptr)
|
||||
{
|
||||
const wchar_t* res = _wcserror(errno);
|
||||
_Analysis_assume_( res != nullptr );
|
||||
return res;
|
||||
}
|
||||
|
||||
int numargs;
|
||||
int numchars;
|
||||
smpd_unpack_cmdline(cmdline, NULL, NULL, &numargs, &numchars);
|
||||
|
||||
if(numargs <= 1)
|
||||
{
|
||||
free(cmdline);
|
||||
return L"no commands in file";
|
||||
}
|
||||
|
||||
wchar_t** argv = (wchar_t**)malloc(numargs * sizeof(wchar_t*) +
|
||||
numchars * sizeof(wchar_t));
|
||||
if(argv == NULL)
|
||||
{
|
||||
free(cmdline);
|
||||
const wchar_t* res = _wcserror(ENOMEM);
|
||||
_Analysis_assume_( res != nullptr );
|
||||
return res;
|
||||
}
|
||||
|
||||
smpd_unpack_cmdline(cmdline, argv, (wchar_t*)(argv + numargs), &numargs, &numchars);
|
||||
|
||||
free(cmdline);
|
||||
*argvp = argv;
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
* (C) 2001 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#include "smpd.h"
|
||||
#include <errno.h>
|
||||
#include <wchar.h>
|
||||
|
||||
//
|
||||
// machinefile_size
|
||||
//
|
||||
// Calculate the machinefile buffer size to allocate by adding 3 to the size of the file.
|
||||
// Zero is returned in indicate an error and errno is set to the error value.
|
||||
//
|
||||
static size_t machinefile_size(FILE* fin)
|
||||
{
|
||||
size_t size = 0;
|
||||
wchar_t buffer[128];
|
||||
|
||||
|
||||
while(fgetws(buffer, _countof(buffer), fin))
|
||||
{
|
||||
//
|
||||
// fgets skips over NULL characters: it is unsafe to use strlen to get the number
|
||||
// of bytes read, since the user may erroneously supply a binary file.
|
||||
//
|
||||
size += _countof(buffer);
|
||||
}
|
||||
|
||||
if(ferror(fin))
|
||||
return 0;
|
||||
|
||||
if(fseek(fin, 0, SEEK_SET) != 0)
|
||||
return 0;
|
||||
|
||||
return size + 3;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// read_machinefile
|
||||
//
|
||||
// Read the complete machinefile into a buffer (space seperated), with the the number of
|
||||
// machines (lines) prepended to the buffer.
|
||||
// NULL is returned to indicate success; Error string is returned to indicate error.
|
||||
//
|
||||
_Success_( return == NULL )
|
||||
_Ret_maybenull_
|
||||
static PCWSTR
|
||||
read_machinefile(
|
||||
_In_ FILE* fin,
|
||||
_Outptr_result_z_ wchar_t** phosts
|
||||
)
|
||||
{
|
||||
const int x_space = 8;
|
||||
size_t size = machinefile_size(fin);
|
||||
if(size == 0)
|
||||
return NULL;
|
||||
|
||||
if(size > INT_MAX)
|
||||
return _wcserror(E2BIG);
|
||||
|
||||
size += x_space;
|
||||
|
||||
wchar_t* hosts = static_cast<wchar_t*>( malloc( size * sizeof(wchar_t) ) );
|
||||
if(hosts == NULL)
|
||||
{
|
||||
return _wcserror(ENOMEM);
|
||||
}
|
||||
|
||||
size_t hosts_len = size;
|
||||
wchar_t* line = hosts;
|
||||
|
||||
//
|
||||
// Prepend spaces
|
||||
//
|
||||
wmemset(line, L' ', x_space);
|
||||
size -= x_space;
|
||||
line += x_space;
|
||||
|
||||
int nhosts = 0;
|
||||
while(fgetws(line, (int)(size), fin))
|
||||
{
|
||||
ASSERT(size > 1);
|
||||
|
||||
wchar_t* p = const_cast<wchar_t*>(skip_ws(line));
|
||||
|
||||
//
|
||||
// On whitespace or comment, read the next line to the same buffer location.
|
||||
//
|
||||
if(*p == L'\0' || *p == L'#')
|
||||
continue;
|
||||
|
||||
//
|
||||
// Skip the machine name (must exist) and the optional whitespace and processors count.
|
||||
//
|
||||
p = const_cast<wchar_t*>(skip_graph(p));
|
||||
p = const_cast<wchar_t*>(skip_ws(p));
|
||||
p = const_cast<wchar_t*>(skip_digits(p));
|
||||
|
||||
//
|
||||
// If we found explicit affinity masks, skip them so they get added to the string
|
||||
// Explicit masks have the following format:
|
||||
// hostname nproc,mask0[:group],...,maskN[:group]
|
||||
//
|
||||
while( *p == L',' )
|
||||
{
|
||||
p++;
|
||||
if( *p != L'\0' )
|
||||
{
|
||||
p = const_cast<wchar_t*>(skip_hex(p));
|
||||
if( *p == L':' )
|
||||
{
|
||||
p++;
|
||||
if( *p != L'\0' )
|
||||
{
|
||||
p = const_cast<wchar_t*>(skip_digits(p));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
p = const_cast<wchar_t*>(skip_ws(p));
|
||||
|
||||
if(*p != L'\0' && *p != L'#')
|
||||
{
|
||||
free(hosts);
|
||||
return L"expecting a positive number of cores following the host name";
|
||||
}
|
||||
|
||||
//
|
||||
// Trim whitespace at the the end of the line (remove CR or LF characters).
|
||||
//
|
||||
--p;
|
||||
while( iswspace(*p) )
|
||||
{
|
||||
p--;
|
||||
}
|
||||
|
||||
*++p = L' ';
|
||||
++p;
|
||||
size -= p - line;
|
||||
line = p;
|
||||
nhosts++;
|
||||
}
|
||||
|
||||
if(ferror(fin))
|
||||
{
|
||||
free(hosts);
|
||||
const wchar_t* res = _wcserror(errno);
|
||||
_Analysis_assume_( res != nullptr );
|
||||
return res;
|
||||
}
|
||||
|
||||
if(nhosts == 0)
|
||||
{
|
||||
free(hosts);
|
||||
return L"expecting host names in file";
|
||||
}
|
||||
|
||||
*--line = L'\0';
|
||||
_itow_s(nhosts, hosts, hosts_len, 10);
|
||||
line = hosts + MPIU_Strlen( hosts, hosts_len );
|
||||
*line = L' ';
|
||||
|
||||
*phosts = hosts;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// smpd_get_hosts_from_file
|
||||
//
|
||||
// Read the entire machinefile into a string.
|
||||
// NULL is returned to indicate success; Error string is returned to indicate error.
|
||||
//
|
||||
_Success_( return == NULL )
|
||||
_Ret_maybenull_
|
||||
PCWSTR
|
||||
smpd_get_hosts_from_file(
|
||||
_In_ PCWSTR filename,
|
||||
_Outptr_result_z_ wchar_t** phosts
|
||||
)
|
||||
{
|
||||
FILE* fin = _wfopen(filename, L"r");
|
||||
if(fin == NULL)
|
||||
{
|
||||
const wchar_t* res = _wcserror(errno);
|
||||
_Analysis_assume_( res != nullptr );
|
||||
return res;
|
||||
}
|
||||
|
||||
const wchar_t* error = read_machinefile(fin, phosts);
|
||||
fclose(fin);
|
||||
return error;
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,868 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
* (C) 2001 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#include "mpiexec.h"
|
||||
#include "PmiDbgImpl.h"
|
||||
#include "mpitrace.h"
|
||||
#include "SvcUtils.h"
|
||||
#include "cs.h"
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
|
||||
#define MPIEXEC_CONNECT_RETRIES_DEFAULT 12
|
||||
#define MPIEXEC_CONNECT_RETRY_INTERVAL_DEFAULT 5
|
||||
|
||||
#define MPIEXEC_EXIT_TIMEOUT 30000
|
||||
|
||||
static int
|
||||
mpiexec_exit_from_rpc(
|
||||
EXOVERLAPPED* /*pexov*/
|
||||
)
|
||||
{
|
||||
if(smpd_process.mpiexec_exit_code == 0)
|
||||
{
|
||||
smpd_process.mpiexec_exit_code = SMPD_EXIT_FROM_RPC;
|
||||
}
|
||||
|
||||
smpd_signal_exit_progress(MPI_SUCCESS);
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void mpiexec_abort_from_rpc_thread()
|
||||
{
|
||||
//
|
||||
// This abort is triggered during the reconnect from the smpd top
|
||||
// of tree manager to mpiexec. At this point no other smpd manager
|
||||
// nor processes have been launched yet. It's safe (or rather,
|
||||
// graceful enough) to just exit mpiexec
|
||||
//
|
||||
|
||||
EXOVERLAPPED ov;
|
||||
ExInitOverlapped(&ov, mpiexec_exit_from_rpc, mpiexec_exit_from_rpc);
|
||||
ExPostOverlappedResult(smpd_process.set, &ov, 0, 0);
|
||||
|
||||
//
|
||||
// Give the engine some time to shutdown and then force an exit
|
||||
//
|
||||
Sleep( MPIEXEC_EXIT_TIMEOUT );
|
||||
smpd_err_printf(
|
||||
L"\nFailed to terminate the job after 30 seconds. Forcing mpiexec exit.\n");
|
||||
exit( SMPD_EXIT_FROM_RPC );
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
mpiexec_init(
|
||||
_In_ bool localonly
|
||||
)
|
||||
{
|
||||
smpd_init_process("mpiexec", localonly);
|
||||
|
||||
smpd_process.abortExFunc = mpiexec_abort_from_rpc_thread;
|
||||
|
||||
for( unsigned int i = 0; i < SMPD_CMD_MAX; ++i )
|
||||
{
|
||||
smpd_process.cmdHandler[i] = mpiexec_handle_invalid_command;
|
||||
}
|
||||
|
||||
//
|
||||
// Setup handler array to handle commands from SMPD. Mpiexec
|
||||
// should only receives these commands from SMPD. To prevent bogus
|
||||
// commands due to bugs/corruption everything else is trapped in
|
||||
// mpiexec_handle_invalid_command which will prompty abort the
|
||||
// process.
|
||||
//
|
||||
smpd_process.cmdHandler[SMPD_ABORT] = mpiexec_handle_abort_command;
|
||||
smpd_process.cmdHandler[SMPD_ABORT_JOB] = mpiexec_handle_abort_job_command;
|
||||
smpd_process.cmdHandler[SMPD_CLOSED] = smpd_handle_closed_command;
|
||||
smpd_process.cmdHandler[SMPD_EXIT] = mpiexec_handle_exit_command;
|
||||
smpd_process.cmdHandler[SMPD_FINALIZE] = mpiexec_handle_finalize_command;
|
||||
smpd_process.cmdHandler[SMPD_INIT] = mpiexec_handle_init_command;
|
||||
smpd_process.cmdHandler[SMPD_STDERR] = mpiexec_handle_stderr_command;
|
||||
smpd_process.cmdHandler[SMPD_STDOUT] = mpiexec_handle_stdout_command;
|
||||
smpd_process.cmdHandler[SMPD_PING] = smpd_handle_ping_command;
|
||||
smpd_process.cmdHandler[SMPD_SPAWN] = mpiexec_handle_spawn_command;
|
||||
|
||||
//
|
||||
// 0 : default behavior (no exclusion)
|
||||
// 1 : disable Kerberos as a package (!Kerberos) - but still use SpNego
|
||||
// 2 : force the use of NTLM
|
||||
//
|
||||
int val = env_to_int( L"MPIEXEC_DISABLE_KERB", 0, 0 );
|
||||
if( val == 1 )
|
||||
{
|
||||
smpd_process.authOptions = SMPD_AUTH_DISABLE_KERB;
|
||||
}
|
||||
else if( val == 2 )
|
||||
{
|
||||
smpd_process.authOptions = SMPD_AUTH_NTLM;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int mpiexec_exit_on_timeout(EXOVERLAPPED* /*pexov*/)
|
||||
{
|
||||
if(smpd_process.mpiexec_exit_code == 0)
|
||||
{
|
||||
smpd_process.mpiexec_exit_code = SMPD_EXIT_FROM_TIMEOUT;
|
||||
}
|
||||
|
||||
smpd_signal_exit_progress(MPI_SUCCESS);
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void CALLBACK TimeoutTimerCallback(void* /*p*/, BOOLEAN /*TimerFired*/)
|
||||
{
|
||||
//
|
||||
// *** This function is called on the timer thread. ***
|
||||
//
|
||||
|
||||
//
|
||||
// Queue the timer expiration callback back to the Executive thread.
|
||||
//
|
||||
EXOVERLAPPED ov;
|
||||
ExInitOverlapped(&ov, mpiexec_exit_on_timeout, mpiexec_exit_on_timeout);
|
||||
|
||||
smpd_err_printf(L"\nTimeout after %d seconds. Terminating job...\n",
|
||||
smpd_process.timeout);
|
||||
ExPostOverlappedResult(smpd_process.set, &ov, 0, 0);
|
||||
|
||||
//
|
||||
// Give the engine some time to shutdown and then force an exit
|
||||
//
|
||||
Sleep( MPIEXEC_EXIT_TIMEOUT );
|
||||
smpd_err_printf(
|
||||
L"\nFailed to terminate the job after 30 seconds. Forcing mpiexec exit.\n");
|
||||
exit( SMPD_EXIT_FROM_TIMEOUT );
|
||||
}
|
||||
|
||||
|
||||
static DWORD
|
||||
gle_start_timeout_timer(
|
||||
DWORD dueTime
|
||||
)
|
||||
{
|
||||
HANDLE hTimer;
|
||||
if( CreateTimerQueueTimer(
|
||||
&hTimer,
|
||||
NULL,
|
||||
TimeoutTimerCallback,
|
||||
0,
|
||||
dueTime,
|
||||
0,
|
||||
WT_EXECUTEDEFAULT ) == FALSE )
|
||||
{
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static void CALLBACK PeriodicSmpdPing(void* /*p*/, BOOLEAN /*TimerFired*/)
|
||||
{
|
||||
//
|
||||
// *** This function is called on the Smpd Ping Timer thread. ***
|
||||
//
|
||||
//
|
||||
// Ping the left child
|
||||
//
|
||||
SmpdCmd* pCmd = smpd_create_command(
|
||||
SMPD_PING,
|
||||
SMPD_IS_ROOT,
|
||||
SMPD_IS_TOP );
|
||||
if( pCmd == nullptr )
|
||||
{
|
||||
smpd_dbg_printf(L"failed to create ping command");
|
||||
return;
|
||||
}
|
||||
|
||||
SmpdResWrapper* pRes = smpd_create_result_command(
|
||||
smpd_process.tree_id,
|
||||
nullptr );
|
||||
if( pRes == nullptr )
|
||||
{
|
||||
delete pCmd;
|
||||
smpd_dbg_printf(L"failed to create ping result command");
|
||||
return;
|
||||
}
|
||||
|
||||
DWORD rc = smpd_post_command(
|
||||
smpd_process.left_context,
|
||||
pCmd,
|
||||
&pRes->Res,
|
||||
nullptr );
|
||||
if( rc != RPC_S_OK )
|
||||
{
|
||||
delete pRes;
|
||||
delete pCmd;
|
||||
smpd_dbg_printf(L"failed to post ping command error %lu\n", rc);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static DWORD
|
||||
StartSmpdPingTimer()
|
||||
{
|
||||
//
|
||||
// User-specified heartbeat in number of seconds. By default there's no
|
||||
// heartbeat.
|
||||
//
|
||||
int period = env_to_int(L"MPIEXEC_SMPD_PING_INTERVAL", 0, 0) * 1000;
|
||||
if( period <= 0 )
|
||||
{
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
if( CreateTimerQueueTimer(
|
||||
&smpd_process.hHeartbeatTimer,
|
||||
NULL,
|
||||
PeriodicSmpdPing,
|
||||
0,
|
||||
period,
|
||||
period,
|
||||
WT_EXECUTEDEFAULT ) == FALSE )
|
||||
{
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static int mpiexec_ctrl_abort(EXOVERLAPPED* /*pexov*/)
|
||||
{
|
||||
if( smpd_process.pg_list == nullptr )
|
||||
{
|
||||
/* no processes have been started yet, so exit here */
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
//
|
||||
// mpiexec_abort_job will do the following
|
||||
// 1) Suspend all the processes
|
||||
// 2) Kill all the processes
|
||||
// 3) Tear down the job tree
|
||||
//
|
||||
DWORD rc = mpiexec_abort_job( smpd_process.pg_list, 0, arCtrlC, 0, nullptr );
|
||||
if(rc != NOERROR)
|
||||
{
|
||||
//
|
||||
// Could not abort; exit the progress engine
|
||||
//
|
||||
smpd_signal_exit_progress( rc );
|
||||
return static_cast<int>( rc ) ;
|
||||
}
|
||||
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
static BOOL WINAPI
|
||||
mpiexec_ctrl_handler(
|
||||
DWORD dwCtrlType
|
||||
)
|
||||
{
|
||||
static bool ctrlHit = false;
|
||||
|
||||
static EXOVERLAPPED exov;
|
||||
|
||||
/* This handler could be modified to send the event to the remote
|
||||
* processes instead of killing the job. */
|
||||
/* Doing so would require new command types for smpd */
|
||||
|
||||
switch (dwCtrlType)
|
||||
{
|
||||
case CTRL_LOGOFF_EVENT:
|
||||
/* The logoff event could be a problem if two users are logged
|
||||
* on to the same machine remotely. If user A runs mpiexec
|
||||
* and user B logs out of his session, this event will cause
|
||||
* user A's mpiexec command to kill the job and make user A
|
||||
* mad. But if we ignore the logoff event then when user A
|
||||
* logs out mpiexec will hang?
|
||||
*/
|
||||
break;
|
||||
case CTRL_C_EVENT:
|
||||
case CTRL_BREAK_EVENT:
|
||||
case CTRL_CLOSE_EVENT:
|
||||
case CTRL_SHUTDOWN_EVENT:
|
||||
if( ctrlHit )
|
||||
{
|
||||
/* The second break signal unconditionally exits mpiexec */
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* The first break signal tries to abort the job with an abort message */
|
||||
ctrlHit = true;
|
||||
fwprintf(stderr, L"mpiexec aborting job...\n");
|
||||
fflush(stderr);
|
||||
|
||||
ExInitOverlapped(&exov, mpiexec_ctrl_abort, mpiexec_ctrl_abort);
|
||||
ExPostOverlappedResult(smpd_process.set, &exov, 0, 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// smpd client connect completion callback. the smpd client framework calls this
|
||||
// function after the connection to the smpd manager has been established
|
||||
///
|
||||
static DWORD
|
||||
mpiexec_connected_child_mgr(
|
||||
_In_ smpd_context_t* context,
|
||||
_In_ smpd_host_t* host
|
||||
)
|
||||
{
|
||||
//
|
||||
// Trigger the connection of the rest of the tree
|
||||
//
|
||||
return mpiexec_handle_node_connection(context, host);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
print_node_tree()
|
||||
{
|
||||
smpd_dbg_printf(L"host tree:\n");
|
||||
for( smpd_host_t* host = smpd_process.host_list;
|
||||
host != nullptr;
|
||||
host = static_cast<smpd_host_t*>( host->Next )
|
||||
)
|
||||
{
|
||||
smpd_dbg_printf(L" host: %s, parent: %d, id: %d\n",
|
||||
host->name,
|
||||
host->parent,
|
||||
host->HostId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void mpiexec_clear_global()
|
||||
{
|
||||
delete smpd_process.host_list;
|
||||
smpd_process.host_list = nullptr;
|
||||
|
||||
smpd_node_id_node_t* pNodeIdNode = smpd_process.node_id_list;
|
||||
while (pNodeIdNode != nullptr)
|
||||
{
|
||||
smpd_node_id_node_t* pDelete = pNodeIdNode;
|
||||
pNodeIdNode = pNodeIdNode->next;
|
||||
delete pDelete;
|
||||
}
|
||||
|
||||
smpd_launch_node_t* pNode = smpd_process.launch_list;
|
||||
while(pNode != nullptr)
|
||||
{
|
||||
smpd_launch_node_t* pDelete = pNode;
|
||||
pNode = pNode->next;
|
||||
delete pDelete;
|
||||
}
|
||||
|
||||
if (smpd_process.pwd != nullptr && smpd_process.pwd[0] != '\0')
|
||||
{
|
||||
delete[] smpd_process.pwd;
|
||||
}
|
||||
|
||||
if( smpd_process.hJobObj != nullptr )
|
||||
{
|
||||
CloseHandle( smpd_process.hJobObj );
|
||||
}
|
||||
|
||||
delete[] smpd_process.job_context;
|
||||
delete reinterpret_cast<mp_global_options_t*>(smpd_process.pGlobalBlockOpt);
|
||||
|
||||
if (smpd_process.pNumaNodeInfo != nullptr)
|
||||
{
|
||||
MPIU_Free(smpd_process.pNumaNodeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// For now all the errors detected at mpiexec will lead to the
|
||||
// aborting of the entire chain. In the future we might have different
|
||||
// kind of errors that don't always abort.
|
||||
//
|
||||
static void
|
||||
MpiexecHandleCmdError(
|
||||
smpd_overlapped_t* pov,
|
||||
_In_ int error
|
||||
)
|
||||
{
|
||||
SmpdCmd* pCmd = pov->pCmd;
|
||||
SmpdCmdHdr* pHeader = reinterpret_cast<SmpdCmdHdr*>(pCmd);
|
||||
SmpdResWrapper* pRes =
|
||||
CONTAINING_RECORD(pov->pRes, SmpdResWrapper, Res);
|
||||
|
||||
smpd_dbg_printf( L"error %d detected during previous command, initiating abort.\n",
|
||||
error );
|
||||
|
||||
if( pHeader->cmdType == SMPD_LAUNCH )
|
||||
{
|
||||
if( pRes->Res.LaunchRes.count != 0 )
|
||||
{
|
||||
smpd_err_printf( L"Error reported: %s\n",
|
||||
pRes->Res.LaunchRes.error_msg );
|
||||
midl_user_free( pRes->Res.LaunchRes.error_msg );
|
||||
}
|
||||
|
||||
smpd_process_group_t* pg = find_pg( pCmd->LaunchCmd.kvs );
|
||||
for( unsigned i = 0; i < pCmd->LaunchCmd.rankCount; ++i )
|
||||
{
|
||||
UINT16 rank = pCmd->LaunchCmd.rankArray[i];
|
||||
ASSERT( pg != nullptr );
|
||||
if( pg->processes[rank].suspend_pending == TRUE )
|
||||
{
|
||||
pg->processes[rank].suspend_pending = FALSE;
|
||||
pg->num_pending_suspends--;
|
||||
|
||||
ASSERT(pg->num_pending_suspends >= 0);
|
||||
}
|
||||
pg->processes[rank].failed_launch = TRUE;
|
||||
}
|
||||
|
||||
if( pg->aborted && pg->num_pending_suspends == 0 )
|
||||
{
|
||||
mpiexec_tear_down_tree();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Walk the list of pg's and abort them all
|
||||
//
|
||||
for( smpd_process_group_t* pg = smpd_process.pg_list;
|
||||
pg != nullptr;
|
||||
pg = pg->next )
|
||||
{
|
||||
DWORD rc = mpiexec_abort_job(
|
||||
pg,
|
||||
0,
|
||||
arFatalError,
|
||||
-1,
|
||||
nullptr );
|
||||
if( rc != NOERROR )
|
||||
{
|
||||
smpd_post_abort_command( L"failed to abort the job error %u.\n", rc );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extern FN_PmiLaunch MpiexecCreateManagerProcess;
|
||||
|
||||
|
||||
int __cdecl wmain(
|
||||
_In_ int argc,
|
||||
_In_reads_(argc+1) wchar_t* argv[]
|
||||
)
|
||||
{
|
||||
if( env_is_on( L"MPIEXEC_UNICODE_OUTPUT", FALSE ) )
|
||||
{
|
||||
if (!EnableUnicodeOutput())
|
||||
{
|
||||
goto CleanUp1;
|
||||
}
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
|
||||
|
||||
/* Make mpiexec an event provider. */
|
||||
EventRegisterMicrosoft_MPI_Channel_Provider();
|
||||
|
||||
/* set default debug options */
|
||||
smpd_process.dbg_state = SMPD_DBG_STATE_ERROUT;
|
||||
|
||||
/* catch an empty command line */
|
||||
if(argc < 2)
|
||||
{
|
||||
mp_print_options();
|
||||
goto CleanUp1;
|
||||
}
|
||||
|
||||
mpiexec_init(true);
|
||||
smpd_process.tree_id = 0;
|
||||
|
||||
if(!mp_parse_command_args(argv))
|
||||
{
|
||||
rc = -1;
|
||||
goto CleanUp1;
|
||||
}
|
||||
|
||||
if(smpd_process.dbg_state & SMPD_DBG_STATE_STDOUT)
|
||||
{
|
||||
print_node_tree();
|
||||
}
|
||||
|
||||
LoadPmiDbgExtensions(PMIDBG_HOST_CONTROLLER);
|
||||
NotifyPmiDbgExtensions(MpiexecNotifyInitialize);
|
||||
|
||||
ExSetHandle_t set = ExCreateSet();
|
||||
if(set == EX_INVALID_SET)
|
||||
{
|
||||
smpd_err_printf(L"Error: failed to create mpiexec completion port; out of memory\n");
|
||||
rc = -1;
|
||||
goto CleanUp1;
|
||||
}
|
||||
smpd_process.set = set;
|
||||
|
||||
if( !smpd_process.local_root )
|
||||
{
|
||||
UINT16 port = static_cast<UINT16>( env_to_int(L"SMPD_MANAGER_PORT",0,0) );
|
||||
rc = smpd_create_mgr_server( &port, nullptr );
|
||||
if( rc != NOERROR )
|
||||
{
|
||||
smpd_err_printf(L"failed to create the manager server\n");
|
||||
rc = -1;
|
||||
goto CleanUp2;
|
||||
}
|
||||
|
||||
smpd_process.mgrServerPort = port;
|
||||
smpd_dbg_printf(L"mpiexec started smpd manager listening on port %u\n", port);
|
||||
}
|
||||
else
|
||||
{
|
||||
GUID lrpcPort;
|
||||
rc = smpd_create_mgr_server( nullptr, &lrpcPort );
|
||||
if( rc != NOERROR )
|
||||
{
|
||||
smpd_err_printf(L"failed to create local root server\n");
|
||||
rc = -1;
|
||||
goto CleanUp2;
|
||||
}
|
||||
|
||||
smpd_process.localServerPort = lrpcPort;
|
||||
smpd_dbg_printf(
|
||||
L"mpiexec started smpd manager listening on port "
|
||||
L"%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
|
||||
lrpcPort.Data1, lrpcPort.Data2, lrpcPort.Data3,
|
||||
lrpcPort.Data4[0], lrpcPort.Data4[1], lrpcPort.Data4[2], lrpcPort.Data4[3],
|
||||
lrpcPort.Data4[4], lrpcPort.Data4[5], lrpcPort.Data4[6], lrpcPort.Data4[7] );
|
||||
}
|
||||
|
||||
//
|
||||
// Indicate the function to use to provide authentication when
|
||||
// launching the local SMPD instance.
|
||||
//
|
||||
PmiManagerInterface manager;
|
||||
manager.Size = sizeof(manager);
|
||||
manager.Launch.AsSelf = MpiexecCreateManagerProcess;
|
||||
manager.LaunchType = PmiLaunchTypeSelf;
|
||||
|
||||
smpd_process.manager_interface = &manager;
|
||||
|
||||
/* Start the timeout mechanism if specified */
|
||||
if(smpd_process.timeout > 0)
|
||||
{
|
||||
DWORD gle = gle_start_timeout_timer(smpd_process.timeout * 1000);
|
||||
if(gle != NO_ERROR)
|
||||
{
|
||||
smpd_err_printf(L"Error: unable to create the timeout timer, gle %u.\n", gle);
|
||||
rc = -1;
|
||||
goto CleanUp2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a break handler to handle aborting the job when mpiexec
|
||||
* receives break signals */
|
||||
if(!SetConsoleCtrlHandler(mpiexec_ctrl_handler, TRUE))
|
||||
{
|
||||
/* Don't error out; allow the job to run without a ctrl handler? */
|
||||
rc = GetLastError();
|
||||
smpd_dbg_printf(L"unable to set a ctrl handler for mpiexec, error %d\n", rc);
|
||||
}
|
||||
|
||||
if(smpd_process.local_root)
|
||||
{
|
||||
smpd_context_t *pContext;
|
||||
pContext = smpd_create_context(SMPD_CONTEXT_LEFT_CHILD, set);
|
||||
if( pContext == nullptr )
|
||||
{
|
||||
smpd_err_printf(
|
||||
L"Error: unable to create a context for the first host in the tree.\n");
|
||||
rc = -1;
|
||||
goto CleanUp3;
|
||||
}
|
||||
|
||||
int dbg_state = smpd_process.verbose ? smpd_process.dbg_state : 0;
|
||||
|
||||
size_t len = MPIU_Strlen( smpd_process.job_context ) + 1;
|
||||
pContext->job_context = new char[len];
|
||||
if( pContext->job_context == nullptr )
|
||||
{
|
||||
smpd_err_printf(L"Error: not enough memory to create context for mpiexec.\n");
|
||||
rc = -1;
|
||||
goto CleanUp3;
|
||||
}
|
||||
MPIU_Strcpy(pContext->job_context,
|
||||
len,
|
||||
smpd_process.job_context );
|
||||
|
||||
//
|
||||
// set MSMPI_LOCALONLY so that MPI can disable sockets automatically.
|
||||
//
|
||||
SetEnvironmentVariableW( L"MSMPI_LOCAL_ONLY", L"1" );
|
||||
|
||||
//
|
||||
// Launch the manager process
|
||||
//
|
||||
HRESULT hr = smpd_start_win_mgr( pContext, dbg_state );
|
||||
if( FAILED(hr) )
|
||||
{
|
||||
smpd_free_context( pContext );
|
||||
smpd_err_printf(L"Error: unable to start the local smpd manager.\n");
|
||||
rc = -1;
|
||||
goto CleanUp3;
|
||||
}
|
||||
|
||||
//
|
||||
// Establish connection to the Smpd Manager Instance that we just launched
|
||||
//
|
||||
rc = smpd_connect_mgr_smpd(
|
||||
SMPD_CONTEXT_LEFT_CHILD,
|
||||
smpd_process.host_list->name,
|
||||
static_cast<INT16>(smpd_process.host_list->HostId),
|
||||
pContext->port_str,
|
||||
&smpd_process.left_context
|
||||
);
|
||||
|
||||
smpd_free_context( pContext );
|
||||
if(rc != MPI_SUCCESS)
|
||||
{
|
||||
rc = -1;
|
||||
goto CleanUp3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
smpd_process.connectRetryCount = env_to_int( L"MPIEXEC_CONNECT_RETRIES",
|
||||
MPIEXEC_CONNECT_RETRIES_DEFAULT,
|
||||
0 );
|
||||
smpd_process.connectRetryInterval = env_to_int( L"MPIEXEC_CONNECT_RETRY_INTERVAL",
|
||||
MPIEXEC_CONNECT_RETRY_INTERVAL_DEFAULT,
|
||||
1 );
|
||||
//
|
||||
// Start connecting the tree by posting a connect to the first host
|
||||
//
|
||||
rc = smpd_connect_root_server(
|
||||
SMPD_CONTEXT_LEFT_CHILD,
|
||||
smpd_process.host_list->HostId,
|
||||
smpd_process.host_list->name,
|
||||
false,
|
||||
smpd_process.connectRetryCount,
|
||||
smpd_process.connectRetryInterval
|
||||
);
|
||||
|
||||
if(rc == NTE_UI_REQUIRED)
|
||||
{
|
||||
//
|
||||
// Prompt for password
|
||||
//
|
||||
if (!MpiexecGetUserInfoInteractive())
|
||||
{
|
||||
//
|
||||
// Session is not interactive or cannot perform this operation.
|
||||
// Simply fail.
|
||||
//
|
||||
smpd_err_printf(
|
||||
L"Failed to get user credentials. Shutting down.\n"
|
||||
L"Use -pwd <password> and -savecreds options to provide and save "
|
||||
L"credentials.\n"
|
||||
);
|
||||
goto CleanUp3;
|
||||
}
|
||||
|
||||
//
|
||||
// Retry with input credentials
|
||||
//
|
||||
rc = smpd_connect_root_server(
|
||||
SMPD_CONTEXT_LEFT_CHILD,
|
||||
smpd_process.host_list->HostId,
|
||||
smpd_process.host_list->name,
|
||||
false,
|
||||
smpd_process.connectRetryCount,
|
||||
smpd_process.connectRetryInterval
|
||||
);
|
||||
}
|
||||
|
||||
if(rc != MPI_SUCCESS)
|
||||
{
|
||||
rc = -1;
|
||||
goto CleanUp3;
|
||||
}
|
||||
}
|
||||
|
||||
smpd_process.left_context->on_cmd_error = MpiexecHandleCmdError;
|
||||
rc = mpiexec_connected_child_mgr( smpd_process.left_context, smpd_process.host_list );
|
||||
if( rc != MPI_SUCCESS )
|
||||
{
|
||||
rc = -1;
|
||||
goto CleanUp3;
|
||||
}
|
||||
|
||||
rc = StartSmpdPingTimer();
|
||||
if( rc != NOERROR )
|
||||
{
|
||||
rc = -1;
|
||||
goto CleanUp3;
|
||||
}
|
||||
|
||||
|
||||
rc = smpd_progress(set);
|
||||
|
||||
if((rc != MPI_SUCCESS) && (smpd_process.mpiexec_exit_code == 0))
|
||||
{
|
||||
smpd_process.mpiexec_exit_code = -1;
|
||||
}
|
||||
|
||||
rc = smpd_process.mpiexec_exit_code;
|
||||
|
||||
|
||||
NotifyPmiDbgExtensions(MpiexecNotifyFinalize);
|
||||
UnloadPmiDbgExtensions();
|
||||
|
||||
CleanUp3:
|
||||
if( smpd_process.hHeartbeatTimer != NULL )
|
||||
{
|
||||
BOOL timer_marked_for_deletion = DeleteTimerQueueTimer(nullptr, smpd_process.hHeartbeatTimer, nullptr);
|
||||
while (!timer_marked_for_deletion)
|
||||
{
|
||||
DWORD last_error = GetLastError();
|
||||
if (last_error == ERROR_IO_PENDING)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
timer_marked_for_deletion = DeleteTimerQueueTimer(nullptr, smpd_process.hHeartbeatTimer, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
smpd_stop_mgr_server();
|
||||
|
||||
CleanUp2:
|
||||
ExCloseSet( smpd_process.set );
|
||||
|
||||
CleanUp1:
|
||||
EventUnregisterMicrosoft_MPI_Channel_Provider();
|
||||
mpiexec_clear_global();
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
bool MpiexecGetUserInfoInteractive()
|
||||
{
|
||||
DWORD mode;
|
||||
DWORD newMode;
|
||||
DWORD numRead = 0;
|
||||
HANDLE stdIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||
HANDLE stdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
WCHAR user[MAX_PATH] = { 0 };
|
||||
WCHAR domain[MAX_PATH] = { 0 };
|
||||
DWORD cchUser = _countof(user);
|
||||
DWORD cchDomain = _countof(domain);
|
||||
BOOL isInteractive = FALSE;
|
||||
HRESULT result;
|
||||
BOOL success;
|
||||
|
||||
result = SecurityUtils::IsCurrentProcessInteractive(&isInteractive);
|
||||
if (FAILED(result) || GetFileType(stdOut) != FILE_TYPE_CHAR)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static CriticalSection csUI;
|
||||
static BOOL inputRetrieved = FALSE;
|
||||
|
||||
CS lockUI(csUI);
|
||||
|
||||
if (inputRetrieved)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
inputRetrieved = TRUE;
|
||||
|
||||
result = SecurityUtils::GetCurrentUser(user, &cchUser, domain, &cchDomain);
|
||||
if (FAILED(result))
|
||||
{
|
||||
smpd_err_printf(L"Failed to retrieve user name. Error 0x%x\n", result);
|
||||
return false;
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
GetConsoleMode(stdIn, &mode);
|
||||
|
||||
//
|
||||
// Hide typed in characters
|
||||
//
|
||||
newMode = (mode & ~ENABLE_ECHO_INPUT) | ENABLE_LINE_INPUT;
|
||||
SetConsoleMode(stdIn, newMode);
|
||||
|
||||
//
|
||||
// Read in user's password
|
||||
//
|
||||
smpd_process.pwd = new wchar_t[MAX_PATH];
|
||||
if (smpd_process.pwd == nullptr)
|
||||
{
|
||||
smpd_err_printf(L"Failed to allocate memory for retrieving password.\n");
|
||||
SetConsoleMode(stdIn, mode);
|
||||
return false;
|
||||
}
|
||||
|
||||
smpd_process.pwd[0] = L'\0';
|
||||
wprintf(L"\nEnter Password for %s\\%s: ", domain, user);
|
||||
|
||||
success = ReadConsoleW(stdIn, smpd_process.pwd, MAX_PATH, &numRead, nullptr);
|
||||
if (!success || numRead == 0)
|
||||
{
|
||||
SetConsoleMode(stdIn, mode);
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// ReadConsole adds CR+LF to buffer, so remove them
|
||||
//
|
||||
bool newLineRemoved = false;
|
||||
for (size_t i = numRead; i-- > 0;)
|
||||
{
|
||||
if (smpd_process.pwd[i] == L'\n' || smpd_process.pwd[i] == L'\r')
|
||||
{
|
||||
smpd_process.pwd[i] = L'\0';
|
||||
newLineRemoved = true;
|
||||
}
|
||||
else if (newLineRemoved)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Recover console mode
|
||||
//
|
||||
SetConsoleMode(stdIn, mode);
|
||||
|
||||
//
|
||||
// Read in saveCreds switch
|
||||
//
|
||||
wprintf(L"\nSave Credentials[y|n]? ");
|
||||
wchar_t saveCreds = L'n';
|
||||
ReadConsoleW(stdIn, &saveCreds, 1, &numRead, nullptr);
|
||||
smpd_process.saveCreds = (saveCreds == L'y' || saveCreds == L'Y');
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,361 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
* (C) 2001 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
#ifndef MPIEXEC_H
|
||||
#define MPIEXEC_H
|
||||
|
||||
#include "smpd.h"
|
||||
#include "PmiDbg.h"
|
||||
|
||||
|
||||
SmpdCmdHandler mpiexec_handle_invalid_command;
|
||||
SmpdCmdHandler mpiexec_handle_abort_command;
|
||||
SmpdCmdHandler mpiexec_handle_abort_job_command;
|
||||
SmpdCmdHandler mpiexec_handle_exit_command;
|
||||
SmpdCmdHandler mpiexec_handle_finalize_command;
|
||||
SmpdCmdHandler mpiexec_handle_init_command;
|
||||
SmpdCmdHandler mpiexec_handle_stderr_command;
|
||||
SmpdCmdHandler mpiexec_handle_stdout_command;
|
||||
SmpdCmdHandler mpiexec_handle_spawn_command;
|
||||
|
||||
|
||||
SmpdResHandler mpiexec_handle_collect_result;
|
||||
SmpdResHandler mpiexec_handle_kill_result;
|
||||
SmpdResHandler mpiexec_handle_launch_result;
|
||||
SmpdResHandler mpiexec_handle_start_dbs_result;
|
||||
SmpdResHandler mpiexec_handle_suspend_result;
|
||||
|
||||
|
||||
DWORD
|
||||
mpiexec_send_connect_command(
|
||||
_In_ smpd_context_t* context,
|
||||
_In_ const smpd_host_t* host
|
||||
);
|
||||
|
||||
|
||||
DWORD
|
||||
mpiexec_send_collect_commands();
|
||||
|
||||
|
||||
DWORD
|
||||
mpiexec_send_start_dbs_command(
|
||||
smpd_context_t* pContext
|
||||
);
|
||||
|
||||
|
||||
DWORD
|
||||
mpiexec_handle_node_connection(
|
||||
_In_ smpd_context_t* context,
|
||||
_Out_ smpd_host_t* host
|
||||
);
|
||||
|
||||
|
||||
DWORD
|
||||
mpiexec_redirect_stdin();
|
||||
|
||||
|
||||
smpd_process_group_t*
|
||||
find_pg(
|
||||
const GUID& kvs
|
||||
);
|
||||
|
||||
|
||||
DWORD
|
||||
mpiexec_abort_job(
|
||||
smpd_process_group_t* pg,
|
||||
UINT16 rank,
|
||||
abort_reason_t abort_reason,
|
||||
int exit_code,
|
||||
const wchar_t* err_msg
|
||||
);
|
||||
|
||||
|
||||
void mpiexec_tear_down_tree();
|
||||
|
||||
|
||||
struct mp_host_t
|
||||
: public HWMACHINEINFO
|
||||
{
|
||||
const wchar_t* name;
|
||||
int nproc;
|
||||
HWAFFINITY* explicit_affinity;
|
||||
UINT32 explicit_count;
|
||||
UINT32 explicit_index;
|
||||
|
||||
public:
|
||||
mp_host_t(const wchar_t* pName = NULL, int nProc = 0)
|
||||
: name(pName)
|
||||
, nproc(nProc)
|
||||
, explicit_affinity( NULL )
|
||||
, explicit_count(0)
|
||||
, explicit_index(0)
|
||||
{
|
||||
Next = NULL;
|
||||
HostId = 0;
|
||||
Summary = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
extern mp_host_t g_mp_host;
|
||||
|
||||
struct mp_host_pool_t
|
||||
{
|
||||
mp_host_t* hosts;
|
||||
int nproc;
|
||||
|
||||
public:
|
||||
mp_host_pool_t()
|
||||
: hosts(NULL)
|
||||
, nproc(0)
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct smpd_launch_node_t
|
||||
{
|
||||
smpd_launch_node_t* next;
|
||||
smpd_launch_node_t* prev;
|
||||
int iproc;
|
||||
int host_id;
|
||||
wchar_t hostname[SMPD_MAX_HOST_LENGTH];
|
||||
HWAFFINITY* affinity;
|
||||
};
|
||||
|
||||
|
||||
struct smpd_env_node_t
|
||||
{
|
||||
smpd_env_node_t* next;
|
||||
wchar_t* name;
|
||||
wchar_t* value;
|
||||
|
||||
~smpd_env_node_t()
|
||||
{
|
||||
MPIU_Free(name);
|
||||
MPIU_Free(value);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct mp_block_options_t
|
||||
{
|
||||
mp_block_options_t* next;
|
||||
smpd_env_node_t* env;
|
||||
wchar_t** envBlock;
|
||||
UINT16 envCount;
|
||||
const wchar_t* path;
|
||||
const wchar_t* wdir;
|
||||
const wchar_t* exe;
|
||||
mp_host_pool_t pool;
|
||||
int priority;
|
||||
int nproc;
|
||||
int appnum;
|
||||
wchar_t cmdline[SMPD_MAX_EXE_LENGTH];
|
||||
|
||||
public:
|
||||
mp_block_options_t()
|
||||
: next(nullptr)
|
||||
, env(nullptr)
|
||||
, envBlock(nullptr)
|
||||
, envCount(0)
|
||||
, path(nullptr)
|
||||
, wdir(nullptr)
|
||||
, exe(nullptr)
|
||||
, priority(SMPD_PRIORITY_CLASS_DEFAULT)
|
||||
, nproc(0)
|
||||
, appnum(0)
|
||||
{
|
||||
cmdline[0] = '\0';
|
||||
}
|
||||
|
||||
~mp_block_options_t()
|
||||
{
|
||||
delete next;
|
||||
while( nullptr != pool.hosts )
|
||||
{
|
||||
mp_host_t* p = static_cast<mp_host_t*>( pool.hosts->Next );
|
||||
|
||||
//
|
||||
// skip the global "local machine" sentinel value
|
||||
//
|
||||
if( &g_mp_host != pool.hosts )
|
||||
{
|
||||
delete pool.hosts;
|
||||
}
|
||||
pool.hosts = p;
|
||||
}
|
||||
|
||||
while( env != nullptr )
|
||||
{
|
||||
smpd_env_node_t* p = env->next;
|
||||
delete env;
|
||||
env = p;
|
||||
}
|
||||
delete [] envBlock;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct mp_global_options_t
|
||||
{
|
||||
smpd_env_node_t* env;
|
||||
const wchar_t* path;
|
||||
wchar_t* wdir;
|
||||
wchar_t* pwd;
|
||||
BOOL saveCreds;
|
||||
mp_host_pool_t pool;
|
||||
int cores_per_host;
|
||||
AffinityOptions affinityOptions;
|
||||
mp_block_options_t* bo_list;
|
||||
|
||||
public:
|
||||
mp_global_options_t()
|
||||
: env(nullptr)
|
||||
, path(nullptr)
|
||||
, wdir(nullptr)
|
||||
, pwd(nullptr)
|
||||
, saveCreds(FALSE)
|
||||
, pool()
|
||||
, cores_per_host(0)
|
||||
, bo_list(nullptr)
|
||||
{
|
||||
affinityOptions.placement = SMPD_AFFINITY_DISABLED;
|
||||
affinityOptions.target = HWNODE_TYPE_MACHINE;
|
||||
affinityOptions.isAuto = FALSE;
|
||||
affinityOptions.affinityTableStyle = 0;
|
||||
affinityOptions.hwTableStyle = 0;
|
||||
}
|
||||
|
||||
~mp_global_options_t()
|
||||
{
|
||||
while( nullptr != pool.hosts )
|
||||
{
|
||||
mp_host_t* p = static_cast<mp_host_t*>( pool.hosts->Next );
|
||||
|
||||
//
|
||||
// skip the global "local machine" sentinel value
|
||||
//
|
||||
if( &g_mp_host != pool.hosts )
|
||||
{
|
||||
delete pool.hosts;
|
||||
}
|
||||
pool.hosts = p;
|
||||
}
|
||||
|
||||
while( env != nullptr )
|
||||
{
|
||||
smpd_env_node_t* p = env->next;
|
||||
delete env;
|
||||
env = p;
|
||||
}
|
||||
|
||||
if( wdir != nullptr )
|
||||
{
|
||||
MPIU_Free( wdir );
|
||||
}
|
||||
|
||||
if( bo_list != nullptr )
|
||||
{
|
||||
delete bo_list;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
smpd_host_t*
|
||||
smpd_get_host_id(
|
||||
_In_ PCWSTR host
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// These externs are required to be in mpiexec to enable debugging
|
||||
// support
|
||||
// MPIR_Proctable_size: World's size at startup
|
||||
// MPIR_Proctable: Information about MPΙ processes (hostname, rank, pid)
|
||||
// MPIR_debug_state
|
||||
// Values are 0 (before MPI_Init), 1 (after MPI_init), and 2 (Aborting).
|
||||
// MPIR_being_debugged
|
||||
// Set to 1 if the process is started or attached under the debugger
|
||||
//
|
||||
extern "C"
|
||||
{
|
||||
extern __declspec(dllexport) MPIR_PROCDESC* MPIR_Proctable;
|
||||
extern __declspec(dllexport) int MPIR_Proctable_size;
|
||||
extern __declspec(dllexport) volatile int MPIR_debug_state;
|
||||
extern __declspec(dllexport) volatile int MPIR_being_debugged;
|
||||
extern __declspec(dllexport) char MPIR_dll_name[];
|
||||
}
|
||||
|
||||
typedef _Success_(return == true) bool (*pfn_on_option_t)(
|
||||
_Inout_ wchar_t* *argvp[],
|
||||
_Inout_ mp_global_options_t* go,
|
||||
_Inout_ mp_block_options_t* bo);
|
||||
|
||||
|
||||
typedef struct mp_option_handler_t
|
||||
{
|
||||
const wchar_t* option;
|
||||
pfn_on_option_t on_option;
|
||||
|
||||
} mp_option_handler_t;
|
||||
|
||||
|
||||
_Success_( return == true )
|
||||
bool
|
||||
mp_parse_command_args(
|
||||
_In_ wchar_t* argv[]
|
||||
);
|
||||
|
||||
|
||||
void
|
||||
mp_print_options(void);
|
||||
|
||||
|
||||
void
|
||||
mpiexec_print_hwtree(
|
||||
_In_ const smpd_host_t* pHosts
|
||||
);
|
||||
|
||||
|
||||
void
|
||||
mpiexec_print_affinity_table(
|
||||
__in const smpd_launch_node_t* pList,
|
||||
__in const smpd_host_t* pHosts
|
||||
);
|
||||
|
||||
|
||||
bool
|
||||
MpiexecGetUserInfoInteractive();
|
||||
|
||||
|
||||
const wchar_t*
|
||||
mp_parse_hosts_string(
|
||||
_Inout_z_ wchar_t* p,
|
||||
mp_host_pool_t* pool
|
||||
);
|
||||
|
||||
|
||||
_Success_(return == NULL)
|
||||
_Ret_maybenull_
|
||||
const wchar_t*
|
||||
mp_parse_hosts_argv(
|
||||
_Inout_ wchar_t* *argvp[],
|
||||
_Inout_ mp_host_pool_t* pool
|
||||
);
|
||||
|
||||
|
||||
_Success_(return != NULL)
|
||||
smpd_env_node_t*
|
||||
add_new_env_node(
|
||||
_Inout_ smpd_env_node_t** list,
|
||||
_In_ PCWSTR name,
|
||||
_In_ PCWSTR value
|
||||
);
|
||||
|
||||
#endif // MPIEXEC_H
|
|
@ -0,0 +1,10 @@
|
|||
#include <windows.h>
|
||||
#include <ntverp.h>
|
||||
|
||||
#define VER_FILETYPE VFT_APP
|
||||
#define VER_FILESUBTYPE VFT2_UNKNOWN
|
||||
#define VER_FILEDESCRIPTION_STR "Microsoft MPI Application Launch"
|
||||
#define VER_INTERNALNAME_STR "mpiexec"
|
||||
#define VER_ORIGINALFILENAME_STR "mpiexec.exe"
|
||||
|
||||
#include "common.ver"
|
|
@ -0,0 +1,86 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<Import Project="$(SrcRoot)\mpi.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<AssemblyDescription>Microsoft MPI Application Launcher</AssemblyDescription>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Globals">
|
||||
<TargetName>mpiexec</TargetName>
|
||||
<ProjectGuid>{e948b96d-1f93-44e0-8033-777d8f96a897}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Configuration">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>
|
||||
%(AdditionalIncludeDirectories);
|
||||
$(MPI_SRC_ROOT)\pmilib;
|
||||
$(MPI_SRC_ROOT)\msmpi\include;
|
||||
$(MPI_SRC_ROOT)\common\$(O);
|
||||
$(MPI_SRC_ROOT)\pmilib\lib\$(O);
|
||||
.\$(O)
|
||||
</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EntryPointSymbol>wmainCRTStartup</EntryPointSymbol>
|
||||
<AdditionalDependencies>
|
||||
%(AdditionalDependencies);
|
||||
$(PUBLIC_SDK_LIB)\kernel32.lib;
|
||||
$(PUBLIC_SDK_LIB)\user32.lib;
|
||||
$(PUBLIC_SDK_LIB)\advapi32.lib;
|
||||
$(PUBLIC_SDK_LIB)\rpcrt4.lib;
|
||||
$(PUBLIC_SDK_LIB)\authz.lib;
|
||||
$(PUBLIC_SDK_LIB)\mswsock.lib;
|
||||
$(PUBLIC_SDK_LIB)\ws2_32.lib;
|
||||
$(PUBLIC_SDK_LIB)\secur32.lib;
|
||||
$(PUBLIC_SDK_LIB)\netapi32.lib;
|
||||
$(PUBLIC_SDK_LIB)\ole32.lib;
|
||||
$(PUBLIC_SDK_LIB)\oleaut32.lib;
|
||||
$(PUBLIC_SDK_LIB)\uuid.lib;
|
||||
$(PUBLIC_SDK_LIB)\ntdsapi.lib;
|
||||
$(PUBLIC_SDK_LIB)\ntdll.lib;
|
||||
$(CRT_Libs);
|
||||
</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<StagingOutputPath>$(MPI_BIN_DESTINATION)</StagingOutputPath>
|
||||
<OutFileType>*.exe</OutFileType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="$(MPI_SRC_ROOT)\common\mpicommon.vcxproj" />
|
||||
<ProjectReference Include="$(MPI_SRC_ROOT)\pmilib\lib\pmilib.vcxproj" />
|
||||
<ProjectReference Include="$(MPI_SRC_ROOT)\msmpi\dbg\mpi_debugger.vcxproj" />
|
||||
<ProjectReference Include="$(MPI_SRC_ROOT)\stub\mpistub.vcxproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include=".\configfile.cpp" />
|
||||
<ClCompile Include=".\machinefile.cpp" />
|
||||
<ClCompile Include=".\mpiexec.cpp" />
|
||||
<ClCompile Include=".\mpiexecpmidbg.cpp" />
|
||||
<ClCompile Include=".\mpiexec_abort.cpp" />
|
||||
<ClCompile Include=".\mpiexec_connect.cpp" />
|
||||
<ClCompile Include=".\mpiexec_handle_command.cpp" />
|
||||
<ClCompile Include=".\mpiexec_print_tables.cpp" />
|
||||
<ClCompile Include=".\mpiexec_redirect.cpp" />
|
||||
<ClCompile Include=".\mpiexec_start_mgr.cpp" />
|
||||
<ClCompile Include=".\mp_parse_command_line.cpp" />
|
||||
<ClCompile Include=".\smpd_host_util.cpp" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
* (C) 2001 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#include "smpd.h"
|
||||
|
||||
|
||||
void smpd_post_abort_command(const wchar_t *fmt, ...)
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
fwprintf(stderr, L"\nAborting: ");
|
||||
vfwprintf(stderr, fmt, list);
|
||||
fflush(stderr);
|
||||
va_end(list);
|
||||
|
||||
smpd_signal_exit_progress(MPI_ERR_INTERN);
|
||||
}
|
||||
|
||||
|
||||
void smpd_kill_all_processes( void )
|
||||
{
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
* (C) 2001 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#include "mpiexec.h"
|
||||
|
||||
|
||||
static void
|
||||
mpiexec_handle_connect_result(
|
||||
_In_ smpd_overlapped_t* pov
|
||||
)
|
||||
{
|
||||
for( smpd_host_t* pHost = smpd_process.host_list;
|
||||
pHost != nullptr;
|
||||
pHost = static_cast<smpd_host_t*>( pHost->Next ) )
|
||||
{
|
||||
if( pHost->HostId == pov->pCmd->ConnectCmd.HostId )
|
||||
{
|
||||
SmpdConnectRes* pConnectRes = &pov->pRes->ConnectRes;
|
||||
|
||||
if (pConnectRes->userInfoNeeded)
|
||||
{
|
||||
if (!MpiexecGetUserInfoInteractive())
|
||||
{
|
||||
//
|
||||
// Session is not interactive, cannot perform this operation. Simply fail.
|
||||
//
|
||||
smpd_post_abort_command(L"Invalid Credentials: Failed to connect the smpd tree.");
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Reconnect with the user provided information
|
||||
//
|
||||
mpiexec_send_connect_command(pov->pContext, pHost);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
smpd_dbg_printf(L"successful connect to %s.\n", pHost->name);
|
||||
DWORD rc = mpiexec_handle_node_connection( pov->pContext, pHost );
|
||||
if( rc == NOERROR )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
smpd_post_abort_command(L"failed to connect the smpd tree. error %d\n", rc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DWORD
|
||||
mpiexec_send_connect_command(
|
||||
_In_ smpd_context_t* pContext,
|
||||
_In_ const smpd_host_t* host
|
||||
)
|
||||
{
|
||||
smpd_dbg_printf(L"creating connect command to '%s'\n", host->name);
|
||||
|
||||
SmpdCmd* pCmd = smpd_create_command(
|
||||
SMPD_CONNECT,
|
||||
SMPD_IS_ROOT,
|
||||
static_cast<INT16>(host->parent) );
|
||||
if( pCmd == nullptr )
|
||||
{
|
||||
smpd_err_printf(L"unable to create a connect command.\n");
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
int rc = MPIU_Strcpy( pCmd->ConnectCmd.hostName,
|
||||
_countof(pCmd->ConnectCmd.hostName),
|
||||
host->name );
|
||||
if( rc != MPI_SUCCESS )
|
||||
{
|
||||
smpd_err_printf( L"unable to add the host parameter to the connect command for host %s\n",
|
||||
host->name );
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
pCmd->ConnectCmd.HostId = static_cast<UINT16>(host->HostId);
|
||||
pCmd->ConnectCmd.retryCount = smpd_process.connectRetryCount;
|
||||
pCmd->ConnectCmd.retryInterval = smpd_process.connectRetryInterval;
|
||||
pCmd->ConnectCmd.jobObjName = smpd_process.jobObjName;
|
||||
pCmd->ConnectCmd.pwd = smpd_process.pwd;
|
||||
pCmd->ConnectCmd.saveCreds = smpd_process.saveCreds;
|
||||
|
||||
SmpdResWrapper* pRes = smpd_create_result_command(
|
||||
smpd_process.tree_id,
|
||||
&mpiexec_handle_connect_result );
|
||||
if( pRes == nullptr )
|
||||
{
|
||||
delete pCmd;
|
||||
smpd_err_printf(L"unable to create result for connect command.\n");
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
DWORD ret = smpd_post_command( pContext,
|
||||
pCmd,
|
||||
&pRes->Res,
|
||||
nullptr );
|
||||
if( ret != RPC_S_OK )
|
||||
{
|
||||
delete pRes;
|
||||
delete pCmd;
|
||||
smpd_err_printf(L"Unable to post connect command error %u.\n", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static DWORD
|
||||
mpiexec_connect_node_children(
|
||||
_In_ smpd_context_t* context,
|
||||
_In_ smpd_host_t* host
|
||||
)
|
||||
{
|
||||
DWORD rc;
|
||||
smpd_host_t* left = host->left;
|
||||
smpd_host_t* right = host->right;
|
||||
|
||||
if( left != nullptr )
|
||||
{
|
||||
smpd_dbg_printf(L"creating connect command for left node\n");
|
||||
|
||||
rc = mpiexec_send_connect_command( context, left );
|
||||
if( rc != NOERROR )
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
if( right != nullptr )
|
||||
{
|
||||
smpd_dbg_printf(L"creating connect command for right node\n");
|
||||
|
||||
rc = mpiexec_send_connect_command( context, right );
|
||||
if( rc != NOERROR )
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
mpiexec_tree_is_connected()
|
||||
{
|
||||
const smpd_host_t* host;
|
||||
for( host = smpd_process.host_list;
|
||||
host != nullptr;
|
||||
host = static_cast<const smpd_host_t*>( host->Next ) )
|
||||
{
|
||||
if(!host->connected)
|
||||
{
|
||||
smpd_dbg_printf(L"host %s is not connected yet\n", host->name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
DWORD
|
||||
mpiexec_handle_node_connection(
|
||||
_In_ smpd_context_t* context,
|
||||
_Out_ smpd_host_t* host
|
||||
)
|
||||
{
|
||||
host->connected = TRUE;
|
||||
|
||||
DWORD rc = mpiexec_connect_node_children(context, host);
|
||||
if( rc != NOERROR )
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
if( mpiexec_tree_is_connected() == false )
|
||||
{
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
return mpiexec_send_collect_commands();
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,587 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "mpiexec.h"
|
||||
|
||||
const wchar_t g_HwNodeChars[] = L"MGNPL";
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Print the specified element from the HWTREE
|
||||
//
|
||||
// Paramters:
|
||||
// pTree - Pointer to the tree being printed
|
||||
// index - index of the current node in the tree
|
||||
//
|
||||
static void
|
||||
mpiexec_print_hwnode(
|
||||
__in const HWTREE* pTree,
|
||||
__in UINT32 index
|
||||
)
|
||||
{
|
||||
wchar_t format[ 128 ] = {};
|
||||
UINT32 machineId = index;
|
||||
const smpd_host_t* host;
|
||||
HWNODE_TYPE type = pTree->Nodes[index].Type;
|
||||
|
||||
while( pTree->Nodes[machineId].Type > HWNODE_TYPE_MACHINE )
|
||||
{
|
||||
machineId = pTree->Nodes[machineId].Parent;
|
||||
}
|
||||
|
||||
for( host = smpd_process.host_list; host != NULL; host = static_cast<smpd_host_t*>( host->Next ) )
|
||||
{
|
||||
if( pTree->Nodes[machineId].HostId == host->HostId )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT(NULL != host);
|
||||
|
||||
if( HWNODE_TYPE_MACHINE == type )
|
||||
{
|
||||
MPIU_Snprintf(format,_countof(format),L"%%%ds %%c %%%ds %%.6d %%.6d %%s\n",type, HWNODE_TYPE_MAX-type);
|
||||
OACR_REVIEWED_CALL(mpicr,
|
||||
wprintf( format,
|
||||
L"",
|
||||
g_HwNodeChars[type] ,
|
||||
L"",
|
||||
index,
|
||||
pTree->Nodes[index].Parent,
|
||||
host->name )
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
MPIU_Snprintf(format,_countof(format),L"%%%ds %%c %%%ds %%.6d %%.6d %%.3d %%.16I64x %%.16I64x\n",type, HWNODE_TYPE_MAX-type);
|
||||
OACR_REVIEWED_CALL(mpicr,
|
||||
wprintf( format,
|
||||
L"",
|
||||
g_HwNodeChars[type] ,
|
||||
L"",
|
||||
index,
|
||||
pTree->Nodes[index].Parent,
|
||||
pTree->Nodes[index].Affinity.GroupId,
|
||||
pTree->Nodes[index].Affinity.Mask,
|
||||
(pTree->Nodes[index].Affinity.Mask & host->Summary->Infos[pTree->Nodes[index].Affinity.GroupId].ActiveMask) )
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if( HWNODEID_NONE != pTree->Nodes[index].FirstChild )
|
||||
{
|
||||
mpiexec_print_hwnode(pTree,pTree->Nodes[index].FirstChild);
|
||||
}
|
||||
if( HWNODEID_NONE != pTree->Nodes[index].NextSibling )
|
||||
{
|
||||
mpiexec_print_hwnode(pTree,pTree->Nodes[index].NextSibling);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// print hwtree table 1. Table is sorted the parent-child relationships.
|
||||
//
|
||||
static void
|
||||
mpiexec_print_hwtree1(
|
||||
__in const smpd_host_t* pHosts
|
||||
)
|
||||
{
|
||||
wprintf(L"_______________________________________________________________________________\n" );
|
||||
wprintf(L" - MSMPI HwTree Table 1 (Parent/Child Tree) - \n" );
|
||||
wprintf(L"Type NodeId Parent Grp Mask ActiveMask HostName\n" );
|
||||
wprintf(L"_______________________________________________________________________________\n" );
|
||||
|
||||
for( const smpd_host_t* pHost = pHosts; NULL != pHost; pHost = static_cast<smpd_host_t*>( pHost->Next ) )
|
||||
{
|
||||
mpiexec_print_hwnode(pHost->hwTree, pHost->hwTree->Nodes[0].FirstChild);
|
||||
}
|
||||
|
||||
wprintf(L"_______________________________________________________________________________\n" );
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// print hwtree table 2. Table is sorted by tree node id. This happens to also be the sorted by node type.
|
||||
//
|
||||
static void
|
||||
mpiexec_print_hwtree2(
|
||||
__in const smpd_host_t* pHosts
|
||||
)
|
||||
{
|
||||
static const wchar_t dashBuf[] = L"------";
|
||||
wchar_t fchildBuf[7];
|
||||
wchar_t siblingBuf[7];
|
||||
wchar_t valBuf[32];
|
||||
|
||||
wprintf(L"_______________________________________________________________________________\n" );
|
||||
wprintf(L" - MSMPI HwTree Table 2 (Flat View) - \n" );
|
||||
wprintf(L"Type Stride Count \n" );
|
||||
wprintf(L"_______________________________________________________________________________\n" );
|
||||
|
||||
for( const smpd_host_t* pHost = pHosts; NULL != pHost; pHost = static_cast<smpd_host_t*>( pHost->Next ) )
|
||||
{
|
||||
HWTREE* pTree = pHost->hwTree;
|
||||
UINT32 totalCount = 1;//1 to start with (world)
|
||||
for( UINT32 i = (UINT32)HWNODE_TYPE_MACHINE; i < HWNODE_TYPE_MAX; i++ )
|
||||
{
|
||||
totalCount += pTree->Counts[i];
|
||||
wprintf(L" %c %.6u %.6u\n", g_HwNodeChars[i], pTree->Strides[i], pTree->Counts[i] );
|
||||
}
|
||||
wprintf(L" ------\n" );
|
||||
wprintf(L" Total: %.6u\n", totalCount );
|
||||
wprintf(L"\n\n" );
|
||||
wprintf(L"Type NodeId Parent FChild Siblng Value\n" );
|
||||
wprintf(L"_______________________________________________________________________________\n" );
|
||||
wprintf(L" W 000000 ------ 000001 ------\n");
|
||||
for( UINT32 i = 1; i < totalCount; i++ )
|
||||
{
|
||||
if( HWNODE_TYPE_MACHINE == pTree->Nodes[i].Type )
|
||||
{
|
||||
const smpd_host_t* host;
|
||||
for( host = smpd_process.host_list; host != NULL; host = static_cast<const smpd_host_t*>( host->Next ) )
|
||||
{
|
||||
if( pTree->Nodes[i].HostId == host->HostId )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT(NULL != host);
|
||||
MPIU_Snprintf(valBuf,_countof(valBuf),L"%.6d:%s",pTree->Nodes[i].HostId, host->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
MPIU_Snprintf(valBuf,_countof(valBuf),L"%.16I64x:%.4d",pTree->Nodes[i].Affinity.Mask,pTree->Nodes[i].Affinity.GroupId);
|
||||
}
|
||||
|
||||
if( HWNODEID_NONE == pTree->Nodes[i].FirstChild )
|
||||
{
|
||||
MPIU_Strcpy(fchildBuf,_countof(fchildBuf),dashBuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
MPIU_Snprintf(fchildBuf,_countof(fchildBuf),L"%.6d",pTree->Nodes[i].FirstChild);
|
||||
}
|
||||
|
||||
if( HWNODEID_NONE == pTree->Nodes[i].NextSibling )
|
||||
{
|
||||
MPIU_Strcpy(siblingBuf,_countof(siblingBuf),dashBuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
MPIU_Snprintf(siblingBuf,_countof(siblingBuf),L"%.6d",pTree->Nodes[i].NextSibling);
|
||||
}
|
||||
|
||||
wprintf( L" %c %.6u %.6u %s %s %s\n",
|
||||
g_HwNodeChars[pTree->Nodes[i].Type],
|
||||
i,
|
||||
pTree->Nodes[i].Parent,
|
||||
fchildBuf,
|
||||
siblingBuf,
|
||||
valBuf
|
||||
);
|
||||
}
|
||||
}
|
||||
wprintf(L"_______________________________________________________________________________\n" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Print the specified HWTREE if the MPIEXEC_HWTREE_TABLE environment variable is defined
|
||||
// 2 == print table 2
|
||||
// 1,on,yes == print table 1
|
||||
//
|
||||
// Parameters:
|
||||
// pHosts - pointer to the hosts whose hwtrees will be printed.
|
||||
//
|
||||
void
|
||||
mpiexec_print_hwtree(
|
||||
__in const smpd_host_t* pHosts
|
||||
)
|
||||
{
|
||||
if(!smpd_process.affinityOptions.isSet)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch(smpd_process.affinityOptions.hwTableStyle)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
mpiexec_print_hwtree1(pHosts);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
mpiexec_print_hwtree2(pHosts);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Test a core bit for existance, enabled, and usage and return string token
|
||||
//
|
||||
// if coreBit not set in full, the core does not exist
|
||||
// if coreBit not set in active, the core is disabled
|
||||
// if coreBit not set in affinity, the core is unused
|
||||
//
|
||||
static inline const wchar_t*
|
||||
get_core_bit_string(
|
||||
__in UINT64 coreBit,
|
||||
__in UINT64 full,
|
||||
__in UINT64 active,
|
||||
__in UINT64 affinity
|
||||
)
|
||||
{
|
||||
if( 0 == (full & coreBit) )
|
||||
{
|
||||
return L"##";
|
||||
}
|
||||
if( coreBit == ( affinity & coreBit ) )
|
||||
{
|
||||
return L"++";
|
||||
}
|
||||
if( 0 == (active & coreBit ) )
|
||||
{
|
||||
return L"@@";
|
||||
}
|
||||
return L"..";
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Test a core bit for existance, enabled, and usage and return char token
|
||||
//
|
||||
// if coreBit not set in full, the core does not exist
|
||||
// if coreBit not set in active, the core is disabled
|
||||
// if coreBit not set in affinity, the cure is unused
|
||||
//
|
||||
static inline wchar_t
|
||||
get_core_bit_char(
|
||||
__in UINT64 coreBit,
|
||||
__in UINT64 full,
|
||||
__in UINT64 active,
|
||||
__in UINT64 affinity
|
||||
)
|
||||
{
|
||||
if( 0 == (full & coreBit) )
|
||||
{
|
||||
return L'#';
|
||||
}
|
||||
if( coreBit == ( affinity & coreBit ) )
|
||||
{
|
||||
return L'+';
|
||||
}
|
||||
if( 0 == (active & coreBit ) )
|
||||
{
|
||||
return L'@';
|
||||
}
|
||||
return L'.';
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// print affinity table 1. Table is sorted by machine then rank
|
||||
// This can display only the first 16 cores per machine.
|
||||
//
|
||||
static void
|
||||
mpiexec_print_affinity_table1(
|
||||
__in const smpd_launch_node_t*const* pList,
|
||||
__in const smpd_host_t* pHosts
|
||||
)
|
||||
{
|
||||
wprintf(L"_______________________________________________________________________________\n" );
|
||||
wprintf(L" - MSMPI Rank Affinity Table 1 (By Machine/Rank) - \n" );
|
||||
wprintf(L" Rank - 0 1 2 3 | 4 5 6 7 | 8 9 10 11 | 12 13 14 15 - Mask\n" );
|
||||
|
||||
for( const smpd_host_t* pHost = pHosts; NULL != pHost; pHost = static_cast<smpd_host_t*>( pHost->Next ) )
|
||||
{
|
||||
wprintf(L"_______________________________________________________________________________\n" );
|
||||
wprintf(L"%s\n", pHost->name );
|
||||
UINT64 fullMask = 0;
|
||||
for( const smpd_launch_node_t*const* ppNode = pList; NULL != *ppNode; ppNode++ )
|
||||
{
|
||||
if( (*ppNode)->host_id != pHost->HostId )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
fullMask |= (*ppNode)->affinity->Mask;
|
||||
wprintf(
|
||||
L" %.5d - %s %s %s %s | %s %s %s %s | %s %s %s %s | %s %s %s %s - %.8I64x\n",
|
||||
(*ppNode)->iproc,
|
||||
get_core_bit_string(0x1, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_string(0x2, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_string(0x4, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_string(0x8, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_string(0x10, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_string(0x20, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_string(0x40, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_string(0x80, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_string(0x100, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_string(0x200, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_string(0x400, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_string(0x800, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_string(0x1000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_string(0x2000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_string(0x4000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_string(0x8000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
(*ppNode)->affinity->Mask
|
||||
);
|
||||
}
|
||||
wprintf(
|
||||
L" - %.8I64x\n",
|
||||
fullMask
|
||||
);
|
||||
|
||||
}
|
||||
wprintf(L"_______________________________________________________________________________\n" );
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// print affinity table 2. Table is sorted by rank
|
||||
// This can display only the first 32 cores per machine.
|
||||
//
|
||||
static void
|
||||
mpiexec_print_affinity_table2(
|
||||
__in const smpd_launch_node_t*const* pList,
|
||||
__in const smpd_host_t* pHosts
|
||||
)
|
||||
{
|
||||
wprintf(L"_______________________________________________________________________________\n" );
|
||||
wprintf(L" - MSMPI Rank Affinity Table 2 (By Rank) -\n" );
|
||||
wprintf(L"Rank HostName Mask 0-3 4-7 8-11 12-15 16-19 20-23 24-27 28-31\n" );
|
||||
wprintf(L"_______________________________________________________________________________\n" );
|
||||
while( NULL != *pList )
|
||||
{
|
||||
const smpd_host_t* pHost = pHosts;
|
||||
while( pHost->HostId != (*pList)->host_id )
|
||||
{
|
||||
pHost = static_cast<const smpd_host_t*>( pHost->Next );
|
||||
}
|
||||
ASSERT(NULL != pHost);
|
||||
|
||||
wprintf( L"%.5d %15s %.8I64x %c%c%c%c %c%c%c%c %c%c%c%c %c%c%c%c %c%c%c%c %c%c%c%c %c%c%c%c %c%c%c%c\n",
|
||||
(*pList)->iproc,
|
||||
(*pList)->hostname,
|
||||
(*pList)->affinity->Mask,
|
||||
get_core_bit_char(0x1, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x2, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x4, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x8, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x10, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x20, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x40, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x80, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x100, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x200, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x400, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x800, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x1000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x2000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x4000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x8000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x10000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x20000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x40000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x80000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x100000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x200000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x400000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x800000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x1000000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x2000000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x4000000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x8000000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x10000000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x20000000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x40000000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask),
|
||||
get_core_bit_char(0x80000000, pHost->Summary->Infos[0].Mask, pHost->Summary->Infos[0].ActiveMask, (*pList)->affinity->Mask)
|
||||
);
|
||||
pList++;
|
||||
}
|
||||
wprintf( L"_______________________________________________________________________________\n" );
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// print affinity table 3. Table is sorted by Machine, Processor Group, then rank
|
||||
// This can display all cores on the machine. It is not restricted to the first group.
|
||||
//
|
||||
static void
|
||||
mpiexec_print_affinity_table3(
|
||||
__in const smpd_launch_node_t*const* pList,
|
||||
__in const smpd_host_t* pHosts
|
||||
)
|
||||
{
|
||||
wprintf( L"_______________________________________________________________________________\n" );
|
||||
wprintf( L" - MSMPI Rank Affinity Table 3 (By Processor Group) - \n" );
|
||||
wprintf( L"Rank Cores\n" );
|
||||
wprintf( L"_______________________________________________________________________________\n" );
|
||||
for( const smpd_host_t* pHost = pHosts; NULL != pHost; pHost = static_cast<const smpd_host_t*>( pHost->Next ) )
|
||||
{
|
||||
for( UINT32 i = 0; i < pHost->Summary->Count; i++ )
|
||||
{
|
||||
wprintf(L"\n%s:%u\n", pHost->name, i );
|
||||
for( const smpd_launch_node_t*const* ppNode = pList; NULL != *ppNode; ppNode++ )
|
||||
{
|
||||
if( (*ppNode)->host_id != pHost->HostId ||
|
||||
(*ppNode)->affinity->GroupId != static_cast<UINT16>( i )
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
wprintf(
|
||||
L" %.8d %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
|
||||
(*ppNode)->iproc,
|
||||
get_core_bit_char(0x1, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x2, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x4, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x8, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x10, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x20, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x40, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x80, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x100, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x200, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x400, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x800, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x1000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x2000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x4000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x8000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x10000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x20000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x40000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x80000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x100000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x200000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x400000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x800000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x1000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x2000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x4000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x8000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x10000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x20000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x40000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x80000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x100000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x200000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x400000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x800000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x1000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x2000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x4000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x8000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x10000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x20000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x40000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x80000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x100000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x200000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x400000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x800000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x1000000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x2000000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x4000000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x8000000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x10000000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x20000000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x40000000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x80000000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x100000000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x200000000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x400000000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x800000000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x1000000000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x2000000000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x4000000000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask),
|
||||
get_core_bit_char(0x8000000000000000, pHost->Summary->Infos[i].Mask, pHost->Summary->Infos[i].ActiveMask, (*ppNode)->affinity->Mask)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
wprintf( L"_______________________________________________________________________________\n" );
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// print affinity table. Enabled with MPIEXEC_AFFINITY_TABLE environment varaible.
|
||||
// 3 = table 3
|
||||
// 2 = table 2
|
||||
// 1,on,yes = table 1
|
||||
//
|
||||
void
|
||||
mpiexec_print_affinity_table(
|
||||
__in const smpd_launch_node_t* pLaunchList,
|
||||
__in const smpd_host_t* pHosts
|
||||
)
|
||||
{
|
||||
if(!smpd_process.affinityOptions.isSet ||
|
||||
smpd_process.affinityOptions.affinityTableStyle == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const smpd_launch_node_t** pFullList = const_cast<const smpd_launch_node_t**>(
|
||||
new smpd_launch_node_t*[smpd_process.nproc + 1] );
|
||||
if( pFullList == nullptr )
|
||||
{
|
||||
return; //print error!!
|
||||
}
|
||||
|
||||
//
|
||||
// the pLaunchList is a singly linked list stored in reverse rank order
|
||||
// we will copy it the pointers to an array in the correct order and use that
|
||||
// for our affinity layout algorithm
|
||||
//
|
||||
int iProc = smpd_process.nproc;
|
||||
pFullList[iProc] = nullptr;
|
||||
const smpd_launch_node_t* node = pLaunchList;
|
||||
do
|
||||
{
|
||||
--iProc;
|
||||
ASSERT(iProc >= 0);
|
||||
pFullList[iProc] = node;
|
||||
node = node->next;
|
||||
} while( NULL != node );
|
||||
|
||||
|
||||
switch(smpd_process.affinityOptions.affinityTableStyle)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
mpiexec_print_affinity_table1(pFullList, pHosts);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
mpiexec_print_affinity_table2(pFullList, pHosts);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
mpiexec_print_affinity_table3(pFullList, pHosts);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
delete [] pFullList;
|
||||
}
|
|
@ -0,0 +1,423 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
* (C) 2001 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#include "smpd.h"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// STDIN redirection
|
||||
// mpiexec reads stdin and sends this data to smpd 1 targeting rank 0
|
||||
// when stdin is closed the signal is sent to smpd 1 targeting rank 0
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
struct stdin_overlapped_t
|
||||
{
|
||||
EXOVERLAPPED ov;
|
||||
char buffer[SMPD_MAX_STDIO_LENGTH];
|
||||
|
||||
stdin_overlapped_t(ExCompletionRoutine pfn)
|
||||
{
|
||||
ExInitOverlapped(&ov, pfn, pfn);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static inline stdin_overlapped_t* stdin_ov_from_exov(EXOVERLAPPED* pexov)
|
||||
{
|
||||
return CONTAINING_RECORD(pexov, stdin_overlapped_t, ov);
|
||||
}
|
||||
|
||||
|
||||
static int mpiexec_state_reading_stdin(EXOVERLAPPED* pexov);
|
||||
|
||||
static DWORD WINAPI mpiexec_stdin_read_thread(LPVOID /*pv*/)
|
||||
{
|
||||
stdin_overlapped_t* pov;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
pov = new stdin_overlapped_t(mpiexec_state_reading_stdin);
|
||||
if(pov == NULL)
|
||||
{
|
||||
smpd_err_printf(L"unable to create a context for stdin.\n");
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
if((hStdin == INVALID_HANDLE_VALUE) || (hStdin == NULL))
|
||||
{
|
||||
//
|
||||
// Don't print an error in case there is no stdin handle
|
||||
//
|
||||
smpd_dbg_printf(L"Unable to get the stdin handle.\n");
|
||||
goto fn_fail;
|
||||
}
|
||||
|
||||
//
|
||||
// ReadFile returns with less than nNumberOfBytesToRead on EOL when
|
||||
// using input device. it returns on EOF when files are piped in.
|
||||
// Try to read as much as posible.
|
||||
//
|
||||
DWORD num_read;
|
||||
if(!ReadFile(hStdin, pov->buffer, sizeof(pov->buffer), &num_read, NULL))
|
||||
{
|
||||
DWORD gle = GetLastError();
|
||||
smpd_dbg_printf(L"ReadFile failed (%u), closing stdin reader thread.\n", gle);
|
||||
goto fn_fail;
|
||||
}
|
||||
|
||||
//
|
||||
// zero bytes indicates no input available
|
||||
//
|
||||
if(num_read == 0)
|
||||
goto fn_fail;
|
||||
|
||||
ExPostOverlappedResult(smpd_process.set, &pov->ov, MPI_SUCCESS, num_read);
|
||||
}
|
||||
|
||||
fn_fail:
|
||||
//
|
||||
// report that stdin is closed or no more input available by posting an error result
|
||||
//
|
||||
ExPostOverlappedResult(smpd_process.set, &pov->ov, STATUS_NO_MEMORY, 0);
|
||||
return ERROR_HANDLE_EOF;
|
||||
}
|
||||
|
||||
|
||||
static DWORD
|
||||
mpiexec_send_stdin_command(
|
||||
_In_reads_z_(cchBuffer) const char* buffer,
|
||||
_In_ UINT32 cchBuffer
|
||||
)
|
||||
{
|
||||
SmpdCmd* pCmd = smpd_create_command(
|
||||
SMPD_STDIN,
|
||||
SMPD_IS_ROOT,
|
||||
SMPD_IS_TOP );
|
||||
if( pCmd == nullptr )
|
||||
{
|
||||
smpd_err_printf(L"unable to create stdin command.\n");
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
pCmd->StdinCmd.size = cchBuffer;
|
||||
pCmd->StdinCmd.buffer = reinterpret_cast<BYTE*>(
|
||||
const_cast<char*>(buffer) );
|
||||
|
||||
SmpdResWrapper* pRes = smpd_create_result_command(
|
||||
smpd_process.tree_id,
|
||||
nullptr );
|
||||
if( pRes == nullptr )
|
||||
{
|
||||
delete pCmd;
|
||||
smpd_err_printf(L"unable to create result for stdin command.\n");
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
DWORD rc = smpd_post_command(
|
||||
smpd_process.left_context,
|
||||
pCmd,
|
||||
&pRes->Res,
|
||||
nullptr );
|
||||
if( rc != RPC_S_OK )
|
||||
{
|
||||
delete pRes;
|
||||
delete pCmd;
|
||||
smpd_err_printf(L"unable to post stdin command from root.\n");
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static DWORD
|
||||
mpiexec_send_stdin_close_command(void)
|
||||
{
|
||||
if( smpd_process.left_context == nullptr )
|
||||
{
|
||||
//
|
||||
// Stdin is getting disconnected due to mpiexec tree being torn down
|
||||
// In this case we do not post a stdin_close command
|
||||
//
|
||||
smpd_dbg_printf(L"child context already closed. Not sending stdin_close request\n");
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
SmpdCmd* pCmd = smpd_create_command(
|
||||
SMPD_STDIN_CLOSE,
|
||||
SMPD_IS_ROOT,
|
||||
SMPD_IS_TOP );
|
||||
if( pCmd == nullptr )
|
||||
{
|
||||
smpd_err_printf(L"unable to create stdin_close command.\n");
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
SmpdResWrapper* pRes = smpd_create_result_command(
|
||||
smpd_process.tree_id,
|
||||
nullptr );
|
||||
if( pRes == nullptr )
|
||||
{
|
||||
delete pCmd;
|
||||
smpd_err_printf(L"unable to create result for stdin_close command.\n");
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
DWORD rc = smpd_post_command(
|
||||
smpd_process.left_context,
|
||||
pCmd,
|
||||
&pRes->Res,
|
||||
nullptr );
|
||||
if( rc != RPC_S_OK )
|
||||
{
|
||||
delete pRes;
|
||||
delete pCmd;
|
||||
smpd_err_printf(L"unable to post stdin_close command from root.\n");
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
mpiexec_state_reading_stdin(
|
||||
EXOVERLAPPED* pexov
|
||||
)
|
||||
{
|
||||
UINT32 num_encoded;
|
||||
DWORD num_read = ExGetBytesTransferred(pexov);
|
||||
HRESULT status = ExGetStatus(pexov);
|
||||
stdin_overlapped_t* pov = stdin_ov_from_exov(pexov);
|
||||
char buffer[SMPD_MAX_STDIO_LENGTH * SMPD_ENCODING_FACTOR + 1];
|
||||
|
||||
if(FAILED(status))
|
||||
{
|
||||
goto fn_stdin_close;
|
||||
}
|
||||
|
||||
ASSERT(num_read > 0);
|
||||
ASSERT(num_read <= SMPD_MAX_STDIO_LENGTH);
|
||||
|
||||
smpd_encode_buffer(buffer, _countof(buffer), pov->buffer, num_read, &num_encoded);
|
||||
ASSERT(num_encoded == num_read);
|
||||
|
||||
//
|
||||
// The number of characters we're sending is the null terminated
|
||||
// encoded string which has the size of num_encoded*2 + 1
|
||||
//
|
||||
DWORD rc = mpiexec_send_stdin_command(buffer, num_encoded*2 + 1);
|
||||
if( rc != NOERROR )
|
||||
{
|
||||
goto fn_stdin_close;
|
||||
}
|
||||
|
||||
fn_exit:
|
||||
delete pov;
|
||||
|
||||
return NOERROR;
|
||||
|
||||
fn_stdin_close:
|
||||
smpd_dbg_printf(L"stdin to mpiexec closed. sending stdin_close command.\n");
|
||||
mpiexec_send_stdin_close_command();
|
||||
goto fn_exit;
|
||||
}
|
||||
|
||||
|
||||
DWORD mpiexec_redirect_stdin(void)
|
||||
{
|
||||
DWORD tid;
|
||||
HANDLE hThread;
|
||||
|
||||
//
|
||||
// Unfortunately, we can't use overlapped operations with stdin;
|
||||
// create a thread to read stdin and post the read buffers to the
|
||||
// main thread.
|
||||
//
|
||||
hThread = CreateThread(nullptr, 0, mpiexec_stdin_read_thread, nullptr, 0, &tid);
|
||||
if(hThread == nullptr)
|
||||
{
|
||||
DWORD gle = GetLastError();
|
||||
smpd_err_printf(L"Unable to create a thread to read stdin, error %u\n", gle);
|
||||
return gle;
|
||||
}
|
||||
|
||||
CloseHandle(hThread);
|
||||
|
||||
smpd_process.stdin_redirecting = TRUE;
|
||||
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// STDOUT/STDERR redirection
|
||||
// mpiexec writes rank n stdout/stderr sent by smpd to mpiexec stdout
|
||||
//
|
||||
// mpiexec output optimizes for a single stdout/err output stream; e.g., the
|
||||
// console or a single file. Extra '\n' might be written when using separate
|
||||
// stdout/stderr streams as a result of cross sream rank switching.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
static void printstd(const void* buffer, size_t num_bytes, HANDLE hFile)
|
||||
{
|
||||
//
|
||||
// N.B. The output is written raw to the target; the CR-LF
|
||||
// translation happen already by the mpi process
|
||||
//
|
||||
DWORD nBytesWritten;
|
||||
WriteFile(hFile, buffer, (DWORD)num_bytes, &nBytesWritten, NULL);
|
||||
}
|
||||
|
||||
|
||||
static const char* search_eol(const char* s)
|
||||
{
|
||||
while(*s != '\0' && *s != '\n')
|
||||
{
|
||||
s++;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
static void write_prefixed_output(const char* data, int rank, BOOL no_prefix, HANDLE std)
|
||||
{
|
||||
const char* start;
|
||||
const char* end;
|
||||
size_t prefix_length;
|
||||
char prefix[20];
|
||||
|
||||
prefix_length = MPIU_Snprintf(prefix, _countof(prefix), "[%d]", rank);
|
||||
|
||||
start = data;
|
||||
for(;;)
|
||||
{
|
||||
end = search_eol(start);
|
||||
if(*end != '\0')
|
||||
{
|
||||
end++;
|
||||
}
|
||||
|
||||
if(end == start)
|
||||
break;
|
||||
|
||||
if(no_prefix)
|
||||
{
|
||||
no_prefix = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
printstd(prefix, prefix_length, std);
|
||||
}
|
||||
printstd(start, end - start, std);
|
||||
|
||||
start = end;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static DWORD
|
||||
mpiexec_handle_stdouterr_command(
|
||||
_In_ smpd_overlapped_t* pov,
|
||||
_In_ HANDLE std
|
||||
)
|
||||
{
|
||||
//
|
||||
// Both StdoutCmd and StderrCmd have the same memory
|
||||
// layout
|
||||
//
|
||||
SmpdStdoutCmd* pStdoutCmd = &pov->pCmd->StdoutCmd;
|
||||
|
||||
//
|
||||
// Save the previous rank to print out. The value -2 signifies that no new line
|
||||
// is required before printing.
|
||||
//
|
||||
// Note that this code is optimized for a single stdout/err output stream, thus
|
||||
// using a single value for both stdout and stderr. (see note above)
|
||||
//
|
||||
static int s_prev_rank = -2;
|
||||
static GUID s_prev_kvs = GUID_NULL;
|
||||
|
||||
//
|
||||
// Get the rank and data to print
|
||||
//
|
||||
UINT16 rank = pStdoutCmd->rank;
|
||||
GUID kvs = pStdoutCmd->kvs;
|
||||
|
||||
UINT32 length = pStdoutCmd->size;
|
||||
|
||||
BOOL same_rank_no_eol = (s_prev_rank == static_cast<int>(rank)) && (IsEqualGUID(s_prev_kvs, kvs));
|
||||
|
||||
if(!same_rank_no_eol && (s_prev_rank != -2))
|
||||
{
|
||||
//
|
||||
// The output is written raw; put CR and LF characters
|
||||
//
|
||||
printstd("\r\n", 2, std);
|
||||
}
|
||||
|
||||
//smpd_dbg_printf(L"Decoding stdout/stderr buffer %S\n", pStdoutCmd->buffer);
|
||||
|
||||
//
|
||||
// Decode the data buffer in-place and remember if it ends with eol.
|
||||
//
|
||||
UINT32 num_decoded = 0;
|
||||
smpd_decode_buffer(
|
||||
reinterpret_cast<char*>(pStdoutCmd->buffer),
|
||||
reinterpret_cast<char*>(pStdoutCmd->buffer),
|
||||
length,
|
||||
&num_decoded);
|
||||
if(pStdoutCmd->buffer[num_decoded - 1] == '\n')
|
||||
{
|
||||
s_prev_rank = -2;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_prev_rank = rank;
|
||||
s_prev_kvs = kvs;
|
||||
}
|
||||
|
||||
//
|
||||
// No need for prefix
|
||||
//
|
||||
if(!smpd_process.prefix_output)
|
||||
{
|
||||
printstd(reinterpret_cast<char*>(pStdoutCmd->buffer), num_decoded, std);
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
write_prefixed_output(reinterpret_cast<char*>(pStdoutCmd->buffer),
|
||||
rank, same_rank_no_eol, std);
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
DWORD
|
||||
mpiexec_handle_stdout_command(
|
||||
smpd_overlapped_t* pov
|
||||
)
|
||||
{
|
||||
smpd_dbg_printf(L"Handling SMPD_STDOUT\n");
|
||||
return mpiexec_handle_stdouterr_command(
|
||||
pov,
|
||||
GetStdHandle(STD_OUTPUT_HANDLE) );
|
||||
}
|
||||
|
||||
|
||||
DWORD
|
||||
mpiexec_handle_stderr_command(
|
||||
smpd_overlapped_t* pov
|
||||
)
|
||||
{
|
||||
smpd_dbg_printf(L"Handling SMPD_STDERR\n");
|
||||
return mpiexec_handle_stdouterr_command(
|
||||
pov,
|
||||
GetStdHandle(STD_ERROR_HANDLE) );
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
* (C) 2001 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#include "smpd.h"
|
||||
|
||||
HRESULT
|
||||
WINAPI
|
||||
MpiexecCreateManagerProcess(
|
||||
_In_z_ const char* app,
|
||||
_In_z_ const char* args,
|
||||
_In_z_ const char* /*context*/
|
||||
)
|
||||
{
|
||||
//
|
||||
// MSPMS passes us multibyte arguments for backcompat purposes.
|
||||
// We need to convert the multibyte into wchar_t because they might
|
||||
// contain true unicode
|
||||
//
|
||||
smpd_dbg_printf(L"create manager process (using mpiexec credentials)\n");
|
||||
wchar_t* appW;
|
||||
wchar_t* argsW;
|
||||
|
||||
DWORD err = MPIU_MultiByteToWideChar( app, &appW );
|
||||
if( err != NOERROR )
|
||||
{
|
||||
smpd_err_printf(L"Failed to convert smpd name to unicode error %u\n", err);
|
||||
return HRESULT_FROM_WIN32( err );
|
||||
}
|
||||
|
||||
err = MPIU_MultiByteToWideChar( args, &argsW );
|
||||
if( err != NOERROR )
|
||||
{
|
||||
delete[] appW;
|
||||
smpd_err_printf(L"Failed to convert smpd arguments to unicode error %u\n", err);
|
||||
return HRESULT_FROM_WIN32( err );
|
||||
}
|
||||
|
||||
smpd_dbg_printf(L"Launching smpd as '%s %s'\n", appW, argsW);
|
||||
|
||||
if( smpd_process.unicodeOutput )
|
||||
{
|
||||
SetEnvironmentVariableW(L"MPIEXEC_UNICODE_OUTPUT", L"1");
|
||||
}
|
||||
STARTUPINFOW si;
|
||||
GetStartupInfoW( &si );
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
PROCESS_INFORMATION pi;
|
||||
|
||||
BOOL fSucc = OACR_REVIEWED_CALL(
|
||||
mpicr,
|
||||
CreateProcessW(
|
||||
appW, // Application Name
|
||||
argsW, // Command Line (must be read/write)
|
||||
NULL, // Process Security Attributes,
|
||||
NULL, // Thread Security Attributes,
|
||||
TRUE, // Inherit Parent Handles,
|
||||
CREATE_UNICODE_ENVIRONMENT | CREATE_SUSPENDED, // Process CreationFlags,
|
||||
NULL, // lpEnvironment,
|
||||
NULL, // lpCurrentDirectory,
|
||||
&si, // lpStartupInfo,
|
||||
&pi // lpProcessInformation (out)
|
||||
));
|
||||
if(!fSucc)
|
||||
{
|
||||
err = GetLastError();
|
||||
smpd_err_printf(L"CreateProcess '%s %s' failed, error %u\n", appW, argsW, err);
|
||||
hr = HRESULT_FROM_WIN32( err );
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Successfully launched the SMPD manager. Create a job object
|
||||
// and assign it so that if mpiexec is terminated unexpectedly,
|
||||
// the SMPD instance will be cleaned up.
|
||||
//
|
||||
if( g_IsWin8OrGreater && !env_is_on(L"SMPD_NO_JOBOBJ", FALSE) )
|
||||
{
|
||||
ASSERT( smpd_process.hJobObj == nullptr );
|
||||
smpd_process.hJobObj = CreateJobObjectW( nullptr, nullptr );
|
||||
if( smpd_process.hJobObj == nullptr )
|
||||
{
|
||||
smpd_dbg_printf(L"mpiexec failed to create job object to launch smpd, error %u",
|
||||
GetLastError());
|
||||
}
|
||||
else
|
||||
{
|
||||
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobLimit = {0};
|
||||
jobLimit.BasicLimitInformation.LimitFlags =
|
||||
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_BREAKAWAY_OK;
|
||||
fSucc = SetInformationJobObject(
|
||||
smpd_process.hJobObj,
|
||||
JobObjectExtendedLimitInformation,
|
||||
&jobLimit,
|
||||
sizeof(jobLimit) );
|
||||
if( !fSucc )
|
||||
{
|
||||
smpd_dbg_printf(L"mpiexec failed to set job object limit to launch smpd, error %u",
|
||||
GetLastError());
|
||||
}
|
||||
else
|
||||
{
|
||||
fSucc = AssignProcessToJobObject(
|
||||
smpd_process.hJobObj,
|
||||
pi.hProcess);
|
||||
if (!fSucc)
|
||||
{
|
||||
smpd_dbg_printf(L"mpiexec failed to assign smpd to job object, error %u",
|
||||
GetLastError());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ResumeThread(pi.hThread);
|
||||
CloseHandle(pi.hThread);
|
||||
CloseHandle(pi.hProcess);
|
||||
}
|
||||
|
||||
if( smpd_process.unicodeOutput )
|
||||
{
|
||||
SetEnvironmentVariableW(L"MPIEXEC_UNICODE_OUTPUT", nullptr);
|
||||
}
|
||||
|
||||
delete[] appW;
|
||||
delete[] argsW;
|
||||
return hr;
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
* (C) 2001 by Argonne National Laboratory.
|
||||
* See COPYRIGHT in top-level directory.
|
||||
*/
|
||||
|
||||
#include "mpiexec.h"
|
||||
|
||||
void smpd_fix_up_host_tree(smpd_host_t* host)
|
||||
{
|
||||
smpd_host_t *cur, *iter;
|
||||
BOOL left_found;
|
||||
|
||||
cur = host;
|
||||
while (cur != NULL)
|
||||
{
|
||||
left_found = FALSE;
|
||||
iter = static_cast<smpd_host_t*>( cur->Next );
|
||||
while (iter != NULL)
|
||||
{
|
||||
if(iter->parent == cur->HostId)
|
||||
{
|
||||
if(left_found)
|
||||
{
|
||||
cur->right = iter;
|
||||
break;
|
||||
}
|
||||
cur->left = iter;
|
||||
left_found = TRUE;
|
||||
}
|
||||
iter = static_cast<smpd_host_t*>( iter->Next );
|
||||
}
|
||||
cur = static_cast<smpd_host_t*>( cur->Next );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
smpd_host_t*
|
||||
smpd_get_host_id(
|
||||
_In_ PCWSTR host_name
|
||||
)
|
||||
{
|
||||
smpd_host_t* host;
|
||||
int bit, mask, temp;
|
||||
|
||||
/* look for the host in the list */
|
||||
host = smpd_process.host_list;
|
||||
while (host)
|
||||
{
|
||||
if( CompareStringW( LOCALE_INVARIANT,
|
||||
0,
|
||||
host->name,
|
||||
-1,
|
||||
host_name,
|
||||
-1 ) == CSTR_EQUAL )
|
||||
{
|
||||
return host;
|
||||
}
|
||||
if(host->Next == NULL)
|
||||
break;
|
||||
host = static_cast<smpd_host_t*>( host->Next );
|
||||
}
|
||||
|
||||
/* allocate a new host */
|
||||
if(host != NULL)
|
||||
{
|
||||
host->Next = new smpd_host_t;
|
||||
host = static_cast<smpd_host_t*>( host->Next );
|
||||
}
|
||||
else
|
||||
{
|
||||
host = new smpd_host_t;
|
||||
smpd_process.host_list = host;
|
||||
}
|
||||
if(host == NULL)
|
||||
{
|
||||
smpd_err_printf(L"malloc failed to allocate a host node structure\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MPIU_Strcpy( host->name, _countof(host->name), host_name );
|
||||
|
||||
//
|
||||
// nameA will be used to store UTF-8 representation of the host name
|
||||
// It will only be necessary if we need to collect the hostname
|
||||
// for the Debug Interface.
|
||||
//
|
||||
host->nameA = nullptr;
|
||||
host->parent = smpd_process.mpiexec_parent_id;
|
||||
host->HostId = smpd_process.mpiexec_tree_id;
|
||||
host->connected = FALSE;
|
||||
host->collected = FALSE;
|
||||
host->nproc = -1;
|
||||
host->Next = nullptr;
|
||||
host->left = nullptr;
|
||||
host->right = nullptr;
|
||||
host->Summary = nullptr;
|
||||
host->hwTree = nullptr;
|
||||
host->nodeProcCount = 0;
|
||||
host->pLaunchBlockList = nullptr;
|
||||
host->pBlockOptions = nullptr;
|
||||
|
||||
/* move to the next id and parent */
|
||||
smpd_process.mpiexec_tree_id++;
|
||||
|
||||
temp = smpd_process.mpiexec_tree_id >> 2;
|
||||
bit = 1;
|
||||
while (temp)
|
||||
{
|
||||
bit <<= 1;
|
||||
temp >>= 1;
|
||||
}
|
||||
mask = bit - 1;
|
||||
smpd_process.mpiexec_parent_id = bit | (smpd_process.mpiexec_tree_id & mask);
|
||||
|
||||
return host;
|
||||
}
|
||||
|
||||
|
||||
smpd_rank_data_t*
|
||||
next_rank_data(
|
||||
_In_opt_ smpd_rank_data_t* pNode,
|
||||
_In_ const smpd_host_t* pHost )
|
||||
{
|
||||
if( pNode == nullptr )
|
||||
{
|
||||
return pHost->pLaunchBlockList->pRankData;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( pNode->next == nullptr )
|
||||
{
|
||||
if( pNode->parent->next != nullptr )
|
||||
{
|
||||
return pNode->parent->next->pRankData;
|
||||
}
|
||||
}
|
||||
|
||||
return pNode->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
smpd_launch_node_t *next_launch_node(smpd_launch_node_t *node, int id)
|
||||
{
|
||||
while (node)
|
||||
{
|
||||
if(node->host_id == id)
|
||||
return node;
|
||||
|
||||
node = node->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
smpd_launch_node_t *prev_launch_node(smpd_launch_node_t *node, int id)
|
||||
{
|
||||
while (node)
|
||||
{
|
||||
if(node->host_id == id)
|
||||
return node;
|
||||
|
||||
node = node->prev;
|
||||
}
|
||||
return NULL;
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,777 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
Licensed under the MIT License.
|
||||
|
||||
mpi_api.h - Defines MPI API support routines, used internally to the API layer,
|
||||
such as error checking, etc.
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _MPI_API_
|
||||
#define _MPI_API_
|
||||
|
||||
#include <oacr.h>
|
||||
|
||||
#include "mpi.h"
|
||||
#include "mpierrs.h"
|
||||
|
||||
|
||||
//
|
||||
// Special case for "is initialized".
|
||||
// This should be used in cases where there is no
|
||||
// additional error checking
|
||||
//
|
||||
inline void MpiaIsInitializedOrExit()
|
||||
{
|
||||
if(Mpi.IsReady() == false)
|
||||
{
|
||||
MPIR_Err_preOrPostInit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Once we get rid of NMPI stuff, we can eliminate the following.
|
||||
//
|
||||
__forceinline void MpiaEnter()
|
||||
{
|
||||
Mpi.CallState->nest_count++;
|
||||
}
|
||||
|
||||
|
||||
__forceinline void MpiaExit()
|
||||
{
|
||||
Mpi.CallState->nest_count--;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaDatatypeValidateHandle(
|
||||
_In_ MPI_Datatype hType,
|
||||
_In_ PCSTR typeParamName,
|
||||
_Out_ TypeHandle* pDatatype
|
||||
)
|
||||
{
|
||||
if( hType == MPI_DATATYPE_NULL )
|
||||
{
|
||||
return MPIU_ERR_CREATE( MPI_ERR_TYPE, "**dtypenull %s", typeParamName );
|
||||
}
|
||||
|
||||
MPID_Datatype* pType = TypePool::Lookup( hType );
|
||||
if( pType == nullptr )
|
||||
{
|
||||
return MPIU_ERR_CREATE(MPI_ERR_TYPE,"**dtype");
|
||||
}
|
||||
|
||||
pDatatype->Init( pType );
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaDatatypeValidateCommitted(
|
||||
_In_ MPI_Datatype hType,
|
||||
_In_ PCSTR typeParamName,
|
||||
_Out_ TypeHandle* pDatatype
|
||||
)
|
||||
{
|
||||
if( hType == MPI_DATATYPE_NULL )
|
||||
{
|
||||
return MPIU_ERR_CREATE( MPI_ERR_TYPE, "**dtypenull %s", typeParamName );
|
||||
}
|
||||
|
||||
MPID_Datatype* pType = TypePool::Lookup( hType );
|
||||
if( pType == nullptr )
|
||||
{
|
||||
return MPIU_ERR_CREATE( MPI_ERR_TYPE,"**dtype" );
|
||||
}
|
||||
|
||||
if( HANDLE_GET_TYPE(hType) != HANDLE_TYPE_BUILTIN )
|
||||
{
|
||||
if( pType->is_committed == false )
|
||||
{
|
||||
return MPIU_ERR_CREATE( MPI_ERR_TYPE, "**dtypecommit" );
|
||||
}
|
||||
pDatatype->Init( pType );
|
||||
}
|
||||
else
|
||||
{
|
||||
*pDatatype = g_hBuiltinTypes.Get( hType );
|
||||
}
|
||||
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaDatatypeValidate(
|
||||
_Pre_maybenull_ const void* buffer,
|
||||
_In_ int count,
|
||||
_In_ MPI_Datatype hType,
|
||||
_In_ PCSTR typeParamName,
|
||||
_Out_ TypeHandle* pDatatype
|
||||
)
|
||||
{
|
||||
if( count == 0 )
|
||||
{
|
||||
//
|
||||
// return a valid handle so future references work.
|
||||
//
|
||||
*pDatatype = g_hBuiltinTypes.MPI_Byte;
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
if( count < 0 )
|
||||
{
|
||||
return MPIU_ERR_CREATE( MPI_ERR_COUNT, "**countneg %d", count );
|
||||
}
|
||||
|
||||
if( hType == MPI_DATATYPE_NULL )
|
||||
{
|
||||
return MPIU_ERR_CREATE( MPI_ERR_TYPE, "**dtypenull %s", typeParamName );
|
||||
}
|
||||
|
||||
MPID_Datatype* pType = TypePool::Lookup( hType );
|
||||
if( pType == nullptr )
|
||||
{
|
||||
return MPIU_ERR_CREATE( MPI_ERR_TYPE,"**dtype" );
|
||||
}
|
||||
|
||||
if( HANDLE_GET_TYPE(hType) != HANDLE_TYPE_BUILTIN )
|
||||
{
|
||||
if( pType->is_committed == false )
|
||||
{
|
||||
return MPIU_ERR_CREATE( MPI_ERR_TYPE, "**dtypecommit" );
|
||||
}
|
||||
|
||||
if( buffer == nullptr && pType->true_lb == 0 && pType->size > 0 )
|
||||
{
|
||||
return MPIU_ERR_CREATE( MPI_ERR_BUFFER, "**bufnull" );
|
||||
}
|
||||
pDatatype->Init( pType );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( buffer == nullptr )
|
||||
{
|
||||
return MPIU_ERR_CREATE( MPI_ERR_BUFFER, "**bufnull" );
|
||||
}
|
||||
*pDatatype = g_hBuiltinTypes.Get( hType );
|
||||
}
|
||||
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaDatatypeValidateNotPermanent(
|
||||
_In_ TypeHandle hType
|
||||
)
|
||||
{
|
||||
MPI_Datatype datatype = hType.GetMpiHandle();
|
||||
|
||||
if( HANDLE_GET_TYPE( datatype ) == HANDLE_TYPE_BUILTIN ||
|
||||
datatype == MPI_FLOAT_INT ||
|
||||
datatype == MPI_DOUBLE_INT ||
|
||||
datatype == MPI_LONG_INT ||
|
||||
datatype == MPI_SHORT_INT ||
|
||||
datatype == MPI_LONG_DOUBLE_INT)
|
||||
{
|
||||
return MPIU_ERR_CREATE( MPI_ERR_TYPE, "**dtypeperm" );
|
||||
}
|
||||
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaDatatypeValidateBuffer(
|
||||
_In_ TypeHandle hType,
|
||||
_Pre_maybenull_ const void* buffer,
|
||||
_In_ int count
|
||||
)
|
||||
{
|
||||
bool contig;
|
||||
MPI_Aint lb;
|
||||
size_t size = hType.GetSizeAndInfo( count, &contig, &lb );
|
||||
|
||||
if( buffer == nullptr && lb == 0 && size > 0 )
|
||||
{
|
||||
return MPIU_ERR_CREATE( MPI_ERR_BUFFER, "**bufnull" );
|
||||
}
|
||||
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaSendTagValidate(
|
||||
_In_ int tag
|
||||
)
|
||||
{
|
||||
if( tag < 0 || tag > Mpi.Attributes.tag_ub )
|
||||
{
|
||||
return MPIU_ERR_CREATE(MPI_ERR_TAG, "**tag %d", tag);
|
||||
}
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaRecvTagValidate(
|
||||
_In_ int tag
|
||||
)
|
||||
{
|
||||
if( tag < MPI_ANY_TAG || tag > Mpi.Attributes.tag_ub )
|
||||
{
|
||||
return MPIU_ERR_CREATE(MPI_ERR_TAG, "**tag %d", tag);
|
||||
}
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaBufferValidateAliasing(
|
||||
_In_opt_ const void* sendbuf,
|
||||
_In_ MPI_Datatype sendtype,
|
||||
_In_ const void* recvbuf,
|
||||
_In_ MPI_Datatype recvtype,
|
||||
_In_ int count
|
||||
)
|
||||
{
|
||||
//
|
||||
// If we had a user-specified level of strictness for error checking
|
||||
// we could do more here.
|
||||
//
|
||||
if( count > 0 && sendtype == recvtype && sendbuf == recvbuf )
|
||||
{
|
||||
return MPIU_ERR_CREATE(
|
||||
MPI_ERR_BUFFER,
|
||||
"**bufalias %s %s",
|
||||
"sendbuf",
|
||||
"recvbuf"
|
||||
);
|
||||
}
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaRequestValidate(
|
||||
_In_ MPI_Request hReq,
|
||||
_Outptr_result_nullonfailure_ MPID_Request** ppReq
|
||||
)
|
||||
{
|
||||
if( HANDLE_GET_MPI_KIND( hReq ) != MPID_REQUEST ||
|
||||
HANDLE_GET_TYPE( hReq ) == HANDLE_TYPE_INVALID )
|
||||
{
|
||||
*ppReq = nullptr;
|
||||
return MPIU_ERR_CREATE( MPI_ERR_REQUEST, "**request" );
|
||||
}
|
||||
|
||||
/* Convert MPI object handles to object pointers */
|
||||
MPID_Request_get_ptr( hReq, *ppReq );
|
||||
if( *ppReq == nullptr )
|
||||
{
|
||||
return MPIU_ERR_CREATE(MPI_ERR_REQUEST, "**nullptrtype %s", "request" );
|
||||
}
|
||||
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaMessageValidate(
|
||||
_In_ MPI_Message hMsg,
|
||||
_Outptr_result_maybenull_ MPID_Request** ppReq
|
||||
)
|
||||
{
|
||||
if( HANDLE_GET_MPI_KIND( hMsg ) != MPID_MESSAGE ||
|
||||
HANDLE_GET_TYPE( hMsg ) == HANDLE_TYPE_INVALID )
|
||||
{
|
||||
*ppReq = nullptr;
|
||||
return MPIU_ERR_CREATE( MPI_ERR_ARG, "**message" );
|
||||
}
|
||||
|
||||
if( hMsg == MPI_MESSAGE_NO_PROC )
|
||||
{
|
||||
*ppReq = nullptr;
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Convert MPI object handles to object pointers.
|
||||
//
|
||||
MPID_Request_get_ptr( HANDLE_SET_MPI_KIND( hMsg, MPID_REQUEST ), *ppReq );
|
||||
if( *ppReq == nullptr )
|
||||
{
|
||||
return MPIU_ERR_CREATE( MPI_ERR_REQUEST, "**nullptrtype %s", "request" );
|
||||
}
|
||||
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaCommValidateHandle(
|
||||
_In_ MPI_Comm hComm,
|
||||
_Outptr_result_nullonfailure_ MPID_Comm** ppComm
|
||||
)
|
||||
{
|
||||
MPID_Comm* pComm = CommPool::Lookup( hComm );
|
||||
if( pComm == nullptr )
|
||||
{
|
||||
*ppComm = nullptr;
|
||||
return MPIU_ERR_CREATE(MPI_ERR_COMM,"**comm");
|
||||
}
|
||||
|
||||
*ppComm = pComm;
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaCommValidateIntracomm(
|
||||
_In_ MPI_Comm hComm,
|
||||
_Outptr_result_nullonfailure_ MPID_Comm** ppComm
|
||||
)
|
||||
{
|
||||
MPID_Comm* pComm = CommPool::Lookup( hComm );
|
||||
if( pComm == nullptr )
|
||||
{
|
||||
*ppComm = nullptr;
|
||||
return MPIU_ERR_CREATE(MPI_ERR_COMM,"**comm");
|
||||
}
|
||||
|
||||
if( pComm->comm_kind == MPID_INTERCOMM )
|
||||
{
|
||||
*ppComm = nullptr;
|
||||
return MPIU_ERR_CREATE(MPI_ERR_COMM,"**commnotintra");
|
||||
}
|
||||
|
||||
*ppComm = pComm;
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaCommValidateRoot(
|
||||
_In_ const MPID_Comm *pComm,
|
||||
_In_ int root
|
||||
)
|
||||
{
|
||||
if( root < 0 || root >= pComm->remote_size )
|
||||
{
|
||||
return MPIU_ERR_CREATE( MPI_ERR_ROOT, "**root %d", root );
|
||||
}
|
||||
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaCommValidateRank(
|
||||
_In_ const MPID_Comm* pComm,
|
||||
_In_ int rank
|
||||
)
|
||||
{
|
||||
if( rank < 0 || rank >= pComm->remote_size )
|
||||
{
|
||||
return MPIU_ERR_CREATE( MPI_ERR_RANK, "**rank %d %d", rank, pComm->remote_size );
|
||||
}
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaCommValidateSendRank(
|
||||
_In_ const MPID_Comm* pComm,
|
||||
_In_ int rank
|
||||
)
|
||||
{
|
||||
if( rank < MPI_PROC_NULL || rank >= pComm->remote_size )
|
||||
{
|
||||
return MPIU_ERR_CREATE( MPI_ERR_RANK, "**rank %d %d", rank, pComm->remote_size );
|
||||
}
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaCommValidateRecvRank(
|
||||
_In_ const MPID_Comm* pComm,
|
||||
_In_ int rank
|
||||
)
|
||||
{
|
||||
if( rank < MPI_ANY_SOURCE || rank >= pComm->remote_size )
|
||||
{
|
||||
return MPIU_ERR_CREATE(MPI_ERR_RANK, "**rank %d %d", rank, pComm->remote_size );
|
||||
}
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaCommValidateTopology(
|
||||
_In_ const MPID_Comm* pComm,
|
||||
_In_ int topoKind,
|
||||
_Outptr_result_nullonfailure_ MPIR_Topology** ppTopo )
|
||||
{
|
||||
MPIR_Topology* pTopo = MPIR_Topology_get( pComm );
|
||||
if( pTopo == nullptr )
|
||||
{
|
||||
*ppTopo = nullptr;
|
||||
return MPIU_ERR_CREATE(MPI_ERR_TOPOLOGY,"**notopology");
|
||||
}
|
||||
|
||||
if( pTopo->kind != topoKind )
|
||||
{
|
||||
*ppTopo = nullptr;
|
||||
if( topoKind == MPI_CART )
|
||||
{
|
||||
return MPIU_ERR_CREATE(MPI_ERR_TOPOLOGY, "**notcarttopo");
|
||||
}
|
||||
else
|
||||
{
|
||||
return MPIU_ERR_CREATE( MPI_ERR_TOPOLOGY, "**notgraphtopo" );
|
||||
}
|
||||
}
|
||||
|
||||
*ppTopo = pTopo;
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaKeyvalValidate(
|
||||
_In_ int keyval,
|
||||
_In_ MPID_Object_kind kind,
|
||||
_Out_ KeyHandle* phKey
|
||||
)
|
||||
{
|
||||
if( keyval == MPI_KEYVAL_INVALID )
|
||||
{
|
||||
return MPIU_ERR_CREATE( MPI_ERR_KEYVAL, "**keyvalinvalid" );
|
||||
}
|
||||
|
||||
if( HANDLE_GET_MPI_KIND(keyval) != MPID_KEYVAL )
|
||||
{
|
||||
return MPIU_ERR_CREATE( MPI_ERR_KEYVAL, "**keyval" );
|
||||
}
|
||||
|
||||
if( MPID_Keyval::GetKind( keyval ) != kind )
|
||||
{
|
||||
return MPIU_ERR_CREATE(
|
||||
MPI_ERR_KEYVAL,
|
||||
"**keyvalobj %s",
|
||||
MPID_Object_kind_names[kind]
|
||||
);
|
||||
}
|
||||
|
||||
if( HANDLE_GET_TYPE(keyval) == HANDLE_TYPE_BUILTIN )
|
||||
{
|
||||
if( MPID_Keyval::GetKind( keyval ) != kind )
|
||||
{
|
||||
return MPIU_ERR_CREATE(
|
||||
MPI_ERR_KEYVAL,
|
||||
"**keyvalobj %s",
|
||||
MPID_Object_kind_names[kind]
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MPID_Keyval* pKeyval;
|
||||
MPID_Keyval_get_ptr( keyval, pKeyval );
|
||||
if( pKeyval == nullptr )
|
||||
{
|
||||
return MPIU_ERR_CREATE(MPI_ERR_KEYVAL, "**nullptrtype %s", "Keyval" );
|
||||
}
|
||||
|
||||
if( pKeyval->kind != kind )
|
||||
{
|
||||
return MPIU_ERR_CREATE(
|
||||
MPI_ERR_KEYVAL,
|
||||
"**keyvalobj %s",
|
||||
MPID_Object_kind_names[kind]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
*phKey = KeyHandle( keyval );
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaKeyvalValidateNotPermanent(
|
||||
_In_ KeyHandle hKey
|
||||
)
|
||||
{
|
||||
if( HANDLE_GET_TYPE( hKey.GetMpiHandle() ) == HANDLE_TYPE_BUILTIN )
|
||||
{
|
||||
return MPIU_ERR_CREATE( MPI_ERR_KEYVAL, "**permattr" );
|
||||
}
|
||||
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaInfoValidateHandle(
|
||||
_In_ MPI_Info hInfo,
|
||||
_Outptr_result_nullonfailure_ MPID_Info** ppInfo
|
||||
)
|
||||
{
|
||||
if( HANDLE_GET_MPI_KIND( hInfo ) != MPID_INFO ||
|
||||
HANDLE_GET_TYPE( hInfo ) == HANDLE_TYPE_INVALID )
|
||||
{
|
||||
*ppInfo = nullptr;
|
||||
return MPIU_ERR_CREATE( MPI_ERR_INFO, "**info" );
|
||||
}
|
||||
|
||||
MPID_Info_get_ptr( hInfo, *ppInfo );
|
||||
if( *ppInfo == nullptr )
|
||||
{
|
||||
return MPIU_ERR_CREATE(MPI_ERR_INFO, "**nullptrtype %s", "Info" );
|
||||
}
|
||||
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaInfoValidateHandleOrNull(
|
||||
_In_ MPI_Info hInfo,
|
||||
_Outptr_result_maybenull_ MPID_Info** ppInfo
|
||||
)
|
||||
{
|
||||
if( hInfo == MPI_INFO_NULL )
|
||||
{
|
||||
*ppInfo = nullptr;
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
return MpiaInfoValidateHandle( hInfo, ppInfo );
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaInfoValidateKey(
|
||||
_In_ PCSTR key
|
||||
)
|
||||
{
|
||||
if( key == nullptr )
|
||||
{
|
||||
return MPIU_ERR_CREATE(MPI_ERR_INFO_KEY, "**infokeynull");
|
||||
}
|
||||
|
||||
size_t keylen = MPIU_Strlen( key, MPI_MAX_INFO_KEY + 1 );
|
||||
if(keylen > MPI_MAX_INFO_KEY)
|
||||
{
|
||||
return MPIU_ERR_CREATE(
|
||||
MPI_ERR_INFO_KEY,
|
||||
"**infokeylong %s %d %d",
|
||||
key,
|
||||
static_cast<int>(keylen),
|
||||
MPI_MAX_INFO_KEY
|
||||
);
|
||||
}
|
||||
|
||||
if(keylen == 0)
|
||||
{
|
||||
return MPIU_ERR_CREATE(MPI_ERR_INFO_KEY, "**infokeyempty");
|
||||
}
|
||||
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaErrhandlerValidateHandle(
|
||||
_In_ MPI_Errhandler hErrHandler,
|
||||
_Outptr_result_nullonfailure_ MPID_Errhandler** ppErrHandler
|
||||
)
|
||||
{
|
||||
if( HANDLE_GET_MPI_KIND( hErrHandler ) != MPID_ERRHANDLER ||
|
||||
HANDLE_GET_TYPE( hErrHandler ) == HANDLE_TYPE_INVALID )
|
||||
{
|
||||
*ppErrHandler = nullptr;
|
||||
return MPIU_ERR_CREATE( MPI_ERR_ARG, "**errhandler" );
|
||||
}
|
||||
|
||||
MPID_Errhandler_get_ptr( hErrHandler, *ppErrHandler );
|
||||
if( *ppErrHandler == nullptr )
|
||||
{
|
||||
return MPIU_ERR_CREATE(MPI_ERR_INFO, "**nullptrtype %s", "Errhandler" );
|
||||
}
|
||||
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaWinValidateHandle(
|
||||
_In_ MPI_Win hWin,
|
||||
_Outptr_result_nullonfailure_ MPID_Win** ppWin
|
||||
)
|
||||
{
|
||||
if( HANDLE_GET_MPI_KIND( hWin ) != MPID_WIN ||
|
||||
HANDLE_GET_TYPE( hWin ) == HANDLE_TYPE_INVALID )
|
||||
{
|
||||
*ppWin = nullptr;
|
||||
return MPIU_ERR_CREATE( MPI_ERR_WIN, "**win" );
|
||||
}
|
||||
|
||||
MPID_Win_get_ptr( hWin, *ppWin );
|
||||
if( *ppWin == nullptr )
|
||||
{
|
||||
return MPIU_ERR_CREATE(MPI_ERR_WIN, "**nullptrtype %s", "Window" );
|
||||
}
|
||||
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaFileValidateHandle(
|
||||
_In_ MPI_File hFile,
|
||||
_Outptr_result_nullonfailure_ ADIOI_FileD** ppFile
|
||||
)
|
||||
{
|
||||
if( hFile == MPI_FILE_NULL )
|
||||
{
|
||||
*ppFile = nullptr;
|
||||
return MPIU_ERR_CREATE( MPI_ERR_ARG, "**iobadfh" );
|
||||
}
|
||||
|
||||
*ppFile = hFile;
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaGroupValidateHandle(
|
||||
_In_ MPI_Group hGroup,
|
||||
_Outptr_result_nullonfailure_ MPID_Group** ppGroup
|
||||
)
|
||||
{
|
||||
if( HANDLE_GET_MPI_KIND( hGroup ) != MPID_GROUP ||
|
||||
HANDLE_GET_TYPE( hGroup ) == HANDLE_TYPE_INVALID )
|
||||
{
|
||||
*ppGroup = nullptr;
|
||||
return MPIU_ERR_CREATE( MPI_ERR_GROUP, "**group" );
|
||||
}
|
||||
|
||||
MPID_Group_get_ptr( hGroup, *ppGroup );
|
||||
if( *ppGroup == nullptr )
|
||||
{
|
||||
return MPIU_ERR_CREATE(MPI_ERR_GROUP, "**nullptrtype %s", "Group" );
|
||||
}
|
||||
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaOpValidateHandle(
|
||||
_In_ MPI_Op hOp,
|
||||
_Outptr_result_nullonfailure_ MPID_Op** ppOp
|
||||
)
|
||||
{
|
||||
if( HANDLE_GET_MPI_KIND( hOp ) != MPID_OP ||
|
||||
HANDLE_GET_TYPE( hOp ) == HANDLE_TYPE_INVALID )
|
||||
{
|
||||
*ppOp = nullptr;
|
||||
return MPIU_ERR_CREATE( MPI_ERR_OP, "**op" );
|
||||
}
|
||||
|
||||
*ppOp = OpPool::Lookup( hOp );
|
||||
if( *ppOp == nullptr )
|
||||
{
|
||||
return MPIU_ERR_CREATE(MPI_ERR_OP, "**nullptrtype %s", "Op" );
|
||||
}
|
||||
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
__forceinline
|
||||
MPI_RESULT
|
||||
MpiaOpValidate(
|
||||
_In_ MPI_Op hOp,
|
||||
_In_ MPI_Datatype hType,
|
||||
_In_ bool rmaOp,
|
||||
_Outptr_result_nullonfailure_ MPID_Op** ppOp
|
||||
)
|
||||
{
|
||||
if( HANDLE_GET_MPI_KIND( hOp ) != MPID_OP ||
|
||||
HANDLE_GET_TYPE( hOp ) == HANDLE_TYPE_INVALID )
|
||||
{
|
||||
*ppOp = nullptr;
|
||||
return MPIU_ERR_CREATE( MPI_ERR_OP, "**op" );
|
||||
}
|
||||
|
||||
*ppOp = OpPool::Lookup( hOp );
|
||||
if( *ppOp == nullptr )
|
||||
{
|
||||
return MPIU_ERR_CREATE(MPI_ERR_OP, "**nullptrtype %s", "Op" );
|
||||
}
|
||||
|
||||
if ( !rmaOp )
|
||||
{
|
||||
if ( (*ppOp)->kind == MPID_OP_REPLACE )
|
||||
{
|
||||
*ppOp = nullptr;
|
||||
return MPIU_ERR_CREATE(MPI_ERR_OP, "**replacenotallowed");
|
||||
}
|
||||
if ( (*ppOp)->kind == MPID_OP_NOOP )
|
||||
{
|
||||
*ppOp = nullptr;
|
||||
return MPIU_ERR_CREATE(MPI_ERR_OP, "**noopnotallowed");
|
||||
}
|
||||
if ( HANDLE_GET_TYPE(hOp) == HANDLE_TYPE_BUILTIN )
|
||||
{
|
||||
int mpi_errno = MPIR_Op_check_dtype_table[hOp % 16 - 1](hType);
|
||||
if (mpi_errno != MPI_SUCCESS)
|
||||
{
|
||||
*ppOp = nullptr;
|
||||
return mpi_errno;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MPI_SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* _MPI_API_ */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче